From dd08c20ec6df3fad6ecd6b16c787f10b0c23feb4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 2 May 2024 00:39:31 -0400
Subject: lots more dependency cycle unwinding.

---
 src/client/views/collections/TabDocView.tsx | 216 +++++++++++++++-------------
 1 file changed, 116 insertions(+), 100 deletions(-)

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

diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 2d900bb73..2d8b2564d 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -9,7 +9,7 @@ import * as ReactDOM from 'react-dom/client';
 import { ClientUtils, DashColor, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../../ClientUtils';
 import { emptyFunction } from '../../../Utils';
 import { Doc, Opt } from '../../../fields/Doc';
-import { DocData } from '../../../fields/DocSymbols';
+import { DocData, DocViews } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { FieldId } from '../../../fields/RefField';
@@ -18,10 +18,8 @@ import { Cast, DocCast, NumCast, StrCast, toList } from '../../../fields/Types';
 import { DocServer } from '../../DocServer';
 import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
 import { Docs } from '../../documents/Documents';
-import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from '../../util/DragManager';
 import { dropActionType } from '../../util/DropActionTypes';
-import { SelectionManager } from '../../util/SelectionManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
 import { UndoManager, undoable } from '../../util/UndoManager';
@@ -29,7 +27,8 @@ import { DashboardView } from '../DashboardView';
 import { LightboxView } from '../LightboxView';
 import { ObservableReactComponent } from '../ObservableReactComponent';
 import { PinDocView, PinProps } from '../PinFuncs';
-import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
+import { StyleProp } from '../StyleProp';
+import { DefaultStyleProvider } from '../StyleProvider';
 import { Colors } from '../global/globalEnums';
 import { DocumentView, returnEmptyDocViewList } from '../nodes/DocumentView';
 import { FieldViewProps } from '../nodes/FieldView';
@@ -194,9 +193,101 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
     _mainCont: HTMLDivElement | null = null;
     _tabReaction: IReactionDisposer | undefined;
 
+    /**
+     * Adds a document to the presentation view
+     * */
+    @action
+    public static PinDoc(docIn: Doc | Doc[], pinProps: PinProps) {
+        const docs = toList(docIn);
+
+        const batch = UndoManager.StartBatch('Pin doc to pres trail');
+        const curPres = Doc.ActivePresentation ?? Doc.MakeCopy(Doc.UserDoc().emptyTrail as Doc, true);
+
+        if (!Doc.ActivePresentation) {
+            Doc.AddDocToList(Doc.MyTrails, 'data', curPres);
+            Doc.ActivePresentation = curPres;
+        }
+
+        docs.forEach(doc => {
+            // Edge Case 1: Cannot pin document to itself
+            if (doc === curPres) {
+                alert('Cannot pin presentation document to itself');
+                return;
+            }
+            const anchorDoc = DocumentView.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps);
+            const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Docs.Create.ConfigDocument({});
+            const targDoc = (pinDoc.presentation_targetDoc = anchorDoc ?? doc);
+            pinDoc.title = doc.title + ' - Slide';
+            pinDoc.data = targDoc.type === DocumentType.PRES ? ComputedField.MakeFunction('copyField(this.presentation_targetDoc.data') : new List<Doc>(); // the children of the embedding's layout are the presentation slide children.  the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data
+            pinDoc.presentation_movement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom;
+            pinDoc.presentation_duration = pinDoc.presentation_duration ?? 1000;
+            pinDoc.presentation_groupWithUp = false;
+            Doc.SetContainer(pinDoc, curPres);
+            // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements.  That way the PresBox could configure all of its children at render time
+            pinDoc.treeView = ''; // not really needed, but makes key value pane look better
+            pinDoc.treeView_RenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
+            pinDoc.treeView_HeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling.
+            pinDoc.treeView_FieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field
+            pinDoc.treeView_ExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view
+            pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header
+            const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null);
+
+            if (pinProps.pinViewport) PinDocView(pinDoc, pinProps, anchorDoc ?? doc);
+            if (!pinProps?.audioRange && duration !== undefined) {
+                pinDoc.presentation_mediaStart = 'manual';
+                pinDoc.presentation_mediaStop = 'manual';
+            }
+            if (pinProps?.activeFrame !== undefined) {
+                pinDoc.config_activeFrame = pinProps?.activeFrame;
+                pinDoc.title = doc.title + ' (move)';
+                pinDoc.presentation_movement = PresMovement.Pan;
+            }
+            if (pinProps?.currentFrame !== undefined) {
+                pinDoc.config_currentFrame = pinProps?.currentFrame;
+                pinDoc.title = doc.title + ' (move)';
+                pinDoc.presentation_movement = PresMovement.Pan;
+            }
+            if (pinDoc.stroke_isInkMask) {
+                pinDoc.presentation_hideAfter = true;
+                pinDoc.presentation_hideBefore = true;
+                pinDoc.presentation_movement = PresMovement.None;
+            }
+            if (curPres.expandBoolean) pinDoc.presentation_expandInlineButton = true;
+            Doc.AddDocToList(curPres, 'data', pinDoc, PresBox.Instance?.sortArray()?.lastElement());
+            PresBox.Instance?.clearSelectedArray();
+            pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); // Update selected array
+        });
+        if (
+            // open the presentation trail if it's not already opened
+            !Array.from(CollectionDockingView.Instance?.tabMap ?? [])
+                .map(d => d.DashDoc)
+                .includes(curPres)
+        ) {
+            if (Doc.IsInMyOverlay(curPres)) Doc.RemFromMyOverlay(curPres);
+            CollectionDockingView.AddSplit(curPres, OpenWhereMod.right);
+            setTimeout(() => DocumentView.showDocument(docs.lastElement(), { willPan: true }), 100); // keeps the pinned doc in view since the sidebar shifts things
+        }
+        setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs
+    }
+
+    static Activate = (tabDoc: Doc) => {
+        const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(findTab => findTab.DashDoc === tabDoc && !findTab.contentItem.config.props.keyValue);
+        tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
+        return tab !== undefined;
+    };
+    // static ActivateTabView(doc: Doc) {
+    //     const tabView = Array.from(TabDocView._allTabs).find(view => view._document === doc);
+    //     if (!tabView?._activated && tabView?._document) {
+    //         TabDocView.Activate(tabView?._document);
+    //         return tabView;
+    //     }
+    //     return undefined;
+    // }
     constructor(props: any) {
         super(props);
         makeObservable(this);
+        DocumentView.activateTabView = TabDocView.Activate;
+        DocumentView.PinDoc = TabDocView.PinDoc;
     }
 
     @observable _activated: boolean = false;
@@ -205,8 +296,14 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
     @observable _hovering = false;
     @observable _isActive: boolean = false;
     @observable _isAnyChildContentActive = false;
+    public static IsSelected = (doc?: Doc) => {
+        if (Array.from(doc?.[DocViews] ?? []).some(dv => dv?.IsSelected)) {
+            return true;
+        }
+        return false;
+    };
     @computed get _isUserActivated() {
-        return SelectionManager.IsSelected(this._document) || this._isAnyChildContentActive;
+        return TabDocView.IsSelected(this._document) || this._isAnyChildContentActive;
     }
     get _isContentActive() {
         return this._isUserActivated || this._hovering;
@@ -279,12 +376,12 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
                         returnFalse,
                         action(clickEv => {
                             if (this.view) {
-                                SelectionManager.SelectView(this.view, false);
+                                DocumentView.SelectView(this.view, false);
                                 const child = getChild();
                                 simulateMouseClick(child, clickEv.clientX, clickEv.clientY + 30, clickEv.screenX, clickEv.screenY + 30);
                             } else {
                                 this._activated = true;
-                                setTimeout(() => this.view && SelectionManager.SelectView(this.view, false));
+                                setTimeout(() => this.view && DocumentView.SelectView(this.view, false));
                             }
                         })
                     );
@@ -350,7 +447,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
             // select the tab document when the tab is directly clicked and activate the tab whenver the tab document is selected
             titleEle.onpointerdown = action((e: any) => {
                 if (e.target.className !== 'lm_iconWrap') {
-                    if (this.view) SelectionManager.SelectView(this.view, false);
+                    if (this.view) DocumentView.SelectView(this.view, false);
                     else this._activated = true;
                     if (Date.now() - titleEle.lastClick < 1000) titleEle.select();
                     titleEle.lastClick = Date.now();
@@ -358,7 +455,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
                 }
             });
             tab._disposers.selectionDisposer = reaction(
-                () => SelectionManager.IsSelected(this._document),
+                () => TabDocView.IsSelected(this._document),
                 action(selected => {
                     if (selected) this._activated = true;
                     if (selected && tab.contentItem !== tab.header.parent.getActiveContentItem()) {
@@ -382,89 +479,12 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
                 .off('click') // unbind the current click handler
                 .click(() => {
                     Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
-                    SelectionManager.DeselectAll();
+                    DocumentView.DeselectAll();
                     UndoManager.RunInBatch(() => tab.contentItem.remove(), 'delete tab');
                 });
         }
     };
 
-    /**
-     * Adds a document to the presentation view
-     * */
-    @action
-    public static PinDoc(docIn: Doc | Doc[], pinProps: PinProps) {
-        const docs = toList(docIn);
-
-        const batch = UndoManager.StartBatch('Pin doc to pres trail');
-        const curPres = Doc.ActivePresentation ?? Doc.MakeCopy(Doc.UserDoc().emptyTrail as Doc, true);
-
-        if (!Doc.ActivePresentation) {
-            Doc.AddDocToList(Doc.MyTrails, 'data', curPres);
-            Doc.ActivePresentation = curPres;
-        }
-
-        docs.forEach(doc => {
-            // Edge Case 1: Cannot pin document to itself
-            if (doc === curPres) {
-                alert('Cannot pin presentation document to itself');
-                return;
-            }
-            const anchorDoc = DocumentManager.Instance.getDocumentView(doc)?.ComponentView?.getAnchor?.(false, pinProps);
-            const pinDoc = anchorDoc?.type === DocumentType.CONFIG ? anchorDoc : Docs.Create.ConfigDocument({});
-            const targDoc = (pinDoc.presentation_targetDoc = anchorDoc ?? doc);
-            pinDoc.title = doc.title + ' - Slide';
-            pinDoc.data = targDoc.type === DocumentType.PRES ? ComputedField.MakeFunction('copyField(this.presentation_targetDoc.data') : new List<Doc>(); // the children of the embedding's layout are the presentation slide children.  the embedding's data field might be children of a collection, PDF data, etc -- in any case we don't want the tree view to "see" this data
-            pinDoc.presentation_movement = doc.type === DocumentType.SCRIPTING || pinProps?.pinDocLayout ? PresMovement.None : PresMovement.Zoom;
-            pinDoc.presentation_duration = pinDoc.presentation_duration ?? 1000;
-            pinDoc.presentation_groupWithUp = false;
-            Doc.SetContainer(pinDoc, curPres);
-            // these should potentially all be props passed down by the CollectionTreeView to the TreeView elements.  That way the PresBox could configure all of its children at render time
-            pinDoc.treeView = ''; // not really needed, but makes key value pane look better
-            pinDoc.treeView_RenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
-            pinDoc.treeView_HeaderWidth = '100%'; // forces the header to grow to be the same size as its largest sibling.
-            pinDoc.treeView_FieldKey = 'data'; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field
-            pinDoc.treeView_ExpandedView = 'data'; // in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view
-            pinDoc.treeView_HideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header
-            const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}_duration`], null);
-
-            if (pinProps.pinViewport) PinDocView(pinDoc, pinProps, anchorDoc ?? doc);
-            if (!pinProps?.audioRange && duration !== undefined) {
-                pinDoc.presentation_mediaStart = 'manual';
-                pinDoc.presentation_mediaStop = 'manual';
-            }
-            if (pinProps?.activeFrame !== undefined) {
-                pinDoc.config_activeFrame = pinProps?.activeFrame;
-                pinDoc.title = doc.title + ' (move)';
-                pinDoc.presentation_movement = PresMovement.Pan;
-            }
-            if (pinProps?.currentFrame !== undefined) {
-                pinDoc.config_currentFrame = pinProps?.currentFrame;
-                pinDoc.title = doc.title + ' (move)';
-                pinDoc.presentation_movement = PresMovement.Pan;
-            }
-            if (pinDoc.stroke_isInkMask) {
-                pinDoc.presentation_hideAfter = true;
-                pinDoc.presentation_hideBefore = true;
-                pinDoc.presentation_movement = PresMovement.None;
-            }
-            if (curPres.expandBoolean) pinDoc.presentation_expandInlineButton = true;
-            Doc.AddDocToList(curPres, 'data', pinDoc, PresBox.Instance?.sortArray()?.lastElement());
-            PresBox.Instance?.clearSelectedArray();
-            pinDoc && PresBox.Instance?.addToSelectedArray(pinDoc); // Update selected array
-        });
-        if (
-            // open the presentation trail if it's not already opened
-            !Array.from(CollectionDockingView.Instance?.tabMap ?? [])
-                .map(d => d.DashDoc)
-                .includes(curPres)
-        ) {
-            if (Doc.IsInMyOverlay(curPres)) Doc.RemFromMyOverlay(curPres);
-            CollectionDockingView.AddSplit(curPres, OpenWhereMod.right);
-            setTimeout(() => DocumentManager.Instance.showDocument(docs.lastElement(), { willPan: true }), 100); // keeps the pinned doc in view since the sidebar shifts things
-        }
-        setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs
-    }
-
     componentDidMount() {
         new _global.ResizeObserver(
             action((entries: any) => {
@@ -484,12 +504,12 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
     }
     componentDidUpdate(prevProps: Readonly<TabDocViewProps>) {
         super.componentDidUpdate(prevProps);
-        this._view && DocumentManager.Instance.AddView(this._view);
+        this._view && DocumentView.addView(this._view);
     }
 
     componentWillUnmount() {
         this._tabReaction?.();
-        this._view && DocumentManager.Instance.RemoveView(this._view);
+        this._view && DocumentView.removeView(this._view);
         runInAction(() => TabDocView._allTabs.delete(this));
 
         this._props.glContainer.layoutManager.off('activeContentItemChanged', this.onActiveContentItemChanged);
@@ -503,7 +523,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
     private onActiveContentItemChanged(contentItem: any) {
         if (!contentItem || (this.stack === contentItem.parent && ((contentItem?.tab === this.tab && !this._isActive) || (contentItem?.tab !== this.tab && this._isActive)))) {
             this._activated = this._isActive = !contentItem || contentItem?.tab === this.tab;
-            if (!this._view && this.tab?.contentItem?.config?.props?.panelName !== TabDocView.DontSelectOnActivate) setTimeout(() => SelectionManager.SelectView(this._view, false));
+            if (!this._view && this.tab?.contentItem?.config?.props?.panelName !== TabDocView.DontSelectOnActivate) setTimeout(() => DocumentView.SelectView(this._view, false));
             !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one.
         }
     }
@@ -517,7 +537,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
     //  lightbox - will add the document to any collection along the path from the document to the docking view that has a field isLightbox. if none is found, it adds to the full screen lightbox
     addDocTab = (docsIn: Doc | Doc[], location: OpenWhere) => {
         const docs = toList(docsIn);
-        SelectionManager.DeselectAll();
+        DocumentView.DeselectAll();
         const whereFields = location.split(':');
         const keyValue = whereFields.includes(OpenWhereMod.keyvalue);
         const whereMods = whereFields.length > 1 ? (whereFields[1] as OpenWhereMod) : OpenWhereMod.none;
@@ -527,7 +547,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
         switch (whereFields[0]) {
             case undefined:
             case OpenWhere.lightbox:   if (this.layoutDoc?._isLightbox) {
-                                            const lightboxView = !docs[0].annotationOn && DocCast(docs[0].embedContainer) ? DocumentManager.Instance.getFirstDocumentView(DocCast(docs[0].embedContainer)) : undefined;
+                                            const lightboxView = !docs[0].annotationOn && DocCast(docs[0].embedContainer) ? DocumentView.getFirstDocumentView(DocCast(docs[0].embedContainer)) : undefined;
                                             const data = lightboxView?.dataDoc[Doc.LayoutFieldKey(lightboxView.Document)];
                                             if (lightboxView && (!data || data instanceof List)) {
                                                 lightboxView.layoutDoc[Doc.LayoutFieldKey(lightboxView.Document)] = new List<Doc>(docs);
@@ -543,7 +563,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
     };
     remDocTab = (doc: Doc | Doc[]) => {
         if (doc === this._document) {
-            SelectionManager.DeselectAll();
+            DocumentView.DeselectAll();
             CollectionDockingView.CloseSplit(this._document);
             return true;
         }
@@ -551,11 +571,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
     };
 
     getCurrentFrame = () => NumCast(Cast(PresBox.Instance.activeItem.presentation_targetDoc, Doc, null)._currentFrame);
-    static Activate = (tabDoc: Doc) => {
-        const tab = Array.from(CollectionDockingView.Instance?.tabMap!).find(findTab => findTab.DashDoc === tabDoc && !findTab.contentItem.config.props.keyValue);
-        tab?.header.parent.setActiveContentItem(tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
-        return tab !== undefined;
-    };
+
     @action
     focusFunc = () => {
         if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) {
@@ -586,7 +602,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
                 <DocumentView
                     key={this._document[Id]}
                     ref={action((r: DocumentView) => {
-                        this._lastView && DocumentManager.Instance.RemoveView(this._lastView);
+                        this._lastView && DocumentView.removeView(this._lastView);
                         this._view = r;
                         this._lastView = this._view;
                     })}
@@ -635,7 +651,7 @@ export class TabDocView extends ObservableReactComponent<TabDocViewProps> {
                     this._mainCont = ref;
                     if (this._mainCont) {
                         if (this._lastTab) {
-                            this._view && DocumentManager.Instance.RemoveView(this._view);
+                            this._view && DocumentView.removeView(this._view);
                         }
                         this._lastTab = this.tab;
                         (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
-- 
cgit v1.2.3-70-g09d2

