From 49cfa95fdb3653a1224d4e5e3380e111c8e2014f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 4 Mar 2024 12:55:05 -0500
Subject: changes to restore template menu and fix freeform templates to always
 show contents.   Fix for alt-dropping an image to replace another image.

---
 src/client/views/DocumentDecorations.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e9c4d9cc5..9d53c58c0 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -77,7 +77,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
                 const {x,y} = Utils.rotPt(e.clientX - center.x, 
                                           e.clientY - center.y, 
                                           NumCast(SelectionManager.Views.lastElement()?.screenToViewTransform().Rotate));
-                (this._showNothing = !(this.Bounds.x !== Number.MAX_VALUE && //
+                (this._showNothing = !DocumentButtonBar.Instance?._tooltipOpen && !(this.Bounds.x !== Number.MAX_VALUE && //
                     (this.Bounds.x > center.x+x || this.Bounds.r < center.x+x || 
                      this.Bounds.y > center.y+y || this.Bounds.b < center.y+y )));
             })); // prettier-ignore
@@ -514,7 +514,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
     //
     // determines if anything being dragged directly or via a group has a fixed aspect ratio (in which case we resize uniformly)
     //
-    hasFixedAspect = (doc: Doc): boolean => (doc.isGroup ? DocListCast(doc.data).some(this.hasFixedAspect) : !BoolCast(doc.layout_nativeDimEditable));
+    hasFixedAspect = (doc: Doc): boolean => (doc.isGroup ? DocListCast(doc.data).some(this.hasFixedAspect) : !BoolCast(doc._layout_nativeDimEditable));
 
     //
     // resize a single DocumentView about the specified reference point, possibly setting/updating the native dimensions of the Doc
-- 
cgit v1.2.3-70-g09d2


From 2e99ef0512b8f1b5c089637643ff6addf5afd943 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 4 Mar 2024 16:07:52 -0500
Subject: cleaned up a number of things related to autoHeight and
 stacking/masonry/notetaking views

---
 src/Utils.ts                                       |   7 ++
 src/client/views/ContextMenu.tsx                   |   5 +-
 src/client/views/DocumentDecorations.tsx           |  10 +-
 src/client/views/PropertiesButtons.tsx             |   3 +-
 .../views/collections/CollectionDockingView.tsx    |   6 +-
 .../collections/CollectionMasonryViewFieldRow.tsx  |  15 ++-
 .../collections/CollectionNoteTakingView.scss      |   1 +
 .../views/collections/CollectionNoteTakingView.tsx | 107 +++++++++------------
 .../collections/CollectionNoteTakingViewColumn.tsx |  22 ++---
 .../views/collections/CollectionStackingView.tsx   |  73 ++++----------
 .../CollectionStackingViewFieldColumn.tsx          |  23 +++--
 .../views/collections/CollectionTreeView.tsx       |   8 +-
 src/client/views/nodes/DocumentView.tsx            |   7 +-
 src/client/views/nodes/EquationBox.tsx             |   5 +-
 src/client/views/nodes/WebBox.tsx                  |   6 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   4 +-
 16 files changed, 136 insertions(+), 166 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index e8bd35ac4..38325a463 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -902,6 +902,13 @@ export function setupMoveUpEvents(
     document.addEventListener('click', _clickEvent, true);
 }
 
+export function DivHeight(ele: HTMLElement): number {
+    return Number(getComputedStyle(ele).height.replace('px', ''));
+}
+export function DivWidth(ele: HTMLElement): number {
+    return Number(getComputedStyle(ele).width.replace('px', ''));
+}
+
 export function dateRangeStrToDates(dateStr: string) {
     // dateStr in yyyy-mm-dd format
     const dateRangeParts = dateStr.split('|'); // splits into from and to date
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 8c3c9df2e..8f4e43978 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -7,6 +7,7 @@ import { SettingsManager } from '../util/SettingsManager';
 import './ContextMenu.scss';
 import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from './ContextMenuItem';
 import { ObservableReactComponent } from './ObservableReactComponent';
+import { DivHeight, DivWidth } from '../../Utils';
 
 @observer
 export class ContextMenu extends ObservableReactComponent<{}> {
@@ -214,8 +215,8 @@ export class ContextMenu extends ObservableReactComponent<{}> {
                 className="contextMenu-cont"
                 ref={action((r: any) => {
                     if (r) {
-                        this._width = Number(getComputedStyle(r).width.replace('px', ''));
-                        this._height = Number(getComputedStyle(r).height.replace('px', ''));
+                        this._width = DivWidth(r);
+                        this._height = DivHeight(r);
                     }
                 })}
                 style={{
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9d53c58c0..87ee962a0 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -562,7 +562,13 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
             doc.y = NumCast(doc.y) + deltaY;
 
             doc._layout_modificationDate = new DateField();
-            scale.y !== 1 && (doc._layout_autoHeight = undefined);
+            if (scale.y !== 1) {
+                docView.layoutDoc._layout_autoHeight = undefined;
+                if (docView.layoutDoc._layout_autoHeight) {
+                    // if autoHeight is still on because of a prototype
+                    docView.layoutDoc._layout_autoHeight = false; // then don't inherit, but explicitly set it to false
+                }
+            }
         }
     };
 
@@ -597,7 +603,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
         this._resizeUndo?.end();
 
         // detect layout_autoHeight gesture and apply
-        SelectionManager.Docs.forEach(doc => NumCast(doc._height) < 20 && (doc._layout_autoHeight = true));
+        SelectionManager.Views.forEach(view => NumCast(view.Document._height) < 20 && (view.layoutDoc._layout_autoHeight = true));
         //need to change points for resize, or else rotation/control points will fail.
         this._inkDragDocs
             .map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index cb38ab602..3cb835e39 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -486,8 +486,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         const isImage = layoutField instanceof ImageField;
         const isMap = this.selectedDoc?.type === DocumentType.MAP;
         const isCollection = this.selectedDoc?.type === DocumentType.COL;
-        //TODO: will likely need to create separate note-taking view type here
-        const isStacking = this.selectedDoc?._type_collection === CollectionViewType.Stacking || this.selectedDoc?._type_collection === CollectionViewType.NoteTaking;
+        const isStacking = [CollectionViewType.Stacking, CollectionViewType.Masonry, CollectionViewType.NoteTaking].includes(this.selectedDoc?._type_collection as any);
         const isFreeForm = this.selectedDoc?._type_collection === CollectionViewType.Freeform;
         const isTree = this.selectedDoc?._type_collection === CollectionViewType.Tree;
         const isTabView = this.selectedTabView;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index d9d6a5eb5..8f1633122 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -11,7 +11,7 @@ import { List } from '../../../fields/List';
 import { ImageCast, NumCast, StrCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { GetEffectiveAcl, inheritParentAcls } from '../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, incrementTitleCopy } from '../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivHeight, DivWidth, emptyFunction, incrementTitleCopy } from '../../../Utils';
 import { DocServer } from '../../DocServer';
 import { Docs } from '../../documents/Documents';
 import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
@@ -432,8 +432,8 @@ export class CollectionDockingView extends CollectionSubView() {
     public CaptureThumbnail() {
         const content = this.DocumentView?.()?.ContentDiv;
         if (content) {
-            const _width = Number(getComputedStyle(content).width.replace('px', ''));
-            const _height = Number(getComputedStyle(content).height.replace('px', ''));
+            const _width = DivWidth(content);
+            const _height = DivHeight(content);
             return CollectionFreeFormView.UpdateIcon(this.layoutDoc[Id] + '-icon' + new Date().getTime(), content, _width, _height, _width, _height, 0, 1, true, this.layoutDoc[Id] + '-icon', (iconFile, _nativeWidth, _nativeHeight) => {
                 const proto = this.dataDoc; // Cast(img.proto, Doc, null)!;
                 proto['thumb_nativeWidth'] = _width;
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 41c5d5b42..763d2e3a6 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -33,8 +33,7 @@ interface CMVFieldRowProps {
     createDropTarget: (ele: HTMLDivElement) => void;
     screenToLocalTransform: () => Transform;
     setDocHeight: (key: string, thisHeight: number) => void;
-    observeHeight: (myref: any) => void;
-    unobserveHeight: (myref: any) => void;
+    refList: any[];
     showHandle: boolean;
 }
 
@@ -68,20 +67,20 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF
 
     createRowDropRef = (ele: HTMLDivElement | null) => {
         this._dropDisposer?.();
-        if (ele) {
-            this._ele = ele;
-            this._props.observeHeight(ele);
-            this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this), this._props.Document);
-        }
+        if (ele) this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this), this._props.Document);
+        else if (this._ele) this.props.refList.splice(this.props.refList.indexOf(this._ele), 1);
+        this._ele = ele;
     };
     @action
     componentDidMount() {
         this.heading = this._props.headingObject?.heading || '';
         this.color = this._props.headingObject?.color || '#f1efeb';
         this.collapsed = this._props.headingObject?.collapsed || false;
+        this._ele && this.props.refList.push(this._ele);
     }
     componentWillUnmount() {
-        this._props.unobserveHeight(this._ele);
+        this._ele && this.props.refList.splice(this.props.refList.indexOf(this._ele), 1);
+        this._ele = null;
     }
 
     getTrueHeight = () => {
diff --git a/src/client/views/collections/CollectionNoteTakingView.scss b/src/client/views/collections/CollectionNoteTakingView.scss
index 91a82d40f..4c2dcf9ab 100644
--- a/src/client/views/collections/CollectionNoteTakingView.scss
+++ b/src/client/views/collections/CollectionNoteTakingView.scss
@@ -98,6 +98,7 @@
         overflow: auto;
         display: flex;
         flex-direction: column;
+        height: max-content;
     }
 
     .collectionSchemaView-previewDoc {
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index b8133806f..6318620e0 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, observe, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Doc, Field, Opt } from '../../../fields/Doc';
@@ -9,7 +9,7 @@ import { listSpec } from '../../../fields/Schema';
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnFalse, returnZero, smoothScroll, Utils } from '../../../Utils';
+import { DivHeight, emptyFunction, returnFalse, returnZero, smoothScroll, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DragManager, dropActionType } from '../../util/DragManager';
 import { SnappingManager } from '../../util/SnappingManager';
@@ -45,6 +45,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     public DividerWidth = 16;
     @observable docsDraggedRowCol: number[] = [];
     @observable _scroll = 0;
+    @observable _refList: any[] = [];
 
     constructor(props: any) {
         super(props);
@@ -157,8 +158,16 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         document.addEventListener('pointerup', this.removeDocDragHighlight, true);
         this._disposers.layout_autoHeight = reaction(
             () => this.layoutDoc._layout_autoHeight,
-            layout_autoHeight =>
-                layout_autoHeight && this._props.setHeight?.(Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), this.headerMargin + Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', ''))))))
+            layout_autoHeight => layout_autoHeight && this._props.setHeight?.(this.headerMargin + Math.max(...this._refList.map(DivHeight)))
+        );
+
+        this._disposers.refList = reaction(
+            () => ({ refList: this._refList.slice(), autoHeight: this.layoutDoc._layout_autoHeight && !LightboxView.Contains(this.DocumentView?.()) }),
+            ({ refList, autoHeight }) => {
+                if (autoHeight) refList.forEach(r => this.observer.observe(r));
+                else this.observer.disconnect();
+            },
+            { fireImmediately: true }
         );
     }
 
@@ -345,7 +354,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
             // get the index for where you need to insert the doc you are currently dragging
             const clientY = this.ScreenToLocalBoxXf().transformPoint(ex, ey)[1];
             let dropInd = -1;
-            let pos0 = (this.refList.lastElement() as HTMLDivElement).children[0].getBoundingClientRect().height + this.yMargin * 2;
+            let pos0 = (this._refList.lastElement() as HTMLDivElement).children[0].getBoundingClientRect().height + this.yMargin * 2;
             colDocs.forEach((doc, i) => {
                 let pos1 = this.getDocHeight(doc) + 2 * this.gridGap;
                 pos1 += pos0;
@@ -424,7 +433,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
             if (super.onInternalDrop(e, de)) {
                 // filter out the currently dragged docs from the child docs, since we will insert them later
                 const rowCol = this.docsDraggedRowCol;
-                const droppedDocs = this.childDocs.slice().filter((d: Doc, ind: number) => ind >= this.childDocs.length); // if the drop operation adds something to the end of the list, then use that as the new document (may be different than what was dropped e.g., in the case of a button which is dropped but which creates say, a note).
+                const droppedDocs = this.childDocs.filter((d: Doc, ind: number) => ind >= this.childDocs.length); // if the drop operation adds something to the end of the list, then use that as the new document (may be different than what was dropped e.g., in the case of a button which is dropped but which creates say, a note).
                 const newDocs = droppedDocs.length ? droppedDocs : de.complete.docDragData.droppedDocuments;
                 const docs = this.childDocList;
                 if (docs && newDocs.length) {
@@ -489,65 +498,45 @@ export class CollectionNoteTakingView extends CollectionSubView() {
 
     headings = () => Array.from(this.Sections);
 
-    refList: any[] = [];
-
     editableViewProps = () => ({
         GetValue: () => '',
         SetValue: this.addGroup,
         contents: '+ New Column',
     });
 
+    refList = () => this._refList;
+
     // sectionNoteTaking returns a CollectionNoteTakingViewColumn (which is an individual column)
-    sectionNoteTaking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
-        const type = 'number';
-        return (
-            <CollectionNoteTakingViewColumn
-                key={heading?.heading ?? 'unset'}
-                unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
-                observeHeight={ref => {
-                    if (ref) {
-                        this.refList.push(ref);
-                        this.observer = new _global.ResizeObserver(
-                            action((entries: any) => {
-                                if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) {
-                                    const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))));
-                                    if (!LightboxView.Contains(this.DocumentView?.())) {
-                                        this._props.setHeight?.(height);
-                                    }
-                                }
-                            })
-                        );
-                        this.observer.observe(ref);
-                    }
-                }}
-                PanelWidth={this._props.PanelWidth}
-                select={this._props.select}
-                addDocument={this.addDocument}
-                chromeHidden={this.chromeHidden}
-                colHeaderData={this.colHeaderData}
-                Document={this.Document}
-                TemplateDataDocument={this._props.TemplateDataDocument}
-                resizeColumns={this.resizeColumns}
-                renderChildren={this.children}
-                numGroupColumns={this.numGroupColumns}
-                gridGap={this.gridGap}
-                pivotField={this.notetakingCategoryField}
-                fieldKey={this.fieldKey}
-                dividerWidth={this.DividerWidth}
-                maxColWidth={this.maxColWidth}
-                availableWidth={this.availableWidth}
-                headings={this.headings}
-                heading={heading?.heading ?? 'unset'}
-                headingObject={heading}
-                docList={docList}
-                yMargin={this.yMargin}
-                type={type}
-                createDropTarget={this.createDashEventsTarget}
-                screenToLocalTransform={this.ScreenToLocalBoxXf}
-                editableViewProps={this.editableViewProps}
-            />
-        );
-    };
+    sectionNoteTaking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => (
+        <CollectionNoteTakingViewColumn
+            key={heading?.heading ?? 'unset'}
+            PanelWidth={this._props.PanelWidth}
+            refList={this._refList}
+            select={this._props.select}
+            addDocument={this.addDocument}
+            chromeHidden={this.chromeHidden}
+            colHeaderData={this.colHeaderData}
+            Document={this.Document}
+            TemplateDataDocument={this._props.TemplateDataDocument}
+            resizeColumns={this.resizeColumns}
+            renderChildren={this.children}
+            numGroupColumns={this.numGroupColumns}
+            gridGap={this.gridGap}
+            pivotField={this.notetakingCategoryField}
+            fieldKey={this.fieldKey}
+            dividerWidth={this.DividerWidth}
+            maxColWidth={this.maxColWidth}
+            availableWidth={this.availableWidth}
+            headings={this.headings}
+            heading={heading?.heading ?? 'unset'}
+            headingObject={heading}
+            docList={docList}
+            yMargin={this.yMargin}
+            createDropTarget={this.createDashEventsTarget}
+            screenToLocalTransform={this.ScreenToLocalBoxXf}
+            editableViewProps={this.editableViewProps}
+        />
+    );
 
     // addGroup is called when adding a new columnHeader, adding a SchemaHeaderField to our list of
     // columnHeaders and resizing the existing columns to make room for our new one.
@@ -619,7 +608,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         return this.isContentActive() === false ? 'none' : undefined;
     }
 
-    observer: any;
+    observer = new _global.ResizeObserver(() => this._props.setHeight?.(this.headerMargin + Math.max(...this._refList.map(DivHeight))));
 
     render() {
         TraceMobx();
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 38846c79d..db178d500 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -36,15 +36,13 @@ interface CSVFieldColumnProps {
     yMargin: number;
     numGroupColumns: number;
     gridGap: number;
-    type: 'string' | 'number' | 'bigint' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function' | undefined;
     headings: () => object[];
     select: (ctrlPressed: boolean) => void;
     renderChildren: (docs: Doc[]) => JSX.Element[];
     addDocument: (doc: Doc | Doc[]) => boolean;
     createDropTarget: (ele: HTMLDivElement) => void;
     screenToLocalTransform: () => Transform;
-    observeHeight: (myref: any) => void;
-    unobserveHeight: (myref: any) => void;
+    refList: any[];
     editableViewProps: () => any;
     resizeColumns: (headers: SchemaHeaderField[]) => boolean;
     maxColWidth: number;
@@ -78,15 +76,18 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
 
     createColumnDropRef = (ele: HTMLDivElement | null) => {
         this.dropDisposer?.();
-        if (ele) {
-            this._ele = ele;
-            this._props.observeHeight(ele);
-            this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document);
-        }
+        if (ele) this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document);
+        else if (this._ele) this.props.refList.slice(this.props.refList.indexOf(this._ele), 1);
+        this._ele = ele;
     };
 
+    componentDidMount(): void {
+        this._ele && this.props.refList.push(this._ele);
+    }
+
     componentWillUnmount() {
-        this._props.unobserveHeight(this._ele);
+        this._ele && this.props.refList.splice(this._props.refList.indexOf(this._ele), 1);
+        this._ele = null;
     }
 
     @undoBatch
@@ -289,11 +290,10 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
 
     render() {
         TraceMobx();
-        const heading = this._heading;
         return (
             <div
                 className="collectionNoteTakingViewFieldColumn"
-                key={heading}
+                key={this._heading}
                 style={{
                     width: this.columnWidth,
                     background: this._background,
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 54314f62c..dc391631a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -11,12 +11,11 @@ import { listSpec } from '../../../fields/Schema';
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
 import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnFalse, returnNone, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils';
+import { DivHeight, emptyFunction, returnEmptyDoclist, returnFalse, returnNone, returnZero, setupMoveUpEvents, smoothScroll, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { CollectionViewType } from '../../documents/DocumentTypes';
 import { DragManager, dropActionType } from '../../util/DragManager';
 import { SettingsManager } from '../../util/SettingsManager';
-import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
 import { undoBatch, UndoManager } from '../../util/UndoManager';
 import { ContextMenu } from '../ContextMenu';
@@ -45,17 +44,16 @@ export type collectionStackingViewProps = {
 
 @observer
 export class CollectionStackingView extends CollectionSubView<Partial<collectionStackingViewProps>>() {
+    _disposers: { [key: string]: IReactionDisposer } = {};
     _masonryGridRef: HTMLDivElement | null = null;
     // used in a column dragger, likely due for the masonry grid view. We want to use this
     _draggerRef = React.createRef<HTMLDivElement>();
-    // Not sure what a pivot field is. Seems like we cause reaction in MobX get rid of it once we exit this view
-    _pivotFieldDisposer?: IReactionDisposer;
-    // Seems like we cause reaction in MobX get rid of our height once we exit this view
-    _layout_autoHeightDisposer?: IReactionDisposer;
     // keeping track of documents. Updated on internal and external drops. What's the difference?
     _docXfs: { height: () => number; width: () => number; stackedDocTransform: () => Transform }[] = [];
     // Doesn't look like this field is being used anywhere. Obsolete?
     _columnStart: number = 0;
+
+    @observable _refList: any[] = [];
     // map of node headers to their heights. Used in Masonry
     @observable _heightMap = new Map<string, number>();
     // Assuming that this is the current css cursor style
@@ -207,27 +205,27 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         this._props.setContentViewBox?.(this);
 
         // reset section headers when a new filter is inputted
-        this._pivotFieldDisposer = reaction(
+        this._disposers.pivotField = reaction(
             () => this.pivotField,
             () => (this.dataDoc['_' + this.fieldKey + '_columnHeaders'] = new List())
         );
-        this._layout_autoHeightDisposer = reaction(
+        this._disposers.autoHeight = reaction(
             () => this.layoutDoc._layout_autoHeight,
-            layout_autoHeight =>
-                layout_autoHeight &&
-                this._props.setHeight?.(
-                    Math.min(
-                        NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER),
-                        this.headerMargin + (this.isStackingView ? Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))) : this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0))
-                    )
-                )
+            layout_autoHeight => layout_autoHeight && this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : this._refList.reduce((p, r) => p + DivHeight(r), 0)))
+        );
+        this._disposers.refList = reaction(
+            () => ({ refList: this._refList.slice(), autoHeight: this.layoutDoc._layout_autoHeight && !LightboxView.Contains(this.DocumentView?.()) }),
+            ({ refList, autoHeight }) => {
+                this.observer.disconnect();
+                if (autoHeight) refList.forEach(r => this.observer.observe(r));
+            },
+            { fireImmediately: true }
         );
     }
 
     componentWillUnmount() {
         super.componentWillUnmount();
-        this._pivotFieldDisposer?.();
-        this._layout_autoHeightDisposer?.();
+        Object.keys(this._disposers).forEach(key => this._disposers[key]());
     }
 
     isAnyChildContentActive = () => this._props.isAnyChildContentActive();
@@ -523,7 +521,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         });
     };
     headings = () => Array.from(this.Sections);
-    refList: any[] = [];
     // what a section looks like if we're in stacking view
     sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
         const key = this.pivotField;
@@ -536,23 +533,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         }
         return (
             <CollectionStackingViewFieldColumn
-                unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
-                observeHeight={ref => {
-                    if (ref) {
-                        this.refList.push(ref);
-                        this.observer = new _global.ResizeObserver(
-                            action((entries: any) => {
-                                if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) {
-                                    const height = this.headerMargin + Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), Math.max(...this.refList.map(r => Number(getComputedStyle(r).height.replace('px', '')))));
-                                    if (!LightboxView.Contains(this.DocumentView?.())) {
-                                        this._props.setHeight?.(height);
-                                    }
-                                }
-                            })
-                        );
-                        this.observer.observe(ref);
-                    }
-                }}
+                refList={this._refList}
                 addDocument={this.addDocument}
                 chromeHidden={this.chromeHidden}
                 colHeaderData={this.colHeaderData}
@@ -591,21 +572,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 Document={this.Document}
                 chromeHidden={this.chromeHidden}
                 pivotField={this.pivotField}
-                unobserveHeight={ref => this.refList.splice(this.refList.indexOf(ref), 1)}
-                observeHeight={ref => {
-                    if (ref) {
-                        this.refList.push(ref);
-                        this.observer = new _global.ResizeObserver(
-                            action((entries: any) => {
-                                if (this.layoutDoc._layout_autoHeight && ref && this.refList.length && !SnappingManager.IsDragging) {
-                                    const height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), 0);
-                                    this._props.setHeight?.(2 * this.headerMargin + height); // bcz: added 2x for header to fix problem with scrollbars appearing in Tools panel
-                                }
-                            })
-                        );
-                        this.observer.observe(ref);
-                    }
-                }}
+                refList={this._refList}
                 key={heading ? heading.heading : ''}
                 rows={rows}
                 headings={this.headings}
@@ -709,7 +676,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     @computed get backgroundEvents() {
         return this._props.isContentActive() === false ? 'none' : undefined;
     }
-    observer: any;
+
+    observer = new _global.ResizeObserver(() => this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : this._refList.reduce((p, r) => p + DivHeight(r), 0))));
+
     render() {
         TraceMobx();
         const editableViewProps = {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index c455f20d8..6a3cb759e 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -9,7 +9,7 @@ import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, NumCast } from '../../../fields/Types';
 import { ImageField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnEmptyString, setupMoveUpEvents } from '../../../Utils';
+import { DivHeight, DivWidth, emptyFunction, returnEmptyString, setupMoveUpEvents } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DragManager } from '../../util/DragManager';
@@ -44,8 +44,7 @@ interface CSVFieldColumnProps {
     addDocument: (doc: Doc | Doc[]) => boolean;
     createDropTarget: (ele: HTMLDivElement) => void;
     screenToLocalTransform: () => Transform;
-    observeHeight: (myref: any) => void;
-    unobserveHeight: (myref: any) => void;
+    refList: any[];
 }
 
 @observer
@@ -53,7 +52,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
     private dropDisposer?: DragManager.DragDropDisposer;
     private _disposers: { [name: string]: IReactionDisposer } = {};
     private _headerRef: React.RefObject<HTMLDivElement> = React.createRef();
-    @observable private _background = 'inherit';
+    @observable _background = 'inherit';
     @observable _paletteOn = false;
     @observable _heading = '';
     @observable _color = '';
@@ -71,15 +70,14 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
     // is that the only way to have drop targets?
     createColumnDropRef = (ele: HTMLDivElement | null) => {
         this.dropDisposer?.();
-        if (ele) {
-            this._ele = ele;
-            this._props.observeHeight(ele);
-            this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document);
-        }
+        if (ele) this.dropDisposer = DragManager.MakeDropTarget(ele, this.columnDrop.bind(this), this._props.Document);
+        else if (this._ele) this.props.refList.splice(this.props.refList.indexOf(this._ele), 1);
+        this._ele = ele;
     };
 
     @action
     componentDidMount() {
+        this._ele && this.props.refList.push(this._ele);
         this._disposers.collapser = reaction(
             () => this._props.headingObject?.collapsed,
             collapsed => (this.collapsed = collapsed !== undefined ? BoolCast(collapsed) : false),
@@ -88,7 +86,8 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
     }
     componentWillUnmount() {
         this._disposers.collapser?.();
-        this._props.unobserveHeight(this._ele);
+        this._ele && this.props.refList.splice(this.props.refList.indexOf(this._ele), 1);
+        this._ele = null;
     }
 
     //TODO: what is scripting? I found it in SetInPlace def but don't know what that is
@@ -217,8 +216,8 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
         const layoutItems: ContextMenuProps[] = [];
         const docItems: ContextMenuProps[] = [];
         const dataDoc = this._props.TemplateDataDocument || this._props.Document;
-        const width = this._ele ? Number(getComputedStyle(this._ele).width.replace('px', '')) : 0;
-        const height = this._ele ? Number(getComputedStyle(this._ele).height.replace('px', '')) : 0;
+        const width = this._ele ? DivWidth(this._ele) : 0;
+        const height = this._ele ? DivHeight(this._ele) : 0;
         DocUtils.addDocumentCreatorMenuItems(
             doc => {
                 FormattedTextBox.SetSelectOnLoad(doc);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4d60cbefc..3b37bdcfa 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -8,7 +8,7 @@ import { listSpec } from '../../../fields/Schema';
 import { ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero, Utils } from '../../../Utils';
+import { DivHeight, emptyFunction, returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnNone, returnOne, returnTrue, returnZero, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager, dropActionType } from '../../util/DragManager';
@@ -113,8 +113,8 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
 
     computeHeight = () => {
         if (!this._isDisposing) {
-            const titleHeight = !this._titleRef ? this.marginTop() : Number(getComputedStyle(this._titleRef).height.replace('px', ''));
-            const bodyHeight = Array.from(this.refList).reduce((p, r) => p + Number(getComputedStyle(r).height.replace('px', '')), this.marginBot()) + 6;
+            const titleHeight = !this._titleRef ? this.marginTop() : DivHeight(this._titleRef);
+            const bodyHeight = Array.from(this.refList).reduce((p, r) => p + DivHeight(r), this.marginBot()) + 6;
             this.layoutDoc._layout_autoHeightMargins = bodyHeight;
             !this._props.dontRegisterView && this._props.setHeight?.(bodyHeight + titleHeight);
         }
@@ -420,7 +420,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
         return (
             <div style={{ display: 'flex', flexDirection: 'column', height: '100%', pointerEvents: 'all' }}>
                 {!this.buttonMenu && !this.noviceExplainer ? null : (
-                    <div className="documentButtonMenu" ref={action((r: HTMLDivElement | null) => r && (this._headerHeight = Number(getComputedStyle(r).height.replace(/px/, ''))))}>
+                    <div className="documentButtonMenu" ref={action((r: HTMLDivElement | null) => r && (this._headerHeight = DivHeight(r)))}>
                         {this.buttonMenu}
                         {this.noviceExplainer}
                     </div>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b0e8cf6ff..ee058c085 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,11 +1,10 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { Dropdown, DropdownType, Type } from 'browndash-components';
 import { Howl } from 'howler';
 import { IReactionDisposer, action, computed, makeObservable, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Bounce, Fade, Flip, JackInTheBox, Roll, Rotate, Zoom } from 'react-awesome-reveal';
-import { Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils';
+import { DivWidth, Utils, emptyFunction, isTargetChildOf as isParentOf, lightOrDark, returnEmptyString, returnFalse, returnTrue, returnVal, simulateMouseClick } from '../../../Utils';
 import { Doc, DocListCast, Field, Opt, StrListCast } from '../../../fields/Doc';
 import { AclPrivate, Animation, AudioPlay, DocData, DocViews } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
@@ -703,7 +702,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
     panelHeight = () => this._props.PanelHeight() - this.headerMargin;
     screenToLocalContent = () => this._props.ScreenToLocalTransform().translate(0, -this.headerMargin);
     onClickFunc = this.disableClickScriptFunc ? undefined : () => this.onClickHandler;
-    setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = height);
+    setHeight = (height: number) => !this._props.suppressSetHeight && (this.layoutDoc._height = Math.min(NumCast(this.layoutDoc._maxHeight, Number.MAX_SAFE_INTEGER), height));
     setContentView = action((view: ViewBoxInterface) => (this._componentView = view));
     isContentActive = (): boolean | undefined => this._isContentActive;
     childFilters = () => [...this._props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
@@ -788,7 +787,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
     fieldsDropdown = (placeholder: string) => {
         return (
             <div
-                ref={action((r: any) => r && (this._titleDropDownInnerWidth = Number(getComputedStyle(r).width.replace('px', ''))))}
+                ref={action((r: any) => r && (this._titleDropDownInnerWidth = DivWidth(r)))}
                 onPointerDown={action(e => (this._changingTitleField = true))}
                 style={{ width: 'max-content', background: SettingsManager.userBackgroundColor, color: SettingsManager.userColor, transformOrigin: 'left', transform: `scale(${this.titleHeight / 30 /* height of Dropdown */})` }}>
                 <FieldsDropdown
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index 2e03a766a..50d4c7c78 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -11,6 +11,7 @@ import { LightboxView } from '../LightboxView';
 import './EquationBox.scss';
 import { FieldView, FieldViewProps } from './FieldView';
 import EquationEditor from './formattedText/EquationEditor';
+import { DivHeight, DivWidth } from '../../../Utils';
 
 @observer
 export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -57,8 +58,8 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @action
     keyPressed = (e: KeyboardEvent) => {
-        const _height = Number(getComputedStyle(this._ref.current!.element.current).height.replace('px', ''));
-        const _width = Number(getComputedStyle(this._ref.current!.element.current).width.replace('px', ''));
+        const _height = DivHeight(this._ref.current!.element.current);
+        const _width = DivWidth(this._ref.current!.element.current);
         if (e.key === 'Enter') {
             const nextEq = Docs.Create.EquationDocument(e.shiftKey ? StrCast(this.dataDoc.text) : 'x', {
                 title: '# math',
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 2c5398e40..c9340edc0 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -14,7 +14,7 @@ import { listSpec } from '../../../fields/Schema';
 import { Cast, NumCast, StrCast, WebCast } from '../../../fields/Types';
 import { ImageField, WebField } from '../../../fields/URLField';
 import { TraceMobx } from '../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, getWordAtPoint, lightOrDark, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, stringHash, Utils } from '../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivHeight, emptyFunction, getWordAtPoint, lightOrDark, returnFalse, returnOne, returnZero, setupMoveUpEvents, smoothScroll, stringHash, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
@@ -83,7 +83,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
         return this.webField?.toString() || '';
     }
     @computed get _urlHash() {
-        return ""+ (stringHash(this._url)??'');
+        return '' + (stringHash(this._url) ?? '');
     }
     @computed get scrollHeight() {
         return Math.max(NumCast(this.layoutDoc._height), this._scrollHeight);
@@ -782,7 +782,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implem
                     className="webBox-htmlSpan"
                     ref={action((r: any) => {
                         if (r) {
-                            this._scrollHeight = Number(getComputedStyle(r).height.replace('px', ''));
+                            this._scrollHeight = DivHeight(r);
                             this.lighttext = Array.from(r.children).some((c: any) => c instanceof HTMLElement && lightOrDark(getComputedStyle(c).color) !== Colors.WHITE);
                         }
                     })}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 56008de8e..266a2442f 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -23,7 +23,7 @@ import { RichTextField } from '../../../../fields/RichTextField';
 import { ComputedField } from '../../../../fields/ScriptField';
 import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, DivWidth, emptyFunction, numberRange, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils';
 import { gptAPICall, GPTCallType } from '../../../apis/gpt/GPT';
 import { DocServer } from '../../../DocServer';
 import { Docs, DocUtils } from '../../../documents/Documents';
@@ -758,7 +758,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     @action
     toggleSidebar = (preview: boolean = false) => {
         const defaultSidebar = 250;
-        const prevWidth = 1 - this.sidebarWidth() / Number(getComputedStyle(this._ref.current!).width.replace('px', ''));
+        const prevWidth = 1 - this.sidebarWidth() / DivWidth(this._ref.current!);
         if (preview) this._showSidebar = true;
         else {
             this.layoutDoc[this.SidebarKey + '_freeform_scale_max'] = 1;
-- 
cgit v1.2.3-70-g09d2


From b938ac2909290bd5dd11eeb0a0056f4679dbb25e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 7 Mar 2024 10:24:56 -0500
Subject: fixed several things related to templates for labels (used as icons)
 and  FontIconboxes. Also made labels non uniformly  resizable .

---
 src/client/documents/Documents.ts                        | 16 +++++++---------
 src/client/util/CurrentUserUtils.ts                      | 16 +++++++++-------
 src/client/views/DocumentDecorations.tsx                 | 10 +++++-----
 .../collectionFreeForm/CollectionFreeFormView.tsx        | 12 ++++++++----
 src/client/views/nodes/FontIconBox/FontIconBox.tsx       |  8 ++++++--
 src/client/views/nodes/LabelBox.tsx                      | 10 +++-------
 6 files changed, 38 insertions(+), 34 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index d41cd24d4..b7d8222b9 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -277,8 +277,8 @@ export class DocumentOptions {
     layout_borderRounding?: string;
     _layout_modificationDate?: DATEt = new DateInfo('last modification date of doc layout', false);
     _layout_nativeDimEditable?: BOOLt = new BoolInfo('native dimensions can be modified using document decoration reizers', false);
-    _layout_reflowVertical?: BOOLt = new BoolInfo('native height can be changed independent of width by dragging decoration resizers');
-    _layout_reflowHorizontal?: BOOLt = new BoolInfo('whether a doc with a native size can be horizonally resized, causing some form of reflow');
+    _layout_reflowVertical?: BOOLt = new BoolInfo('permit vertical resizing with content "reflow"');
+    _layout_reflowHorizontal?: BOOLt = new BoolInfo('permit horizontal resizing with content reflow');
     layout_boxShadow?: string; // box-shadow css string OR "standard" to use dash standard box shadow
     layout_maxShown?: NUMt = new NumInfo('maximum number of children to display at one time (see multicolumnview)');
     _layout_autoHeight?: BOOLt = new BoolInfo('whether document automatically resizes vertically to display contents');
@@ -317,7 +317,6 @@ export class DocumentOptions {
     _label_minFontSize?: NUMt = new NumInfo('minimum font size for labelBoxes', false);
     _label_maxFontSize?: NUMt = new NumInfo('maximum font size for labelBoxes', false);
     stroke_width?: NUMt = new NumInfo('width of an ink stroke', false);
-    icon_label?: STRt = new StrInfo('label to use for a fontIcon doc (otherwise, the title is used)', false);
     mediaState?: STRt = new StrInfo(`status of audio/video media document: ${media_state.PendingRecording}, ${media_state.Recording}, ${media_state.Paused}, ${media_state.Playing}`, false);
     recording?: BOOLt = new BoolInfo('whether WebCam is recording or not');
     slides?: DOCt = new DocInfo('presentation slide associated with video recording (bcz: should be renamed!!)');
@@ -652,8 +651,8 @@ export namespace Docs {
             [
                 DocumentType.LABEL,
                 {
-                    layout: { view: LabelBox, dataField: defaultDataKey },
-                    options: { _singleLine: true },
+                    layout: { view: LabelBox, dataField: 'title' },
+                    options: { _singleLine: true, layout_nativeDimEditable: true, layout_reflowHorizontal: true, layout_reflowVertical: true },
                 },
             ],
             [
@@ -684,8 +683,8 @@ export namespace Docs {
             [
                 DocumentType.BUTTON,
                 {
-                    layout: { view: LabelBox, dataField: 'onClick' },
-                    options: {},
+                    layout: { view: LabelBox, dataField: 'title' },
+                    options: { layout_nativeDimEditable: true, layout_reflowHorizontal: true, layout_reflowVertical: true },
                 },
             ],
             [
@@ -1881,8 +1880,7 @@ export namespace DocUtils {
         const hasContextAnchor = LinkManager.Links(doc).some(l => (l.link_anchor_2 === doc && Cast(l.link_anchor_1, Doc, null)?.annotationOn === context) || (l.link_anchor_1 === doc && Cast(l.link_anchor_2, Doc, null)?.annotationOn === context));
         if (context && !hasContextAnchor && (context.type === DocumentType.VID || context.type === DocumentType.WEB || context.type === DocumentType.PDF || context.type === DocumentType.IMG)) {
             const pushpin = Docs.Create.FontIconDocument({
-                title: 'pushpin',
-                icon_label: '',
+                title: '',
                 annotationOn: Cast(doc.annotationOn, Doc, null),
                 followLinkToggle: true,
                 icon: 'map-pin',
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 310613bc9..cfba003fc 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -22,7 +22,7 @@ import { CollectionTreeView, TreeViewType } from "../views/collections/Collectio
 import { Colors } from "../views/global/globalEnums";
 import { media_state } from "../views/nodes/AudioBox";
 import { OpenWhere } from "../views/nodes/DocumentView";
-import { ButtonType } from "../views/nodes/FontIconBox/FontIconBox";
+import { ButtonType, FontIconBox } from "../views/nodes/FontIconBox/FontIconBox";
 import { ImportElementBox } from "../views/nodes/importBox/ImportElementBox";
 import { DragManager, dropActionType } from "./DragManager";
 import { MakeTemplate } from "./DropConverter";
@@ -32,6 +32,8 @@ import { ScriptingGlobals } from "./ScriptingGlobals";
 import { ColorScheme } from "./SettingsManager";
 import { SnappingManager } from "./SnappingManager";
 import { UndoManager } from "./UndoManager";
+import { LabelBox } from "../views/nodes/LabelBox";
+import { ImageBox } from "../views/nodes/ImageBox";
 
 interface Button {
     // DocumentOptions fields a button can set
@@ -156,14 +158,14 @@ export class CurrentUserUtils {
             }
             const allopts = {isSystem: true, onClickScriptDisable: "never",  ...opts};
             return DocUtils.AssignScripts(  (curIcon?.iconTemplate === opts.iconTemplate ? 
-                      DocUtils.AssignOpts(curIcon, allopts):undefined) ?? ((templateIconsDoc[iconFieldName] = MakeTemplate(creator(allopts), true, iconFieldName, templateField))),
+                      DocUtils.AssignOpts(curIcon, allopts):undefined) ?? ((templateIconsDoc[iconFieldName] = MakeTemplate(creator(allopts, templateField), true, iconFieldName, templateField))),
                 {onClick:"deiconifyView(documentView)", onDoubleClick: "deiconifyViewToLightbox(documentView)", });
         };
-        const labelBox = (opts: DocumentOptions, data?:string) => Docs.Create.LabelDocument({
-            textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 14, layout_borderRounding: "5px",  _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
+        const labelBox = (opts: DocumentOptions, fieldKey:string) => Docs.Create.LabelDocument({
+            layout: LabelBox.LayoutString(fieldKey), textTransform: "unset", letterSpacing: "unset", _singleLine: false, _label_minFontSize: 14, _label_maxFontSize: 14, layout_borderRounding: "5px",  _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, ...opts
         });
-        const imageBox = (opts: DocumentOptions, url?:string) => Docs.Create.ImageDocument(url ?? "http://www.cs.brown.edu/~bcz/noImage.png", { "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG,  _width: 360 / 4, _height: 270 / 4,  _layout_showTitle: "title", ...opts });
-        const fontBox = (opts:DocumentOptions, data?:string) => Docs.Create.FontIconDocument({ _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts  });
+        const imageBox = (opts: DocumentOptions, fieldKey:string) => Docs.Create.ImageDocument( "http://www.cs.brown.edu/~bcz/noImage.png", { layout:ImageBox.LayoutString(fieldKey), "icon_nativeWidth": 360 / 4, "icon_nativeHeight": 270 / 4, iconTemplate:DocumentType.IMG,  _width: 360 / 4, _height: 270 / 4,  _layout_showTitle: "title", ...opts });
+        const fontBox = (opts:DocumentOptions, fieldKey:string) => Docs.Create.FontIconDocument({ layout:FontIconBox.LayoutString(fieldKey), _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, ...opts  });
         const iconTemplates = [
             makeIconTemplate(undefined,          "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "dimgray"}),
             makeIconTemplate(DocumentType.AUDIO, "title", { iconTemplate:DocumentType.LABEL, backgroundColor: "lightgreen"}),
@@ -174,7 +176,7 @@ export class CurrentUserUtils {
             makeIconTemplate(DocumentType.COL,   "icon",  { iconTemplate:DocumentType.IMG}),
             makeIconTemplate(DocumentType.COL,   "icon",  { iconTemplate:DocumentType.IMG}),
             makeIconTemplate(DocumentType.VID,   "icon",  { iconTemplate:DocumentType.IMG}),
-            makeIconTemplate(DocumentType.BUTTON,"data",  { iconTemplate:DocumentType.FONTICON}),
+            makeIconTemplate(DocumentType.BUTTON,"title", { iconTemplate:DocumentType.FONTICON}),
             //nasty hack .. templates are looked up exclusively by type -- but we want a template for a document with a certain field (transcription) .. so this hack and the companion hack in createCustomView does this for now
             makeIconTemplate("transcription" as any, "transcription", { iconTemplate:DocumentType.LABEL, backgroundColor: "orange" }),
             //makeIconTemplate(DocumentType.PDF, "icon", {iconTemplate:DocumentType.IMG}, (opts) => imageBox("http://www.cs.brown.edu/~bcz/noImage.png", opts))
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 87ee962a0..2fb9f0fc1 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -323,7 +323,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
                 SelectionManager.Docs.map(doc => {
                     const docMax = Math.min(NumCast(doc.width) / 2, NumCast(doc.height) / 2);
                     const radius = Math.min(1, dist / maxDist) * docMax; // set radius based on ratio of drag distance to half diagonal distance of bounding box
-                    doc.layout_borderRounding = `${radius}px`;
+                    doc._layout_borderRounding = `${radius}px`;
                 });
                 return false;
             },
@@ -533,9 +533,9 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
             const [initWidth, initHeight] = [NumCast(doc._width, 1), NumCast(doc._height)];
 
             const modifyNativeDim =
-                (opts.ctrlKey && doc.layout_nativeDimEditable) || // e.g., PDF or web page
-                (doc.layout_reflowHorizontal && opts.dragHdl !== 'bottom' && opts.dragHdl !== 'top') || // eg rtf or some web pages
-                (doc.layout_reflowVertical && (opts.dragHdl === 'bottom' || opts.dragHdl === 'top' || opts.ctrlKey)); // eg rtf, web, pdf
+                (opts.ctrlKey && doc._layout_nativeDimEditable) || // e.g., PDF or web page
+                (doc._layout_reflowHorizontal && opts.dragHdl !== 'bottom' && opts.dragHdl !== 'top') || // eg rtf or some web pages
+                (doc._layout_reflowVertical && (opts.dragHdl === 'bottom' || opts.dragHdl === 'top' || opts.ctrlKey)); // eg rtf, web, pdf
             if (nwidth && nheight && !modifyNativeDim) {
                 // eg., dragging right resizer on PDF -- enforce native dimensions because not expliclty overridden with ctrl or bottom resize drag
                 scale.x === 1 ? (scale.x = scale.y) : (scale.y = scale.x);
@@ -545,7 +545,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
                 const setData = Doc.NativeWidth(doc[DocData]) === doc.nativeWidth;
                 doc.nativeWidth = scale.x * Doc.NativeWidth(doc);
                 if (setData) Doc.SetNativeWidth(doc[DocData], NumCast(doc.nativeWidth));
-                if (doc.layout_reflowVertical && !NumCast(doc.nativeHeight)) {
+                if (doc._layout_reflowVertical && !NumCast(doc.nativeHeight)) {
                     doc._nativeHeight = (initHeight / initWidth) * nwidth; // initializes the nativeHeight for a PDF
                 }
             }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 877569ab3..4eb946939 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,6 +1,6 @@
 import { Bezier } from 'bezier-js';
 import { Colors } from 'browndash-components';
-import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, trace } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import * as React from 'react';
@@ -840,10 +840,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     if (excludeT < startSegmentT || excludeT > docCurveTVal) {
                         const localStartTVal = startSegmentT - Math.floor(i / 4);
                         t !== (localStartTVal < 0 ? 0 : localStartTVal) && segment.push(inkSegment.split(localStartTVal < 0 ? 0 : localStartTVal, t));
-                        segment.length && segments.push(segment);
+                        if (segment.length && (Math.abs(segment[0].points[0].x - segment[0].points.lastElement().x) > 0.5 || Math.abs(segment[0].points[0].y - segment[0].points.lastElement().y) > 0.5)) segments.push(segment);
                     }
                     // start a new segment from the intersection t value
-                    segment = tVals.length - 1 === index ? [inkSegment.split(t).right] : [];
+                    if (tVals.length - 1 === index) {
+                        const split = inkSegment.split(t).right;
+                        if (split && (Math.abs(split.points[0].x - split.points.lastElement().x) > 0.5 || Math.abs(split.points[0].y - split.points.lastElement().y) > 0.5)) segment = [split];
+                        else segment = [];
+                    } else segment = [];
                     startSegmentT = docCurveTVal;
                 });
             } else {
@@ -1647,7 +1651,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         !this._props.isAnnotationOverlay &&
             !Doc.noviceMode &&
             optionItems.push({ description: (this._showAnimTimeline ? 'Close' : 'Open') + ' Animation Timeline', event: action(() => (this._showAnimTimeline = !this._showAnimTimeline)), icon: 'eye' });
-        this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor)), icon: 'palette' });
+        this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null).backgroundColor = StrCast(this.layoutDoc.backgroundColor)), icon: 'palette' });
         this._props.renderDepth && optionItems.push({ description: 'Fit Content Once', event: this.fitContentOnce, icon: 'object-group' });
         if (!Doc.noviceMode) {
             optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? 'Freeze' : 'Unfreeze') + ' Aspect', event: this.toggleNativeDimensions, icon: 'snowflake' });
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index d24c79b10..46043eefb 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -81,9 +81,13 @@ export class FontIconBox extends ViewBoxBaseComponent<ButtonProps>() {
         }
     };
 
-    // Determining UI Specs
+    /**
+     * this chooses the appropriate title for the label
+     * if the Document is a template, then we use the title of the data doc that it renders
+     * otherwise, we use the Document's title itself.
+     */
     @computed get label() {
-        return StrCast(this.dataDoc.icon_label, StrCast(this.Document.title));
+        return StrCast(this.Document.isTemplateDoc ? this.dataDoc.title : this.Document.title);
     }
     Icon = (color: string, iconFalse?: boolean) => {
         let icon;
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index fd3074a88..be20b5934 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -17,12 +17,8 @@ import './LabelBox.scss';
 import { PinProps, PresBox } from './trails';
 import { Docs } from '../../documents/Documents';
 
-export interface LabelBoxProps extends FieldViewProps {
-    label?: string;
-}
-
 @observer
-export class LabelBox extends ViewBoxBaseComponent<LabelBoxProps>() {
+export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
     public static LayoutString(fieldKey: string) {
         return FieldView.LayoutString(LabelBox, fieldKey);
     }
@@ -32,7 +28,7 @@ export class LabelBox extends ViewBoxBaseComponent<LabelBoxProps>() {
     private dropDisposer?: DragManager.DragDropDisposer;
     private _timeout: any;
 
-    constructor(props: LabelBoxProps) {
+    constructor(props: FieldViewProps) {
         super(props);
         makeObservable(this);
     }
@@ -45,7 +41,7 @@ export class LabelBox extends ViewBoxBaseComponent<LabelBoxProps>() {
     }
 
     @computed get Title() {
-        return this.dataDoc.title_custom ? StrCast(this.Document.title) : this._props.label ? this._props.label : Field.toString(this.dataDoc[this.fieldKey] as Field);
+        return Field.toString(this.dataDoc[this.fieldKey] as Field);
     }
 
     protected createDropTarget = (ele: HTMLDivElement) => {
-- 
cgit v1.2.3-70-g09d2

