From 647b66c965f5896d784de0f321d31cc712937e1c Mon Sep 17 00:00:00 2001
From: eleanor-park <eleanor_park@brown.edu>
Date: Fri, 26 Jul 2024 01:23:06 -0400
Subject: Revert "Merge branch 'master' into eleanor-gptdraw"

This reverts commit decbefe23a1da35c838222bafe8a2c029c6ea794, reversing
changes made to 8ca26551622d36b7856f5c1865498fa9e5d888b5.
---
 src/client/views/nodes/LabelBox.tsx | 223 +++++++++++++++++++++---------------
 1 file changed, 133 insertions(+), 90 deletions(-)

(limited to 'src/client/views/nodes/LabelBox.tsx')

diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index d33d12603..f80ff5f94 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -1,17 +1,21 @@
-import { Property } from 'csstype';
-import { action, computed, makeObservable, trace } from 'mobx';
+import { action, computed, makeObservable, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import * as textfit from 'textfit';
-import { Field, FieldType } from '../../../fields/Doc';
-import { BoolCast, NumCast, StrCast } from '../../../fields/Types';
+import { Doc, DocListCast, Field, FieldType } from '../../../fields/Doc';
+import { List } from '../../../fields/List';
+import { listSpec } from '../../../fields/Schema';
+import { BoolCast, Cast, NumCast, StrCast } from '../../../fields/Types';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { Docs } from '../../documents/Documents';
 import { DragManager } from '../../util/DragManager';
+import { undoBatch } from '../../util/UndoManager';
+import { ContextMenu } from '../ContextMenu';
+import { ContextMenuProps } from '../ContextMenuItem';
 import { ViewBoxBaseComponent } from '../DocComponent';
 import { PinDocView, PinProps } from '../PinFuncs';
 import { StyleProp } from '../StyleProp';
 import { FieldView, FieldViewProps } from './FieldView';
+import BigText from './LabelBigText';
 import './LabelBox.scss';
 
 @observer
@@ -19,15 +23,28 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
     public static LayoutString(fieldKey: string) {
         return FieldView.LayoutString(LabelBox, fieldKey);
     }
+    public static LayoutStringWithTitle(fieldStr: string, label?: string) {
+        return !label ? LabelBox.LayoutString(fieldStr) : `<LabelBox fieldKey={'${fieldStr}'} label={'${label}'} {...props} />`; // e.g., "<ImageBox {...props} fieldKey={"data} />"
+    }
     private dropDisposer?: DragManager.DragDropDisposer;
-    private _timeout: NodeJS.Timeout | undefined;
-    _divRef: HTMLDivElement | null = null;
+    private _timeout: any;
 
     constructor(props: FieldViewProps) {
         super(props);
         makeObservable(this);
     }
 
+    componentDidMount() {
+        this._props.setContentViewBox?.(this);
+    }
+    componentWillUnMount() {
+        this._timeout && clearTimeout(this._timeout);
+    }
+
+    @computed get Title() {
+        return Field.toString(this.dataDoc[this.fieldKey] as FieldType) || StrCast(this.Document.title);
+    }
+
     protected createDropTarget = (ele: HTMLDivElement) => {
         this.dropDisposer?.();
         if (ele) {
@@ -35,27 +52,44 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
         }
     };
 
-    @computed get Title() {
-        return Field.toString(this.dataDoc[this.fieldKey] as FieldType) || StrCast(this.Document.title);
-    }
-
-    @computed get backgroundColor() {
-        return this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor) as string;
-    }
-
-    componentDidMount() {
-        this._props.setContentViewBox?.(this);
-    }
-    componentWillUnMount() {
-        this._timeout && clearTimeout(this._timeout);
+    get paramsDoc() {
+        return Doc.AreProtosEqual(this.layoutDoc, this.dataDoc) ? this.dataDoc : this.layoutDoc;
     }
+    specificContextMenu = (): void => {
+        const funcs: ContextMenuProps[] = [];
+        !Doc.noviceMode &&
+            funcs.push({
+                description: 'Clear Script Params',
+                event: () => {
+                    const params = Cast(this.paramsDoc['onClick-paramFieldKeys'], listSpec('string'), []);
+                    params?.forEach(p => {
+                        this.paramsDoc[p] = undefined;
+                    });
+                },
+                icon: 'trash',
+            });
 
-    specificContextMenu = (): void => {};
+        funcs.length && ContextMenu.Instance.addItem({ description: 'OnClick...', noexpand: true, subitems: funcs, icon: 'mouse-pointer' });
+    };
 
-    drop = (/* e: Event, de: DragManager.DropEvent */) => {
+    @undoBatch
+    drop = (e: Event, de: DragManager.DropEvent) => {
+        const { docDragData } = de.complete;
+        const params = Cast(this.paramsDoc['onClick-paramFieldKeys'], listSpec('string'), []);
+        const missingParams = params?.filter(p => !this.paramsDoc[p]);
+        if (docDragData && missingParams?.includes((e.target as any).textContent)) {
+            this.paramsDoc[(e.target as any).textContent] = new List<Doc>(docDragData.droppedDocuments.map((d, i) => (d.onDragStart ? docDragData.draggedDocuments[i] : d)));
+            e.stopPropagation();
+            return true;
+        }
         return false;
     };
 
+    @observable _mouseOver = false;
+    @computed get hoverColor() {
+        return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : this._props.styleProvider?.(this.Document, this._props, StyleProp.BackgroundColor);
+    }
+
     getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => {
         if (!pinProps) return this.Document;
         const anchor = Docs.Create.ConfigDocument({ title: StrCast(this.Document.title), annotationOn: this.Document });
@@ -70,92 +104,101 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
     };
 
     fitTextToBox = (
-        r: HTMLElement | null | undefined
-    ): {
-        minFontSize: number;
-        maxFontSize: number;
-        multiLine: boolean;
-        alignHoriz: boolean;
-        alignVert: boolean;
-        detectMultiLine: boolean;
-    } => {
-        this._timeout && clearTimeout(this._timeout);
-        const textfitParams = {
-            minFontSize: NumCast(this.layoutDoc._label_minFontSize, 1),
-            maxFontSize: NumCast(this.layoutDoc._label_maxFontSize, 100),
-            multiLine: BoolCast(this.layoutDoc._singleLine, true) ? false : true,
-            alignHoriz: true,
-            alignVert: true,
-            detectMultiLine: true,
+        r: any
+    ):
+        | NodeJS.Timeout
+        | {
+              rotateText: null;
+              fontSizeFactor: number;
+              minimumFontSize: number;
+              maximumFontSize: number;
+              limitingDimension: string;
+              horizontalAlign: string;
+              verticalAlign: string;
+              textAlign: string;
+              singleLine: boolean;
+              whiteSpace: string;
+          } => {
+        const singleLine = BoolCast(this.layoutDoc._singleLine, true);
+        const params = {
+            rotateText: null,
+            fontSizeFactor: 1,
+            minimumFontSize: NumCast(this.layoutDoc._label_minFontSize, 8),
+            maximumFontSize: NumCast(this.layoutDoc._label_maxFontSize, 1000),
+            limitingDimension: 'both',
+            horizontalAlign: 'center',
+            verticalAlign: 'center',
+            textAlign: 'center',
+            singleLine,
+            whiteSpace: singleLine ? 'nowrap' : 'pre-wrap',
         };
-        if (r) {
-            if (!r.offsetHeight || !r.offsetWidth) {
-                console.log("CAN'T FIT TO EMPTY BOX");
-                this._timeout && clearTimeout(this._timeout);
-                this._timeout = setTimeout(() => this.fitTextToBox(r));
-                return textfitParams;
-            }
-            textfit(r, textfitParams);
+        this._timeout = undefined;
+        if (!r) return params;
+        if (!r.offsetHeight || !r.offsetWidth) {
+            this._timeout = setTimeout(() => this.fitTextToBox(r));
+            return this._timeout;
         }
-        return textfitParams;
+        const parent = r.parentNode;
+        const parentStyle = parent.style;
+        parentStyle.display = '';
+        parentStyle.alignItems = '';
+        r.setAttribute('style', '');
+        r.style.width = singleLine ? '' : '100%';
+
+        r.style.textOverflow = 'ellipsis';
+        r.style.overflow = 'hidden';
+        BigText(r, params);
+        return params;
     };
+    // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
     render() {
-        trace();
-        const boxParams = this.fitTextToBox(undefined); // this causes mobx to trigger re-render when data changes
-        const label = this.Title.startsWith('#') ? null : this.Title;
+        const boxParams = this.fitTextToBox(null); // this causes mobx to trigger re-render when data changes
+        const params = Cast(this.paramsDoc['onClick-paramFieldKeys'], listSpec('string'), []);
+        const missingParams = params?.filter(p => !this.paramsDoc[p]);
+        params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ...
+        const label = this.Title;
         return (
-            <div key={label?.length} className="labelBox-outerDiv" ref={this.createDropTarget} onContextMenu={this.specificContextMenu} style={{ boxShadow: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BoxShadow) as string }}>
+            <div
+                className="labelBox-outerDiv"
+                onMouseLeave={action(() => {
+                    this._mouseOver = false;
+                })}
+                // eslint-disable-next-line jsx-a11y/mouse-events-have-key-events
+                onMouseOver={action(() => {
+                    this._mouseOver = true;
+                })}
+                ref={this.createDropTarget}
+                onContextMenu={this.specificContextMenu}
+                style={{ boxShadow: this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BoxShadow) }}>
                 <div
                     className="labelBox-mainButton"
                     style={{
-                        backgroundColor: this.backgroundColor,
-                        // fontSize: StrCast(this.layoutDoc._text_fontSize),
+                        backgroundColor: this.hoverColor,
+                        fontSize: StrCast(this.layoutDoc._text_fontSize),
                         color: StrCast(this.layoutDoc._color),
                         fontFamily: StrCast(this.layoutDoc._text_fontFamily) || 'inherit',
                         letterSpacing: StrCast(this.layoutDoc.letterSpacing),
-                        textTransform: StrCast(this.layoutDoc.textTransform) as Property.TextTransform,
+                        textTransform: StrCast(this.layoutDoc.textTransform) as any,
                         paddingLeft: NumCast(this.layoutDoc._xPadding),
                         paddingRight: NumCast(this.layoutDoc._xPadding),
                         paddingTop: NumCast(this.layoutDoc._yPadding),
                         paddingBottom: NumCast(this.layoutDoc._yPadding),
                         width: this._props.PanelWidth(),
                         height: this._props.PanelHeight(),
-                        whiteSpace: 'multiLine' in boxParams && boxParams.multiLine ? 'pre-wrap' : 'pre',
+                        whiteSpace: 'singleLine' in boxParams && boxParams.singleLine ? 'pre' : 'pre-wrap',
                     }}>
-                    <div
-                        style={{
-                            width: this._props.PanelWidth() - 2 * NumCast(this.layoutDoc._xPadding),
-                            height: this._props.PanelHeight() - 2 * NumCast(this.layoutDoc._yPadding),
-                            outline: 'unset !important',
-                        }}
-                        onKeyDown={action(e => {
-                            e.stopPropagation();
-                        })}
-                        onKeyUp={action(e => {
-                            e.stopPropagation();
-                            if (e.key === 'Enter') {
-                                this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? '';
-                                setTimeout(() => this._props.select(false));
-                            }
-                        })}
-                        onBlur={() => {
-                            this.dataDoc[this.fieldKey] = this._divRef?.innerText ?? '';
-                        }}
-                        contentEditable={this._props.onClickScript?.() ? false : true}
-                        ref={r => {
-                            this._divRef = r;
-                            this.fitTextToBox(r);
-                            if (this._props.isSelected() && this._divRef) {
-                                const range = document.createRange();
-                                range.setStart(this._divRef, this._divRef.childNodes.length);
-                                range.setEnd(this._divRef, this._divRef.childNodes.length);
-                                const sel = window.getSelection();
-                                sel?.removeAllRanges();
-                                sel?.addRange(range);
-                            }
-                        }}>
-                        {label}
-                    </div>
+                    <span style={{ width: 'singleLine' in boxParams ? '' : '100%' }} ref={action((r: any) => this.fitTextToBox(r))}>
+                        {label.startsWith('#') ? null : label.replace(/([^a-zA-Z])/g, '$1\u200b')}
+                    </span>
+                </div>
+                <div className="labelBox-fieldKeyParams">
+                    {!missingParams?.length
+                        ? null
+                        : missingParams.map(m => (
+                              <div key={m} className="labelBox-missingParam">
+                                  {m}
+                              </div>
+                          ))}
                 </div>
             </div>
         );
-- 
cgit v1.2.3-70-g09d2


From 22376ded1271629974bfafc31b77e3288d593c3d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 2 Oct 2024 12:24:11 -0400
Subject: added showTags button for cardView.  fixed unnecessary invalidations
 of TagsView based on child screenToLocal changing when its not rendered.

---
 src/ClientUtils.ts                                       |  7 ++-----
 src/client/util/CurrentUserUtils.ts                      |  5 +++--
 src/client/views/DashboardView.tsx                       |  8 ++++----
 src/client/views/TagsView.tsx                            | 10 ++++++++--
 src/client/views/collections/CollectionCardDeckView.tsx  | 10 ++++++----
 src/client/views/collections/CollectionDockingView.tsx   |  9 ++++-----
 .../views/collections/collectionFreeForm/MarqueeView.tsx |  3 +--
 src/client/views/global/globalScripts.ts                 | 16 +++++++++++++---
 src/client/views/nodes/LabelBox.tsx                      |  2 +-
 9 files changed, 42 insertions(+), 28 deletions(-)

(limited to 'src/client/views/nodes/LabelBox.tsx')

diff --git a/src/ClientUtils.ts b/src/ClientUtils.ts
index 01eda7e98..972910071 100644
--- a/src/ClientUtils.ts
+++ b/src/ClientUtils.ts
@@ -119,7 +119,6 @@ export namespace ClientUtils {
     }
 
     export function readUploadedFileAsText(inputFile: File) {
-        // eslint-disable-next-line no-undef
         const temporaryFileReader = new FileReader();
 
         return new Promise((resolve, reject) => {
@@ -163,7 +162,7 @@ export namespace ClientUtils {
 
     export function GetScreenTransform(ele?: HTMLElement | null): { scale: number; translateX: number; translateY: number } {
         if (!ele) {
-            return { scale: 1, translateX: 1, translateY: 1 };
+            return { scale: 0, translateX: 1, translateY: 1 };
         }
         const rect = ele.getBoundingClientRect();
         const scale = ele.offsetWidth === 0 && rect.width === 0 ? 1 : rect.width / ele.offsetWidth;
@@ -336,7 +335,7 @@ export namespace ClientUtils {
 
         try {
             document.execCommand('paste');
-        } catch (err) {
+        } catch {
             /* empty */
         }
 
@@ -575,9 +574,7 @@ export function setupMoveUpEvents(
     moveEvent: (e: PointerEvent, down: number[], delta: number[]) => boolean,
     upEvent: (e: PointerEvent, movement: number[], isClick: boolean) => void,
     clickEvent: (e: PointerEvent, doubleTap?: boolean) => unknown,
-    // eslint-disable-next-line default-param-last
     stopPropagation: boolean = true,
-    // eslint-disable-next-line default-param-last
     stopMovePropagation: boolean = true,
     noDoubleTapTimeout?: () => void
 ) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 96d69e7a1..556c8f072 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -693,8 +693,9 @@ pie title Minerals in my tap water
             { title: "Type",      icon:"eye",            toolTip:"Sort by document type",                          btnType: ButtonType.ToggleButton, expertMode: false, toolType:"docType",    funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
             { title: "Color",     icon:"palette",        toolTip:"Sort by document color",                         btnType: ButtonType.ToggleButton, expertMode: false, toolType:"color",      funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
             { title: "Tags",      icon:"bolt",           toolTip:"Sort by document's tags",                        btnType: ButtonType.ToggleButton, expertMode: false, toolType:"tag",        funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
-            { title: "Pile",      icon:"layer-group",    toolTip:"View the cards as a pile in the free form view!",btnType: ButtonType.ClickButton,  expertMode: false, toolType:"pile",       funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
-            { title: "Chat Popup",icon:"lightbulb",      toolTip:"Toggle the chat popup's visibility!", width: 45, btnType: ButtonType.ToggleButton, expertMode: false, toolType:"toggle-chat",funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
+            { title: "Pile",      icon:"layer-group",    toolTip:"View the cards as a pile in the free form view", btnType: ButtonType.ClickButton,  expertMode: false, toolType:"pile",       funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'}},
+            { title: "Chat Popup",icon:"lightbulb",      toolTip:"Toggle the chat popup's visibility", width: 45,  btnType: ButtonType.ToggleButton, expertMode: false, toolType:"toggle-chat",funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
+            { title: "Show Tags", icon:"id-card",        toolTip:"Toggle tag annotation panel",         width: 45, btnType: ButtonType.ToggleButton, expertMode: false, toolType:"toggle-tags",funcs: {}, scripts: { onClick: '{ return showFreeform(this.toolType, _readOnly_);}'} },
 
             { title: "Sort",      icon: "sort" ,         toolTip: "Manage sort order / lock status",               btnType: ButtonType.MultiToggleButton,               toolType:"alignment", ignoreClick: true,
               subMenu: [
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index eced64524..448178397 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -433,15 +433,15 @@ export class DashboardView extends ObservableReactComponent<object> {
         dashboardDoc[DocData].myPublishedDocs = new List<Doc>();
         dashboardDoc[DocData].myTagCollections = new List<Doc>();
         dashboardDoc[DocData].myUniqueFaces = new List<Doc>();
-        dashboardDoc[DocData].myTrails = DashboardView.SetupDashboardTrails(dashboardDoc);
-        dashboardDoc[DocData].myCalendars = DashboardView.SetupDashboardCalendars(dashboardDoc);
+        dashboardDoc[DocData].myTrails = DashboardView.SetupDashboardTrails();
+        dashboardDoc[DocData].myCalendars = DashboardView.SetupDashboardCalendars();
         // open this new dashboard
         Doc.ActiveDashboard = dashboardDoc;
         Doc.ActivePage = 'dashboard';
         Doc.ActivePresentation = undefined;
     };
 
-    public static SetupDashboardCalendars(dashboardDoc: Doc) {
+    public static SetupDashboardCalendars() {
         // this section is creating the button document itself  ===  myTrails = new Button
 
         //  create a a list of calendars (as a CalendarCollectionDocument) and store it on the new dashboard
@@ -470,7 +470,7 @@ export class DashboardView extends ObservableReactComponent<object> {
         return new PrefetchProxy(myCalendars);
     }
 
-    public static SetupDashboardTrails(dashboardDoc: Doc) {
+    public static SetupDashboardTrails() {
         // this section is creating the button document itself  ===  myTrails = new Button
         const reqdBtnOpts: DocumentOptions = {
             _forceActive: true,
diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx
index f44fd1d03..9858e7b61 100644
--- a/src/client/views/TagsView.tsx
+++ b/src/client/views/TagsView.tsx
@@ -274,12 +274,18 @@ export class TagsView extends ObservableReactComponent<TagViewProps> {
     @observable _currentInput = '';
     @observable _isEditing = !StrListCast(this.View.dataDoc.tags).length;
     _heightDisposer: IReactionDisposer | undefined;
+    _lastXf = this.View.screenToContentsTransform();
 
     componentDidMount() {
         this._heightDisposer = reaction(
             () => this.View.screenToContentsTransform(),
-            () => {
-                this._panelHeightDirty = this._panelHeightDirty + 1;
+            xf => {
+                if (xf.Scale === 0) return;
+                if (this.View.ComponentView?.isUnstyledView?.() || (!this.View.showTags && this._props.Views.length === 1)) return;
+                if (xf.TranslateX !== this._lastXf.TranslateX || xf.TranslateY !== this._lastXf.TranslateY || xf.Scale !== this._lastXf.Scale) {
+                    this._panelHeightDirty = this._panelHeightDirty + 1;
+                }
+                this._lastXf = xf;
             }
         );
     }
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index e5a6ebc7f..101cc8082 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -1,4 +1,4 @@
-import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, trace } from 'mobx';
+import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { ClientUtils, DashColor, returnFalse, returnZero } from '../../../ClientUtils';
@@ -139,7 +139,7 @@ export class CollectionCardView extends CollectionSubView() {
      * custom group
      */
     @computed get childDocsWithoutLinks() {
-        return this.childDocs.filter(l => l.type !== DocumentType.LINK);
+        return this.childDocs.filter(l => !l.layout_isSvg);
     }
 
     /**
@@ -402,7 +402,7 @@ export class CollectionCardView extends CollectionSubView() {
             PanelHeight={this.childPanelHeight}
             dontCenter="y" // Don't center it vertically, because the grid it's in is already doing that and we don't want to do it twice.
             dragAction={(this.Document.childDragAction ?? this._props.childDragAction) as dropActionType}
-            showTags={true}
+            showTags={BoolCast(this.layoutDoc.showChildTags)}
             dontHideOnDrag
         />
     );
@@ -607,6 +607,8 @@ export class CollectionCardView extends CollectionSubView() {
 
                 const dref = this._docRefs.get(doc);
                 const { translateX, translateY, scale } = ClientUtils.GetScreenTransform(dref?.ContentDiv);
+                if (!scale) return new Transform(0, 0, 0);
+
                 return new Transform(-translateX + (dref?.centeringX || 0) * scale, 
                                      -translateY + (dref?.centeringY || 0) * scale, 1)
                           .scale(1 / scale).rotate(!isSelected ? -this.rotate(amCards, calcRowIndex) : 0); // prettier-ignore
@@ -639,7 +641,7 @@ export class CollectionCardView extends CollectionSubView() {
                                     SnappingManager.SetIsResizing(undefined);
                                     this._forceChildXf++;
                                 }),
-                                600
+                                1000
                             );
                         }
                     })}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 028133a6e..d1304b8f4 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -203,7 +203,6 @@ export class CollectionDockingView extends CollectionSubView() {
             } else if (instance._goldenLayout.root.contentItems[0].isRow) {
                 // if row
                 switch (pullSide) {
-                    // eslint-disable-next-line default-case-last
                     default:
                     case OpenWhereMod.none:
                     case OpenWhereMod.right:
@@ -299,7 +298,7 @@ export class CollectionDockingView extends CollectionSubView() {
                     this._goldenLayout.unbind('tabCreated', this.tabCreated);
                     this._goldenLayout.unbind('tabDestroyed', this.tabDestroyed);
                     this._goldenLayout.unbind('stackCreated', this.stackCreated);
-                } catch (e) {
+                } catch {
                     /* empty */
                 }
                 this.tabMap.clear();
@@ -380,7 +379,7 @@ export class CollectionDockingView extends CollectionSubView() {
         try {
             this._goldenLayout.unbind('stackCreated', this.stackCreated);
             this._goldenLayout.unbind('tabDestroyed', this.tabDestroyed);
-        } catch (e) {
+        } catch {
             /* empty */
         }
         this._goldenLayout?.destroy();
@@ -507,8 +506,8 @@ export class CollectionDockingView extends CollectionSubView() {
         dashboardDoc.myOverlayDocs = new List<Doc>();
         dashboardDoc.myPublishedDocs = new List<Doc>();
 
-        DashboardView.SetupDashboardTrails(dashboardDoc);
-        DashboardView.SetupDashboardCalendars(dashboardDoc); // Zaul TODO: needed?
+        DashboardView.SetupDashboardTrails();
+        DashboardView.SetupDashboardCalendars(); // Zaul TODO: needed?
         return DashboardView.openDashboard(dashboardDoc);
     }
 
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index b1f6815b3..10709cc00 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -685,8 +685,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
             <div
                 className="marqueeView"
                 ref={r => {
-                    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-                    r?.addEventListener('dashDragMovePause', this.onDragMovePause as any);
+                    r?.addEventListener('dashDragMovePause', this.onDragMovePause as EventListenerOrEventListenerObject);
                     this.MarqueeRef = r;
                 }}
                 style={{
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index 0ab431740..423a2d6ef 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -18,7 +18,7 @@ import { InkTranscription } from '../InkTranscription';
 import { InkingStroke } from '../InkingStroke';
 import { MainView } from '../MainView';
 import { PropertiesView } from '../PropertiesView';
-import { CollectionFreeFormView, MarqueeView } from '../collections/collectionFreeForm';
+import { CollectionFreeFormView } from '../collections/collectionFreeForm';
 import { CollectionFreeFormDocumentView } from '../nodes/CollectionFreeFormDocumentView';
 import {
     ActiveEraserWidth,
@@ -135,7 +135,11 @@ ScriptingGlobals.add(function toggleOverlay(checkResult?: boolean) {
 });
 
 // eslint-disable-next-line prefer-arrow-callback
-ScriptingGlobals.add(function showFreeform(attr: 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce', checkResult?: boolean, persist?: boolean) {
+ScriptingGlobals.add(function showFreeform(
+    attr: 'flashcards' | 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat' | 'toggle-tags' | 'tag',
+    checkResult?: boolean,
+    persist?: boolean
+) {
     const selected = DocumentView.SelectedDocs().lastElement();
 
     function isAttrFiltered(attribute: string) {
@@ -143,7 +147,7 @@ ScriptingGlobals.add(function showFreeform(attr: 'hcenter' | 'vcenter' | 'grid'
     }
 
     // prettier-ignore
-    const map: Map<'flashcards' | 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'arrange' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat' | 'tag', 
+    const map: Map<'flashcards' | 'hcenter' | 'vcenter' | 'grid' | 'snaplines' | 'clusters' | 'viewAll' | 'fitOnce' | 'time' | 'docType' | 'color' | 'chat' | 'up' | 'down' | 'pile' | 'toggle-chat' | 'toggle-tags' | 'tag', 
     { 
         waitForRender?: boolean; 
         checkResult: (doc: Doc) => boolean; 
@@ -227,6 +231,12 @@ ScriptingGlobals.add(function showFreeform(attr: 'hcenter' | 'vcenter' | 'grid'
 
             },
         }],
+        ['toggle-tags', {
+            checkResult: (doc: Doc) => BoolCast(doc?.showChildTags),
+            setDoc: (doc: Doc, dv: DocumentView) => {
+                doc.showChildTags = !doc.showChildTags;
+            },
+        }],
         ['pile', {
             checkResult: (doc: Doc) => doc._type_collection == CollectionViewType.Freeform,
             setDoc: (doc: Doc, dv: DocumentView) => {
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index e39caecb6..8974cccaf 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -91,7 +91,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
         };
         if (r) {
             if (!r.offsetHeight || !r.offsetWidth) {
-                console.log("CAN'T FIT TO EMPTY BOX");
+                //console.log("CAN'T FIT TO EMPTY BOX");
                 this._timeout && clearTimeout(this._timeout);
                 this._timeout = setTimeout(() => this.fitTextToBox(r));
                 return textfitParams;
-- 
cgit v1.2.3-70-g09d2

