From c8be94244bcd094efba739e5a46034bceccea80f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 24 Jan 2024 16:13:27 -0500
Subject: several fixes to drag/drop so that dropAction's set on target work
 for tree views, notetaking, formattedText, etc.   make bringToFront an
 optional prop.

---
 src/client/views/collections/TreeView.tsx | 72 +++++++++++++++++++------------
 1 file changed, 45 insertions(+), 27 deletions(-)

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

diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 38a2fe978..40933321f 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -4,7 +4,7 @@ import { IconButton, Size } from 'browndash-components';
 import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
-import { Utils, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick } from '../../../Utils';
+import { Utils, emptyFunction, lightOrDark, return18, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick } from '../../../Utils';
 import { Doc, DocListCast, Field, FieldResult, Opt, StrListCast } from '../../../fields/Doc';
 import { DocData } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
@@ -282,12 +282,13 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
     _treeEle: any;
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
         this._treedropDisposer?.();
-        ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), undefined, this.preTreeDrop.bind(this))), this.Document);
+        ele && ((this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this), this.Document, this.preTreeDrop.bind(this))), this.Document);
         if (this._treeEle) this._props.unobserveHeight(this._treeEle);
         this._props.observeHeight((this._treeEle = ele));
     };
 
     componentWillUnmount() {
+        this._treedropDisposer?.();
         this._renderTimer && clearTimeout(this._renderTimer);
         Object.values(this._disposers).forEach(disposer => disposer?.());
         this._treeEle && this._props.unobserveHeight(this._treeEle);
@@ -339,11 +340,9 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
         const before = pt[1] < rect.top + rect.height / 2;
         const inside = pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length);
         this._header.current!.className = 'treeView-header';
-        if (!this.treeView.outlineMode || DragManager.DocDragData?.treeViewDoc === this.treeView.Document) {
-            if (inside) this._header.current!.className += ' treeView-header-inside';
-            else if (before) this._header.current!.className += ' treeView-header-above';
-            else if (!before) this._header.current!.className += ' treeView-header-below';
-        }
+        if (inside) this._header.current!.className += ' treeView-header-inside';
+        else if (before) this._header.current!.className += ' treeView-header-above';
+        else if (!before) this._header.current!.className += ' treeView-header-below';
         e.stopPropagation();
     };
 
@@ -387,9 +386,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
         return this._props.addDocument(folder);
     };
 
-    preTreeDrop = (e: Event, de: DragManager.DropEvent) => {
-        const dragData = de.complete.docDragData;
-        dragData && (dragData.dropAction = this.treeView.Document === dragData.treeViewDoc ? 'same' : dragData.dropAction);
+    preTreeDrop = (e: Event, de: DragManager.DropEvent, docDropAction: dropActionType) => {
+        // fall through and let the CollectionTreeView handle this since treeView items have no special properties of their own
     };
 
     @undoBatch
@@ -416,7 +414,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
                 docDragData.dropAction,
                 docDragData.removeDocument,
                 docDragData.moveDocument,
-                docDragData.treeViewDoc === this.treeView.Document
+                docDragData.treeViewDoc === this.treeView.Document,
+                de.embedKey
             );
             e.stopPropagation();
             !added && e.preventDefault();
@@ -426,7 +425,16 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
     };
 
     dropping: boolean = false;
-    dropDocuments(droppedDocuments: Doc[], before: boolean, inside: number | boolean, dropAction: dropActionType, removeDocument: DragManager.RemoveFunction | undefined, moveDocument: DragManager.MoveFunction | undefined, forceAdd: boolean) {
+    dropDocuments(
+        droppedDocuments: Doc[],
+        before: boolean,
+        inside: number | boolean,
+        dropAction: dropActionType,
+        removeDocument: DragManager.RemoveFunction | undefined,
+        moveDocument: DragManager.MoveFunction | undefined,
+        forceAdd: boolean,
+        canEmbed?: boolean
+    ) {
         const parentAddDoc = (doc: Doc | Doc[]) => this._props.addDocument(doc, undefined, undefined, before);
         const localAdd = (doc: Doc | Doc[]) => {
             const innerAdd = (doc: Doc) => {
@@ -438,9 +446,9 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
             return (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && innerAdd(doc), true as boolean);
         };
         const addDoc = inside ? localAdd : parentAddDoc;
-        const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument;
         const canAdd = (!this.treeView.outlineMode && !StrCast((inside ? this.Document : this._props.treeViewParent)?.treeView_FreezeChildren).includes('add')) || forceAdd;
         if (canAdd && (dropAction !== 'inSame' || droppedDocuments.every(d => d.embedContainer === this._props.parentTreeView?.Document))) {
+            const move = (!dropAction || canEmbed || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same' || dropAction === 'inSame') && moveDocument;
             this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = true);
             const res = droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false);
             this._props.parentTreeView instanceof TreeView && (this._props.parentTreeView.dropping = false);
@@ -602,7 +610,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
                     docs.sort((a, b) => (NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1)).forEach((d, i) => (d.zIndex = i));
                 }
                 const dataIsComputed = ComputedField.WithoutComputed(() => FieldValue(this.dataDoc[key])) instanceof ComputedField;
-                const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
+                const added = (!dataIsComputed || (this.dropping && this.moving)) && Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false);
                 !dataIsComputed && added && Doc.SetContainer(doc, this.Document);
 
                 return added;
@@ -841,7 +849,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
                 ? folderOp
                 : Doc.IsSystem(this.Document)
                   ? []
-                  : this.treeView.fileSysMode && this.Document === Doc.GetProto(this.Document)
+                  : this.treeView.fileSysMode && this.Document === this.Document[DocData]
                     ? [openEmbedding, makeFolder]
                     : this.Document._type_collection === CollectionViewType.Docking
                       ? []
@@ -974,8 +982,8 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
                 Document={this.Document}
                 layout_fitWidth={returnTrue}
                 scriptContext={this}
-                hideDecorationTitle={this.treeView.outlineMode}
-                hideResizeHandles={this.treeView.outlineMode}
+                hideDecorations={true}
+                hideClickBehaviors={true}
                 styleProvider={this.titleStyleProvider}
                 onClickScriptDisable="never" // tree docViews have a script to show fields, etc.
                 containerViewPath={this.treeView.childContainerViewPath}
@@ -999,7 +1007,6 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
                 isDocumentActive={this._props.isContentActive}
                 focus={this.refocus}
                 whenChildContentsActiveChanged={this._props.whenChildContentsActiveChanged}
-                bringToFront={emptyFunction}
                 disableBrushing={this.treeView._props.disableBrushing}
                 hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)}
                 dontRegisterView={BoolCast(this.treeView.Document.childDontRegisterViews, this._props.dontRegisterView)}
@@ -1041,7 +1048,19 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
                     key="titleheader"
                     ref={this._header}
                     onClick={this.ignoreEvent}
-                    onPointerDown={this.ignoreEvent}
+                    onPointerDown={e => {
+                        this.treeView.isContentActive() &&
+                            setupMoveUpEvents(
+                                this,
+                                e,
+                                () => {
+                                    this._dref?.startDragging(e.clientX, e.clientY, '' as any);
+                                    return true;
+                                },
+                                returnFalse,
+                                emptyFunction
+                            );
+                    }}
                     onPointerEnter={this.onPointerEnter}
                     onPointerLeave={this.onPointerLeave}>
                     <div
@@ -1073,22 +1092,22 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
                     isContentActive={isActive}
                     isDocumentActive={isActive}
                     styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
-                    hideTitle={asText}
                     fitContentsToBox={returnTrue}
-                    hideDecorationTitle={this.treeView.outlineMode}
-                    hideResizeHandles={this.treeView.outlineMode}
-                    onClickScript={this.onChildClick}
-                    focus={this.refocus}
-                    onKey={this.onKeyDown}
+                    hideTitle={asText}
+                    hideDecorations={true}
+                    hideClickBehaviors={true}
                     hideLinkButton={BoolCast(this.treeView.Document.childHideLinkButton)}
                     dontRegisterView={BoolCast(this.treeView.Document.childDontRegisterViews, this._props.dontRegisterView)}
                     ScreenToLocalTransform={this.docTransform}
                     renderDepth={this._props.renderDepth + 1}
+                    onClickScript={this.onChildClick}
+                    onKey={this.onKeyDown}
                     treeViewDoc={this.treeView?.Document}
                     containerViewPath={this.treeView.childContainerViewPath}
                     childFilters={returnEmptyFilter}
                     childFiltersByRanges={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
+                    focus={this.refocus}
                     addDocument={this._props.addDocument}
                     moveDocument={this.move}
                     removeDocument={this._props.removeDoc}
@@ -1098,7 +1117,6 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
                     addDocTab={this._props.addDocTab}
                     pinToPres={this.treeView._props.pinToPres}
                     disableBrushing={this.treeView._props.disableBrushing}
-                    bringToFront={returnFalse}
                     scriptContext={this}
                 />
             </div>
@@ -1143,7 +1161,7 @@ export class TreeView extends ObservableReactComponent<TreeViewProps> {
         const before = pt[1] < rect.top + rect.height / 2;
         const inside = this.treeView.fileSysMode && !this.Document.isFolder ? false : pt[0] > rect.left + rect.width * 0.33 || (!before && this.treeViewOpen && this.childDocs?.length ? true : false);
 
-        const docs = this.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, undefined, false));
+        const docs = this.treeView.onTreeDrop(de, (docs: Doc[]) => this.dropDocuments(docs, before, inside, 'copy', undefined, undefined, false, false));
     };
 
     render() {
-- 
cgit v1.2.3-70-g09d2

