From 205fdacf9807be2691e13e1d9d04d6b98620391a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 15 Jan 2025 13:03:59 -0500
Subject: fixed so that users are sentt to dropbox to authorized uploads once,
 and then a refresh token is used afterwards.  fixed up some collection views
 to work better with the tagsView.  fixed grid view to show entire image. 
 tweaked notetaking view to work better with tags, but it's incomplete.

---
 src/client/views/collections/CollectionStackingView.tsx | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

(limited to 'src/client/views/collections/CollectionStackingView.tsx')

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 1ac0b6d70..a57256424 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -146,7 +146,17 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             // assuming we need to get rowSpan because we might be dealing with many columns. Grid gap makes sense if multiple columns
             const rowSpan = Math.ceil((this.getDocHeight(d)() + this.gridGap) / this.gridGap);
             // just getting the style
-            const style = this.isStackingView ? { margin: undefined, transition: this.getDocTransition(d)(), width: this.columnWidth, marginTop: i ? this.gridGap : 0, height: this.getDocHeight(d)() } : { gridRowEnd: `span ${rowSpan}` };
+            const style = this.isStackingView
+                ? {
+                      //
+                      margin: undefined,
+                      transition: this.getDocTransition(d)(),
+                      width: this.columnWidth,
+                      marginTop: i ? this.gridGap : 0,
+                      height: this.getDocHeight(d)(),
+                      zIndex: DocumentView.getFirstDocumentView(d)?.IsSelected ? 1000 : 0,
+                  }
+                : { gridRowEnd: `span ${rowSpan}`, zIndex: DocumentView.getFirstDocumentView(d)?.IsSelected ? 1000 : 0 };
             // So we're choosing whether we're going to render a column or a masonry doc
             return (
                 <div className={`collectionStackingView-${this.isStackingView ? 'columnDoc' : 'masonryDoc'}`} key={d[Id]} style={style}>
@@ -344,6 +354,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 dontRegisterView={BoolCast(this.layoutDoc.childDontRegisterViews, this._props.dontRegisterView)} // used to be true if DataDoc existed, but template textboxes won't layout_autoHeight resize if dontRegisterView is set, but they need to.
                 rootSelected={this.rootSelected}
                 showTitle={this._props.childlayout_showTitle}
+                showTags={BoolCast(this.layoutDoc.showChildTags) || BoolCast(this.Document._layout_showTags)}
                 dragAction={(this.layoutDoc.childDragAction ?? this._props.childDragAction) as dropActionType}
                 onClickScript={this.onChildClickHandler}
                 onDoubleClickScript={this.onChildDoubleClickHandler}
-- 
cgit v1.2.3-70-g09d2


From cfccfd0639dff68e47862fb8e78d75b0a1b287a1 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Feb 2025 10:44:09 -0500
Subject: fixed column dragging and yMargin in masonry view. made columns
 always fit width of  masonry

---
 .../views/collections/CollectionStackingView.scss  |  8 ++-
 .../views/collections/CollectionStackingView.tsx   | 68 +++++++++++++---------
 2 files changed, 48 insertions(+), 28 deletions(-)

(limited to 'src/client/views/collections/CollectionStackingView.tsx')

diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 5237bdffb..565536623 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -121,11 +121,15 @@
     }
 
     .collectionStackingView-columnDragger {
-        width: 15;
-        height: 15;
+        width: 28;
+        height: 28;
         position: absolute;
         margin-left: -5;
         z-index: 10;
+        > svg {
+            width: 100%;
+            height: 100%;
+        }
     }
 
     // Documents in stacking view
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a57256424..0a25882ff 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -110,7 +110,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     }
     // columnWidth handles the margin on the left and right side of the documents
     @computed get columnWidth() {
-        return Math.min(this._props.PanelWidth() - 2 * this.xMargin, this.isStackingView ? Number.MAX_VALUE : this.layoutDoc._columnWidth === -1 ? this._props.PanelWidth() - 2 * this.xMargin : NumCast(this.layoutDoc._columnWidth, 250));
+        const availableWidth = this._props.PanelWidth() - 2 * this.xMargin;
+        const cwid = availableWidth / NumCast(this.Document._layout_columnCount, 1);
+        return Math.min(availableWidth, this.isStackingView ? Number.MAX_VALUE : cwid - this.gridGap);
     }
 
     @computed get NodeWidth() {
@@ -221,6 +223,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         return fields;
     }
 
+    setAutoHeight = () => this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : 2 * this.yMargin + this._refList.reduce((p, r) => p + DivHeight(r), 0)));
+    observer = new ResizeObserver(this.setAutoHeight);
+
     componentDidMount() {
         super.componentDidMount?.();
         this._props.setContentViewBox?.(this);
@@ -232,10 +237,21 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 this.dataDoc['_' + this.fieldKey + '_columnHeaders'] = new List();
             }
         );
+        // reset section headers when a new filter is inputted
+        this._disposers.width = reaction(
+            () => [this._props.PanelWidth() - 2 * this.xMargin, NumCast(this.Document._layout_columnWidth, 250)],
+            ([pw, cw]) => {
+                if (!this.isStackingView) {
+                    this.layoutDoc._layout_columnCount = Math.round(pw / cw);
+                }
+            }
+        );
+
         this._disposers.autoHeight = reaction(
-            () => this.layoutDoc._layout_autoHeight,
-            layoutAutoHeight => layoutAutoHeight && this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : this._refList.reduce((p, r) => p + DivHeight(r), 0)))
+            () => [this.layoutDoc._layout_autoHeight, this.yMargin],
+            ([autoH]) => autoH && this.setAutoHeight()
         );
+
         this._disposers.refList = reaction(
             () => ({ refList: this._refList.slice(), autoHeight: this.layoutDoc._layout_autoHeight && !DocumentView.LightboxContains(this.DocumentView?.()) }),
             ({ refList, autoHeight }) => {
@@ -435,8 +451,8 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         );
     };
     @action
-    onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
-        this.layoutDoc._columnWidth = Math.max(10, this.columnWidth + delta[0]);
+    onDividerMove = (e: PointerEvent) => {
+        this.Document._layout_columnWidth = Math.max(10, this.ScreenToLocalBoxXf().transformPoint(e.clientX, 0)[0] - this.xMargin);
         return false;
     };
 
@@ -446,7 +462,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 className="collectionStackingView-columnDragger"
                 onPointerDown={this.columnDividerDown}
                 ref={this._draggerRef}
-                style={{ cursor: this._cursor, color: SettingsManager.userColor, left: `${this.columnWidth + this.xMargin}px`, top: `${Math.max(0, this.yMargin - 9)}px` }}>
+                style={{ cursor: this._cursor, color: SettingsManager.userColor, left: `${NumCast(this.Document._layout_columnWidth) + this.xMargin}px` }}>
                 <FontAwesomeIcon icon="arrows-alt-h" />
             </div>
         );
@@ -590,24 +606,26 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         }
         const rows = () => (!this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, Math.floor((this._props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))));
         return (
-            <CollectionMasonryViewFieldRow
-                showHandle={first}
-                Document={this.Document}
-                chromeHidden={this.chromeHidden}
-                pivotField={this.pivotField}
-                refList={this._refList}
-                key={heading ? heading.heading : ''}
-                rows={rows}
-                headings={this.headings}
-                heading={heading ? heading.heading : ''}
-                headingObject={heading}
-                docList={docList}
-                parent={this}
-                type={type}
-                createDropTarget={this.createDashEventsTarget}
-                screenToLocalTransform={this.ScreenToLocalBoxXf}
-                setDocHeight={this.setDocHeight}
-            />
+            <div style={{ top: this.yMargin }}>
+                <CollectionMasonryViewFieldRow
+                    showHandle={first}
+                    Document={this.Document}
+                    chromeHidden={this.chromeHidden}
+                    pivotField={this.pivotField}
+                    refList={this._refList}
+                    key={heading ? heading.heading : ''}
+                    rows={rows}
+                    headings={this.headings}
+                    heading={heading ? heading.heading : ''}
+                    headingObject={heading}
+                    docList={docList}
+                    parent={this}
+                    type={type}
+                    createDropTarget={this.createDashEventsTarget}
+                    screenToLocalTransform={this.ScreenToLocalBoxXf}
+                    setDocHeight={this.setDocHeight}
+                />
+            </div>
         );
     };
 
@@ -699,8 +717,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         return this._props.isContentActive() === false ? 'none' : undefined;
     }
 
-    observer = new ResizeObserver(() => this._props.setHeight?.(this.headerMargin + (this.isStackingView ? Math.max(...this._refList.map(DivHeight)) : this._refList.reduce((p, r) => p + DivHeight(r), 0))));
-
     onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
     render() {
         TraceMobx();
-- 
cgit v1.2.3-70-g09d2


From bcf3b005d55ec851374049f4c188d96ffc7a7c8b Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Feb 2025 14:46:20 -0500
Subject: prevent tagsview from appeqring in spreadsheet.  set default fill
 color only if nothing is selected.  place column divider at top of
 stacking/card views.  move card view flashcard view to top left independent
 of margin settings.

---
 .../views/collections/CollectionCardDeckView.tsx   |   5 +-
 .../collections/CollectionMasonryViewFieldRow.tsx  |   1 -
 .../views/collections/CollectionStackingView.scss  | 194 ++++++++++-----------
 .../views/collections/CollectionStackingView.tsx   |  45 ++---
 src/client/views/global/globalScripts.ts           |   2 +-
 src/client/views/nodes/DocumentView.tsx            |   2 +-
 6 files changed, 125 insertions(+), 124 deletions(-)

(limited to 'src/client/views/collections/CollectionStackingView.tsx')

diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 94f85d429..756b37f99 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -540,11 +540,10 @@ export class CollectionCardView extends CollectionSubView() {
                             height: `${100 / this.nativeScaling / fitContentScale}%`,
                             width: `${100 / this.nativeScaling / fitContentScale}%`,
                             transform: `scale(${this.nativeScaling * fitContentScale})`,
-                        }}>
-                        {this.flashCardUI(this.curDoc, this.docViewProps, this.answered)}
-                    </div>
+                        }}></div>
                 </div>
 
+                {this.flashCardUI(this.curDoc, this.docViewProps, this.answered)}
                 <div
                     className="collectionCardView-cardSizeDragger"
                     onPointerDown={this.cardSizerDown}
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 710c00841..a0d5f9f70 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -258,7 +258,6 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF
         const stackPad = showChrome ? `0px ${this._props.parent.xMargin}px` : `${this._props.parent.yMargin}px ${this._props.parent.xMargin}px 0px ${this._props.parent.xMargin}px `;
         return this.collapsed ? null : (
             <div style={{ position: 'relative' }}>
-                {this._props.showHandle && this._props.parent._props.isContentActive() ? this._props.parent.columnDragger : null}
                 {showChrome ? (
                     <div
                         className="collectionStackingView-addDocumentButton"
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 565536623..05ac52ff9 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -12,123 +12,123 @@
     position: relative;
     height: 100%;
     width: 100%;
-}
-
-// TODO:glr Turn this into a seperate class
-.documentButtonMenu {
-    position: relative;
-    height: fit-content;
-    border-bottom: global.$standard-border;
-    display: flex;
-    justify-content: center;
-    flex-direction: column;
-    align-items: center;
-    align-content: center;
-    padding: 5px 0 5px 0;
 
-    .documentExplanation {
-        width: 90%;
-        margin: 5px;
-        font-size: 11px;
-        color: global.$medium-blue;
-        padding: 10px;
-        border-radius: 5px;
-        border: solid 0.5px global.$medium-blue;
+    .collectionStackingView-columnDragger {
+        width: 28;
+        height: 28;
+        position: absolute;
+        margin-left: -5;
+        z-index: 10;
+        > svg {
+            width: 100%;
+            height: 100%;
+        }
     }
-}
 
-.collectionStackingView,
-.collectionMasonryView {
-    height: 100%;
-    width: 100%;
-    position: absolute;
-    top: 0;
-    overflow-y: auto;
-    overflow-x: hidden;
-    flex-wrap: wrap;
-    transition: top 0.5s;
-
-    > div {
+    // TODO:glr Turn this into a seperate class
+    .documentButtonMenu {
         position: relative;
-        display: block;
-    }
-
-    .collectionStackingViewFieldColumn {
+        height: fit-content;
+        border-bottom: global.$standard-border;
         display: flex;
+        justify-content: center;
         flex-direction: column;
+        align-items: center;
+        align-content: center;
+        padding: 5px 0 5px 0;
+
+        .documentExplanation {
+            width: 90%;
+            margin: 5px;
+            font-size: 11px;
+            color: global.$medium-blue;
+            padding: 10px;
+            border-radius: 5px;
+            border: solid 0.5px global.$medium-blue;
+        }
     }
 
-    .collectionSchemaView-previewDoc {
+    .collectionStackingView,
+    .collectionMasonryView {
         height: 100%;
+        width: 100%;
         position: absolute;
-    }
+        top: 0;
+        overflow-y: auto;
+        overflow-x: hidden;
+        flex-wrap: wrap;
+        transition: top 0.5s;
 
-    .collectionStackingView-docView-container {
-        width: 45%;
-        margin: 5% 2.5%;
-        padding-left: 2.5%;
-        height: auto;
-    }
+        > div {
+            position: relative;
+            display: block;
+        }
 
-    .collectionStackingView-flexCont {
-        display: flex;
-        flex-direction: row;
-        flex-wrap: wrap;
-        align-items: center;
-    }
+        .collectionStackingViewFieldColumn {
+            display: flex;
+            flex-direction: column;
+        }
 
-    .collectionStackingView-masonrySingle,
-    .collectionStackingView-masonryGrid {
-        width: 100%;
-        display: grid;
-        top: 0;
-        left: 0;
-    }
+        .collectionSchemaView-previewDoc {
+            height: 100%;
+            position: absolute;
+        }
 
-    .collectionStackingView-masonrySingle {
-        height: 100%;
-        position: absolute;
-    }
+        .collectionStackingView-docView-container {
+            width: 45%;
+            margin: 5% 2.5%;
+            padding-left: 2.5%;
+            height: auto;
+        }
 
-    .collectionStackingView-masonryGrid {
-        margin: auto;
-        height: max-content;
-        position: relative;
-        grid-auto-rows: 0px;
-    }
+        .collectionStackingView-flexCont {
+            display: flex;
+            flex-direction: row;
+            flex-wrap: wrap;
+            align-items: center;
+        }
 
-    .collectionStackingView-masonrySingle {
-        width: 100%;
-        height: 100%;
-        position: absolute;
-        display: flex;
-        flex-direction: column;
-        top: 0;
-        left: 0;
-        width: 100%;
-        position: absolute;
-    }
+        .collectionStackingView-masonrySingle,
+        .collectionStackingView-masonryGrid {
+            width: 100%;
+            display: grid;
+            top: 0;
+            left: 0;
+        }
 
-    .collectionStackingView-description {
-        font-size: 100%;
-        margin-bottom: 1vw;
-        padding: 10px;
-        height: 2vw;
-        width: 100%;
-        font-family: global.$sans-serif;
-        background: global.$dark-gray;
-        color: global.$white;
-    }
+        .collectionStackingView-masonrySingle {
+            height: 100%;
+            position: absolute;
+        }
 
-    .collectionStackingView-columnDragger {
-        width: 28;
-        height: 28;
-        position: absolute;
-        margin-left: -5;
-        z-index: 10;
-        > svg {
+        .collectionStackingView-masonryGrid {
+            margin: auto;
+            height: max-content;
+            position: relative;
+            grid-auto-rows: 0px;
+        }
+
+        .collectionStackingView-masonrySingle {
             width: 100%;
             height: 100%;
+            position: absolute;
+            display: flex;
+            flex-direction: column;
+            top: 0;
+            left: 0;
+            width: 100%;
+            position: absolute;
+        }
+
+        .collectionStackingView-description {
+            font-size: 100%;
+            margin-bottom: 1vw;
+            padding: 10px;
+            height: 2vw;
+            width: 100%;
+            font-family: global.$sans-serif;
+            background: global.$dark-gray;
+            color: global.$white;
         }
     }
 
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 0a25882ff..e8fa8b01e 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -452,7 +452,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     };
     @action
     onDividerMove = (e: PointerEvent) => {
-        this.Document._layout_columnWidth = Math.max(10, this.ScreenToLocalBoxXf().transformPoint(e.clientX, 0)[0] - this.xMargin);
+        this.Document._layout_columnWidth = Math.max(10, (this._props.DocumentView?.().screenToViewTransform().transformPoint(e.clientX, 0)[0] ?? 0) - this.xMargin);
         return false;
     };
 
@@ -606,26 +606,29 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         }
         const rows = () => (!this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, Math.floor((this._props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))));
         return (
-            <div style={{ top: this.yMargin }}>
-                <CollectionMasonryViewFieldRow
-                    showHandle={first}
-                    Document={this.Document}
-                    chromeHidden={this.chromeHidden}
-                    pivotField={this.pivotField}
-                    refList={this._refList}
-                    key={heading ? heading.heading : ''}
-                    rows={rows}
-                    headings={this.headings}
-                    heading={heading ? heading.heading : ''}
-                    headingObject={heading}
-                    docList={docList}
-                    parent={this}
-                    type={type}
-                    createDropTarget={this.createDashEventsTarget}
-                    screenToLocalTransform={this.ScreenToLocalBoxXf}
-                    setDocHeight={this.setDocHeight}
-                />
-            </div>
+            <>
+                {this._props.isContentActive() && !this.isStackingView ? this.columnDragger : null}
+                <div style={{ top: this.yMargin }}>
+                    <CollectionMasonryViewFieldRow
+                        showHandle={first}
+                        Document={this.Document}
+                        chromeHidden={this.chromeHidden}
+                        pivotField={this.pivotField}
+                        refList={this._refList}
+                        key={heading ? heading.heading : ''}
+                        rows={rows}
+                        headings={this.headings}
+                        heading={heading ? heading.heading : ''}
+                        headingObject={heading}
+                        docList={docList}
+                        parent={this}
+                        type={type}
+                        createDropTarget={this.createDashEventsTarget}
+                        screenToLocalTransform={this.ScreenToLocalBoxXf}
+                        setDocHeight={this.setDocHeight}
+                    />
+                </div>
+            </>
         );
     };
 
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index b455f76e4..835c28daa 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -127,7 +127,7 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
             const contentFrameNumber = Cast(selView.Document?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
             return CollectionFreeFormDocumentView.getStringValues(selView?.Document, contentFrameNumber)[fieldKey] || defaultFill();
         }
-        setDefaultFill(color ?? 'transparent');
+        !selectedViews.length && setDefaultFill(color ?? 'transparent');
         selectedViews.forEach(dv => {
             const fieldKey = dv.Document._layout_isSvg ? 'fillColor' : 'backgroundColor';
             const layoutFrameNumber = Cast(dv.containerViewPath?.().lastElement()?.Document?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b40ead03a..5f5dd1210 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -780,7 +780,7 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
                             transform: `scale(${this.uiBtnScaling})`,
                             bottom: Number.isNaN(this.maxWidgetSize) ? undefined : this.maxWidgetSize,
                         }}>
-                        {this._props.DocumentView?.() ? <TagsView Views={[this._props.DocumentView?.()]} /> : null}
+                        {this._props.DocumentView?.() && !this._props.docViewPath().slice(-2)[0].ComponentView?.isUnstyledView?.() ? <TagsView Views={[this._props.DocumentView?.()]} /> : null}
                     </div>
                 ) : (
                     <>
-- 
cgit v1.2.3-70-g09d2


From 2838b8d98ab88df974fd52ba96cf5046d99298cb Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 27 Feb 2025 16:05:35 -0500
Subject: fixed passive wheel prevention on document.root.  fixed key waring on
 masonry view.

---
 src/client/views/Main.tsx                               | 2 +-
 src/client/views/collections/CollectionStackingView.tsx | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/client/views/collections/CollectionStackingView.tsx')

diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 3c1da88cc..f02677d95 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -87,7 +87,7 @@ FieldLoader.ServerLoadStatus = { requested: 0, retrieved: 0, message: 'cache' };
     await CurrentUserUtils.loadUserDocument(info);
     setTimeout(() => {
         // prevent zooming browser
-        document.getElementById('root')!.addEventListener('wheel', event => event.ctrlKey && event.preventDefault(), { capture: true, passive: true });
+        document.getElementById('root')!.addEventListener('wheel', event => event.ctrlKey && event.preventDefault(), true);
         const startload = (document as unknown as { startLoad: number }).startLoad; // see index.html in deploy/
         const loading = Date.now() - (startload ? Number(startload) : Date.now() - 3000);
         const d = new Date();
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index e8fa8b01e..f06e0b551 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -606,7 +606,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         }
         const rows = () => (!this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, Math.floor((this._props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))));
         return (
-            <>
+            <div key={(heading?.heading ?? '') + 'head'}>
                 {this._props.isContentActive() && !this.isStackingView ? this.columnDragger : null}
                 <div style={{ top: this.yMargin }}>
                     <CollectionMasonryViewFieldRow
@@ -628,7 +628,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         setDocHeight={this.setDocHeight}
                     />
                 </div>
-            </>
+            </div>
         );
     };
 
-- 
cgit v1.2.3-70-g09d2


From 93d4c71fe523a4b1f473ee6ab5e8a9b8ca715625 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 4 Mar 2025 11:07:40 -0500
Subject: fixed column width default / columnDragger for masonry view.

---
 src/client/views/collections/CollectionStackingView.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/client/views/collections/CollectionStackingView.tsx')

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index f06e0b551..96125f2c2 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -111,7 +111,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
     // columnWidth handles the margin on the left and right side of the documents
     @computed get columnWidth() {
         const availableWidth = this._props.PanelWidth() - 2 * this.xMargin;
-        const cwid = availableWidth / NumCast(this.Document._layout_columnCount, 1);
+        const cwid = availableWidth / (NumCast(this.Document._layout_columnCount) || this._props.PanelWidth() / NumCast(this.Document._layout_columnWidth, this._props.PanelWidth() / 4));
         return Math.min(availableWidth, this.isStackingView ? Number.MAX_VALUE : cwid - this.gridGap);
     }
 
@@ -241,7 +241,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         this._disposers.width = reaction(
             () => [this._props.PanelWidth() - 2 * this.xMargin, NumCast(this.Document._layout_columnWidth, 250)],
             ([pw, cw]) => {
-                if (!this.isStackingView) {
+                if (!this.isStackingView && Math.round(pw / cw)) {
                     this.layoutDoc._layout_columnCount = Math.round(pw / cw);
                 }
             }
@@ -607,7 +607,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         const rows = () => (!this.isStackingView ? 1 : Math.max(1, Math.min(docList.length, Math.floor((this._props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))));
         return (
             <div key={(heading?.heading ?? '') + 'head'}>
-                {this._props.isContentActive() && !this.isStackingView ? this.columnDragger : null}
+                {this._props.isContentActive() && !this.isStackingView && !this.chromeHidden ? this.columnDragger : null}
                 <div style={{ top: this.yMargin }}>
                     <CollectionMasonryViewFieldRow
                         showHandle={first}
-- 
cgit v1.2.3-70-g09d2


From 1ab6f6c87b746e0c2898694216db50d5faadf7f5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 6 Mar 2025 19:46:43 -0500
Subject: a bunch of changes to improve how docs are selected automatically
 when created.

---
 src/client/documents/DocUtils.ts                   |  5 +-
 src/client/views/GlobalKeyHandler.ts               | 19 +++--
 src/client/views/MarqueeAnnotator.tsx              |  2 +-
 src/client/views/SidebarAnnos.tsx                  |  9 +--
 .../collections/CollectionMasonryViewFieldRow.tsx  |  7 +-
 .../views/collections/CollectionNoteTakingView.tsx |  2 +-
 .../collections/CollectionNoteTakingViewColumn.tsx | 21 ++----
 .../views/collections/CollectionStackingView.tsx   |  2 +-
 .../CollectionStackingViewFieldColumn.tsx          | 26 ++-----
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 src/client/views/collections/TreeView.tsx          |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  5 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 .../collectionGrid/CollectionGridView.tsx          |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  6 ++
 src/client/views/nodes/EquationBox.tsx             | 10 +--
 src/client/views/nodes/LabelBox.tsx                |  5 +-
 src/client/views/nodes/MapBox/MapBox.tsx           |  2 +-
 src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx |  2 +-
 .../views/nodes/MapboxMapBox/MapboxContainer.tsx   |  2 +-
 .../views/nodes/formattedText/DailyJournal.tsx     | 25 +++----
 .../views/nodes/formattedText/FormattedTextBox.tsx | 41 +++-------
 src/fields/Doc.ts                                  |  4 -
 src/fields/RichTextField.ts                        | 87 +++++++++++++++++-----
 24 files changed, 149 insertions(+), 141 deletions(-)

(limited to 'src/client/views/collections/CollectionStackingView.tsx')

diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts
index 7e0416447..9797a407b 100644
--- a/src/client/documents/DocUtils.ts
+++ b/src/client/documents/DocUtils.ts
@@ -385,7 +385,7 @@ export namespace DocUtils {
                         newDoc.x = x;
                         newDoc.y = y;
                         newDoc[DocData].backgroundColor = Doc.UserDoc().textBackgroundColor;
-                        Doc.SetSelectOnLoad(newDoc);
+                        DocumentView.SetSelectOnLoad(newDoc);
                         if (pivotField) {
                             newDoc[pivotField] = pivotValue;
                         }
@@ -408,6 +408,7 @@ export namespace DocUtils {
             description: ':Daily Journal',
             event: undoable(() => {
                 const newDoc = Docs.Create.DailyJournalDocument('', { x, y });
+                DocumentView.SetSelectOnLoad(newDoc);
                 docAdder?.(newDoc);
             }, 'Create Daily Journal'),
             icon: 'book',
@@ -456,7 +457,7 @@ export namespace DocUtils {
                         newDoc.author = ClientUtils.CurrentUserEmail();
                         newDoc.x = x;
                         newDoc.y = y;
-                        Doc.SetSelectOnLoad(newDoc);
+                        DocumentView.SetSelectOnLoad(newDoc);
                         if (pivotField) {
                             newDoc[pivotField] = pivotValue;
                         }
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index b200aff65..2d342d1b1 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -23,7 +23,6 @@ import { CollectionFreeFormDocumentView } from './nodes/CollectionFreeFormDocume
 import { DocumentLinksButton } from './nodes/DocumentLinksButton';
 import { DocumentView } from './nodes/DocumentView';
 import { OpenWhereMod } from './nodes/OpenWhere';
-import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { AnchorMenu } from './pdf/AnchorMenu';
 
 const modifiers = ['control', 'meta', 'shift', 'alt'];
@@ -75,7 +74,6 @@ export class KeyManager {
 
     public handle = action((e: KeyboardEvent) => {
         // accumulate buffer of characters to insert in a new text note.  once the note is created, it will stop keyboard events from reaching this function.
-        if (FormattedTextBox.SelectOnLoadChar) FormattedTextBox.SelectOnLoadChar += e.key === 'Enter' ? '\n' : e.key;
         const keyname = e.key && e.key.toLowerCase();
         this.handleGreedy(/* keyname */);
 
@@ -106,6 +104,10 @@ export class KeyManager {
     };
 
     private unmodified = action((keyname: string, e: KeyboardEvent) => {
+        const nothing = {
+            stopPropagation: false,
+            preventDefault: false,
+        };
         switch (keyname) {
             case 'u':
                 if (document.activeElement?.tagName !== 'INPUT' && document.activeElement?.tagName !== 'TEXTAREA') {
@@ -169,17 +171,14 @@ export class KeyManager {
                     return { stopPropagation: true, preventDefault: true };
                 }
                 break;
-            case 'arrowleft':  return (e.target as any).type !== 'text' && this.nudge(-1, 0, 'nudge left') // if target is an input box, then we don't want to nudge any Docs since we're justing moving within the text itself.
-            case 'arrowright': return (e.target as any).type !== 'text' && this.nudge( 1, 0, 'nudge right');
-            case 'arrowup':    return (e.target as any).type !== 'text' && this.nudge(0, -1, 'nudge up');
-            case 'arrowdown':  return (e.target as any).type !== 'text' && this.nudge(0,  1, 'nudge down');
+            case 'arrowleft':  return (e.target as HTMLInputElement)?.type !== 'text' ? this.nudge(-1, 0, 'nudge left') : nothing; // if target is an input box, then we don't want to nudge any Docs since we're justing moving within the text itself.
+            case 'arrowright': return (e.target as HTMLInputElement)?.type !== 'text' ? this.nudge( 1, 0, 'nudge right') : nothing;
+            case 'arrowup':    return (e.target as HTMLInputElement)?.type !== 'text' ? this.nudge(0, -1, 'nudge up') : nothing;
+            case 'arrowdown':  return (e.target as HTMLInputElement | null)?.type !== 'text'?  this.nudge(0,  1, 'nudge down'): nothing;
             default:
         } // prettier-ignore
 
-        return {
-            stopPropagation: false,
-            preventDefault: false,
-        };
+        return nothing;
     });
 
     private shift = action((keyname: string) => {
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 02516264c..3f4200dce 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -199,7 +199,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
 
             const targetCreator = (annotationOn: Doc | undefined) => {
                 const target = DocUtils.GetNewTextDoc('Note linked to ' + this.props.Document.title, 0, 0, 100, 100, annotationOn, 'yellow');
-                Doc.SetSelectOnLoad(target);
+                DocumentView.SetSelectOnLoad(target);
                 return target;
             };
             DragManager.StartAnchorAnnoDrag([ele], new DragManager.AnchorAnnoDragData(this.props.docView(), sourceAnchorCreator, targetCreator), e.pageX, e.pageY, {
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 87076bf65..816fc8ed3 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -3,23 +3,23 @@ import { observer } from 'mobx-react';
 import * as React from 'react';
 import { ClientUtils, returnAll, returnFalse, returnOne, returnZero } from '../../ClientUtils';
 import { emptyFunction } from '../../Utils';
-import { Doc, DocListCast, Field, FieldType, FieldResult, StrListCast } from '../../fields/Doc';
+import { Doc, DocListCast, Field, FieldResult, FieldType, StrListCast } from '../../fields/Doc';
 import { DocData } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
 import { List } from '../../fields/List';
 import { RichTextField } from '../../fields/RichTextField';
 import { DocCast, NumCast, StrCast } from '../../fields/Types';
+import { DocUtils } from '../documents/DocUtils';
 import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
 import { Docs } from '../documents/Documents';
-import { DocUtils } from '../documents/DocUtils';
 import { SearchUtil } from '../util/SearchUtil';
 import { Transform } from '../util/Transform';
 import { ObservableReactComponent } from './ObservableReactComponent';
 import './SidebarAnnos.scss';
 import { StyleProp } from './StyleProp';
 import { CollectionStackingView } from './collections/CollectionStackingView';
+import { DocumentView } from './nodes/DocumentView';
 import { FieldViewProps } from './nodes/FieldView';
-import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 
 interface ExtraProps {
     fieldKey: string;
@@ -81,8 +81,7 @@ export class SidebarAnnos extends ObservableReactComponent<FieldViewProps & Extr
             text_fontSize: StrCast(Doc.UserDoc().fontSize),
             text_fontFamily: StrCast(Doc.UserDoc().fontFamily),
         });
-        Doc.SetSelectOnLoad(target);
-        FormattedTextBox.DontSelectInitialText = true;
+        DocumentView.SetSelectOnLoad(target);
         DocUtils.MakeLink(anchor, target, { link_relationship: 'inline comment:comment on' });
 
         const taggedContent = this.childFilters()
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index a0d5f9f70..996626575 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -16,7 +16,7 @@ import { Transform } from '../../util/Transform';
 import { undoBatch, undoable } from '../../util/UndoManager';
 import { EditableView } from '../EditableView';
 import { ObservableReactComponent } from '../ObservableReactComponent';
-import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
+import { DocumentView } from '../nodes/DocumentView';
 import { CollectionStackingView } from './CollectionStackingView';
 import './CollectionStackingView.scss';
 
@@ -162,9 +162,8 @@ export class CollectionMasonryViewFieldRow extends ObservableReactComponent<CMVF
         if (!value && !forceEmptyNote) return false;
         this._createEmbeddingSelected = false;
         const { pivotField } = this._props;
-        const newDoc = Docs.Create.TextDocument('', { _layout_autoHeight: true, _width: 200, _layout_fitWidth: true, title: value });
-        Doc.SetSelectOnLoad(newDoc);
-        FormattedTextBox.SelectOnLoadChar = value;
+        const newDoc = Docs.Create.TextDocument(value, { _layout_autoHeight: true, _width: 200, _layout_fitWidth: true, title: value });
+        DocumentView.SetSelectOnLoad(newDoc);
         pivotField && (newDoc[DocData][pivotField] = this.getValue(this._props.heading));
         const docs = this._props.parent.childDocList;
         return docs ? !!docs.splice(0, 0, newDoc) : this._props.parent._props.addDocument?.(newDoc) || false; // should really extend addDocument to specify insertion point (at beginning of list)
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 4c23d4c48..c499bd288 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -442,7 +442,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
             e.stopPropagation?.();
             const newDoc = Doc.MakeCopy(fieldProps.Document, true);
             newDoc[DocData].text = undefined;
-            Doc.SetSelectOnLoad(newDoc);
+            DocumentView.SetSelectOnLoad(newDoc);
             return this.addDocument?.(newDoc);
         }
         return undefined;
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 226d06f37..40b3f9ef2 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -2,7 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, makeObservable, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { lightOrDark, returnEmptyString } from '../../../ClientUtils';
+import { lightOrDark, returnEmptyString, returnTrue } from '../../../ClientUtils';
 import { Doc, Opt } from '../../../fields/Doc';
 import { listSpec } from '../../../fields/Schema';
 import { SchemaHeaderField } from '../../../fields/SchemaHeaderField';
@@ -17,8 +17,8 @@ import { undoBatch, undoable } from '../../util/UndoManager';
 import { ContextMenu } from '../ContextMenu';
 import { EditableProps, EditableView } from '../EditableView';
 import { ObservableReactComponent } from '../ObservableReactComponent';
-import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import './CollectionNoteTakingView.scss';
+import { DocumentView } from '../nodes/DocumentView';
 
 interface CSVFieldColumnProps {
     Document: Doc;
@@ -140,20 +140,15 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
         this._hover = false;
     };
 
-    addTextNote = undoable(() => this.addNewTextDoc('-typed text-', false, true), 'add text note');
-
     // addNewTextDoc is called when a user starts typing in a column to create a new node
-    @action
-    addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
-        if (!value && !forceEmptyNote) return false;
+    addTextNote = undoable(() => {
         const key = this._props.pivotField;
-        const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _layout_fitWidth: true, title: value, _layout_autoHeight: true });
+        const newDoc = Docs.Create.TextDocument('', { _height: 18, _width: 200, _layout_fitWidth: true, _layout_autoHeight: true });
         const colValue = this.getValue(this._props.heading);
         newDoc[key] = colValue;
-        Doc.SetSelectOnLoad(newDoc);
-        FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
+        DocumentView.SetSelectOnLoad(newDoc);
         return this._props.addDocument?.(newDoc) || false;
-    };
+    }, 'add text note');
 
     // deleteColumn is called when a user deletes a column using the 'trash' icon in the button area.
     // If the user deletes the first column, the documents get moved to the second column. Otherwise,
@@ -177,7 +172,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
             doc => {
                 const key = this._props.pivotField;
                 doc[key] = this.getValue(this._props.heading);
-                Doc.SetSelectOnLoad(doc);
+                DocumentView.SetSelectOnLoad(doc);
                 return this._props.addDocument?.(doc);
             },
             this._props.addDocument,
@@ -249,7 +244,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV
                         {!this._props.chromeHidden ? (
                             <div className="collectionNoteTakingView-DocumentButtons" style={{ display: this._props.isContentActive() ? 'flex' : 'none', marginBottom: 10 }}>
                                 <div className="collectionNoteTakingView-addDocumentButton" style={{ color: lightOrDark(this._props.backgroundColor?.()) }}>
-                                    <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} textCallback={this.addTextNote} placeholder={"Type ':' for commands"} contents="+ Node" menuCallback={this.menuCallback} />
+                                    <EditableView GetValue={returnEmptyString} SetValue={returnTrue} textCallback={this.addTextNote} placeholder={"Type ':' for commands"} contents="+ Node" menuCallback={this.menuCallback} />
                                 </div>
                                 <div className="collectionNoteTakingView-addDocumentButton" style={{ color: lightOrDark(this._props.backgroundColor?.()) }}>
                                     <EditableView {...this._props.editableViewProps()} />
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 96125f2c2..72e6bb8f2 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -321,7 +321,7 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 newDoc[layoutFieldKey] = fieldProps.Document[layoutFieldKey];
             }
             newDoc[DocData].text = undefined;
-            Doc.SetSelectOnLoad(newDoc);
+            DocumentView.SetSelectOnLoad(newDoc);
             return this.addDocument?.(newDoc);
         }
         return false;
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index ed0cabd0a..6f32dd2e0 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -2,7 +2,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { DivHeight, DivWidth, returnEmptyString, setupMoveUpEvents } from '../../../ClientUtils';
+import { DivHeight, DivWidth, returnEmptyString, returnTrue, setupMoveUpEvents } from '../../../ClientUtils';
 import { Doc, DocListCast, Opt } from '../../../fields/Doc';
 import { RichTextField } from '../../../fields/RichTextField';
 import { PastelSchemaPalette, SchemaHeaderField } from '../../../fields/SchemaHeaderField';
@@ -23,7 +23,7 @@ import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from '../ContextMenu';
 import { ContextMenuProps } from '../ContextMenuItem';
 import { EditableView } from '../EditableView';
-import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
+import { DocumentView } from '../nodes/DocumentView';
 import { ObservableReactComponent } from '../ObservableReactComponent';
 import './CollectionStackingView.scss';
 
@@ -149,19 +149,14 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
 
     @action pointerEntered = () => { SnappingManager.IsDragging && (this._background = '#b4b4b4'); } // prettier-ignore
     @action pointerLeave = () => { this._background = 'inherit'}; // prettier-ignore
-    @undoBatch typedNote = () => this.addNewTextDoc('-typed text-', false, true);
-
-    @action
-    addNewTextDoc = (value: string, shiftDown?: boolean, forceEmptyNote?: boolean) => {
-        if (!value && !forceEmptyNote) return false;
+    @undoBatch typedNote = () => {
         const key = this._props.pivotField;
-        const newDoc = Docs.Create.TextDocument(value, { _height: 18, _width: 200, _layout_fitWidth: true, title: value, _layout_autoHeight: true });
+        const newDoc = Docs.Create.TextDocument('', { _height: 18, _width: 200, _layout_fitWidth: true, _layout_autoHeight: true });
         key && (newDoc[key] = this.getValue(this._props.heading));
         const maxHeading = this._props.docList.reduce((prevHeading, doc) => (NumCast(doc.heading) > prevHeading ? NumCast(doc.heading) : prevHeading), 0);
         const heading = maxHeading === 0 || this._props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
         newDoc.heading = heading;
-        Doc.SetSelectOnLoad(newDoc);
-        FormattedTextBox.SelectOnLoadChar = forceEmptyNote ? '' : ' ';
+        DocumentView.SetSelectOnLoad(newDoc);
         return this._props.addDocument?.(newDoc) || false;
     };
 
@@ -240,7 +235,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
         const height = this._ele ? DivHeight(this._ele) : 0;
         DocUtils.addDocumentCreatorMenuItems(
             doc => {
-                Doc.SetSelectOnLoad(doc);
+                DocumentView.SetSelectOnLoad(doc);
                 return this._props.addDocument?.(doc);
             },
             this._props.addDocument,
@@ -394,14 +389,7 @@ export class CollectionStackingViewFieldColumn extends ObservableReactComponent<
                                 onKeyDown={e => e.stopPropagation()}
                                 className="collectionStackingView-addDocumentButton"
                                 style={{ width: 'calc(100% - 25px)', maxWidth: this._props.columnWidth / this._props.numGroupColumns - 25, marginBottom: 10 }}>
-                                <EditableView
-                                    GetValue={returnEmptyString}
-                                    SetValue={this.addNewTextDoc}
-                                    textCallback={this.typedNote}
-                                    placeholder={"Type ':' for commands"}
-                                    contents={<FontAwesomeIcon icon="plus" />}
-                                    menuCallback={this.menuCallback}
-                                />
+                                <EditableView GetValue={returnEmptyString} SetValue={returnTrue} textCallback={this.typedNote} placeholder={"Type ':' for commands"} contents={<FontAwesomeIcon icon="plus" />} menuCallback={this.menuCallback} />
                             </div>
                         ) : null}
                     </div>
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index a60cd98ac..e93724dd4 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -174,7 +174,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 const prev = ind && DocListCast(targetDataDoc[this._props.fieldKey])[ind - 1];
                 this._props.removeDocument?.(docIn);
                 if (ind > 0 && prev) {
-                    Doc.SetSelectOnLoad(prev);
+                    DocumentView.SetSelectOnLoad(prev);
                     DocumentView.getDocumentView(prev, this.DocumentView?.())?.select(false);
                 }
                 return true;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index ab4d8b060..6208905fe 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1300,7 +1300,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
                     const fieldKey = Doc.LayoutFieldKey(newParent);
                     if (remove && fieldKey && Cast(newParent[fieldKey], listSpec(Doc)) !== undefined) {
                         remove(child);
-                        Doc.SetSelectOnLoad(child);
+                        DocumentView.SetSelectOnLoad(child);
                         TreeView._editTitleOnLoad = editTitle ? { id: child[Id], parent } : undefined;
                         Doc.AddDocToList(newParent, fieldKey, child, addAfter, false);
                         newParent.treeView_Open = true;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 43addfc29..89aa53c35 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -293,7 +293,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     getActiveDocuments = () => this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map(pair => pair.layout);
     isAnyChildContentActive = () => this._props.isAnyChildContentActive();
     addLiveTextBox = (newDoc: Doc) => {
-        Doc.SetSelectOnLoad(newDoc); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
+        DocumentView.SetSelectOnLoad(newDoc); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
         this.addDocument(newDoc);
     };
     selectDocuments = (docs: Doc[]) => {
@@ -1496,8 +1496,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         newDoc[DocData][Doc.LayoutFieldKey(newDoc, fieldProps.LayoutTemplateString)] = undefined; // the copy should not copy the text contents of it source, just the render style
         newDoc.x = NumCast(textDoc.x) + (below ? 0 : NumCast(textDoc._width) + 10);
         newDoc.y = NumCast(textDoc.y) + (below ? NumCast(textDoc._height) + 10 : 0);
-        Doc.SetSelectOnLoad(newDoc);
-        FormattedTextBox.DontSelectInitialText = true;
+        DocumentView.SetSelectOnLoad(newDoc);
         return this.addDocument?.(newDoc);
     }, 'copied text note');
 
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 9cfb0416c..00d7ea451 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -173,7 +173,7 @@ export class MarqueeView extends ObservableReactComponent<SubCollectionViewProps
             const slide = DocUtils.copyDragFactory(DocCast(Doc.UserDoc().emptySlide))!;
             slide.x = x;
             slide.y = y;
-            Doc.SetSelectOnLoad(slide);
+            DocumentView.SetSelectOnLoad(slide);
             TreeView._editTitleOnLoad = { id: slide[Id], parent: undefined };
             this._props.addDocument?.(slide);
             e.stopPropagation();
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index 80bf4bd12..e7f1de7f1 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -368,7 +368,7 @@ export class CollectionGridView extends CollectionSubView() {
                         undoable(
                             action(() => {
                                 const text = Docs.Create.TextDocument('', { _width: 150, _height: 50 });
-                                Doc.SetSelectOnLoad(text); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
+                                DocumentView.SetSelectOnLoad(text); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
                                 Doc.AddDocToList(this.Document, this._props.fieldKey, text);
                                 this.setLayoutList(this.addLayoutItem(this.savedLayoutList, this.makeLayoutItem(text, this.screenToCell(clickEv.clientX, clickEv.clientY))));
                             }),
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 595abc7f8..a514ee04e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1110,6 +1110,12 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
     public static DeselectAll: (except?: Doc) => void | undefined;
     public static DeselectView: (dv: DocumentView | undefined) => void | undefined;
     public static SelectView: (dv: DocumentView | undefined, extendSelection: boolean) => void | undefined;
+
+    public static SelectOnLoad: Doc | undefined;
+    public static SetSelectOnLoad(doc?: Doc) {
+        DocumentView.SelectOnLoad = doc;
+        doc && DocumentView.addViewRenderedCb(doc, dv => dv.select(false));
+    }
     /**
      * returns a list of all currently selected DocumentViews
      */
diff --git a/src/client/views/nodes/EquationBox.tsx b/src/client/views/nodes/EquationBox.tsx
index 576b5bbe0..dcc6e27ed 100644
--- a/src/client/views/nodes/EquationBox.tsx
+++ b/src/client/views/nodes/EquationBox.tsx
@@ -30,12 +30,12 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     componentDidMount() {
         this._props.setContentViewBox?.(this);
-        if (Doc.SelectOnLoad === this.Document && (!DocumentView.LightboxDoc() || DocumentView.LightboxContains(this.DocumentView?.()))) {
+        if (DocumentView.SelectOnLoad === this.Document && (!DocumentView.LightboxDoc() || DocumentView.LightboxContains(this.DocumentView?.()))) {
             this._props.select(false);
 
-            this._ref.current!.mathField.focus();
-            this.dataDoc.text === 'x' && this._ref.current!.mathField.select();
-            Doc.SetSelectOnLoad(undefined);
+            this._ref.current?.mathField.focus();
+            this.dataDoc.text === 'x' && this._ref.current?.mathField.select();
+            DocumentView.SetSelectOnLoad(undefined);
         }
         reaction(
             () => this._props.isSelected(),
@@ -66,7 +66,7 @@ export class EquationBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 color: StrCast(this.Document.color),
                 fontSize: this.fontSize,
             });
-            Doc.SetSelectOnLoad(nextEq);
+            DocumentView.SetSelectOnLoad(nextEq);
             this._props.addDocument?.(nextEq);
             e.stopPropagation();
         }
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index dcf9e1fed..7fb83571f 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -17,6 +17,7 @@ import { FieldView, FieldViewProps } from './FieldView';
 import './LabelBox.scss';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
 import { RichTextMenu } from './formattedText/RichTextMenu';
+import { DocumentView } from './DocumentView';
 
 @observer
 export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
@@ -230,8 +231,8 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps>() {
                             if (this._divRef) {
                                 this._divRef.addEventListener('beforeinput', this.beforeInput);
 
-                                if (Doc.SelectOnLoad === this.Document) {
-                                    Doc.SelectOnLoad = undefined;
+                                if (DocumentView.SelectOnLoad === this.Document) {
+                                    DocumentView.SetSelectOnLoad(undefined);
                                     this._divRef.focus();
                                 }
                                 this.fitTextToBox(this._divRef);
diff --git a/src/client/views/nodes/MapBox/MapBox.tsx b/src/client/views/nodes/MapBox/MapBox.tsx
index 541b41bf7..792cb6b46 100644
--- a/src/client/views/nodes/MapBox/MapBox.tsx
+++ b/src/client/views/nodes/MapBox/MapBox.tsx
@@ -353,7 +353,7 @@ export class MapBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
         const targetCreator = (annotationOn: Doc | undefined) => {
             const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, annotationOn, 'yellow');
-            Doc.SetSelectOnLoad(target);
+            DocumentView.SetSelectOnLoad(target);
             return target;
         };
         const docView = this.DocumentView?.();
diff --git a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
index eb0431b85..a27a8bda1 100644
--- a/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
+++ b/src/client/views/nodes/MapBox/MapBoxInfoWindow.tsx
@@ -32,7 +32,7 @@
 //     addNoteClick = (e: React.PointerEvent) => {
 //         setupMoveUpEvents(this, e, returnFalse, emptyFunction, e => {
 //             const newDoc = Docs.Create.TextDocument('Note', { _layout_autoHeight: true });
-//             Doc.SetSelectOnLoad(newDoc); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
+//             DocumentView.SetSelectOnLoad(newDoc); // track the new text box so we can give it a prop that tells it to focus itself when it's displayed
 //             Doc.AddDocToList(this.props.place, 'data', newDoc);
 //             this._stack?.scrollToBottom();
 //             e.stopPropagation();
diff --git a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
index 95f89a573..0627d382e 100644
--- a/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
+++ b/src/client/views/nodes/MapboxMapBox/MapboxContainer.tsx
@@ -237,7 +237,7 @@ export class MapBoxContainer extends ViewBoxAnnotatableComponent<FieldViewProps>
 
         const targetCreator = (annotationOn: Doc | undefined) => {
             const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, annotationOn, 'yellow');
-            Doc.SetSelectOnLoad(target);
+            DocumentView.SetSelectOnLoad(target);
             return target;
         };
         const docView = this.DocumentView?.();
diff --git a/src/client/views/nodes/formattedText/DailyJournal.tsx b/src/client/views/nodes/formattedText/DailyJournal.tsx
index 9decbfaf0..7999357b0 100644
--- a/src/client/views/nodes/formattedText/DailyJournal.tsx
+++ b/src/client/views/nodes/formattedText/DailyJournal.tsx
@@ -51,22 +51,13 @@ export class DailyJournal extends ViewBoxAnnotatableComponent<FieldViewProps>()
     @action
     setDailyText() {
         console.log('setDailyText() called...');
-        const initialText = `Journal Entry - ${this.journalDate}\n\nStart writing here...`;
+        const placeholderText = 'Start writing here...';
+        const initialText = `Journal Entry - ${this.journalDate}\n${placeholderText}`;
 
         console.log('Checking if dataDoc has text field...');
 
         console.log('Setting new text field with:', initialText);
-        this.dataDoc[this.fieldKey] = new RichTextField(
-            JSON.stringify({
-                doc: {
-                    type: 'doc',
-                    content: [{ type: 'paragraph', content: [{ type: 'text', text: initialText }] }],
-                },
-                selection: { type: 'text', anchor: 1, head: 1 },
-                storedMarks: [],
-            }),
-            initialText
-        );
+        this.dataDoc[this.fieldKey] = RichTextField.textToRtf(initialText, undefined, placeholderText.length);
 
         console.log('Current text field:', this.dataDoc[this.fieldKey]);
     }
@@ -85,10 +76,11 @@ export class DailyJournal extends ViewBoxAnnotatableComponent<FieldViewProps>()
     }
 
     render() {
-        return <div style={{ background: 'beige', width: '100%', height: '100%' }}>     
-         <FormattedTextBox {...this._props} fieldKey={'text'} Document={this.Document} TemplateDataDocument={undefined} />
-                          
-        </div>;
+        return (
+            <div style={{ background: 'beige', width: '100%', height: '100%' }}>
+                <FormattedTextBox {...this._props} fieldKey={'text'} Document={this.Document} TemplateDataDocument={undefined} />
+            </div>
+        );
     }
 }
 
@@ -99,6 +91,7 @@ Docs.Prototypes.TemplateMap.set(DocumentType.JOURNAL, {
         _height: 35,
         _xMargin: 10,
         _yMargin: 10,
+        _layout_autoHeight: true,
         _layout_nativeDimEditable: true,
         _layout_reflowVertical: true,
         _layout_reflowHorizontal: true,
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index c2a2caecf..83ee619d0 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -99,7 +99,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
     public static Init(nodeViews: (self: FormattedTextBox) => { [key: string]: NodeViewConstructor }) { FormattedTextBox._nodeViews = nodeViews; } // prettier-ignore
 
     public static PasteOnLoad: ClipboardEvent | undefined;
-    public static DontSelectInitialText = false; // whether initial text should be selected or not
     public static SelectOnLoadChar = '';
     public static LiveTextUndo: UndoManager.Batch | undefined; // undo batch when typing a new text note into a collection
 
@@ -286,7 +285,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             e.stopPropagation();
             const targetCreator = (annotationOn?: Doc) => {
                 const target = DocUtils.GetNewTextDoc('Note linked to ' + this.Document.title, 0, 0, 100, 100, annotationOn);
-                Doc.SetSelectOnLoad(target);
+                DocumentView.SetSelectOnLoad(target);
                 return target;
             };
 
@@ -1542,44 +1541,26 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
             this._editorView.TextView = this;
         }
 
-        const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.Document, Doc.SelectOnLoad) && (!DocumentView.LightboxDoc() || DocumentView.LightboxContains(this.DocumentView?.()));
+        const selectOnLoad = Doc.AreProtosEqual(this._props.TemplateDataDocument ?? this.Document, DocumentView.SelectOnLoad) && (!DocumentView.LightboxDoc() || DocumentView.LightboxContains(this.DocumentView?.()));
         const selLoadChar = FormattedTextBox.SelectOnLoadChar;
         if (selectOnLoad) {
-            Doc.SetSelectOnLoad(undefined);
+            DocumentView.SetSelectOnLoad(undefined);
             FormattedTextBox.SelectOnLoadChar = '';
         }
         if (this.EditorView && selectOnLoad && !this._props.dontRegisterView && !this._props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
-            this._props.select(false);
+            const $from = this.EditorView.state.selection.anchor ? this.EditorView.state.doc.resolve(this.EditorView.state.selection.anchor - 1) : undefined;
+            const mark = schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) });
+            const curMarks = this.EditorView.state.storedMarks ?? $from?.marksAcross(this.EditorView.state.selection.$head) ?? [];
+            const storedMarks = [...curMarks.filter(m => m.type !== mark.type), mark];
+            let { tr } = this.EditorView.state;
             if (selLoadChar) {
-                const $from = this.EditorView.state.selection.anchor ? this.EditorView.state.doc.resolve(this.EditorView.state.selection.anchor - 1) : undefined;
-                const mark = schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) });
-                const curMarks = this.EditorView.state.storedMarks ?? $from?.marksAcross(this.EditorView.state.selection.$head) ?? [];
-                const storedMarks = [...curMarks.filter(m => m.type !== mark.type), mark];
                 const tr1 = this.EditorView.state.tr.setStoredMarks(storedMarks);
-                const tr2 = selLoadChar === 'Enter' ? tr1.insert(this.EditorView.state.doc.content.size - 1, schema.nodes.paragraph.create()) : tr1.insertText(selLoadChar, this.EditorView.state.doc.content.size - 1);
-                const tr = tr2.setStoredMarks(storedMarks);
-
-                this.EditorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
-                this.tryUpdateDoc(true); // calling select() above will make isContentActive() true only after a render .. which means the selectAll() above won't write to the Document and the incomingValue will overwrite the selection with the non-updated data
-            } else if (!FormattedTextBox.DontSelectInitialText) {
-                const mark = schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) });
-                selectAll(this.EditorView.state, (tx: Transaction) => {
-                    this.EditorView?.dispatch(tx.addStoredMark(mark));
-                });
-                this.EditorView?.dispatch(this.EditorView.state.tr.setSelection(new TextSelection(this.EditorView.state.doc.resolve(1))));
-                this.tryUpdateDoc(true); // calling select() above will make isContentActive() true only after a render .. which means the selectAll() above won't write to the Document and the incomingValue will overwrite the selection with the non-updated data
-            } else {
-                const $from = this.EditorView.state.selection.anchor ? this.EditorView.state.doc.resolve(this.EditorView.state.selection.anchor - 1) : undefined;
-                const mark = schema.marks.user_mark.create({ userid: ClientUtils.CurrentUserEmail(), modified: Math.floor(Date.now() / 1000) });
-                const curMarks = this.EditorView.state.storedMarks ?? $from?.marksAcross(this.EditorView.state.selection.$head) ?? [];
-                const storedMarks = [...curMarks.filter(m => m.type !== mark.type), mark];
-                const { tr } = this.EditorView.state;
-                this.EditorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))).setStoredMarks(storedMarks));
-                this.tryUpdateDoc(true); // calling select() above will make isContentActive() true only after a render .. which means the selectAll() above won't write to the Document and the incomingValue will overwrite the selection with the non-updated data
+                tr = selLoadChar === 'Enter' ? tr1.insert(this.EditorView.state.doc.content.size - 1, schema.nodes.paragraph.create()) : tr1.insertText(selLoadChar, this.EditorView.state.doc.content.size - 1);
             }
+            this.EditorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))).setStoredMarks(storedMarks));
+            this.tryUpdateDoc(true); // calling select() above will make isContentActive() true only after a render .. which means the selectAll() above won't write to the Document and the incomingValue will overwrite the selection with the non-updated data
         }
         if (selectOnLoad) {
-            FormattedTextBox.DontSelectInitialText = false;
             this.EditorView!.focus();
         }
         if (this._props.isContentActive()) this.prepareForTyping();
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index bdd41b0bb..805bb4526 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -468,10 +468,6 @@ export class Doc extends RefField {
     }
 }
 export namespace Doc {
-    export let SelectOnLoad: Doc | undefined;
-    export function SetSelectOnLoad(doc: Doc | undefined) {
-        SelectOnLoad = doc;
-    }
     export let DocDragDataName: string = '';
     export function SetDocDragDataName(name: string) {
         DocDragDataName = name;
diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts
index dc636031a..4b1403b88 100644
--- a/src/fields/RichTextField.ts
+++ b/src/fields/RichTextField.ts
@@ -48,26 +48,77 @@ export class RichTextField extends ObjectField {
             ''
         );
     }
+    static Initialize = (initial?: string) => {
+        const content: object[] = [];
+        const state = {
+            doc: {
+                type: 'doc',
+                content,
+            },
+            selection: {
+                type: 'text',
+                anchor: 0,
+                head: 0,
+            },
+        };
+        if (initial && initial.length) {
+            content.push({
+                type: 'paragraph',
+                content: {
+                    type: 'text',
+                    text: initial,
+                },
+            });
+            state.selection.anchor = state.selection.head = initial.length + 1;
+        }
+        return JSON.stringify(state);
+    };
+
+    private static ToProsemirrorState = (plainText: string, selectBack?: number, delimeter = '\n') => {
+        // Remap the text, creating blocks split on newlines
+        const elements = plainText.split(delimeter);
+
+        // Google Docs adds in an extra carriage return automatically, so this counteracts it
+        !elements[elements.length - 1].length && elements.pop();
+
+        // Preserve the current state, but re-write the content to be the blocks
+        const parsed: Record<string, unknown> = JSON.parse(RichTextField.Initialize());
+        (parsed.doc as Record<string, unknown>).content = elements.map(text => {
+            const paragraph: object = {
+                type: 'paragraph',
+                content: text.length ? [{ type: 'text', marks: [], text }] : undefined, // An empty paragraph gets treated as a line break
+            };
+            return paragraph;
+        });
 
-    public static textToRtf(text: string, imgDocId?: string) {
+        // If the new content is shorter than the previous content and selection is unchanged, may throw an out of bounds exception, so we reset it
+        parsed.selection = { type: 'text', anchor: 2 + plainText.length - (selectBack ?? 0), head: 2 + plainText.length };
+
+        // Export the ProseMirror-compatible state object we've just built
+        return JSON.stringify(parsed);
+    };
+
+    public static textToRtf(text: string, imgDocId?: string, selectBack?: number) {
         return new RichTextField(
-            JSON.stringify({
-                // this is a RichText json that has the question text placed above a related image
-                doc: {
-                    type: 'doc',
-                    content: [
-                        {
-                            type: 'paragraph',
-                            attrs: { align: 'center', color: null, id: null, indent: null, inset: null, lineSpacing: null, paddingBottom: null, paddingTop: null },
-                            content: [
-                                ...(text ? [{ type: 'text', text }] : []), //
-                                ...(imgDocId ? [{ type: 'dashDoc', attrs: { width: '200px', height: '200px', title: 'dashDoc', float: 'unset', hidden: false, docId: imgDocId } }] : []),
-                            ],
-                        },
-                    ],
-                },
-                selection: { type: 'text', anchor: 2, head: 2 },
-            }),
+            !imgDocId
+                ? this.ToProsemirrorState(text, selectBack)
+                : JSON.stringify({
+                      // this is a RichText json that has the question text placed above a related image
+                      doc: {
+                          type: 'doc',
+                          content: [
+                              {
+                                  type: 'paragraph',
+                                  attrs: { align: 'center', color: null, id: null, indent: null, inset: null, lineSpacing: null, paddingBottom: null, paddingTop: null },
+                                  content: [
+                                      ...(text ? [{ type: 'text', text }] : []), //
+                                      ...(imgDocId ? [{ type: 'dashDoc', attrs: { width: '200px', height: '200px', title: 'dashDoc', float: 'unset', hidden: false, docId: imgDocId } }] : []),
+                                  ],
+                              },
+                          ],
+                      },
+                      selection: { type: 'text', anchor: 2 + text.length, head: 2 + text.length },
+                  }),
             text
         );
     }
-- 
cgit v1.2.3-70-g09d2


From d5eb3271f705b62deb20d6044a9f9e1562ab9ae4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 7 Mar 2025 11:06:31 -0500
Subject: changed masonryView so that if column count is set w/o a columnWidth,
 then it stays fixed

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

(limited to 'src/client/views/collections/CollectionStackingView.tsx')

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 72e6bb8f2..6bbd43b1b 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -239,9 +239,9 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
         );
         // reset section headers when a new filter is inputted
         this._disposers.width = reaction(
-            () => [this._props.PanelWidth() - 2 * this.xMargin, NumCast(this.Document._layout_columnWidth, 250)],
+            () => [this._props.PanelWidth() - 2 * this.xMargin, NumCast(this.Document._layout_columnWidth)],
             ([pw, cw]) => {
-                if (!this.isStackingView && Math.round(pw / cw)) {
+                if (cw && !this.isStackingView && Math.round(pw / cw)) {
                     this.layoutDoc._layout_columnCount = Math.round(pw / cw);
                 }
             }
-- 
cgit v1.2.3-70-g09d2

