From 72dad52c4fea5a2fccabacbb6a49ca1494093954 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 22 Jun 2023 10:14:26 -0400
Subject: cleaned up dragging - abort presItem drags properly, fix naming for
 drag/dropAction, small fix undo of drag removeproperties, dragging in/out of
 headerBar,  fixed isContentActive to avoid SnappingManager.GetIsDragging. 
 fixed resizing videos.

---
 .../views/nodes/formattedText/FormattedTextBox.tsx  | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 079129dc9..2cd3c6cd6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -297,7 +297,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     };
 
     dispatchTransaction = (tx: Transaction) => {
-        if (this._editorView) {
+        if (this._editorView && (this._editorView as any).docView) {
             const state = this._editorView.state.apply(tx);
             this._editorView.updateState(state);
 
@@ -2020,17 +2020,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     _oldWheel: any;
     render() {
         TraceMobx();
-        const active = this.props.isContentActive() || this.props.isSelected();
-        const selected = active;
+        const active = this.props.isContentActive();
         const scale = (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._freeform_scale, 1);
         const rounded = StrCast(this.layoutDoc.layout_borderRounding) === '100%' ? '-rounded' : '';
-        const interactive = (Doc.ActiveTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition);
-        if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
+        if (!active && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
         const minimal = this.props.ignoreAutoHeight;
         const paddingX = NumCast(this.layoutDoc._xMargin, this.props.xPadding || 0);
         const paddingY = NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
-        const selPad = (selected && !this.layoutDoc._createDocOnCR) || minimal ? Math.min(paddingY, Math.min(paddingX, 10)) : 0;
-        const selPaddingClass = selected && !this.layoutDoc._createDocOnCR && paddingY >= 10 ? '-selected' : '';
+        const selPad = (active && !this.layoutDoc._createDocOnCR) || minimal ? Math.min(paddingY, Math.min(paddingX, 10)) : 0;
+        const selPaddingClass = active && !this.layoutDoc._createDocOnCR && paddingY >= 10 ? '-selected' : '';
         const styleFromLayoutString = Doc.styleFromLayoutString(this.rootDoc, this.layoutDoc, this.props, scale); // this converts any expressions in the format string to style props.  e.g., <FormattedTextBox height='{this._headerHeight}px' >
         return styleFromLayoutString?.height === '0px' ? null : (
             <div
@@ -2051,7 +2049,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                               width: `${100 / scale}%`,
                               height: `${100 / scale}%`,
                           }),
-                    display: !SnappingManager.GetIsDragging() && this.props.thumbShown?.() ? 'none' : undefined,
+                    display: !this.props.isContentActive() && this.props.thumbShown?.() ? 'none' : undefined,
                     transition: 'inherit',
                     // overflowY: this.layoutDoc._layout_autoHeight ? "hidden" : undefined,
                     color: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color),
@@ -2066,7 +2064,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     style={{
                         overflow: this.layout_autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an layout_autoHeight doc in its own tab, or in the lightbox
                         height: this.props.height || (this.layout_autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
-                        pointerEvents: interactive ? undefined : 'none',
+                        pointerEvents: Doc.ActiveTool === InkTool.None ? undefined : 'none',
                     }}
                     onContextMenu={this.specificContextMenu}
                     onKeyDown={this.onKeyDown}
@@ -2078,11 +2076,10 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     onPointerDown={this.onPointerDown}
                     onDoubleClick={this.onDoubleClick}>
                     <div
-                        className={`formattedTextBox-outer${selected ? '-selected' : ''}`}
+                        className={`formattedTextBox-outer${active ? '-selected' : ''}`}
                         ref={this._scrollRef}
                         style={{
                             width: this.props.dontSelectOnLoad ? '100%' : `calc(100% - ${this.layout_sidebarWidthPercent})`,
-                            pointerEvents: !active && !SnappingManager.GetIsDragging() ? 'none' : undefined,
                             overflow: this.layoutDoc._createDocOnCR ? 'hidden' : this.layoutDoc._layout_autoHeight ? 'visible' : undefined,
                         }}
                         onScroll={this.onScroll}
@@ -2096,7 +2093,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                                 paddingRight: StrCast(this.layoutDoc._textBoxPaddingX, `${paddingX - selPad}px`),
                                 paddingTop: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY - selPad}px`),
                                 paddingBottom: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY - selPad}px`),
-                                pointerEvents: !active && !SnappingManager.GetIsDragging() ? (IsFollowLinkScript(this.layoutDoc.onClick) ? 'none' : undefined) : undefined,
+                                // pointerEvents: !active && IsFollowLinkScript(this.layoutDoc.onClick) ? 'none' : undefined,
                             }}
                         />
                     </div>
-- 
cgit v1.2.3-70-g09d2


From 5c32758dbc26a0c0e034d878e9dff633061dc2c6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 22 Jun 2023 10:32:04 -0400
Subject: fix so that text boxes don't sometimes collapse when being dragged.

---
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 2cd3c6cd6..2e8f6c696 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1837,7 +1837,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     tryUpdateScrollHeight = () => {
         const margins = 2 * NumCast(this.layoutDoc._yMargin, this.props.yPadding || 0);
         const children = this.ProseRef?.children.length ? Array.from(this.ProseRef.children[0].children) : undefined;
-        if (children) {
+        if (children && !SnappingManager.GetIsDragging()) {
             const toNum = (val: string) => Number(val.replace('px', '').replace('auto', '0'));
             const toHgt = (node: Element) => {
                 const { height, marginTop, marginBottom } = getComputedStyle(node);
@@ -1848,6 +1848,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             if (this.props.setHeight && scrollHeight && !this.props.dontRegisterView) {
                 // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation
                 const setScrollHeight = () => (this.rootDoc[this.fieldKey + '_scrollHeight'] = scrollHeight);
+
                 if (this.rootDoc === this.layoutDoc || this.layoutDoc.resolvedDataDoc) {
                     setScrollHeight();
                 } else {
-- 
cgit v1.2.3-70-g09d2


From 1429ab79eac9aa316082f52c14c576f6b3a97111 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 23 Jun 2023 13:14:18 -0400
Subject: cleaned up more issues with pointer events/contents active.  fixed
 dragging from piles.

---
 src/client/documents/Documents.ts                  |  7 ++-
 src/client/util/UndoManager.ts                     |  3 +-
 src/client/views/DocComponent.tsx                  |  2 +-
 src/client/views/PropertiesButtons.tsx             |  1 +
 .../collections/CollectionMasonryViewFieldRow.tsx  |  9 +--
 src/client/views/collections/CollectionMenu.tsx    |  3 +-
 .../views/collections/CollectionNoteTakingView.tsx | 13 +++--
 .../collections/CollectionNoteTakingViewColumn.tsx |  1 +
 .../views/collections/CollectionPileView.tsx       |  8 +--
 .../collections/CollectionStackedTimeline.tsx      | 30 +++++-----
 .../views/collections/CollectionStackingView.tsx   | 10 +++-
 .../CollectionStackingViewFieldColumn.tsx          |  1 +
 src/client/views/collections/CollectionSubView.tsx | 18 +++---
 .../views/collections/CollectionTreeView.tsx       | 15 +++--
 src/client/views/collections/TreeView.tsx          | 23 ++++++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 17 +++---
 .../collections/collectionFreeForm/MarqueeView.tsx |  1 +
 .../CollectionMulticolumnView.tsx                  |  1 +
 .../CollectionMultirowView.tsx                     |  1 +
 .../collectionSchema/CollectionSchemaView.tsx      |  3 +-
 src/client/views/nodes/ComparisonBox.tsx           | 11 ++--
 src/client/views/nodes/DocumentView.tsx            | 22 +++++---
 src/client/views/nodes/FunctionPlotBox.tsx         |  5 +-
 src/client/views/nodes/ImageBox.tsx                | 17 +++---
 src/client/views/nodes/LabelBox.tsx                |  2 +
 src/client/views/nodes/ScriptingBox.tsx            |  8 ++-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 64 +++++++++++++---------
 src/fields/Proxy.ts                                |  4 +-
 src/fields/util.ts                                 |  3 +-
 29 files changed, 184 insertions(+), 119 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a61ef1da3..acd323eca 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -361,12 +361,13 @@ export class DocumentOptions {
     _forceActive?: BOOLt = new BoolInfo('flag to handle pointer events when not selected (or otherwise active)');
     _dragOnlyWithinContainer?: BOOLt = new BoolInfo('whether the document should remain in its collection when someone tries to drag and drop it elsewhere');
     _raiseWhenDragged?: BOOLt = new BoolInfo('whether a document is brought to front when dragged.');
-    childDragAction?: DROPt = new DAInfo('what should happen to the child documents when they are dragged fromt he collection');
+    childDragAction?: DROPt = new DAInfo('what should happen to the child documents when they are dragged from the collection');
     dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
     dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
     _dropAction?: DROPt = new DAInfo("what should happen to this document when it's dropped somewhere else");
     _dropPropertiesToRemove?: List<string>; // list of properties that should be removed from a document when it is dropped.  e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
     cloneFieldFilter?: List<string>; // fields not to copy when the document is clonedclipboard?: Doc;
+    dragWhenActive?: BOOLt = new BoolInfo('should document drag when it is active - e.g., pileView, group');
     dragAction?: DROPt = new DAInfo('how to drag document when it is active (e.g., tree, groups)');
     dragFactory_count?: NUMt = new NumInfo('number of items created from a drag button (used for setting title with incrementing index)', true);
     dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script
@@ -667,7 +668,7 @@ export namespace Docs {
                 {
                     data: new List<Doc>(),
                     layout: { view: EmptyBox, dataField: defaultDataKey },
-                    options: { childDragAction: 'embed', title: 'Global Group Database' },
+                    options: { title: 'Global Group Database' },
                 },
             ],
             [
@@ -1663,7 +1664,7 @@ export namespace DocUtils {
             });
         });
         if (create) {
-            const newCollection = Docs.Create.PileDocument(docList, { title: 'pileup', x: (x || 0) - size, y: (y || 0) - size, _width: size * 2, _height: size * 2 });
+            const newCollection = Docs.Create.PileDocument(docList, { title: 'pileup', x: (x || 0) - size, y: (y || 0) - size, _width: size * 2, _height: size * 2, dragWhenActive: true });
             newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - size;
             newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - size;
             newCollection._width = newCollection._height = size * 2;
diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts
index 2379cb2ab..b59af6656 100644
--- a/src/client/util/UndoManager.ts
+++ b/src/client/util/UndoManager.ts
@@ -1,4 +1,5 @@
 import { observable, action, runInAction } from 'mobx';
+import { Field } from '../../fields/Doc';
 import { Without } from '../../Utils';
 
 function getBatchName(target: any, key: string | symbol): string {
@@ -95,7 +96,7 @@ export namespace UndoManager {
 
     export function AddEvent(event: UndoEvent, value?: any): void {
         if (currentBatch && batchCounter.get() && !undoing) {
-            console.log('                         '.slice(0, batchCounter.get()) + 'UndoEvent : ' + event.prop + ' = ' + value);
+            console.log('                         '.slice(0, batchCounter.get()) + 'UndoEvent : ' + event.prop + ' = ' + (value instanceof Array ? value.map(val => Field.toScriptString(val)).join(',') : Field.toScriptString(value)));
             currentBatch.push(event);
             tempEvents?.push(event);
         }
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 0709d6cb9..3de40a640 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -220,7 +220,7 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                             Doc.ActiveDashboard && inheritParentAcls(Doc.ActiveDashboard, doc);
                         });
                     const annoDocs = targetDataDoc[annotationKey ?? this.annotationKey] as List<Doc>;
-                    if (annoDocs instanceof List) annoDocs.push(...added);
+                    if (annoDocs instanceof List) annoDocs.push(...added.filter(add => !annoDocs.includes(add)));
                     else targetDataDoc[annotationKey ?? this.annotationKey] = new List<Doc>(added);
                     targetDataDoc[(annotationKey ?? this.annotationKey) + '_modificationDate'] = new DateField(new Date(Date.now()));
                 }
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 11b89fd69..74dd1c2f7 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -209,6 +209,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             (dv, doc) => {
                 doc.isGroup = !doc.isGroup;
                 doc.forceActive = doc.isGroup;
+                doc.dragWhenActive = doc.isGroup;
             }
         );
     }
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 64f9c6a87..6f88f6727 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -98,14 +98,15 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     rowDrop = action((e: Event, de: DragManager.DropEvent) => {
         this._createEmbeddingSelected = false;
         if (de.complete.docDragData) {
-            this.props.parent.Document.dropConverter instanceof ScriptField && this.props.parent.Document.dropConverter.script.run({ dragData: de.complete.docDragData });
             const key = this.props.pivotField;
             const castedValue = this.getValue(this.heading);
             const onLayoutDoc = this.onLayoutDoc(key);
-            de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, !onLayoutDoc));
-            this.props.parent.onInternalDrop(e, de);
-            e.stopPropagation();
+            if (this.props.parent.onInternalDrop(e, de)) {
+                de.complete.docDragData.droppedDocuments.forEach(d => Doc.SetInPlace(d, key, castedValue, !onLayoutDoc));
+            }
+            return true;
         }
+        return false;
     });
 
     getValue = (value: string): any => {
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index fc3f713ce..7d71bce13 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -427,8 +427,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
         if (docDragData?.draggedDocuments.length) {
             this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => c.immediate(docDragData.draggedDocuments || []));
             e.stopPropagation();
+            return true;
         }
-        return true;
+        return false;
     }
 
     dragViewDown = (e: React.PointerEvent) => {
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index 9a3ab8074..f1c4c2cdf 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -441,23 +441,24 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                         docs.splice(previousDocIndex + 1, 0, ...newDocs);
                     }
                 }
+                return true;
             }
         } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
             const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' });
-            this.props.addDocument?.(source);
+            if (!this.props.addDocument?.(source)) e.preventDefault();
             de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
             e.stopPropagation();
-        } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
+            return true;
+        } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) {
+            return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
+        }
         return false;
     };
 
     @undoBatch
     internalAnchorAnnoDrop(e: Event, annoDragData: DragManager.AnchorAnnoDragData) {
         const dropCreator = annoDragData.dropDocCreator;
-        annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => {
-            const dropDoc = dropCreator(annotationOn);
-            return dropDoc || this.rootDoc;
-        };
+        annoDragData.dropDocCreator = (annotationOn: Doc | undefined) => dropCreator(annotationOn) || this.rootDoc;
         return true;
     }
 
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
index 2f28ecd00..3286d60bd 100644
--- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
+++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx
@@ -92,6 +92,7 @@ export class CollectionNoteTakingViewColumn extends React.Component<CSVFieldColu
     columnDrop = action((e: Event, de: DragManager.DropEvent) => {
         const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) };
         drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false));
+        return true;
     });
 
     getValue = (value: string): any => {
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 15570b195..91be31289 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -63,12 +63,14 @@ export class CollectionPileView extends CollectionSubView() {
             <div className="collectionPileView-innards" style={{ pointerEvents: this.contentEvents }}>
                 <CollectionFreeFormView
                     {...this.props} //
-                    childContentsActive={returnFalse}
                     layoutEngine={this.layoutEngine}
                     addDocument={this.addPileDoc}
+                    moveDocument={this.removePileDoc}
+                    // pile children never have their contents active, but will be document active whenever the entire pile is.
+                    childContentsActive={returnFalse}
+                    childDocumentsActive={this.props.isDocumentActive}
                     childDragAction="move"
                     childClickScript={this.toggleIcon}
-                    moveDocument={this.removePileDoc}
                 />
             </div>
         );
@@ -106,7 +108,6 @@ export class CollectionPileView extends CollectionSubView() {
     _undoBatch: UndoManager.Batch | undefined;
     pointerDown = (e: React.PointerEvent) => {
         let dist = 0;
-        SnappingManager.SetIsDragging(true);
         setupMoveUpEvents(
             this,
             e,
@@ -129,7 +130,6 @@ export class CollectionPileView extends CollectionSubView() {
             () => {
                 this._undoBatch?.end();
                 this._undoBatch = undefined;
-                SnappingManager.SetIsDragging(false);
             },
             emptyFunction,
             e.shiftKey && this.layoutEngine() === computePassLayout.name,
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index e835fa659..ad84d859d 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -369,22 +369,22 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
     // handles dragging and dropping markers in timeline
     @action
     internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number) {
-        if (!de.embedKey && this.props.Document._isGroup) return false;
-        if (!super.onInternalDrop(e, de)) return false;
-
-        // determine x coordinate of drop and assign it to the documents being dragged  --- see internalDocDrop of collectionFreeFormView.tsx for how it's done when dropping onto a 2D freeform view
-        const localPt = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
-        const x = localPt[0] - docDragData.offset[0];
-        const timelinePt = this.toTimeline(x + this._scroll, this.timelineContentWidth);
-        docDragData.droppedDocuments.forEach(drop => {
-            const anchorEnd = this.anchorEnd(drop);
-            if (anchorEnd !== undefined) {
-                Doc.SetInPlace(drop, drop._timecodeToHide === undefined ? this.props.endTag : 'timecodeToHide', timelinePt + anchorEnd - this.anchorStart(drop), false);
-            }
-            Doc.SetInPlace(drop, drop._timecodeToShow === undefined ? this.props.startTag : 'timecodeToShow', timelinePt, false);
-        });
+        if (super.onInternalDrop(e, de)) {
+            // determine x coordinate of drop and assign it to the documents being dragged  --- see internalDocDrop of collectionFreeFormView.tsx for how it's done when dropping onto a 2D freeform view
+            const localPt = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y);
+            const x = localPt[0] - docDragData.offset[0];
+            const timelinePt = this.toTimeline(x + this._scroll, this.timelineContentWidth);
+            docDragData.droppedDocuments.forEach(drop => {
+                const anchorEnd = this.anchorEnd(drop);
+                if (anchorEnd !== undefined) {
+                    Doc.SetInPlace(drop, drop._timecodeToHide === undefined ? this.props.endTag : 'timecodeToHide', timelinePt + anchorEnd - this.anchorStart(drop), false);
+                }
+                Doc.SetInPlace(drop, drop._timecodeToShow === undefined ? this.props.startTag : 'timecodeToShow', timelinePt, false);
+            });
 
-        return true;
+            return true;
+        }
+        return false;
     }
 
     onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 8eed4f716..4756b4cd3 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -459,18 +459,24 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 const docs = this.childDocList;
                 // still figuring out where to add the document
                 if (docs && newDocs.length) {
+                    newDocs.forEach(newdoc => docs.indexOf(newdoc) !== -1 && docs.splice(docs.indexOf(newdoc), 1));
                     const insertInd = dropInd === -1 ? docs.length : dropInd + dropAfter;
                     const offset = newDocs.reduce((off, ndoc) => (this.filteredChildren.find((fdoc, i) => ndoc === fdoc && i < insertInd) ? off + 1 : off), 0);
                     newDocs.filter(ndoc => docs.indexOf(ndoc) !== -1).forEach(ndoc => docs.splice(docs.indexOf(ndoc), 1));
                     docs.splice(insertInd - offset, 0, ...newDocs);
                 }
+                return true;
             }
         } else if (de.complete.linkDragData?.dragDocument.embedContainer === this.props.Document && de.complete.linkDragData?.linkDragView?.props.CollectionFreeFormDocumentView?.()) {
             const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, _layout_fitWidth: true, title: 'dropped annotation' });
-            this.props.addDocument?.(source);
+            if (!this.props.addDocument?.(source)) e.preventDefault();
             de.complete.linkDocument = DocUtils.MakeLink(source, de.complete.linkDragData.linkSourceGetAnchor(), { link_relationship: 'doc annotation' }); // TODODO this is where in text links get passed
             e.stopPropagation();
-        } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
+            return true;
+        } else if (de.complete.annoDragData?.dragDocument && super.onInternalDrop(e, de)) {
+            return this.internalAnchorAnnoDrop(e, de.complete.annoDragData);
+        }
+        e.preventDefault();
         return false;
     };
 
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 6be9cb72d..ebb4ba5a1 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -94,6 +94,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     columnDrop = action((e: Event, de: DragManager.DropEvent) => {
         const drop = { docs: de.complete.docDragData?.droppedDocuments, val: this.getValue(this._heading) };
         this.props.pivotField && drop.docs?.forEach(d => Doc.SetInPlace(d, this.props.pivotField, drop.val, false));
+        return true;
     });
     getValue = (value: string): any => {
         const parsed = parseInt(value);
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 539dde7e0..39fb2db1e 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -185,12 +185,14 @@ export function CollectionSubView<X>(moreProps?: X) {
         @undoBatch
         protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {}
 
-        protected onInternalPreDrop(e: Event, de: DragManager.DropEvent, targetAction: dropActionType) {
+        protected onInternalPreDrop(e: Event, de: DragManager.DropEvent) {
             if (de.complete.docDragData) {
-                // if dropAction is, say 'embed', but we're just dragging within a collection, we want to ignore the targetAction.
-                // otherwise, the targetAction should become the actual action (which can still be overridden by the userDropAction -eg, shift/ctrl keys)
-                if (targetAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) {
-                    de.complete.docDragData.dropAction = targetAction;
+                // override the dropEvent's dropAction
+                const dropAction = this.layoutDoc.dropAction as dropActionType;
+                // if the dropEvent's dragAction is, say 'embed', but we're just dragging within a collection, we may not actually want to make an embedding.
+                // so we check if our collection has a dropAction set on it and if so, we use that instead.
+                if (dropAction && !de.complete.docDragData.draggedDocuments.some(d => d.embedContainer === this.props.Document && this.childDocs.includes(d))) {
+                    de.complete.docDragData.dropAction = dropAction;
                 }
                 e.stopPropagation();
             }
@@ -218,16 +220,16 @@ export function CollectionSubView<X>(moreProps?: X) {
                         ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData });
                         added = addedDocs.length ? this.addDocument(addedDocs) : true;
                     }
-                    added && e.stopPropagation();
-                    return added;
                 } else {
                     ScriptCast(this.rootDoc.dropConverter)?.script.run({ dragData: docDragData });
                     added = this.addDocument(docDragData.droppedDocuments);
+                    !added && alert('You cannot perform this move');
                 }
-                !added && alert('You cannot perform this move');
+                !added && e.preventDefault();
                 e.stopPropagation();
                 return added;
             } else if (de.complete.annoDragData) {
+                e.stopPropagation();
                 const dropCreator = de.complete.annoDragData.dropDocCreator;
                 de.complete.annoDragData.dropDocCreator = () => {
                     const dropped = dropCreator(this.props.isAnnotationOverlay ? this.rootDoc : undefined);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 7598bb753..4cd3885f5 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -140,11 +140,16 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
         if ((this._mainEle = ele)) this._treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.doc, this.onInternalPreDrop.bind(this));
     };
 
-    protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
+    protected onInternalPreDrop = (e: Event, de: DragManager.DropEvent) => {
+        const dropAction = this.layoutDoc.dropAction as dropActionType;
         const dragData = de.complete.docDragData;
         if (dragData) {
-            const isInTree = () => Doc.AreProtosEqual(dragData.treeViewDoc, this.props.Document) || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d));
-            dragData.dropAction = targetAction && !isInTree() ? targetAction : this.doc === dragData?.treeViewDoc ? 'same' : dragData.dropAction;
+            const sameTree = Doc.AreProtosEqual(dragData.treeViewDoc, this.rootDoc) ? true : false;
+            const isAlreadyInTree = () => sameTree || dragData.draggedDocuments.some(d => d.embedContainer === this.doc && this.childDocs.includes(d));
+            if (isAlreadyInTree() !== sameTree) {
+                console.log('WHAAAT');
+            }
+            dragData.dropAction = dropAction && !isAlreadyInTree() ? dropAction : sameTree ? 'same' : dragData.dropAction;
         }
     };
 
@@ -394,6 +399,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 <div
                     className="collectionTreeView-contents"
                     key="tree"
+                    ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}
                     style={{
                         ...(!titleBar ? { marginLeft: this.marginX(), paddingTop: this.marginTop() } : {}),
                         overflow: 'auto',
@@ -417,8 +423,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                                 minHeight: '100%',
                             }}
                             onWheel={e => e.stopPropagation()}
-                            onDrop={this.onTreeDrop}
-                            ref={r => !this.doc.treeViewHasOverlay && r && this.createTreeDropTarget(r)}>
+                            onDrop={this.onTreeDrop}>
                             <ul className={`no-indent${this.outlineMode ? '-outline' : ''}`}>{this.treeViewElements}</ul>
                         </div>
                     </div>
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 91ae2b3cc..8d8d895c6 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -347,7 +347,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     };
     deleteItem = () => this.props.removeDoc?.(this.doc);
 
-    preTreeDrop = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
+    preTreeDrop = (e: Event, de: DragManager.DropEvent) => {
         const dragData = de.complete.docDragData;
         dragData && (dragData.dropAction = this.props.treeView.props.Document === dragData.treeViewDoc ? 'same' : dragData.dropAction);
     };
@@ -355,7 +355,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     @undoBatch
     treeDrop = (e: Event, de: DragManager.DropEvent) => {
         const pt = [de.x, de.y];
-        if (!this._header.current) return;
+        if (!this._header.current) return false;
         const rect = this._header.current.getBoundingClientRect();
         const before = pt[1] < rect.top + rect.height / 2;
         const inside = this.props.treeView.fileSysMode && !this.doc.isFolder ? false : pt[0] > Math.min(rect.left + 75, rect.left + rect.width * 0.75) || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
@@ -364,14 +364,25 @@ export class TreeView extends React.Component<TreeViewProps> {
             const destDoc = this.doc;
             DocUtils.MakeLink(sourceDoc, destDoc, { link_relationship: 'tree link' });
             e.stopPropagation();
+            return true;
         }
         const docDragData = de.complete.docDragData;
         if (docDragData && pt[0] < rect.left + rect.width) {
             if (docDragData.draggedDocuments[0] === this.doc) return true;
-            if (this.dropDocuments(docDragData.droppedDocuments, before, inside, docDragData.dropAction, docDragData.removeDocument, docDragData.moveDocument, docDragData.treeViewDoc === this.props.treeView.props.Document)) {
-                e.stopPropagation();
-            }
+            const added = this.dropDocuments(
+                docDragData.droppedDocuments, //
+                before,
+                inside,
+                docDragData.dropAction,
+                docDragData.removeDocument,
+                docDragData.moveDocument,
+                docDragData.treeViewDoc === this.props.treeView.props.Document
+            );
+            e.stopPropagation();
+            !added && e.preventDefault();
+            return added;
         }
+        return false;
     };
 
     dropping: boolean = false;
@@ -924,7 +935,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 PanelHeight={return18}
                 contextMenuItems={this.contextMenuItems}
                 renderDepth={1}
-                isContentActive={this.props.isContentActive}
+                isContentActive={emptyFunction} //this.props.isContentActive}
                 isDocumentActive={this.props.isContentActive}
                 focus={this.refocus}
                 whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d7e073c5f..e6f8f3071 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -418,15 +418,16 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @undoBatch
     internalLinkDrop(e: Event, de: DragManager.DropEvent, linkDragData: DragManager.LinkDragData, xp: number, yp: number) {
         if (linkDragData.linkDragView.props.docViewPath().includes(this.props.docViewPath().lastElement())) {
-            // dragged document is a child of this collection
-            if (!linkDragData.linkDragView.props.CollectionFreeFormDocumentView?.() || linkDragData.dragDocument.embedContainer !== this.props.Document) {
-                // if the source doc view's embedContainer isn't this same freeformcollectionlinkDragData.dragDocument.embedContainer === this.props.Document
+            let added = false;
+            //  do nothing if link is dropped into any freeform view parent of dragged document
+            if (!linkDragData.dragDocument.embedContainer || linkDragData.dragDocument.embedContainer !== this.rootDoc) {
                 const source = Docs.Create.TextDocument('', { _width: 200, _height: 75, x: xp, y: yp, title: 'dropped annotation' });
-                this.props.addDocument?.(source);
+                added = this.props.addDocument?.(source) ? true : false;
                 de.complete.linkDocument = DocUtils.MakeLink(linkDragData.linkSourceGetAnchor(), source, { link_relationship: 'annotated by:annotation of' }); // TODODO this is where in text links get passed
             }
-            e.stopPropagation(); //  do nothing if link is dropped into any freeform view parent of dragged document
-            return true;
+            e.stopPropagation();
+            !added && e.preventDefault();
+            return added;
         }
         return false;
     }
@@ -1297,8 +1298,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 childFilters={this.childDocFilters}
                 childFiltersByRanges={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
-                isContentActive={this.props.childContentsActive ?? this.props.isContentActive() === false ? returnFalse : emptyFunction}
+                isDocumentActive={this.props.childDocumentsActive?.() || this.rootDoc._isGroup ? this.props.isDocumentActive : this.isContentActive}
+                isContentActive={this.props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction}
                 focus={this.Document._isGroup ? this.groupFocus : this.isAnnotationOverlay ? this.props.focus : this.focus}
                 addDocTab={this.addDocTab}
                 addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 898452ccb..5febbe83e 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -385,6 +385,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         newCollection._width = this.Bounds.width;
         newCollection._height = this.Bounds.height;
         newCollection._isGroup = makeGroup;
+        newCollection._dragWhenActive = makeGroup;
         newCollection.forceActive = makeGroup;
         newCollection.x = this.Bounds.left;
         newCollection.y = this.Bounds.top;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 32b42223b..6dcd2d422 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -220,6 +220,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                         }
                     })
                 );
+                return true;
             }
         }
         return false;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index fa3a9f352..4df5dad5a 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -220,6 +220,7 @@ export class CollectionMultirowView extends CollectionSubView() {
                         }
                     })
                 );
+                return true;
             }
         }
         return false;
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index 06b227b4b..ee5bf82ed 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -434,7 +434,6 @@ export class CollectionSchemaView extends CollectionSubView() {
     @action
     onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
         if (de.complete.columnDragData) {
-            e.stopPropagation();
             const mouseX = this.props.ScreenToLocalTransform().transformPoint(de.x, de.y)[0];
             const index = this.findDropIndex(mouseX);
             this.moveColumn(de.complete.columnDragData.colIndex, index ?? de.complete.columnDragData.colIndex);
@@ -448,6 +447,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                 });
             });
 
+            e.stopPropagation();
             return true;
         }
         const draggedDocs = de.complete.docDragData?.draggedDocuments;
@@ -462,7 +462,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                 if (draggedView) DocumentManager.Instance.RemoveView(draggedView);
                 DocumentManager.Instance.AddViewRenderedCb(doc, dv => dv.select(true));
             });
-            e.stopPropagation();
             return true;
         }
         return false;
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index d747c4527..2290e0711 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -42,13 +42,14 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
     };
 
     @undoBatch
-    private internalDrop = (event: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
+    private internalDrop = (e: Event, dropEvent: DragManager.DropEvent, fieldKey: string) => {
         if (dropEvent.complete.docDragData) {
-            event.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
             const droppedDocs = dropEvent.complete.docDragData?.droppedDocuments;
-            const res = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
-            res && (droppedDocs.lastElement().embedContainer = this.dataDoc);
-            return res;
+            const added = dropEvent.complete.docDragData.moveDocument?.(droppedDocs, this.rootDoc, (doc: Doc | Doc[]) => this.addDoc(doc instanceof Doc ? doc : doc.lastElement(), fieldKey));
+            droppedDocs.lastElement().embedContainer = this.dataDoc;
+            !added && e.preventDefault();
+            e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
+            return added;
         }
     };
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index fbc84389d..b6f1626f8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -356,9 +356,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     componentDidMount() {
         this.setupHandlers();
     }
-    preDropFunc = (e: Event, de: DragManager.DropEvent, targetAction: dropActionType) => {
-        if (de.complete.docDragData && this.isContentActive()) {
-            targetAction && (de.complete.docDragData.dropAction = targetAction);
+    preDropFunc = (e: Event, de: DragManager.DropEvent) => {
+        const dropAction = this.layoutDoc.dropAction as dropActionType;
+        if (de.complete.docDragData && this.isContentActive() && !this.props.treeViewDoc) {
+            dropAction && (de.complete.docDragData.dropAction = dropAction);
             e.stopPropagation();
         }
     };
@@ -492,8 +493,13 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     }
                     preventDefault = false;
                 }
-
-                this._singleClickFunc = clickFunc ?? (() => this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this.props.select(e.ctrlKey || e.metaKey || e.shiftKey));
+                const sendToBack = e.altKey;
+                this._singleClickFunc =
+                    clickFunc ??
+                    (() =>
+                        sendToBack
+                            ? this.props.DocumentView().props.CollectionFreeFormDocumentView?.().props.bringToFront(this.rootDoc, true)
+                            : this._componentView?.select?.(e.ctrlKey || e.metaKey, e.shiftKey) ?? this.props.select(e.ctrlKey || e.metaKey || e.shiftKey));
                 const waitFordblclick = this.props.waitForDoubleClickToClick?.() ?? this.Document.waitForDoubleClickToClick;
                 if ((clickFunc && waitFordblclick !== 'never') || waitFordblclick === 'always') {
                     this._doubleClickTimeout && clearTimeout(this._doubleClickTimeout);
@@ -541,7 +547,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 //if (this.props.isSelected(true) && this.rootDoc.type !== DocumentType.PDF && this.layoutDoc._type_collection !== CollectionViewType.Docking) e.preventDefault();
 
                 // listen to move events if document content isn't active or document is draggable
-                if (!this.layoutDoc._lockedPosition && (!this.isContentActive() || this.props.dragAction || this.rootDoc.dragAction)) {
+                if (!this.layoutDoc._lockedPosition && (!this.isContentActive() || BoolCast(this.rootDoc._dragWhenActive))) {
                     document.addEventListener('pointermove', this.onPointerMove);
                 }
             }
@@ -617,15 +623,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         if (this.props.dontRegisterView || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return false;
         if (this.props.Document === Doc.ActiveDashboard) {
             e.stopPropagation();
-            alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you don't have permission to modify the destination." : 'Linking to document tabs not yet supported. Drop link on document content.');
             e.preventDefault();
+            alert((e.target as any)?.closest?.('*.lm_content') ? "You can't perform this move most likely because you don't have permission to modify the destination." : 'Linking to document tabs not yet supported. Drop link on document content.');
             return true;
         }
         const linkdrag = de.complete.annoDragData ?? de.complete.linkDragData;
         if (linkdrag) {
             linkdrag.linkSourceDoc = linkdrag.linkSourceGetAnchor();
             if (linkdrag.linkSourceDoc) {
-                e.stopPropagation();
                 if (de.complete.annoDragData && !de.complete.annoDragData.dropDocument) {
                     de.complete.annoDragData.dropDocument = de.complete.annoDragData.dropDocCreator(undefined);
                 }
@@ -633,6 +638,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.rootDoc;
                     de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
                 }
+                e.stopPropagation();
                 return true;
             }
         }
diff --git a/src/client/views/nodes/FunctionPlotBox.tsx b/src/client/views/nodes/FunctionPlotBox.tsx
index 8a88bede6..61711417f 100644
--- a/src/client/views/nodes/FunctionPlotBox.tsx
+++ b/src/client/views/nodes/FunctionPlotBox.tsx
@@ -80,9 +80,10 @@ export class FunctionPlotBox extends ViewBoxAnnotatableComponent<FieldViewProps>
     @undoBatch
     drop = (e: Event, de: DragManager.DropEvent) => {
         if (de.complete.docDragData?.droppedDocuments.length) {
+            const added = de.complete.docDragData.droppedDocuments.reduce((res, doc) => res && Doc.AddDocToList(this.dataDoc, this.props.fieldKey, doc), true);
+            !added && e.preventDefault();
             e.stopPropagation(); // prevent parent Doc from registering new position so that it snaps back into place
-            de.complete.docDragData.droppedDocuments.map(doc => Doc.AddDocToList(this.dataDoc, this.props.fieldKey, doc));
-            return false;
+            return added;
         }
         return false;
     };
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 64d6814df..f67930a3f 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -135,19 +135,17 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
         if (de.complete.docDragData) {
+            let added = true;
             const targetIsBullseye = (ele: HTMLElement): boolean => {
                 if (!ele) return false;
                 if (ele === this._overlayIconRef.current) return true;
                 return targetIsBullseye(ele.parentElement as HTMLElement);
             };
             if (de.metaKey || targetIsBullseye(e.target as HTMLElement)) {
-                de.complete.docDragData.droppedDocuments.forEach(
-                    action((drop: Doc) => {
-                        Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop);
-                        this.rootDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
-                        e.stopPropagation();
-                    })
-                );
+                added = de.complete.docDragData.droppedDocuments.reduce((last: boolean, drop: Doc) => {
+                    this.rootDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
+                    return last && Doc.AddDocToList(this.dataDoc, this.fieldKey + '-alternates', drop);
+                }, true);
             } else if (de.altKey || !this.dataDoc[this.fieldKey]) {
                 const layoutDoc = de.complete.docDragData?.draggedDocuments[0];
                 const targetField = Doc.LayoutFieldKey(layoutDoc);
@@ -156,10 +154,13 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                     this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField);
                     Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(targetDoc), this.fieldKey);
                     Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey);
-                    e.stopPropagation();
                 }
             }
+            !added && e.preventDefault();
+            e.stopPropagation();
+            return added;
         }
+        return false;
     };
 
     @undoBatch
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 52f3575cb..4439be0cd 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -74,7 +74,9 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps & LabelBoxProp
         if (docDragData && missingParams?.includes((e.target as any).textContent)) {
             this.paramsDoc[(e.target as any).textContent] = new List<Doc>(docDragData.droppedDocuments.map((d, i) => (d.onDragStart ? docDragData.draggedDocuments[i] : d)));
             e.stopPropagation();
+            return true;
         }
+        return false;
     };
 
     @observable _mouseOver = false;
diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx
index 37fda14fc..3ad3c911d 100644
--- a/src/client/views/nodes/ScriptingBox.tsx
+++ b/src/client/views/nodes/ScriptingBox.tsx
@@ -270,8 +270,12 @@ export class ScriptingBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatable
     // sets field of the corresponding field key (param name) to be dropped document
     @action
     onDrop = (e: Event, de: DragManager.DropEvent, fieldKey: string) => {
-        Doc.SetInPlace(this.rootDoc, fieldKey, de.complete.docDragData?.droppedDocuments[0], true);
-        e.stopPropagation();
+        if (de.complete.docDragData) {
+            de.complete.docDragData.droppedDocuments.forEach(doc => Doc.SetInPlace(this.rootDoc, fieldKey, doc, true));
+            e.stopPropagation();
+            return true;
+        }
+        return false;
     };
 
     // deletes a param from all areas in which it is stored
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 2e8f6c696..da0fc9ffb 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -531,36 +531,50 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     @undoBatch
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
-        if (de.complete.annoDragData) de.complete.annoDragData.dropDocCreator = () => this.getAnchor(true);
+        if (de.complete.annoDragData) {
+            de.complete.annoDragData.dropDocCreator = () => this.getAnchor(true);
+            e.stopPropagation();
+            return true;
+        }
         const dragData = de.complete.docDragData;
         if (dragData) {
-            const draggedDoc = dragData.draggedDocuments.length && dragData.draggedDocuments[0];
-            // replace text contents whend dragging with Alt
-            if (draggedDoc && draggedDoc.type === DocumentType.RTF && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.altKey) {
-                if (draggedDoc.data instanceof RichTextField) {
-                    Doc.GetProto(this.dataDoc)[this.fieldKey] = new RichTextField(draggedDoc.data.Data, draggedDoc.data.Text);
-                    e.stopPropagation();
-                }
-                // embed document when dragg marked as embed
-            } else if (de.embedKey) {
-                const target = dragData.droppedDocuments[0];
-                const node = schema.nodes.dashDoc.create({
-                    width: target[Width](),
-                    height: target[Height](),
-                    title: 'dashDoc',
-                    docId: target[Id],
-                    float: 'unset',
-                });
-                if (!['embed', 'copy'].includes((dragData.dropAction ?? '') as any)) {
-                    dragData.removeDocument?.(dragData.draggedDocuments[0]);
+            const dataDoc = Doc.IsDelegateField(DocCast(this.layoutDoc.proto), this.fieldKey) ? DocCast(this.layoutDoc.proto) : this.dataDoc;
+            const effectiveAcl = GetEffectiveAcl(dataDoc);
+            let added = [AclEdit, AclAdmin, AclSelfEdit].includes(effectiveAcl);
+            const draggedDoc = dragData.draggedDocuments.lastElement();
+            if (added) {
+                // replace text contents when dragging with Alt
+                if (de.altKey) {
+                    const fieldKey = Doc.LayoutFieldKey(draggedDoc);
+                    if (draggedDoc[fieldKey] instanceof RichTextField && !Doc.AreProtosEqual(draggedDoc, this.props.Document)) {
+                        Doc.GetProto(this.dataDoc)[this.fieldKey] = Field.Copy(draggedDoc[fieldKey]);
+                    }
+
+                    // embed document when drag marked as embed
+                } else if (de.embedKey) {
+                    const node = schema.nodes.dashDoc.create({
+                        width: draggedDoc[Width](),
+                        height: draggedDoc[Height](),
+                        title: 'dashDoc',
+                        docId: draggedDoc[Id],
+                        float: 'unset',
+                    });
+                    if (!['embed', 'copy'].includes((dragData.dropAction ?? '') as any)) {
+                        added = dragData.removeDocument?.(draggedDoc) ? true : false;
+                    }
+                    if (added) {
+                        draggedDoc._freeform_fitContentsToBox = true;
+                        draggedDoc.embedContainer = this.rootDoc;
+                        const view = this._editorView!;
+                        view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
+                    }
                 }
-                target._freeform_fitContentsToBox = true;
-                target.embedContainer = this.rootDoc;
-                const view = this._editorView!;
-                view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
-                e.stopPropagation();
             } // otherwise, fall through to outer collection to handle drop
+            !added && e.preventDefault();
+            e.stopPropagation();
+            return added;
         }
+        return false;
     };
 
     getNodeEndpoints(context: Node, node: Node): { from: number; to: number } | null {
diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts
index 55d1d9ea4..c076f5fe1 100644
--- a/src/fields/Proxy.ts
+++ b/src/fields/Proxy.ts
@@ -1,5 +1,5 @@
 import { Deserializable } from '../client/util/SerializationHelper';
-import { FieldWaiting, Opt } from './Doc';
+import { Field, FieldWaiting, Opt } from './Doc';
 import { primitive, serializable } from 'serializr';
 import { observable, action, runInAction, computed } from 'mobx';
 import { DocServer } from '../client/DocServer';
@@ -39,7 +39,7 @@ export class ProxyField<T extends RefField> extends ObjectField {
     }
 
     [ToScriptString]() {
-        return 'invalid';
+        return Field.toScriptString(this[ToValue](undefined)?.value); // not sure this is quite right since it doesn't recreate a proxy field, but better than 'invalid' ?
     }
     [ToString]() {
         return 'ProxyField';
diff --git a/src/fields/util.ts b/src/fields/util.ts
index e3d1abc53..e439768ee 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -433,7 +433,8 @@ export function updateFunction(target: any, prop: any, value: any, receiver: any
                                   lastValue = ObjectField.MakeCopy(receiver[prop]);
                               },
                               prop: 'assign list',
-                          }
+                          },
+                    diff?.items
                 );
         }
         target[Update](op);
-- 
cgit v1.2.3-70-g09d2


From c0d45c06df10d29cae5f46eeecb220a11588c3a1 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 30 Jun 2023 23:43:59 -0400
Subject: fixed onBrowseClick for notetaking. fixed panning when in onBrowse
 explore mode.   fixed switching dashboards to not display an empty stack.

---
 src/client/util/DocumentManager.ts                 | 23 +++++++++++------
 src/client/views/DashboardView.tsx                 |  3 ++-
 .../views/collections/CollectionDockingView.tsx    |  1 +
 .../views/collections/CollectionNoteTakingView.tsx |  3 ++-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 30 ++++++++++------------
 src/client/views/nodes/DocumentView.tsx            |  5 ++--
 .../views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 7 files changed, 38 insertions(+), 29 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 7e3302067..351f9ef7c 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -228,7 +228,7 @@ export class DocumentManager {
     public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => {
         const docViewPath = targetDocView.docViewPath.slice();
         let rootContextView = docViewPath.shift();
-        await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined })));
+        await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined, focused: false })));
         if (options.toggleTarget && (!options.didMove || targetDocView.rootDoc.hidden)) targetDocView.rootDoc.hidden = !targetDocView.rootDoc.hidden;
         else if (options.openLocation?.startsWith(OpenWhere.toggle) && !options.didMove && rootContextView) DocumentViewInternal.addDocTabFunc(rootContextView.rootDoc, options.openLocation);
     };
@@ -242,7 +242,7 @@ export class DocumentManager {
     public showDocument = async (
         targetDoc: Doc, // document to display
         options: DocFocusOptions, // options for how to navigate to target
-        finished?: () => void
+        finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done.
     ) => {
         const docContextPath = DocumentManager.GetContextPath(targetDoc, true);
         if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false;
@@ -269,22 +269,29 @@ export class DocumentManager {
         docContextPath.shift();
         const childViewIterator = async (docView: DocumentView) => {
             const innerDoc = docContextPath.shift();
-            return { viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc)) ?? this.getDocumentView(innerDoc) : undefined };
+            return { focused: false, viewSpec: innerDoc, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc)) ?? this.getDocumentView(innerDoc) : undefined };
         };
+
         if (rootContextView) {
             const target = await this.focusViewsInPath(rootContextView, options, childViewIterator);
             this.restoreDocView(target.viewSpec, target.docView, options, target.contextView ?? target.docView, targetDoc);
-        }
-        finished?.();
+            finished?.(target.focused);
+        } else finished?.(false);
     };
 
-    focusViewsInPath = async (docView: DocumentView, options: DocFocusOptions, iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt<Doc>; childDocView: Opt<DocumentView> }>) => {
+    focusViewsInPath = async (
+        docView: DocumentView, //
+        options: DocFocusOptions,
+        iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt<Doc>; childDocView: Opt<DocumentView>; focused: boolean }>
+    ) => {
         let contextView: DocumentView | undefined; // view containing context that contains target
+        let focused = false;
         while (true) {
             docView.rootDoc.layout_fieldKey === 'layout_icon' ? await new Promise<void>(res => docView.iconify(res)) : undefined;
-            docView.props.focus(docView.rootDoc, options); // focus the view within its container
+            const nextFocus = docView.props.focus(docView.rootDoc, options); // focus the view within its container
+            focused = focused || (nextFocus === undefined ? false : true);
             const { childDocView, viewSpec } = await iterator(docView);
-            if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView };
+            if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView, focused };
             contextView = docView;
             docView = childDocView;
         }
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 6aae302ac..f6d843201 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -347,7 +347,8 @@ export class DashboardView extends React.Component {
                 },
             ],
         };
-        Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true);
+        if (dashboard.dockingConfig && dashboard.dockingConfig !== Doc.GetProto(dashboard).dockingConfig) dashboard.dockingConfig = JSON.stringify(reset);
+        else Doc.SetInPlace(dashboard, 'dockingConfig', JSON.stringify(reset), true);
         return reset;
     };
 
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index a5d7e7864..3bf3f1a74 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -359,6 +359,7 @@ export class CollectionDockingView extends CollectionSubView() {
         } catch (e) {}
         this._goldenLayout?.destroy();
         window.removeEventListener('resize', this.onResize);
+        window.removeEventListener('mouseup', this.onPointerUp);
 
         this._reactionDisposer?.();
         this._lightboxReactionDisposer?.();
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index f1c4c2cdf..fb995301a 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -192,7 +192,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
         if (found) {
             const top = found.getBoundingClientRect().top;
             const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
-            if (Math.floor(localTop[1]) !== 0) {
+            if (Math.floor(localTop[1]) !== 0 && Math.ceil(this.props.PanelHeight()) < (this._mainCont?.scrollHeight || 0)) {
                 let focusSpeed = options.zoomTime ?? 500;
                 smoothScroll(focusSpeed, this._mainCont!, localTop[1] + this._mainCont!.scrollTop, options.easeFunc);
                 return focusSpeed;
@@ -252,6 +252,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 layout_showTitle={this.props.childlayout_showTitle}
                 dragAction={StrCast(this.layoutDoc.childDragAction) as dropActionType}
                 onClick={this.onChildClickHandler}
+                onBrowseClick={this.props.onBrowseClick}
                 onDoubleClick={this.onChildDoubleClickHandler}
                 ScreenToLocalTransform={noteTakingDocTransform}
                 focus={this.focusDocument}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ef396c6b3..ba31916a7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -2256,22 +2256,20 @@ class CollectionFreeFormBackgroundGrid extends React.Component<CollectionFreeFor
 export function CollectionBrowseClick(dv: DocumentView, clientX: number, clientY: number) {
     const browseTransitionTime = 500;
     SelectionManager.DeselectAll();
-    if (
-        dv.props.focus(dv.props.Document, {
-            willZoomCentered: true,
-            zoomScale: 0.8,
-            zoomTime: browseTransitionTime,
-        }) === undefined
-    ) {
-        const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
-        let parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
-        while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
-        const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it.  Otherwise, zoom out on the parent ffview
-        ffview?.zoomSmoothlyAboutPt(ffview.getTransform().transformPoint(clientX, clientY), 0.5, browseTransitionTime);
-        Doc.linkFollowHighlight(dv?.props.Document, false);
-    } else {
-        DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true });
-    }
+    DocumentManager.Instance.showDocument(dv.rootDoc, { zoomScale: 0.8, willZoomCentered: true }, (focused: boolean) => {
+        if (!focused) {
+            const selfFfview = !dv.rootDoc._isGroup && dv.ComponentView instanceof CollectionFreeFormView ? dv.ComponentView : undefined;
+            let containers = dv.props.docViewPath();
+            let parFfview = dv.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+            for (var cont of containers) {
+                parFfview = parFfview ?? cont.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+            }
+            while (parFfview?.rootDoc._isGroup) parFfview = parFfview.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+            const ffview = selfFfview && selfFfview.rootDoc[selfFfview.scaleFieldKey] !== 0.5 ? selfFfview : parFfview; // if focus doc is a freeform that is not at it's default 0.5 scale, then zoom out on it.  Otherwise, zoom out on the parent ffview
+            ffview?.zoomSmoothlyAboutPt(ffview.getTransform().transformPoint(clientX, clientY), 0.5, browseTransitionTime);
+            Doc.linkFollowHighlight(dv?.props.Document, false);
+        }
+    });
 }
 ScriptingGlobals.add(CollectionBrowseClick);
 ScriptingGlobals.add(function nextKeyFrame(readOnly: boolean) {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b6f1626f8..733ee1ed1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -900,8 +900,9 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     };
     childFilters = () => [...this.props.childFilters(), ...StrListCast(this.layoutDoc.childFilters)];
 
-    /// disable pointer events on content when there's an enabled onClick script, or if contents are marked inactive
-    contentPointerEvents = () => ((!this.disableClickScriptFunc && this.onClickHandler) || this.isContentActive() === false ? 'none' : this.pointerEvents);
+    /// disable pointer events on content when there's an enabled onClick script (but not the browse script), or if contents are marked inactive
+    contentPointerEvents = () => ((!this.disableClickScriptFunc && this.onClickHandler && !this.props.onBrowseClick?.()) || this.isContentActive() === false ? 'none' : this.pointerEvents);
+
     @computed get contents() {
         TraceMobx();
         const isInk = StrCast(this.layoutDoc.layout).includes(InkingStroke.name) && !this.props.LayoutTemplateString;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index da0fc9ffb..026864ddd 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -2079,7 +2079,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     style={{
                         overflow: this.layout_autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an layout_autoHeight doc in its own tab, or in the lightbox
                         height: this.props.height || (this.layout_autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
-                        pointerEvents: Doc.ActiveTool === InkTool.None ? undefined : 'none',
+                        pointerEvents: Doc.ActiveTool === InkTool.None && !this.props.onBrowseClick ? undefined : 'none',
                     }}
                     onContextMenu={this.specificContextMenu}
                     onKeyDown={this.onKeyDown}
-- 
cgit v1.2.3-70-g09d2


From f96be621d52ebad3a65b891fe105eac5d128feee Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 1 Jul 2023 13:25:40 -0400
Subject: turned off notetaking chrome in browse mode.  fixed pointereventrs
 for text in/out of browse mode. changed background to be gray by default

---
 src/client/util/DocumentManager.ts                        | 2 +-
 src/client/views/StyleProvider.tsx                        | 2 +-
 src/client/views/collections/CollectionNoteTakingView.tsx | 2 +-
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 351f9ef7c..fb6bc67d8 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -289,7 +289,7 @@ export class DocumentManager {
         while (true) {
             docView.rootDoc.layout_fieldKey === 'layout_icon' ? await new Promise<void>(res => docView.iconify(res)) : undefined;
             const nextFocus = docView.props.focus(docView.rootDoc, options); // focus the view within its container
-            focused = focused || (nextFocus === undefined ? false : true);
+            focused = focused || (nextFocus === undefined ? false : true); // keep track of whether focusing on a view needed to actually change anything
             const { childDocView, viewSpec } = await iterator(docView);
             if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView, focused };
             contextView = docView;
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 330ccc583..f293733fb 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -227,7 +227,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                             ? '#00000010' // faint interior for collections on PDFs, images, etc
                             : doc?._isGroup
                             ? undefined
-                            : Cast((props?.renderDepth || 0) > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground, 'string') ?? (darkScheme() ? Colors.BLACK : 'linear-gradient(#065fff, #85c1f9)'));
+                            : Cast((props?.renderDepth || 0) > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground, 'string') ?? (darkScheme() ? Colors.BLACK : Colors.MEDIUM_GRAY));
                     break;
                 //if (doc._type_collection !== CollectionViewType.Freeform && doc._type_collection !== CollectionViewType.Time) return "rgb(62,62,62)";
                 default: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE);
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index fb995301a..53a42d2a6 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -47,7 +47,7 @@ export class CollectionNoteTakingView extends CollectionSubView() {
     @observable _cursor: CursorProperty = 'grab';
     @observable _scroll = 0;
     @computed get chromeHidden() {
-        return BoolCast(this.layoutDoc.chromeHidden);
+        return BoolCast(this.layoutDoc.chromeHidden) || this.props.onBrowseClick?.() ? true : false;
     }
     // columnHeaders returns the list of SchemaHeaderFields currently being used by the layout doc to render the columns
     @computed get colHeaderData() {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 026864ddd..62b3443d4 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -2079,7 +2079,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                     style={{
                         overflow: this.layout_autoHeight && this.props.CollectionFreeFormDocumentView?.() ? 'hidden' : undefined, //x this breaks viewing an layout_autoHeight doc in its own tab, or in the lightbox
                         height: this.props.height || (this.layout_autoHeight && this.props.renderDepth && !this.props.suppressSetHeight ? 'max-content' : undefined),
-                        pointerEvents: Doc.ActiveTool === InkTool.None && !this.props.onBrowseClick ? undefined : 'none',
+                        pointerEvents: Doc.ActiveTool === InkTool.None && !this.props.onBrowseClick?.() ? undefined : 'none',
                     }}
                     onContextMenu={this.specificContextMenu}
                     onKeyDown={this.onKeyDown}
-- 
cgit v1.2.3-70-g09d2


From 446ab35c19ae18a609acf26babbc4e6dc1c46876 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 2 Jul 2023 19:06:56 -0400
Subject: improved highlighting of tabs to show focus/active. added. menu item
 to open a tab in lightbox

---
 .../views/collections/CollectionDockingView.scss   |   6 +
 .../views/collections/CollectionDockingView.tsx    |  10 +-
 src/client/views/collections/TabDocView.tsx        | 144 +++++++++++----------
 src/client/views/nodes/DocumentView.tsx            |   4 +
 .../views/nodes/formattedText/FormattedTextBox.tsx |  11 +-
 5 files changed, 104 insertions(+), 71 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 78e44dfa2..4c15d5eed 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -15,6 +15,12 @@
     cursor: grab;
     color: $black;
 }
+.collectiondockingview-container .lm_splitter {
+    opacity: 0.2;
+    &:hover {
+        opacity: 1;
+    }
+}
 
 .lm_title.focus-visible {
     -webkit-appearance: none;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 3bf3f1a74..2ed55b3ca 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -29,6 +29,7 @@ import { CollectionFreeFormView } from './collectionFreeForm';
 import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
 import { TabDocView } from './TabDocView';
 import React = require('react');
+import { DocumentManager } from '../../util/DocumentManager';
 const _global = (window /* browser */ || global) /* node */ as any;
 
 @observer
@@ -410,7 +411,14 @@ export class CollectionDockingView extends CollectionSubView() {
             if (!htmlTarget.closest('*.lm_content') && (htmlTarget.closest('*.lm_tab') || htmlTarget.closest('*.lm_stack'))) {
                 const className = typeof htmlTarget.className === 'string' ? htmlTarget.className : '';
                 if (className.includes('lm_maximise')) this._flush = UndoManager.StartBatch('tab maximize');
-                else if (!className.includes('lm_close')) DocServer.UPDATE_SERVER_CACHE();
+                else {
+                    const tabTarget = (e.target as HTMLElement)?.parentElement?.className.includes('lm_tab') ? (e.target as HTMLElement).parentElement : (e.target as HTMLElement);
+                    const map = Array.from(this.tabMap).find(tab => tab.element[0] === tabTarget);
+                    if (map?.DashDoc && DocumentManager.Instance.getFirstDocumentView(map.DashDoc)) {
+                        SelectionManager.SelectView(DocumentManager.Instance.getFirstDocumentView(map.DashDoc), false);
+                    }
+                    if (!className.includes('lm_close')) DocServer.UPDATE_SERVER_CACHE();
+                }
             }
         }
         if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 118b216bf..83edc60df 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -43,12 +43,17 @@ interface TabDocViewProps {
 }
 @observer
 export class TabDocView extends React.Component<TabDocViewProps> {
+    static _firstTab = true;
     _mainCont: HTMLDivElement | null = null;
     _tabReaction: IReactionDisposer | undefined;
     @observable _activated: boolean = false;
     @observable _panelWidth = 0;
     @observable _panelHeight = 0;
     @observable _isActive: boolean = false;
+    @observable _isAnyChildContentActive = false;
+    @computed get _isContentActive() {
+        return SelectionManager.Views().some(view => view.rootDoc === this._document) || this._isAnyChildContentActive;
+    }
     @observable _document: Doc | undefined;
     @observable _view: DocumentView | undefined;
 
@@ -61,9 +66,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         return 'transparent';
     }
     @computed get tabColor() {
-        let tabColor = StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor)));
-        if (tabColor === 'transparent') return 'black';
-        return tabColor;
+        return this._isContentActive ? Colors.WHITE : Colors.MEDIUM_GRAY;
     }
     @computed get tabTextColor() {
         return this._document?.type === DocumentType.PRES ? 'black' : StrCast(this._document?._color, StrCast(this._document?.color, DefaultStyleProvider(this._document, undefined, StyleProp.Color)));
@@ -191,7 +194,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 }
             });
             tab._disposers.selectionDisposer = reaction(
-                () => SelectionManager.Views().some(v => v.topMost && v.props.Document === doc),
+                () => SelectionManager.Views().some(view => view.rootDoc === this._document),
                 action(selected => {
                     if (selected) this._activated = true;
                     const toggle = tab.element[0].children[2].children[0] as HTMLInputElement;
@@ -322,11 +325,13 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     }
     componentDidUpdate() {
         this._view && DocumentManager.Instance.AddView(this._view);
+        if (TabDocView._firstTab) SelectionManager.SelectView(this._view, false);
     }
 
     componentWillUnmount() {
         this._tabReaction?.();
         this._view && DocumentManager.Instance.RemoveView(this._view);
+        TabDocView._firstTab = false;
 
         this.props.glContainer.layoutManager.off('activeContentItemChanged', this.onActiveContentItemChanged);
     }
@@ -405,11 +410,15 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     };
     PanelWidth = () => this._panelWidth;
     PanelHeight = () => this._panelHeight;
-    miniMapColor = () => this.tabColor;
+    miniMapColor = () => Colors.MEDIUM_GRAY;
     tabView = () => this._view;
     disableMinimap = () => !this._document || this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._type_collection !== CollectionViewType.Freeform;
-    hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.layout_hideMinimap);
-
+    whenChildContentActiveChanges = (isActive: boolean) => (this._isAnyChildContentActive = isActive);
+    tabs = () => Array.from(CollectionDockingView.Instance?.tabMap ?? new Set());
+    isContentActive = () =>
+        SelectionManager.Views().some(dv => dv.rootDoc === this._document) ||
+        this._isAnyChildContentActive ||
+        (this.tabs().findIndex(tab => tab.DashDoc === this._document) === 0 && !this.tabs().some(tab => SelectionManager.Views().some(dv => dv.rootDoc === tab.DashDoc)));
     @computed get docView() {
         return !this._activated || !this._document ? null : (
             <>
@@ -427,7 +436,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     DataDoc={!Doc.AreProtosEqual(this._document[DocData], this._document) ? this._document[DocData] : undefined}
                     onBrowseClick={MainView.Instance.exploreMode}
                     waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick}
-                    isContentActive={returnTrue}
+                    isContentActive={this.isContentActive}
                     isDocumentActive={returnFalse}
                     PanelWidth={this.PanelWidth}
                     PanelHeight={this.PanelHeight}
@@ -441,30 +450,15 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     ScreenToLocalTransform={this.ScreenToLocalTransform}
                     dontCenter={'y'}
                     rootSelected={returnTrue}
-                    whenChildContentsActiveChanged={emptyFunction}
+                    whenChildContentsActiveChanged={this.whenChildContentActiveChanges}
                     focus={this.focusFunc}
                     docViewPath={returnEmptyDoclist}
                     bringToFront={emptyFunction}
                     pinToPres={TabDocView.PinDoc}
                 />
-                <TabMinimapView key="minimap" hideMinimap={this.hideMinimap} addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} />
-                <Tooltip key="ttip" title={<div className="dash-tooltip">{this._document.layout_hideMinimap ? 'Open minimap' : 'Close minimap'}</div>}>
-                    <div
-                        className="miniMap-hidden"
-                        style={{
-                            display: this.disableMinimap() || this._document._type_collection !== 'freeform' ? 'none' : undefined,
-                            color: this._document.layout_hideMinimap ? Colors.BLACK : Colors.WHITE,
-                            backgroundColor: this._document.layout_hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,
-                            boxShadow: this._document.layout_hideMinimap ? Shadows.STANDARD_SHADOW : undefined,
-                        }}
-                        onPointerDown={e => e.stopPropagation()}
-                        onClick={action(e => {
-                            e.stopPropagation();
-                            this._document!.layout_hideMinimap = !this._document!.layout_hideMinimap;
-                        })}>
-                        <FontAwesomeIcon icon={'globe-asia'} size="lg" />
-                    </div>
-                </Tooltip>
+                {this.disableMinimap() || this._document._type_collection !== CollectionViewType.Freeform ? null : (
+                    <TabMinimapView key="minimap" addDocTab={this.addDocTab} PanelHeight={this.PanelHeight} PanelWidth={this.PanelWidth} background={this.miniMapColor} document={this._document} tabView={this.tabView} />
+                )}
             </>
         );
     }
@@ -495,7 +489,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
 interface TabMinimapViewProps {
     document: Doc;
-    hideMinimap: () => boolean;
     tabView: () => DocumentView | undefined;
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
     PanelWidth: () => number;
@@ -573,43 +566,64 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
         const miniLeft = 50 + ((NumCast(this.props.document._freeform_panX) - this.renderBounds.cx) / this.renderBounds.dim) * 100 - miniWidth / 2;
         const miniTop = 50 + ((NumCast(this.props.document._freeform_panY) - this.renderBounds.cy) / this.renderBounds.dim) * 100 - miniHeight / 2;
         const miniSize = this.returnMiniSize();
-        return this.props.hideMinimap() ? null : (
-            <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
-                <CollectionFreeFormView
-                    Document={this.props.document}
-                    docViewPath={returnEmptyDoclist}
-                    childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
-                    noOverlay={true} // don't render overlay Docs since they won't scale
-                    setHeight={returnFalse}
-                    isContentActive={emptyFunction}
-                    isAnyChildContentActive={returnFalse}
-                    select={emptyFunction}
-                    isSelected={returnFalse}
-                    dontRegisterView={true}
-                    fieldKey={Doc.LayoutFieldKey(this.props.document)}
-                    bringToFront={emptyFunction}
-                    rootSelected={returnTrue}
-                    addDocument={returnFalse}
-                    moveDocument={returnFalse}
-                    removeDocument={returnFalse}
-                    PanelWidth={this.returnMiniSize}
-                    PanelHeight={this.returnMiniSize}
-                    ScreenToLocalTransform={Transform.Identity}
-                    renderDepth={0}
-                    whenChildContentsActiveChanged={emptyFunction}
-                    focus={emptyFunction}
-                    styleProvider={TabMinimapView.miniStyleProvider}
-                    addDocTab={this.props.addDocTab}
-                    pinToPres={TabDocView.PinDoc}
-                    childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
-                    childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
-                    searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
-                    fitContentsToBox={returnTrue}
-                />
-                <div className="miniOverlay" onPointerDown={this.miniDown}>
-                    <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% ` }} />
-                </div>
-            </div>
+        return (
+            <>
+                {' '}
+                {this.props.document?.layout_hideMinimap ? null : (
+                    <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.props.background() }}>
+                        <CollectionFreeFormView
+                            Document={this.props.document}
+                            docViewPath={returnEmptyDoclist}
+                            childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
+                            noOverlay={true} // don't render overlay Docs since they won't scale
+                            setHeight={returnFalse}
+                            isContentActive={emptyFunction}
+                            isAnyChildContentActive={returnFalse}
+                            select={emptyFunction}
+                            isSelected={returnFalse}
+                            dontRegisterView={true}
+                            fieldKey={Doc.LayoutFieldKey(this.props.document)}
+                            bringToFront={emptyFunction}
+                            rootSelected={returnTrue}
+                            addDocument={returnFalse}
+                            moveDocument={returnFalse}
+                            removeDocument={returnFalse}
+                            PanelWidth={this.returnMiniSize}
+                            PanelHeight={this.returnMiniSize}
+                            ScreenToLocalTransform={Transform.Identity}
+                            renderDepth={0}
+                            whenChildContentsActiveChanged={emptyFunction}
+                            focus={emptyFunction}
+                            styleProvider={TabMinimapView.miniStyleProvider}
+                            addDocTab={this.props.addDocTab}
+                            pinToPres={TabDocView.PinDoc}
+                            childFilters={CollectionDockingView.Instance?.childDocFilters ?? returnEmptyDoclist}
+                            childFiltersByRanges={CollectionDockingView.Instance?.childDocRangeFilters ?? returnEmptyDoclist}
+                            searchFilterDocs={CollectionDockingView.Instance?.searchFilterDocs ?? returnEmptyDoclist}
+                            fitContentsToBox={returnTrue}
+                        />
+                        <div className="miniOverlay" onPointerDown={this.miniDown}>
+                            <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% ` }} />
+                        </div>
+                    </div>
+                )}
+                <Tooltip key="ttip" title={<div className="dash-tooltip">{this.props.document.layout_hideMinimap ? 'Open minimap' : 'Close minimap'}</div>}>
+                    <div
+                        className="miniMap-hidden"
+                        style={{
+                            color: this.props.document.layout_hideMinimap ? Colors.BLACK : Colors.WHITE,
+                            backgroundColor: this.props.document.layout_hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,
+                            boxShadow: this.props.document.layout_hideMinimap ? Shadows.STANDARD_SHADOW : undefined,
+                        }}
+                        onPointerDown={e => e.stopPropagation()}
+                        onClick={action(e => {
+                            e.stopPropagation();
+                            this.props.document!.layout_hideMinimap = !this.props.document!.layout_hideMinimap;
+                        })}>
+                        <FontAwesomeIcon icon="globe-asia" size="lg" />
+                    </div>
+                </Tooltip>
+            </>
         );
     }
 }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c10c0005d..19f9f15a4 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -729,6 +729,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             const templateDoc = Cast(this.props.Document[StrCast(this.props.Document.layout_fieldKey)], Doc, null);
             const appearance = cm.findByDescription('UI Controls...');
             const appearanceItems: ContextMenuProps[] = appearance && 'subitems' in appearance ? appearance.subitems : [];
+
+            if (this.props.renderDepth === 0) {
+                appearanceItems.push({ description: 'Open in Lightbox', event: () => LightboxView.SetLightboxDoc(this.rootDoc), icon: 'hand-point-right' });
+            }
             !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template   ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' });
             !appearance && appearanceItems.length && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' });
 
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 62b3443d4..f1305b64b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -879,11 +879,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         const optionItems = options && 'subitems' in options ? options.subitems : [];
         optionItems.push({ description: `Generate Dall-E Image`, event: () => this.generateImage(), icon: 'star' });
         optionItems.push({ description: `Ask GPT-3`, event: () => this.askGPT(), icon: 'lightbulb' });
-        optionItems.push({
-            description: !this.Document._createDocOnCR ? 'Create New Doc on Carriage Return' : 'Allow Carriage Returns',
-            event: () => (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR),
-            icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars',
-        });
+        this.props.renderDepth &&
+            optionItems.push({
+                description: !this.Document._createDocOnCR ? 'Create New Doc on Carriage Return' : 'Allow Carriage Returns',
+                event: () => (this.layoutDoc._createDocOnCR = !this.layoutDoc._createDocOnCR),
+                icon: !this.Document._createDocOnCR ? 'grip-lines' : 'bars',
+            });
         !Doc.noviceMode &&
             optionItems.push({
                 description: `${this.Document._layout_autoHeight ? 'Lock' : 'Auto'} Height`,
-- 
cgit v1.2.3-70-g09d2


From 638a3ce3bcd4aa7287544be82d8d9d07ee963600 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 4 Jul 2023 09:15:38 -0400
Subject: fixed undo stack when typing, then switching tabs.  combined mark
 settings into one dispatch on text box load.

---
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index f1305b64b..44cb56d53 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1521,8 +1521,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
             } else if (curText && !FormattedTextBox.DontSelectInitialText) {
                 selectAll(this._editorView.state, this._editorView?.dispatch);
-            } else {
-                this._editorView.dispatch(this._editorView.state.tr.addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })));
             }
         }
         selectOnLoad && this._editorView!.focus();
@@ -1535,7 +1533,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             this._editorView.dispatch(
                 this._editorView.state.tr.setStoredMarks([
                     ...(this._editorView.state.storedMarks ?? []),
-                    ...(!this._editorView.state.storedMarks?.some(mark => mark.type === schema.marks.user_mark) ? [schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })] : []),
+                    ...[schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })],
                     ...(Doc.UserDoc().fontColor !== 'transparent' && Doc.UserDoc().fontColor ? [schema.mark(schema.marks.pFontColor, { color: StrCast(Doc.UserDoc().fontColor) })] : []),
                     ...(Doc.UserDoc().fontStyle === 'italics' ? [schema.mark(schema.marks.em)] : []),
                     ...(Doc.UserDoc().textDecoration === 'underline' ? [schema.mark(schema.marks.underline)] : []),
@@ -1556,6 +1554,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
     componentWillUnmount() {
         Object.values(this._disposers).forEach(disposer => disposer?.());
         this.endUndoTypingBatch();
+        FormattedTextBox.LiveTextUndo?.end();
+        FormattedTextBox.LiveTextUndo = undefined;
         this.unhighlightSearchTerms();
         this._editorView?.destroy();
         RichTextMenu.Instance?.TextView === this && RichTextMenu.Instance.updateMenu(undefined, undefined, undefined);
-- 
cgit v1.2.3-70-g09d2

