From 3573a81d334cf8cc13d19b04c6f2094c24c43932 Mon Sep 17 00:00:00 2001
From: Aubrey Li <Aubrey-Li>
Date: Thu, 3 Mar 2022 18:12:13 -0500
Subject: edit: lightbox opens tab in the same stack

---
 src/client/views/collections/TabDocView.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(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 7e57d0e89..c11b6c7b3 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -300,7 +300,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack);
             case "lightbox": {
                 // TabDocView.PinDoc(doc, { hidePresBox: true });
-                return LightboxView.AddDocTab(doc, location);
+                return LightboxView.AddDocTab(doc, location, undefined, this.addDocTab);
             }
             case "inPlace":
             case "add":
-- 
cgit v1.2.3-70-g09d2


From 55a5322fffc09bde04ef8b466e19b701bad2762b Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 29 Apr 2022 17:38:06 -0400
Subject: added 'enter' to toggle iconify.  fixed webBox deiconify to render
 webpage.   updated colors in minimap to match icon colors.

---
 src/client/views/DocumentDecorations.tsx    | 11 ++++++-----
 src/client/views/GlobalKeyHandler.ts        |  4 ++++
 src/client/views/collections/TabDocView.tsx | 17 ++++++++++++++---
 src/client/views/nodes/WebBox.tsx           |  8 ++++----
 4 files changed, 28 insertions(+), 12 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 1feb643df..fb8cfbc15 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -146,14 +146,15 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
 
     _deleteAfterIconify = false;
     _iconifyBatch: UndoManager.Batch | undefined;
-    onCloseClick = (force = false) => {
+    onCloseClick = (forceDeleteOrIconify: boolean | undefined) => {
         if (this.canDelete) {
             const views = SelectionManager.Views().slice().filter(v => v);
-            this._deleteAfterIconify = force || this._iconifyBatch ? true : false;
+            if (forceDeleteOrIconify === false && this._iconifyBatch) return;
+            this._deleteAfterIconify = forceDeleteOrIconify || this._iconifyBatch ? true : false;
             if (!this._iconifyBatch) {
                 this._iconifyBatch = UndoManager.StartBatch("iconifying");
             } else {
-                force = false; // can't force immediate close in the middle of iconifying -- have to wait until iconifying completes
+                forceDeleteOrIconify = false; // can't force immediate close in the middle of iconifying -- have to wait until iconifying completes
             }
             var iconifyingCount = views.length;
             const finished = action((force?: boolean) => {
@@ -166,7 +167,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                     this._iconifyBatch = undefined;
                 }
             });
-            if (force) finished(force);
+            if (forceDeleteOrIconify) finished(forceDeleteOrIconify);
             else if (!this._deleteAfterIconify) views.forEach(dv => dv.iconify(finished));
         }
     }
@@ -531,7 +532,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                     left: bounds.x - this._resizeBorderWidth / 2,
                     top: bounds.y - this._resizeBorderWidth / 2 - this._titleHeight,
                 }}>
-                    {!canDelete ? <div /> : topBtn("close", this.hasIcons ? "times" : "window-maximize", undefined, e => this.onCloseClick(this.hasIcons), "Close")}
+                    {!canDelete ? <div /> : topBtn("close", this.hasIcons ? "times" : "window-maximize", undefined, e => this.onCloseClick(this.hasIcons ? true : undefined), "Close")}
                     {titleArea}
                     {!canOpen ? (null) : topBtn("open", "external-link-alt", this.onMaximizeDown, undefined, "Open in Tab (ctrl: as alias, shift: in new collection)")}
                     {hideResizers ? (null) :
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 6120c4c9e..914802041 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -139,6 +139,10 @@ export class KeyManager {
                 window.getSelection()?.empty();
                 document.body.focus();
                 break;
+            case "enter": {
+                DocumentDecorations.Instance.onCloseClick(false);
+                break;
+            }
             case "delete":
             case "backspace":
                 if (document.activeElement?.tagName !== "INPUT" && document.activeElement?.tagName !== "TEXTAREA") {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 8e45ec3b3..78b125e07 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -443,9 +443,20 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                 default: return DefaultStyleProvider(doc, props, property);
                 case StyleProp.PointerEvents: return "none";
                 case StyleProp.DocContents:
-                    const background = doc.type === DocumentType.PDF ? "red" : doc.type === DocumentType.IMG ? "blue" : doc.type === DocumentType.RTF ? "orange" :
-                        doc.type === DocumentType.VID ? "purple" : doc.type === DocumentType.WEB ? "yellow" : doc.type === DocumentType.MAP ? "blue" : "gray";
-                    return doc.type === DocumentType.COL ?
+                    const background = ((type: DocumentType) => {
+                        switch (type) {
+                            case DocumentType.PDF: return "pink";
+                            case DocumentType.AUDIO: return "lightgreen";
+                            case DocumentType.WEB: return "brown";
+                            case DocumentType.IMG: return "blue";
+                            case DocumentType.MAP: return "orange";
+                            case DocumentType.VID: return "purple";
+                            case DocumentType.RTF: return "yellow";
+                            case DocumentType.COL: return undefined;
+                            default: return "gray";
+                        }
+                    })(doc.type as DocumentType);
+                    return !background ?
                         undefined :
                         <div style={{ width: doc[WidthSym](), height: doc[HeightSym](), position: "absolute", display: "block", background }} />;
             }
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 5a39123b9..5c72417cc 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -158,7 +158,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                             });
                     }
                 }
-            });
+            }, { fireImmediately: this.props.isSelected() });
 
         this._disposers.autoHeight = reaction(() => this.layoutDoc._autoHeight,
             autoHeight => {
@@ -202,10 +202,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         );
         quickScroll = false;
     }
-    componentWillUnmount() {
+    @action componentWillUnmount() {
         Object.values(this._disposers).forEach(disposer => disposer?.());
-        this._iframe?.removeEventListener('wheel', this.iframeWheel, true);
-        this._iframe?.contentDocument?.removeEventListener("pointerup", this.iframeUp);
+        // this._iframe?.removeEventListener('wheel', this.iframeWheel, true);
+        // this._iframe?.contentDocument?.removeEventListener("pointerup", this.iframeUp);
     }
 
     @action
-- 
cgit v1.2.3-70-g09d2


From f072a9f2c1ad69eb8ae4242fa5d2e18bbd94f6ef Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 6 May 2022 11:45:44 -0400
Subject: changed following links to open up icons all the way down to the
 target document. allow StartLink to work with webBox w/ text selection. 
 fixed web clippings to have a cursor and grab keyDown events.

---
 src/client/util/DocumentManager.ts                 | 42 +++++++++++++++-------
 .../util/Import & Export/DirectoryImportBox.tsx    |  2 +-
 src/client/util/LinkManager.ts                     | 11 +++---
 src/client/util/SharingManager.tsx                 | 30 ++++++++--------
 src/client/views/DocumentDecorations.tsx           | 13 ++++---
 src/client/views/MainView.tsx                      |  2 +-
 src/client/views/collections/TabDocView.tsx        |  2 +-
 src/client/views/collections/TreeView.tsx          |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../collectionLinear/CollectionLinearView.tsx      |  2 +-
 .../collectionSchema/CollectionSchemaCells.tsx     |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  3 +-
 src/client/views/nodes/LinkDescriptionPopup.tsx    |  1 +
 src/client/views/nodes/PDFBox.tsx                  |  1 +
 src/client/views/nodes/WebBox.scss                 |  3 ++
 src/client/views/nodes/WebBox.tsx                  | 11 +++---
 src/client/views/nodes/trails/PresBox.tsx          |  4 +--
 src/client/views/search/SearchBox.tsx              |  2 +-
 18 files changed, 84 insertions(+), 51 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index b6c28d2fe..aeddc3249 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -156,7 +156,7 @@ export class DocumentManager {
         targetDoc: Doc,        // document to display
         willZoom: boolean,     // whether to zoom doc to take up most of screen
         createViewFunc = DocumentManager.addView, // how to create a view of the doc if it doesn't exist
-        docContext?: Doc,  // context to load that should contain the target
+        docContext: Doc[],  // context to load that should contain the target
         linkDoc?: Doc,   // link that's being followed
         closeContextIfNotFound: boolean = false, // after opening a context where the document should be, this determines whether the context should be closed if the Doc isn't actually there
         originatingDoc: Opt<Doc> = undefined, // doc that initiated the display of the target odoc
@@ -190,31 +190,40 @@ export class DocumentManager {
             finished?.();
         };
         const annoContainerView = (!wasHidden || resolvedTarget !== annotatedDoc) && annotatedDoc && getFirstDocView(annotatedDoc);
-        const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined;
-        const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext : undefined;
+        const contextDocs = docContext.length ? await DocListCastAsync(docContext[0].data) : undefined;
+        const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext.lastElement() : undefined;
         const targetDocContext = contextDoc || annotatedDoc;
         const targetDocContextView = (targetDocContext && getFirstDocView(targetDocContext)) ||
             (wasHidden && annoContainerView);// if we have an annotation container and the target was hidden, then try again because we just un-hid the document above
         const focusView = !docView && targetDoc.type === DocumentType.MARKER && annoContainerView ? annoContainerView : docView;
-        if ((!docView && targetDoc.type !== DocumentType.MARKER) && annoContainerView) {
+        if (annoContainerView) {
             if (annoContainerView.props.Document.layoutKey === "layout_icon") {
-                annoContainerView.iconify(() => this.jumpToDocument(
-                    targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc,
-                    finished, originalTarget, noSelect, presZoom));
+                annoContainerView.iconify(() => annoContainerView.focus(targetDoc, {
+                    originalTarget, willZoom, scale: presZoom, afterFocus: (didFocus: boolean) =>
+                        new Promise<ViewAdjustment>(res => {
+                            focusAndFinish(true);
+                            res(ViewAdjustment.doNothing);
+                        })
+                }));
                 return;
-            } else {
+            } else if (!docView && targetDoc.type !== DocumentType.MARKER) {
                 annoContainerView.focus(targetDoc);  // this allows something like a PDF view to remove its doc filters to expose the target so that it can be found in the retry code below
             }
         }
         if (focusView) {
             !noSelect && Doc.linkFollowHighlight(focusView.rootDoc); //TODO:glr make this a setting in PresBox
-            focusView.focus(targetDoc, {
+            const doFocus = (forceDidFocus: boolean) => focusView.focus(originalTarget ?? targetDoc, {
                 originalTarget, willZoom, scale: presZoom, afterFocus: (didFocus: boolean) =>
                     new Promise<ViewAdjustment>(res => {
-                        focusAndFinish(didFocus);
+                        focusAndFinish(forceDidFocus || didFocus);
                         res(ViewAdjustment.doNothing);
                     })
             });
+            if (focusView.props.Document.layoutKey === "layout_icon") {
+                focusView.iconify(() => doFocus(true));
+            } else {
+                doFocus(false);
+            }
         } else {
             if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default
                 createViewFunc(Doc.BrushDoc(targetDoc), finished); // bcz: should we use this?: Doc.MakeAlias(targetDoc)));
@@ -228,7 +237,7 @@ export class DocumentManager {
                             targetDocContext._viewTransition = undefined;
                             if (targetDocContext.layoutKey === "layout_icon") {
                                 targetDocContextView.iconify(() => this.jumpToDocument(
-                                    targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc,
+                                    resolvedTarget ?? targetDoc, willZoom, createViewFunc, docContext, linkDoc, closeContextIfNotFound, originatingDoc,
                                     finished, originalTarget, noSelect, presZoom));
                             }
                             return ViewAdjustment.doNothing;
@@ -263,7 +272,16 @@ export class DocumentManager {
                         };
                         setTimeout(() => findView(0), 0);
                     }
-                } else {  // there's no context view so we need to create one first and try again when that finishes
+                } else {
+                    if (docContext.length && docContext[0]?.layoutKey === "layout_icon") {
+                        const docContextView = this.getFirstDocumentView(docContext[0]);
+                        if (docContextView) {
+                            return docContextView.iconify(() => this.jumpToDocument(
+                                targetDoc, willZoom, createViewFunc, docContext.slice(1, docContext.length), linkDoc, closeContextIfNotFound, originatingDoc,
+                                finished, originalTarget, noSelect, presZoom));
+                        }
+                    }
+                    // there's no context view so we need to create one first and try again when that finishes
                     const finishFunc = () => this.jumpToDocument(targetDoc, true, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished, originalTarget);
                     createViewFunc(targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target
                         finishFunc);
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index 39e9251a5..37571ae01 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx	
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx	
@@ -161,7 +161,7 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
             await GooglePhotos.Export.CollectionToAlbum({ collection: importContainer });
             Doc.AddDocToList(Doc.GetProto(parent.props.Document), "data", importContainer);
             !this.persistent && this.props.removeDocument && this.props.removeDocument(doc);
-            DocumentManager.Instance.jumpToDocument(importContainer, true);
+            DocumentManager.Instance.jumpToDocument(importContainer, true, undefined, []);
         }
 
         runInAction(() => {
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 9445533dc..b28662a57 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,3 +1,4 @@
+import { validationResult } from "express-validator/check";
 import { action, observable, observe } from "mobx";
 import { computedFn } from "mobx-utils";
 import { DirectLinksSym, Doc, DocListCast, Field, Opt } from "../../fields/Doc";
@@ -241,10 +242,12 @@ export class LinkManager {
                     } else {
                         const containerAnnoDoc = Cast(target.annotationOn, Doc, null);
                         const containerDoc = containerAnnoDoc || target;
-                        const containerDocContext = Cast(containerDoc?.context, Doc, null);
-                        const targetContext = LightboxView.LightboxDoc ? containerAnnoDoc || containerDocContext : containerDocContext;
-                        const targetNavContext = !Doc.AreProtosEqual(targetContext, currentContext) ? targetContext : undefined;
-                        DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "lightbox"), finished), targetNavContext, linkDoc, undefined, sourceDoc, allFinished);
+                        var containerDocContext = containerDoc?.context ? [Cast(containerDoc?.context, Doc, null)] : [] as Doc[];
+                        while (containerDocContext.length && !DocumentManager.Instance.getDocumentView(containerDocContext[0]) && containerDocContext[0].context) {
+                            containerDocContext = [Cast(containerDocContext[0].context, Doc, null), ...containerDocContext];
+                        }
+                        const targetContexts = LightboxView.LightboxDoc ? [containerAnnoDoc || containerDocContext[0]] : containerDocContext;
+                        DocumentManager.Instance.jumpToDocument(target, zoom, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, "lightbox"), finished), targetContexts, linkDoc, undefined, sourceDoc, allFinished);
                     }
                 } else {
                     allFinished();
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 6d7f7e8df..11450309a 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -370,11 +370,11 @@ export class SharingManager extends React.Component<{}> {
         if (!uniform) dropdownValues.unshift("-multiple-");
         if (override) dropdownValues.unshift("None");
         return dropdownValues.filter(permission => !Doc.UserDoc().noviceMode || ![SharingPermissions.View, SharingPermissions.SelfEdit].includes(permission as any)).map(permission =>
-            (
-                <option key={permission} value={permission}>
-                    {permission}
-                </option>
-            )
+        (
+            <option key={permission} value={permission}>
+                {permission}
+            </option>
+        )
         );
     }
 
@@ -388,7 +388,7 @@ export class SharingManager extends React.Component<{}> {
                 onClick={() => {
                     let context: Opt<CollectionView>;
                     if (this.targetDoc && this.targetDocView && docs.length === 1 && (context = this.targetDocView.props.ContainingCollectionView)) {
-                        DocumentManager.Instance.jumpToDocument(this.targetDoc, true, undefined, context.props.Document);
+                        DocumentManager.Instance.jumpToDocument(this.targetDoc, true, undefined, [context.props.Document]);
                     }
                 }}
                 onPointerEnter={action(() => {
@@ -548,10 +548,10 @@ export class SharingManager extends React.Component<{}> {
                                 {this.sharingOptions(uniform)}
                             </select>
                         ) : (
-                                <div className={"permissions-dropdown"}>
-                                    {permissions}
-                                </div>
-                            )}
+                            <div className={"permissions-dropdown"}>
+                                {permissions}
+                            </div>
+                        )}
                     </div>
                 </div>
             );
@@ -572,7 +572,7 @@ export class SharingManager extends React.Component<{}> {
                         <div className="edit-actions">
                             <div className={"permissions-dropdown"}>
                                 Owner
-                        </div>
+                            </div>
                         </div>
                     </div>
                 ) : null,
@@ -622,10 +622,10 @@ export class SharingManager extends React.Component<{}> {
                                 {this.sharingOptions(uniform, group.title === "Override")}
                             </select>
                         ) : (
-                                <div className={"permissions-dropdown"}>
-                                    {permissions}
-                                </div>
-                            )}
+                            <div className={"permissions-dropdown"}>
+                                {permissions}
+                            </div>
+                        )}
                     </div>
                 </div>
             );
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index eb2bcc18c..936946df0 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -113,7 +113,12 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         }
     }
 
-    titleEntered = (e: React.KeyboardEvent) => e.key === "Enter" && (e.target as any).blur();
+    titleEntered = (e: React.KeyboardEvent) => {
+        if (e.key === "Enter") {
+            e.stopPropagation();
+            (e.target as any).blur();
+        }
+    }
 
     @action onTitleDown = (e: React.PointerEvent): void => {
         setupMoveUpEvents(this, e, e => this.onBackgroundMove(true, e), (e) => { }, action((e) => {
@@ -288,7 +293,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         if (fixedAspect && (resizeHdl === "documentDecorations-bottomRightResizer" || resizeHdl === "documentDecorations-topLeftResizer")) { // need to generalize for bl and tr drag handles
             const project = (p: number[], a: number[], b: number[]) => {
                 const atob = [b[0] - a[0], b[1] - a[1]];
-                const atop = [p[0] - a[0], p[1] - a[1]]; first
+                const atop = [p[0] - a[0], p[1] - a[1]];
                 const len = atob[0] * atob[0] + atob[1] * atob[1];
                 let dot = atop[0] * atob[0] + atop[1] * atob[1];
                 const t = dot / len;
@@ -501,7 +506,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                     value={this._accumulatedTitle}
                     onBlur={e => this.titleBlur()}
                     onChange={action(e => this._accumulatedTitle = e.target.value)}
-                    onKeyPress={this.titleEntered} /> :
+                    onKeyDown={this.titleEntered} /> :
                 <div className="documentDecorations-title" key="title" onPointerDown={this.onTitleDown} >
                     <span className={`documentDecorations-titleSpan${colorScheme}`}>{`${this.selectionTitle}`}</span>
                 </div>;
@@ -521,7 +526,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         const useRotation = seldoc.ComponentView instanceof InkingStroke || seldoc.ComponentView instanceof ImageBox;
         const resizerScheme = colorScheme ? "documentDecorations-resizer" + colorScheme : "";
 
-        const rotation = NumCast(seldoc.rootDoc._jitterRotation)
+        const rotation = NumCast(seldoc.rootDoc._jitterRotation);
         const rdeg = rotation / 180 * Math.PI;
 
         return (<div className={`documentDecorations${colorScheme}`}>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index c794c73db..db51c54f8 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -133,7 +133,7 @@ export class MainView extends React.Component {
         window.addEventListener("paste", KeyManager.Instance.paste as any);
         document.addEventListener("dash", (e: any) => {  // event used by chrome plugin to tell Dash which document to focus on
             const id = FormattedTextBox.GetDocFromUrl(e.detail);
-            DocServer.GetRefField(id).then(doc => (doc instanceof Doc) ? DocumentManager.Instance.jumpToDocument(doc, false, undefined) : (null));
+            DocServer.GetRefField(id).then(doc => (doc instanceof Doc) ? DocumentManager.Instance.jumpToDocument(doc, false, undefined, []) : (null));
         });
         document.addEventListener("linkAnnotationToDash", Hypothesis.linkListener);
         this.initEventListeners();
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 78b125e07..8dfc7edc7 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -256,7 +256,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 }
                 PresBox.Instance?._selectedArray.clear();
                 pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array
-                DocumentManager.Instance.jumpToDocument(doc, false, undefined);
+                DocumentManager.Instance.jumpToDocument(doc, false, undefined, []);
                 batch.end();
             });
         }
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 72480b094..164021358 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -72,7 +72,7 @@ export enum TreeSort {
     Down = "down",
     Zindex = "z",
     None = "none"
-};
+}
 /**
  * Renders a treeView of a collection of documents
  * 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 5d1e1892c..5b3a7db41 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1423,7 +1423,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     }
 
     replaceCanvases = (oldDiv: HTMLElement, newDiv: HTMLElement) => {
-        if (oldDiv.childNodes) {
+        if (oldDiv.childNodes && newDiv) {
             for (let i = 0; i < oldDiv.childNodes.length; i++) {
                 this.replaceCanvases(oldDiv.childNodes[i] as HTMLElement, newDiv.childNodes[i] as HTMLElement);
             }
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index e3d4f86c1..c615bfb8e 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -231,7 +231,7 @@ export class CollectionLinearView extends CollectionSubView() {
                         <span className="bottomPopup-text">
                             Currently playing:
                             {CollectionStackedTimeline.CurrentlyPlaying.map((clip, i) =>
-                                <span className="audio-title" onPointerDown={() => DocumentManager.Instance.jumpToDocument(clip, true)}>
+                                <span className="audio-title" onPointerDown={() => DocumentManager.Instance.jumpToDocument(clip, true, undefined, [])}>
                                     {clip.title + (i === CollectionStackedTimeline.CurrentlyPlaying.length - 1 ? "" : ",")}
                                 </span>)}
                         </span>
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx
index c2bb3b3ac..adcd9e1e3 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaCells.tsx
@@ -199,7 +199,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             const aliasdoc = await SearchUtil.GetAliasesOfDocument(this._rowDataDoc);
             const targetContext = aliasdoc.length <= 0 ? undefined : Cast(aliasdoc[0].context, Doc, null);
             // Jump to the this document
-            DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext,
+            DocumentManager.Instance.jumpToDocument(this._rowDoc, false, emptyFunction, targetContext ? [targetContext] : [],
                 undefined, undefined, undefined, () => this.props.setPreviewDoc(this._rowDoc));
         }
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8570f6fff..02ea87103 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -663,7 +663,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             }
             if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) {
                 const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.() ?? this.props.Document;
-                de.complete.linkDocument = DocUtils.MakeLink({ doc: linkdrag.linkSourceDoc }, { doc: dropDoc }, undefined, undefined, undefined, undefined, [de.x, de.y]);
+                de.complete.linkDocument = DocUtils.MakeLink({ doc: linkdrag.linkSourceDoc }, { doc: dropDoc }, undefined, undefined, undefined, undefined, [de.x, de.y - 50]);
             }
         }
     }
@@ -857,6 +857,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     }
     @observable _retryThumb = 1;
     thumbShown = () => !this.props.isSelected() && LightboxView.LightboxDoc !== this.rootDoc && this.thumb &&
+        !Doc.AreProtosEqual(DocumentLinksButton.StartLink, this.rootDoc) &&
         !this._componentView?.isAnyChildContentActive?.() ? true : false
     @computed get contents() {
         TraceMobx();
diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx
index a9d33f161..ccac66996 100644
--- a/src/client/views/nodes/LinkDescriptionPopup.tsx
+++ b/src/client/views/nodes/LinkDescriptionPopup.tsx
@@ -54,6 +54,7 @@ export class LinkDescriptionPopup extends React.Component<{}> {
                 top: LinkDescriptionPopup.popupY ? LinkDescriptionPopup.popupY : 350,
             }}>
             <input className="linkDescriptionPopup-input"
+                onKeyDown={e => e.stopPropagation()}
                 onKeyPress={e => e.key === "Enter" && this.onDismiss(true)}
                 placeholder={"(Optional) Enter link description..."}
                 onChange={(e) => this.descriptionChanged(e)}>
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 69662d53a..48465976a 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -75,6 +75,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
 
     updateIcon = () => {
+        return; // currently we render pdf icons as text labels
         const docViewContent = this.props.docViewPath().lastElement().ContentDiv!;
         const newDiv = docViewContent.cloneNode(true) as HTMLDivElement;
         newDiv.style.width = (this.layoutDoc[WidthSym]()).toString();
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index b037e7220..d8dd074a5 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -156,6 +156,9 @@
             position: absolute;
             top: 0;
             left: 0;
+            cursor: text;
+            padding: 15px;
+            height: 100%
         }
 
         .webBox-cont {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 80961c92f..f441e5d36 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -207,8 +207,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     }
 
     @action
-    createTextAnnotation = (sel: Selection, selRange: Range) => {
-        if (this._mainCont.current) {
+    createTextAnnotation = (sel: Selection, selRange: Range | undefined) => {
+        if (this._mainCont.current && selRange) {
             const clientRects = selRange.getClientRects();
             for (let i = 0; i < clientRects.length; i++) {
                 const rect = clientRects.item(i);
@@ -235,7 +235,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     menuControls = () => this.urlEditor; // controls to be added to the top bar when a document of this type is selected
 
     scrollFocus = (doc: Doc, smooth: boolean) => {
-        this.props.select(true);
+        this.props.select(false); // hack to preven the webBox from being replaced with a thumbnail that currently doesn't show the the anchors
         if (StrCast(doc.webUrl) !== this._url) this.submitURL(StrCast(doc.webUrl), !smooth);
         if (DocListCast(this.props.Document[this.fieldKey + "-sidebar"]).includes(doc) && !this.SidebarShown) {
             this.toggleSidebar(!smooth);
@@ -252,7 +252,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             }
         }
         this._initialScroll = NumCast(this.layoutDoc._scrollTop);
-        return 0;
+        return undefined;
     }
 
     getAnchor = () => {
@@ -279,7 +279,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             const scale = (this.props.scaling?.() || 1) * mainContBounds.scale;
             const sel = this._iframe.contentWindow.getSelection();
             if (sel) {
-                this._textAnnotationCreator = () => this.createTextAnnotation(sel, sel.getRangeAt(0));
+                this._textAnnotationCreator = () => this.createTextAnnotation(sel, !sel.isCollapsed ? sel.getRangeAt(0) : undefined);
                 AnchorMenu.Instance.jumpTo(e.clientX * scale + mainContBounds.translateX,
                     e.clientY * scale + mainContBounds.translateY - NumCast(this.layoutDoc._scrollTop) * scale);
             }
@@ -650,6 +650,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @computed get content() {
         const interactive = !this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.isContentActive() && this.props.pointerEvents !== "none" && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting;
         return <div className={"webBox-cont" + (interactive ? "-interactive" : "")}
+            onKeyDown={e => e.stopPropagation()}
             style={{ width: !this.layoutDoc.forceReflow ? NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]) || `100%` : "100%", }}>
             {this.urlContent}
         </div>;
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 30ad43562..820d7ef96 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -389,11 +389,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             LightboxView.SetLightboxDoc(targetDoc);
         } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
             LightboxView.SetLightboxDoc(undefined);
-            await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right
+            await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, [srcContext], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right
         } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
             LightboxView.SetLightboxDoc(undefined);
             //awaiting jump so that new scale can be found, since jumping is async     
-            await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right    
+            await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, [srcContext], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right    
         }
         // After navigating to the document, if it is added as a presPinView then it will
         // adjust the pan and scale to that of the pinView when it was added.
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 9257cb75e..3d36efbc4 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -365,7 +365,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
      * or opening it in a new tab.
      */
     selectElement = async (doc: Doc, finishFunc: () => void) => {
-        await DocumentManager.Instance.jumpToDocument(doc, true, undefined, undefined, undefined, undefined, undefined, finishFunc);
+        await DocumentManager.Instance.jumpToDocument(doc, true, undefined, [], undefined, undefined, undefined, finishFunc);
     }
 
     /**
-- 
cgit v1.2.3-70-g09d2


From 57c1b8235b26a1b6a315922b4dc2926e1e597674 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 13 May 2022 18:17:10 -0400
Subject: removed layerProvider functionality.

---
 src/client/documents/Documents.ts                  |  3 +-
 src/client/views/DocComponent.tsx                  |  4 --
 src/client/views/GestureOverlay.tsx                |  1 -
 src/client/views/InkingStroke.tsx                  |  2 +-
 src/client/views/LightboxView.tsx                  |  1 -
 src/client/views/MainView.tsx                      |  6 ---
 src/client/views/OverlayView.tsx                   |  1 -
 src/client/views/Palette.tsx                       |  1 -
 src/client/views/PropertiesView.tsx                |  2 -
 src/client/views/StyleProvider.tsx                 | 52 +++-------------------
 src/client/views/TemplateMenu.tsx                  |  1 -
 src/client/views/collections/CollectionMenu.tsx    |  1 -
 .../collections/CollectionStackedTimeline.tsx      |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  2 -
 .../views/collections/CollectionTreeView.tsx       |  1 -
 src/client/views/collections/CollectionView.tsx    |  2 +-
 src/client/views/collections/TabDocView.tsx        | 19 +-------
 src/client/views/collections/TreeView.tsx          |  2 -
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 24 +++++-----
 .../collections/collectionFreeForm/MarqueeView.tsx | 10 ++---
 .../collectionLinear/CollectionLinearView.tsx      |  1 -
 .../CollectionMulticolumnView.tsx                  |  1 -
 .../CollectionMultirowView.tsx                     |  1 -
 .../collectionSchema/CollectionSchemaView.tsx      |  1 -
 .../collections/collectionSchema/SchemaTable.tsx   |  1 -
 src/client/views/linking/LinkPopup.tsx             |  3 +-
 src/client/views/nodes/AudioBox.tsx                |  2 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  2 -
 src/client/views/nodes/DocumentView.tsx            |  5 +--
 src/client/views/nodes/FilterBox.tsx               |  1 -
 src/client/views/nodes/ImageBox.tsx                |  2 +-
 src/client/views/nodes/KeyValuePair.tsx            |  1 -
 src/client/views/nodes/LinkAnchorBox.tsx           |  1 -
 src/client/views/nodes/LinkDocPreview.tsx          |  1 -
 src/client/views/nodes/VideoBox.tsx                |  2 +-
 src/client/views/nodes/WebBox.tsx                  |  6 +--
 .../views/nodes/formattedText/DashDocView.tsx      |  1 -
 .../views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 src/client/views/nodes/trails/PresBox.tsx          |  2 +-
 src/client/views/nodes/trails/PresElementBox.tsx   |  1 -
 src/client/views/pdf/Annotation.tsx                |  2 +-
 src/client/views/search/SearchBox.tsx              |  2 +-
 src/fields/Doc.ts                                  |  2 +-
 src/mobile/AudioUpload.tsx                         |  1 -
 src/mobile/MobileInterface.tsx                     |  1 -
 src/server/server_Initialization.ts                |  2 +-
 46 files changed, 41 insertions(+), 143 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index d9c2e0d8b..797a129c4 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -122,7 +122,6 @@ export class DocumentOptions {
     _scrollTop?: number; // scroll location for pdfs
     _noAutoscroll?: boolean;// whether collections autoscroll when this item is dragged
     _chromeHidden?: boolean; // whether the editing chrome for a document is hidden
-    _layerTags?: List<string>; // layer tags a document has (used for tab filtering "layers" in document tab)
     _searchDoc?: boolean; // is this a search document (used to change UI for search results in schema view)
     _forceActive?: boolean; // flag to handle pointer events when not selected (or otherwise active)
     _stayInCollection?: boolean;// whether the document should remain in its collection when someone tries to drag and drop it elsewhere
@@ -426,7 +425,7 @@ export namespace Docs {
                     childDontRegisterViews: true, _isLinkButton: true, _height: 150, description: "", showCaption: "description",
                     backgroundColor: "lightblue", // lightblue is default color for linking dot and link documents text comment area
                     links: "@links(self)",
-                    _removeDropProperties: new List(["_layerTags", "isLinkButton"]),
+                    _removeDropProperties: new List(["isLinkButton"]),
                 }
             }],
             [DocumentType.LINKDB, {
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 79aaf2158..9c176a4fd 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -44,7 +44,6 @@ interface ViewBoxBaseProps {
     ContainingCollectionDoc: Opt<Doc>;
     DocumentView?: () => DocumentView;
     fieldKey: string;
-    layerProvider?: (doc: Doc, assign?: boolean) => boolean;
     isSelected: (outsideReaction?: boolean) => boolean;
     isContentActive: () => boolean | undefined;
     renderDepth: number;
@@ -85,7 +84,6 @@ export interface ViewBoxAnnotatableProps {
     DataDoc?: Doc;
     fieldKey: string;
     filterAddDocument?: (doc: Doc[]) => boolean;  // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
-    layerProvider?: (doc: Doc, assign?: boolean) => boolean;
     isContentActive: () => boolean | undefined;
     select: (isCtrlPressed: boolean) => void;
     whenChildContentsActiveChanged: (isActive: boolean) => void;
@@ -209,13 +207,11 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps>()
                             if ([AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))) inheritParentAcls(CurrentUserUtils.ActiveDashboard, doc);
                             doc.context = this.props.Document;
                             if (annotationKey ?? this._annotationKeySuffix()) Doc.GetProto(doc).annotationOn = this.props.Document;
-                            this.props.layerProvider?.(doc, true);
                             Doc.AddDocToList(targetDataDoc, annotationKey ?? this.annotationKey, doc);
                         });
                     }
                     else {
                         added.filter(doc => [AclAdmin, AclEdit].includes(GetEffectiveAcl(doc))).map(doc => {  // only make a pushpin if we have acl's to edit the document
-                            this.props.layerProvider?.(doc, true);
                             //DocUtils.LeavePushpin(doc);
                             doc._stayInCollection = undefined;
                             doc.context = this.props.Document;
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 50dca0a99..482b62479 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -881,7 +881,6 @@ export class GestureOverlay extends Touchable {
                 isContentActive={returnFalse}
                 renderDepth={0}
                 styleProvider={returnEmptyString}
-                layerProvider={undefined}
                 docViewPath={returnEmptyDoclist}
                 focus={DocUtils.DefaultFocus}
                 whenChildContentsActiveChanged={emptyFunction}
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 3d9c048e5..d0f01c363 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -332,7 +332,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
             inkStrokeWidth, inkStrokeWidth + (highlightIndex && closed && fillColor && (new Color(fillColor)).alpha() < 1 ? 6 : 15),
             StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap),
             StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" || suppressFill ? "none" : fillColor, startMarker, endMarker,
-            markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents?.() ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0,
+            markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents?.() ?? (this.rootDoc._lockedPosition ? "none" : "visiblepainted"), 0.0,
             false, downHdlr);
         const fsize = +(StrCast(this.props.Document.fontSize, "12px").replace("px", ""));
         // bootsrap 3 style sheet sets line height to be 20px for default 14 point font size. 
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 59ed0dc92..9882693ee 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -246,7 +246,6 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                         docFilters={this.docFilters}
                         removeDocument={undefined}
                         styleProvider={DefaultStyleProvider}
-                        layerProvider={returnTrue}
                         ScreenToLocalTransform={this.lightboxScreenToLocal}
                         PanelWidth={this.lightboxWidth}
                         PanelHeight={this.lightboxHeight}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index db51c54f8..2e1d10955 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -281,7 +281,6 @@ export class MainView extends React.Component {
             addDocTab={this.addDocTabFunc}
             pinToPres={emptyFunction}
             docViewPath={returnEmptyDoclist}
-            layerProvider={undefined}
             styleProvider={undefined}
             rootSelected={returnTrue}
             isContentActive={returnTrue}
@@ -361,7 +360,6 @@ export class MainView extends React.Component {
                         addDocTab={this.addDocTabFunc}
                         pinToPres={emptyFunction}
                         docViewPath={returnEmptyDoclist}
-                        layerProvider={undefined}
                         styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards || this._sidebarContent.proto === Doc.UserDoc().myFilesystem ? DashboardStyleProvider : DefaultStyleProvider}
                         rootSelected={returnTrue}
                         removeDocument={returnFalse}
@@ -402,7 +400,6 @@ export class MainView extends React.Component {
                 docViewPath={returnEmptyDoclist}
                 focus={DocUtils.DefaultFocus}
                 styleProvider={DefaultStyleProvider}
-                layerProvider={undefined}
                 isContentActive={returnTrue}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
@@ -516,7 +513,6 @@ export class MainView extends React.Component {
                     dropAction={"alias"}
                     setHeight={returnFalse}
                     styleProvider={DefaultStyleProvider}
-                    layerProvider={undefined}
                     rootSelected={returnTrue}
                     bringToFront={emptyFunction}
                     select={emptyFunction}
@@ -591,7 +587,6 @@ export class MainView extends React.Component {
                     ContainingCollectionDoc={undefined}
                     Document={DocumentLinksButton.invisibleWebDoc}
                     dropAction={"move"}
-                    layerProvider={undefined}
                     styleProvider={undefined}
                     isSelected={returnFalse}
                     select={returnFalse}
@@ -673,7 +668,6 @@ export class MainView extends React.Component {
                             rootSelected={returnFalse}
                             renderDepth={0}
                             setHeight={returnFalse}
-                            layerProvider={undefined}
                             styleProvider={undefined}
                             addDocTab={returnFalse}
                             pinToPres={returnFalse}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 0f51cf9b2..ebad2981d 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -195,7 +195,6 @@ export class OverlayView extends React.Component {
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={DocUtils.DefaultFocus}
                     styleProvider={DefaultStyleProvider}
-                    layerProvider={undefined}
                     docViewPath={returnEmptyDoclist}
                     addDocTab={returnFalse}
                     pinToPres={emptyFunction}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 529697f71..954529bc9 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -54,7 +54,6 @@ export default class Palette extends React.Component<PaletteProps> {
                             focus={emptyFunction}
                             docViewPath={returnEmptyDoclist}
                             styleProvider={returnEmptyString}
-                            layerProvider={undefined}
                             whenChildContentsActiveChanged={emptyFunction}
                             bringToFront={emptyFunction}
                             docFilters={returnEmptyFilter}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 21c688421..bba2ac211 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -303,7 +303,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     fitContentsToDoc={returnTrue}
                     rootSelected={returnFalse}
                     styleProvider={DefaultStyleProvider}
-                    layerProvider={undefined}
                     docViewPath={returnEmptyDoclist}
                     freezeDimensions={true}
                     dontCenter={"y"}
@@ -1010,7 +1009,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             createNewFilterDoc={this.createNewFilterDoc}
                             updateFilterDoc={this.updateFilterDoc}
                             docViewPath={returnEmptyDoclist}
-                            layerProvider={undefined}
                             dontCenter="y"
                         />
                     </div>
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 5056dedaf..334415b38 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -26,10 +26,6 @@ import React = require("react");
 import { InkingStroke } from './InkingStroke';
 import { TreeSort } from './collections/TreeView';
 
-export enum StyleLayers {
-    Background = "background"
-}
-
 export enum StyleProp {
     TreeViewIcon = "treeViewIcon",
     TreeViewSortings = "treeViewSortings",// options for how to sort tree view items
@@ -56,14 +52,9 @@ export enum StyleProp {
 
 function darkScheme() { return CurrentUserUtils.ActiveDashboard?.colorScheme === ColorScheme.Dark; }
 
-function toggleBackground(doc: Doc) {
+function toggleLockedPosition(doc: Doc) {
     UndoManager.RunInBatch(() => runInAction(() => {
-        const layers = StrListCast(doc._layerTags);
-        if (!layers.includes(StyleLayers.Background)) {
-            if (!layers.length) doc._layerTags = new List<string>([StyleLayers.Background]);
-            else layers.push(StyleLayers.Background);
-        }
-        else layers.splice(layers.indexOf(StyleLayers.Background), 1);
+        doc._lockedPosition = !doc._lockedPosition;
     }), "toggleBackground");
 }
 
@@ -86,7 +77,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
     const isOpen = property.includes(":open");
     const fieldKey = props?.fieldKey ? props.fieldKey + "-" : isCaption ? "caption-" : "";
     const comicStyle = () => doc && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === "comic";
-    const isBackground = () => StrListCast(doc?._layerTags).includes(StyleLayers.Background);
+    const isBackground = () => doc && BoolCast(doc._lockedPosition);
     const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
     const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity);
     const showTitle = () => props?.styleProvider?.(doc, props, StyleProp.ShowTitle);
@@ -177,7 +168,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)";
                 default: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE); break;
             }
-            if (docColor && (!doc || props?.layerProvider?.(doc) === false)) docColor = DashColor(docColor).fade(0.5).toString();
+            if (docColor && !doc) docColor = DashColor(docColor).fade(0.5).toString();
             return docColor;
         }
         case StyleProp.BoxShadow: {
@@ -205,17 +196,15 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         case StyleProp.PointerEvents:
             if (doc?.type === DocumentType.MARKER) return "none";
             if (props?.pointerEvents?.() === "none") return "none";
-            const layer = doc && props?.layerProvider?.(doc);
             const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name);
-            if (opacity() === 0 || (isInk && !docProps?.treeViewDoc) || doc?.isInkMask) return "none";
-            if (layer === false && !selected && !SnappingManager.GetIsDragging()) return "none";
-            if (!isInk && layer === true) return "all";
+            if (doc?._lockedPosition || opacity() === 0 || (isInk && !docProps?.treeViewDoc) || doc?.isInkMask) return "none";
+            if (!isInk) return "all";
             return undefined;
         case StyleProp.Decorations:
             if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform || doc?.x !== undefined || doc?.y !== undefined) {
                 return doc && (isBackground() || selected) && (props?.renderDepth || 0) > 0 &&
                     ((doc.type === DocumentType.COL && doc._viewType !== CollectionViewType.Pile) || [DocumentType.RTF, DocumentType.IMG, DocumentType.INK].includes(doc.type as DocumentType)) ?
-                    <div className="styleProvider-lock" onClick={() => toggleBackground(doc)}>
+                    <div className="styleProvider-lock" onClick={() => toggleLockedPosition(doc)}>
                         <FontAwesomeIcon icon={isBackground() ? "lock" : "unlock"} style={{ color: isBackground() ? "red" : undefined }} size="lg" />
                     </div>
                     : (null);
@@ -251,30 +240,3 @@ export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps
     }
     return DefaultStyleProvider(doc, props, property);
 }
-
-//
-// a preliminary semantic-"layering/grouping" mechanism for determining interactive properties of documents
-//  currently, the provider tests whether the docuemnt's layer field matches the activeLayer field of the tab.
-//     if it matches, then the document gets pointer events, otherwise it does not.
-//
-export function DefaultLayerProvider(thisDoc: Doc) {
-    return (doc: Doc, assign?: boolean) => {
-        if (doc.z) return true;
-        if (assign) {
-            const activeLayer = StrCast(thisDoc?.activeLayer);
-            if (activeLayer) {
-                const layers = Cast(doc._layerTags, listSpec("string"), []);
-                if (layers.length && !layers.includes(activeLayer)) layers.push(activeLayer);
-                else if (!layers.length) doc._layerTags = new List<string>([activeLayer]);
-                if (activeLayer === "red" || activeLayer === "green" || activeLayer === "blue") doc._backgroundColor = activeLayer;
-            }
-            return true;
-        } else {
-            if (Doc.AreProtosEqual(doc, thisDoc)) return true;
-            const layers = StrListCast(doc._layerTags);
-            if (!layers.length && !thisDoc?.activeLayer) return true;
-            if (layers.includes(StrCast(thisDoc?.activeLayer))) return true;
-            return false;
-        }
-    };
-}
\ No newline at end of file
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index b3a24e031..636f7042f 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -131,7 +131,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 ContainingCollectionDoc={undefined}
                 ContainingCollectionView={undefined}
                 styleProvider={DefaultStyleProvider}
-                layerProvider={undefined}
                 setHeight={returnFalse}
                 docViewPath={returnEmptyDoclist}
                 docFilters={returnEmptyFilter}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 364a2440e..b3fbd4ca4 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -108,7 +108,6 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps>{
                 dropAction={"alias"}
                 setHeight={returnFalse}
                 styleProvider={DefaultStyleProvider}
-                layerProvider={undefined}
                 rootSelected={returnTrue}
                 bringToFront={emptyFunction}
                 select={emptyFunction}
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index de307416f..683b6d51d 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -392,7 +392,7 @@ 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.layerProvider?.(this.props.Document) !== false && this.props.Document._isGroup) return false;
+        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
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 509005b45..4338dedcc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -222,7 +222,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
             PanelWidth={width}
             PanelHeight={height}
             styleProvider={this.styleProvider}
-            layerProvider={this.props.layerProvider}
             docViewPath={this.props.docViewPath}
             fitWidth={this.props.childFitWidth}
             isContentActive={emptyFunction}
@@ -543,7 +542,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                     renderDepth={this.props.renderDepth}
                     focus={emptyFunction}
                     styleProvider={this.props.styleProvider}
-                    layerProvider={this.props.layerProvider}
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 41970eb96..5e89016db 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -296,7 +296,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     renderDepth={this.props.renderDepth + 1}
                     focus={emptyFunction}
                     styleProvider={this.props.styleProvider}
-                    layerProvider={this.props.layerProvider}
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ee2c28b5f..7c5f49b42 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -261,7 +261,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             CollectionView: this,
         };
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
-            style={{ pointerEvents: this.props.layerProvider?.(this.rootDoc) === false ? "none" : undefined }}>
+            style={{ pointerEvents: this.rootDoc._lockedPosition ? "none" : undefined }}>
             {this.showIsTagged()}
             {this.renderSubView(this.collectionViewType, props)}
         </div>);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 8dfc7edc7..73e5a9178 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -26,7 +26,7 @@ import { Colors, Shadows } from '../global/globalEnums';
 import { LightboxView } from '../LightboxView';
 import { DocFocusOptions, DocumentView, DocumentViewProps } from "../nodes/DocumentView";
 import { PinProps, PresBox, PresMovement } from '../nodes/trails';
-import { DefaultLayerProvider, DefaultStyleProvider, StyleLayers, StyleProp } from '../StyleProvider';
+import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
 import { CollectionDockingView } from './CollectionDockingView';
 import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
@@ -94,20 +94,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
 
             if (tab.element[0].children[1].children.length === 1) {
-                const toggle = document.createElement("div");
-                toggle.style.width = "10px";
-                toggle.style.height = "calc(100% - 2px)";
-                toggle.style.left = "-2px";
-                toggle.style.bottom = "1px";
-                toggle.style.borderTopRightRadius = "7px";
-                toggle.style.position = "relative";
-                toggle.style.display = "inline-block";
-                toggle.style.background = "transparent";
-                toggle.onclick = (e: MouseEvent) => {
-                    if (tab.contentItem === tab.header.parent.getActiveContentItem()) {
-                        tab.DashDoc.activeLayer = tab.DashDoc.activeLayer ? undefined : StyleLayers.Background;
-                    }
-                };
                 iconWrap.className = "lm_iconWrap";
                 iconWrap.id = "lm_iconWrap";
                 closeWrap.className = "lm_iconWrap";
@@ -357,7 +343,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     disableMinimap = () => !this._document || (this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform);
     hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.hideMinimap);
 
-    @computed get layerProvider() { return this._document && DefaultLayerProvider(this._document); }
     @computed get docView() {
         return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
             <><DocumentView key={this._document[Id]} ref={action((r: DocumentView) => this._view = r)}
@@ -369,7 +354,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 isContentActive={returnTrue}
                 PanelWidth={this.PanelWidth}
                 PanelHeight={this.PanelHeight}
-                layerProvider={this.layerProvider}
                 styleProvider={DefaultStyleProvider}
                 docFilters={CollectionDockingView.Instance.childDocFilters}
                 docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters}
@@ -520,7 +504,6 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={DocUtils.DefaultFocus}
                     styleProvider={TabMinimapView.miniStyleProvider}
-                    layerProvider={undefined}
                     addDocTab={this.props.addDocTab}
                     pinToPres={TabDocView.PinDoc}
                     docFilters={CollectionDockingView.Instance.childDocFilters}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 164021358..d608f800c 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -663,7 +663,6 @@ export class TreeView extends React.Component<TreeViewProps> {
                 hideDecorationTitle={this.props.treeView.outlineMode}
                 hideResizeHandles={this.props.treeView.outlineMode}
                 styleProvider={this.titleStyleProvider}
-                layerProvider={returnTrue}
                 docViewPath={returnEmptyDoclist}
                 treeViewDoc={this.props.treeView.props.Document}
                 addDocument={undefined}
@@ -760,7 +759,6 @@ export class TreeView extends React.Component<TreeViewProps> {
             renderDepth={this.props.renderDepth + 1}
             treeViewDoc={this.props.treeView?.props.Document}
             rootSelected={returnTrue}
-            layerProvider={returnTrue}
             docViewPath={this.props.treeView.props.docViewPath}
             docFilters={returnEmptyFilter}
             docRangeFilters={returnEmptyFilter}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4f79d19ad..322944d92 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -44,7 +44,7 @@ import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
 import { PresBox } from "../../nodes/trails/PresBox";
 import { VideoBox } from "../../nodes/VideoBox";
 import { CreateImage } from "../../nodes/WebBoxRenderer";
-import { StyleLayers, StyleProp } from "../../StyleProvider";
+import { StyleProp } from "../../StyleProvider";
 import { CollectionDockingView } from "../CollectionDockingView";
 import { CollectionSubView } from "../CollectionSubView";
 import { CollectionViewType } from "../CollectionView";
@@ -122,8 +122,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     @observable ChildDrag: DocumentView | undefined; // child document view being dragged.  needed to update drop areas of groups when a group item is dragged.
 
     @computed get views() { return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele); }
-    @computed get backgroundEvents() { return this.props.layerProvider?.(this.layoutDoc) === false && SnappingManager.GetIsDragging(); }
-    @computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && this.props.isContentActive(); }
     @computed get fitToContentVals() {
         return {
             bounds: { ...this.contentBounds, cx: (this.contentBounds.x + this.contentBounds.r) / 2, cy: (this.contentBounds.y + this.contentBounds.b) / 2 },
@@ -222,8 +220,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) {
-        if (!de.embedKey && !this.ChildDrag && this.props.layerProvider?.(this.props.Document) !== false && this.props.Document._isGroup) return false;
-        if (!super.onInternalDrop(e, de)) return false;
+        if (!de.embedKey && !this.ChildDrag && this.rootDoc._isGroup) return false;
+        if (this.rootDoc._lockedPosition || !super.onInternalDrop(e, de)) return false;
         const refDoc = docDragData.droppedDocuments[0];
         const [xpo, ypo] = this.getContainerTransform().transformPoint(de.x, de.y);
         const z = NumCast(refDoc.z);
@@ -251,7 +249,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             const nd = [Doc.NativeWidth(layoutDoc), Doc.NativeHeight(layoutDoc)];
             layoutDoc._width = NumCast(layoutDoc._width, 300);
             layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? nd[1] / nd[0] * NumCast(layoutDoc._width) : 300);
-            !StrListCast(d._layerTags).includes(StyleLayers.Background) && (d._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront
+            (d._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront
         }
 
         (docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(docDragData.droppedDocuments);
@@ -418,8 +416,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 styleProp = colors[cluster % colors.length];
                 const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor);
                 // override the cluster color with an explicitly set color on a non-background document.  then override that with an explicitly set color on a background document
-                set?.filter(s => !StrListCast(s._layerTags).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor));
-                set?.filter(s => StrListCast(s._layerTags).includes(StyleLayers.Background)).map(s => styleProp = StrCast(s.backgroundColor));
+                set?.map(s => styleProp = StrCast(s.backgroundColor));
             }
         } //else if (doc && NumCast(doc.group, -1) !== -1) styleProp = "gray";
         return styleProp;
@@ -1017,7 +1014,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     bringToFront = (doc: Doc, sendToBack?: boolean) => {
-        if (sendToBack || StrListCast(doc._layerTags).includes(StyleLayers.Background)) {
+        if (sendToBack) {
             doc.zIndex = 0;
         } else if (doc.isInkMask) {
             doc.zIndex = 5000;
@@ -1155,7 +1152,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     pointerEvents = () => {
         const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
-        const pointerEvents = this.props.isContentActive() === false ? "none" : this.backgroundActive || this.props.childPointerEvents ? "all" :
+        const pointerEvents = this.props.isContentActive() === false ? "none" : this.props.childPointerEvents ? "all" :
             (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : this.props.pointerEvents?.();
         return pointerEvents;
     }
@@ -1195,7 +1192,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             whenChildContentsActiveChanged={this.props.whenChildContentsActiveChanged}
             docViewPath={this.props.docViewPath}
             styleProvider={this.getClusterColor}
-            layerProvider={this.props.layerProvider}
             dataProvider={this.childDataProvider}
             sizeProvider={this.childSizeProvider}
             freezeDimensions={BoolCast(this.props.Document.childFreezeDimensions, this.props.childFreezeDimensions)}
@@ -1614,7 +1610,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const isDocInView = (doc: Doc, rect: { left: number, top: number, width: number, height: number }) => intersectRect(docDims(doc), rect);
 
         const otherBounds = { left: this.panX(), top: this.panY(), width: Math.abs(size[0]), height: Math.abs(size[1]) };
-        let snappableDocs = activeDocs.filter(doc => !StrListCast(doc._layerTags).includes(StyleLayers.Background) && doc.z === undefined && isDocInView(doc, selRect));  // first see if there are any foreground docs to snap to
+        let snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect));  // first see if there are any foreground docs to snap to
         !snappableDocs.length && (snappableDocs = activeDocs.filter(doc => doc.z === undefined && isDocInView(doc, selRect))); // if not, see if there are background docs to snap to
         !snappableDocs.length && (snappableDocs = activeDocs.filter(doc => doc.z !== undefined && isDocInView(doc, otherBounds))); // if not, then why not snap to floating docs
 
@@ -1739,7 +1735,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             onContextMenu={this.onContextMenu}
             style={{
                 pointerEvents: this.props.Document.type === DocumentType.MARKER ? "none" :  // bcz: ugh.. this is here to prevent markers, which render as freeform views, from grabbing events -- need a better approach.
-                    this.backgroundEvents ? "all" : this.props.pointerEvents?.() as any,
+                    this.props.pointerEvents?.() as any,
                 transform: `scale(${this.contentScaling || 1})`,
                 width: `${100 / (this.contentScaling || 1)}%`,
                 height: this.isAnnotationOverlay && this.Document.scrollHeight ? NumCast(this.Document.scrollHeight) : `${100 / (this.contentScaling || 1)}%`// : this.isAnnotationOverlay ? (this.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight()
@@ -1767,7 +1763,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                     </svg>
                 </div>}
 
-            {this.props.Document._isGroup && SnappingManager.GetIsDragging() && (this.ChildDrag || this.props.layerProvider?.(this.props.Document) === false) ?
+            {this.props.Document._isGroup && SnappingManager.GetIsDragging() && this.ChildDrag ?
                 <div className="collectionFreeForm-groupDropper" ref={this.createGroupEventsTarget} style={{
                     width: this.ChildDrag ? "10000" : "100%",
                     height: this.ChildDrag ? "10000" : "100%",
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 5f303b428..1c4d47d57 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -28,7 +28,6 @@ import { CollectionView } from "../CollectionView";
 import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
 import "./MarqueeView.scss";
 import React = require("react");
-import { StyleLayers } from "../../StyleProvider";
 import { TreeView } from "../TreeView";
 import { VideoBox } from "../../nodes/VideoBox";
 import { ImageField, WebField } from "../../../../fields/URLField";
@@ -348,7 +347,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         this.hideMarquee();
     }
 
-    getCollection = action((selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, layers: string[], makeGroup: Opt<boolean>) => {
+    getCollection = action((selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, makeGroup: Opt<boolean>) => {
         const newCollection = creator ? creator(selected, { title: "nested stack", }) : ((doc: Doc) => {
             Doc.GetProto(doc).data = new List<Doc>(selected);
             Doc.GetProto(doc).title = makeGroup ? "grouping" : "nested freeform";
@@ -357,7 +356,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             return doc;
         })(Doc.MakeCopy(Doc.UserDoc().emptyCollection as Doc, true));
         newCollection.system = undefined;
-        newCollection._layerTags = new List<string>(layers);
         newCollection._width = this.Bounds.width;
         newCollection._height = this.Bounds.height;
         newCollection._isGroup = makeGroup;
@@ -437,7 +435,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             }));
             this.props.removeDocument?.(selected);
         }
-        const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined, [], group);
+        const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined, group);
         this.props.addDocument?.(newCollection);
         this.props.selectDocuments([newCollection]);
         MarqueeOptionsMenu.Instance.fadeOut(true);
@@ -531,7 +529,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
 
     @action
     background = (e: KeyboardEvent | React.PointerEvent | undefined) => {
-        const newCollection = this.getCollection([], undefined, [StyleLayers.Background], undefined);
+        const newCollection = this.getCollection([], undefined, undefined);
         this.props.addDocument?.(newCollection);
         MarqueeOptionsMenu.Instance.fadeOut(true);
         this.hideMarquee();
@@ -617,7 +615,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                 (this.touchesLine(bounds) || this.boundingShape(bounds)) && selection.push(doc);
             }
         };
-        this.props.activeDocuments().filter(doc => this.props.layerProvider?.(doc) !== false && !doc.z).map(selectFunc);
+        this.props.activeDocuments().filter(doc => !doc.z && !doc._lockedPosition).map(selectFunc);
         if (!selection.length && selectBackgrounds) this.props.activeDocuments().filter(doc => doc.z === undefined).map(selectFunc);
         if (!selection.length) this.props.activeDocuments().filter(doc => doc.z !== undefined).map(selectFunc);
         return selection;
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index c615bfb8e..bec582dcd 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -155,7 +155,6 @@ export class CollectionLinearView extends CollectionSubView() {
                 renderDepth={this.props.renderDepth + 1}
                 focus={emptyFunction}
                 styleProvider={this.props.styleProvider}
-                layerProvider={this.props.layerProvider}
                 docViewPath={returnEmptyDoclist}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 6929a1cd8..92f9b2f49 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -219,7 +219,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
             styleProvider={this.props.styleProvider}
-            layerProvider={this.props.layerProvider}
             docViewPath={this.props.docViewPath}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 7e2b83230..4c4054b09 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -218,7 +218,6 @@ export class CollectionMultirowView extends CollectionSubView() {
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
             styleProvider={this.props.styleProvider}
-            layerProvider={this.props.layerProvider}
             docViewPath={this.props.docViewPath}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index a93762ea4..b731479a5 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -417,7 +417,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                     docRangeFilters={this.childDocRangeFilters}
                     searchFilterDocs={this.searchFilterDocs}
                     styleProvider={DefaultStyleProvider}
-                    layerProvider={undefined}
                     docViewPath={returnEmptyDoclist}
                     ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                     ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/collectionSchema/SchemaTable.tsx b/src/client/views/collections/collectionSchema/SchemaTable.tsx
index 605481ddf..bea5b3be6 100644
--- a/src/client/views/collections/collectionSchema/SchemaTable.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTable.tsx
@@ -573,7 +573,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         Document={this._showDoc}
                         DataDoc={this._showDataDoc}
                         styleProvider={DefaultStyleProvider}
-                        layerProvider={undefined}
                         docViewPath={returnEmptyDoclist}
                         freezeDimensions={true}
                         focus={DocUtils.DefaultFocus}
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index c8be9069c..4b33ef8ae 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -67,7 +67,7 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                     <input defaultValue={""} autoComplete="off" type="text" placeholder="Search for Document..." id="search-input"
                         className="linkPopup-searchBox searchBox-input" /> */}
 
-                    <SearchBox 
+                    <SearchBox
                         Document={CurrentUserUtils.MySearchPanelDoc}
                         DataDoc={CurrentUserUtils.MySearchPanelDoc}
                         linkFrom={linkDoc}
@@ -83,7 +83,6 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                         pinToPres={emptyFunction}
                         rootSelected={returnTrue}
                         styleProvider={DefaultStyleProvider}
-                        layerProvider={undefined}
                         removeDocument={undefined}
                         ScreenToLocalTransform={Transform.Identity}
                         PanelWidth={this.getPWidth}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index e28e5b453..d97cb6f84 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -654,7 +654,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             className="audiobox-container"
             onContextMenu={this.specificContextMenu}
             onClick={!this.path && !this._recorder ? this.recordAudioAnnotation : undefined}
-            style={{ pointerEvents: this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined }}
+            style={{ pointerEvents: this.layoutDoc._lockedPosition ? "none" : undefined }}
         >
             {!this.path ? this.recordingControls : this.playbackControls}
         </div>;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index edadd59c0..5a0ab9110 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -21,7 +21,6 @@ import React = require("react");
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
     dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined;
     sizeProvider?: (doc: Doc, replica: string) => { width: number, height: number } | undefined;
-    layerProvider: ((doc: Doc, assign?: boolean) => boolean) | undefined;
     renderCutoffProvider: (doc: Doc) => boolean;
     zIndex?: number;
     highlight?: boolean;
@@ -159,7 +158,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             ...this.props,
             CollectionFreeFormDocumentView: this.returnThis,
             styleProvider: this.styleProvider,
-            layerProvider: this.props.layerProvider,
             ScreenToLocalTransform: this.screenToLocalTransform,
             PanelWidth: this.panelWidth,
             PanelHeight: this.panelHeight,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f30d093a1..c999b3224 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -37,7 +37,7 @@ import { DocComponent } from "../DocComponent";
 import { EditableView } from '../EditableView';
 import { InkingStroke } from "../InkingStroke";
 import { LightboxView } from "../LightboxView";
-import { StyleLayers, StyleProp } from "../StyleProvider";
+import { StyleProp } from "../StyleProvider";
 import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView";
 import { DocumentContentsView } from "./DocumentContentsView";
 import { DocumentLinksButton } from './DocumentLinksButton';
@@ -123,7 +123,6 @@ export interface DocumentViewSharedProps {
     PanelHeight: () => number;
     docViewPath: () => DocumentView[];
     dataTransition?: string; // specifies animation transition - used by collectionPile and potentially other layout engines when changing the size of documents so that the change won't be abrupt
-    layerProvider: undefined | ((doc: Doc, assign?: boolean) => boolean);
     styleProvider: Opt<StyleProviderFunc>;
     focus: DocFocusFunc;
     fitWidth?: (doc: Doc) => boolean;
@@ -474,7 +473,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             let stopPropagate = true;
             let preventDefault = true;
-            !StrListCast(this.props.Document._layerTags).includes(StyleLayers.Background) && (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
+            (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
             if (this._doubleTap && (this.props.Document.type !== DocumentType.FONTICON || this.onDoubleClickHandler)) {// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
                 if (this._timeout) {
                     clearTimeout(this._timeout);
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 78adf63cb..a47e17dfc 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -423,7 +423,6 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     treeViewHideHeaderFields={false}
                     dontRegisterView={true}
                     styleProvider={this.FilterStyleProvider}
-                    layerProvider={this.props.layerProvider}
                     docViewPath={this.props.docViewPath}
                     scriptContext={this.props.scriptContext}
                     moveDocument={returnFalse}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index e7c43e5cd..3b04aa807 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -379,7 +379,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             style={{
                 width: this.props.PanelWidth() ? undefined : `100%`,
                 height: this.props.PanelWidth() ? undefined : `100%`,
-                pointerEvents: this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined,
+                pointerEvents: this.layoutDoc._lockedPosition ? "none" : undefined,
                 borderRadius
             }} >
             <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 881cbf2bb..80def3025 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -60,7 +60,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             docRangeFilters: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
-            layerProvider: undefined,
             docViewPath: returnEmptyDoclist,
             ContainingCollectionView: undefined,
             ContainingCollectionDoc: undefined,
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index 437d29f39..7fd289a97 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -89,7 +89,6 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps>() {
     openLinkTargetOnRight = (e: React.MouseEvent) => {
         const alias = Doc.MakeAlias(Cast(this.layoutDoc[this.fieldKey], Doc, null));
         alias._isLinkButton = undefined;
-        alias._layerTags = undefined;
         alias.layoutKey = "layout";
         this.props.addDocTab(alias, "add:right");
     }
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 375434933..ba515fb89 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -179,7 +179,6 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             moveDocument={returnFalse}
                             rootSelected={returnFalse}
                             styleProvider={this.props.docProps?.styleProvider}
-                            layerProvider={this.props.docProps?.layerProvider}
                             docViewPath={returnEmptyDoclist}
                             ScreenToLocalTransform={Transform.Identity}
                             isDocumentActive={returnFalse}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 3b4c94562..c350e3139 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -809,7 +809,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
         const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / this.scaling()}px` : borderRad;
         return (<div className="videoBox" onContextMenu={this.specificContextMenu} ref={this._mainCont}
             style={{
-                pointerEvents: this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined,
+                pointerEvents: this.layoutDoc._lockedPosition ? "none" : undefined,
                 borderRadius,
                 overflow: this.props.docViewPath?.().slice(-1)[0].fitWidth ? "auto" : undefined
             }} onWheel={e => { e.stopPropagation(); e.preventDefault(); }}>
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 20e01be05..445df8ddd 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -74,7 +74,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @computed get allAnnotations() { return DocListCast(this.dataDoc[this.annotationKey]); }
     @computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); }
     @computed get webField() { return Cast(this.dataDoc[this.props.fieldKey], WebField)?.url; }
-    @computed get webThumb() { return this.props.thumbShown?.() && ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop ? this.layoutDoc.thumb : undefined))?.url }
+    @computed get webThumb() { return this.props.thumbShown?.() && ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop ? this.layoutDoc.thumb : undefined))?.url; }
 
     constructor(props: any) {
         super(props);
@@ -134,7 +134,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                         returnedfilename => setTimeout(action(() => {
                             this.lockout = false;
                             this.layoutDoc.thumb = new ImageField(returnedfilename);
-                            this.layoutDoc.thumbScrollTop = scrollTop
+                            this.layoutDoc.thumbScrollTop = scrollTop;
                         }), 500));
                 })
                 .catch(function (error: any) {
@@ -717,7 +717,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     pointerEvents = () => !this._draggingSidebar && this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none";
     annotationPointerEvents = () => this._isAnnotating || SnappingManager.GetIsDragging() ? "all" : "none";
     render() {
-        const pointerEvents = this.props.layerProvider?.(this.layoutDoc) === false ? "none" : this.props.pointerEvents?.() as any;
+        const pointerEvents = this.layoutDoc._lockedPosition ? "none" : this.props.pointerEvents?.() as any;
         const previewScale = this._previewNativeWidth ? 1 - this.sidebarWidth() / this._previewNativeWidth : 1;
         const scale = previewScale * (this.props.scaling?.() || 1);
         const renderAnnotations = (docFilters?: () => string[]) =>
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 364be461f..1d8e3a2cf 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -182,7 +182,6 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                     removeDocument={this.removeDoc}
                     isDocumentActive={returnFalse}
                     isContentActive={this._textBox.props.isContentActive}
-                    layerProvider={this._textBox.props.layerProvider}
                     styleProvider={this._textBox.props.styleProvider}
                     docViewPath={this._textBox.props.docViewPath}
                     ScreenToLocalTransform={this.getDocTransform}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 29117794e..f2a222cee 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1630,7 +1630,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const active = this.props.isContentActive();
         const scale = (this.props.scaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1);
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
-        const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || this.props.layerProvider?.(this.layoutDoc) !== false);
+        const interactive = (CurrentUserUtils.SelectedTool === InkTool.None || SnappingManager.GetIsDragging()) && (this.layoutDoc.z || !this.layoutDoc._lockedPosition);
         if (!selected && FormattedTextBoxComment.textBox === this) setTimeout(FormattedTextBoxComment.Hide);
         const minimal = this.props.ignoreAutoHeight;
         const paddingX = NumCast(this.layoutDoc._xMargin, this.props.xPadding || 0);
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 820d7ef96..64f5a296f 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -700,7 +700,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.rootDoc, this.fieldKey, doc);
     getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight
     panelHeight = () => this.props.PanelHeight() - 40;
-    isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && this.props.layerProvider?.(this.layoutDoc) !== false) &&
+    isContentActive = (outsideReaction?: boolean) => ((CurrentUserUtils.SelectedTool === InkTool.None && !this.layoutDoc._lockedPosition) &&
         (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
 
     /**
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index f4dc9b615..ef918d991 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -80,7 +80,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     Document={this.targetDoc}
                     DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
                     styleProvider={this.styleProvider}
-                    layerProvider={this.props.layerProvider}
                     docViewPath={returnEmptyDoclist}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index fb2e33e2a..5bdce273d 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -26,7 +26,7 @@ export
             {DocListCast(this.props.anno.textInlineAnnotations).map(a =>
                 <RegionAnnotation pointerEvents={this.props.pointerEvents} {...this.props} document={a} key={a[Id]} />
             )}
-        </div>
+        </div>;
     }
 }
 
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 2905e96d9..152b7bbcb 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -127,7 +127,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps>() {
     static foreachRecursiveDoc(docs: Doc[], func: (depth: number, doc: Doc) => void) {
         let newarray: Doc[] = [];
         var depth = 0;
-        let visited: Doc[] = [];
+        const visited: Doc[] = [];
         while (docs.length > 0) {
             newarray = [];
             docs.filter(d => d && !visited.includes(d)).forEach(d => {
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 9de8d0831..194b3ba27 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1026,7 +1026,7 @@ export namespace Doc {
         if (status === DocBrushStatus.unbrushed) {
             const lastBrushed = Array.from(brushManager.BrushedDoc.keys()).lastElement();
             if (lastBrushed) {
-                for (var link of LinkManager.Instance.getAllDirectLinks(lastBrushed)) {
+                for (const link of LinkManager.Instance.getAllDirectLinks(lastBrushed)) {
                     const a1 = Cast(link.anchor1, Doc, null);
                     const a2 = Cast(link.anchor2, Doc, null);
                     if (Doc.AreProtosEqual(a1, doc) || Doc.AreProtosEqual(a2, doc) ||
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 88221732e..418464f0e 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -96,7 +96,6 @@ export class AudioUpload extends React.Component {
                         isDocumentActive={returnTrue}
                         isContentActive={emptyFunction}
                         focus={emptyFunction}
-                        layerProvider={undefined}
                         styleProvider={() => "rgba(0,0,0,0)"}
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index cfcc48608..78ec706d7 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -214,7 +214,6 @@ export class MobileInterface extends React.Component {
                     isContentActive={emptyFunction}
                     focus={DocUtils.DefaultFocus}
                     styleProvider={this.whitebackground}
-                    layerProvider={undefined}
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index bdea57cb2..fd000a83c 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -195,7 +195,7 @@ function proxyServe(req: any, requrl: string, response: any) {
                 console.log("EROR?: ", e);
             }
         } else req.pipe(request(requrl)).pipe(response);
-    }
+    };
     retrieveHTTPBody = () => {
         req.headers.cookie = "";
         req.pipe(request(requrl))
-- 
cgit v1.2.3-70-g09d2


From 444f5b91f28e12ab9d48c5445eb02021a6a563a1 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 15 May 2022 11:32:35 -0400
Subject: fixed enterting titles in tab's to not trigger inconify.  added drop
 placement for mulitirow/col.  added time delay for switching to tab dragging.
  all this helps support a worktop-style topBar.

---
 src/client/util/DragManager.ts                     | 27 ++++++++++-----
 src/client/views/collections/TabDocView.tsx        |  3 ++
 .../CollectionMulticolumnView.tsx                  | 39 +++++++++++++++++++---
 .../CollectionMultirowView.tsx                     | 38 ++++++++++++++++++---
 4 files changed, 89 insertions(+), 18 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 12c0fe6c0..037da132b 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -449,20 +449,27 @@ export namespace DragManager {
             SnappingManager.clearSnapLines();
             batch.end();
         });
-        const moveHandler = async (e: PointerEvent) => {
+        var startWindowDragTimer: any;
+        const moveHandler = (e: PointerEvent) => {
             e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop
             if (dragData instanceof DocumentDragData) {
                 dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : dragData.defaultDropAction;
             }
             if (((e.target as any)?.className === "lm_tabs" || e?.shiftKey) && dragData.draggedDocuments.length === 1) {
-                dragData.dropAction = dragData.userDropAction || "same";
-                AbortDrag();
-                await finishDrag?.(new DragCompleteEvent(true, dragData));
-                DragManager.StartWindowDrag?.(e, dragData.droppedDocuments, (aborted) => {
-                    if (!aborted && (dragData.dropAction === "move" || dragData.dropAction === "same")) {
-                        dragData.removeDocument?.(dragData.draggedDocuments[0]);
-                    }
-                });
+                if (!startWindowDragTimer) startWindowDragTimer = setTimeout(async () => {
+                    startWindowDragTimer = undefined;
+                    dragData.dropAction = dragData.userDropAction || "same";
+                    AbortDrag();
+                    await finishDrag?.(new DragCompleteEvent(true, dragData));
+                    DragManager.StartWindowDrag?.(e, dragData.droppedDocuments, (aborted) => {
+                        if (!aborted && (dragData.dropAction === "move" || dragData.dropAction === "same")) {
+                            dragData.removeDocument?.(dragData.draggedDocuments[0]);
+                        }
+                    });
+                }, 500);
+            } else {
+                clearTimeout(startWindowDragTimer);
+                startWindowDragTimer = undefined;
             }
 
             const target = document.elementFromPoint(e.x, e.y);
@@ -528,6 +535,8 @@ export namespace DragManager {
             );
         };
         const upHandler = (e: PointerEvent) => {
+            clearTimeout(startWindowDragTimer);
+            startWindowDragTimer = undefined;
             dispatchDrag(document.elementFromPoint(e.x, e.y) || document.body, e, new DragCompleteEvent(false, dragData), snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom), finishDrag, options, cleanupDrag);
         };
         document.addEventListener("pointermove", moveHandler, true);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 73e5a9178..1310a582c 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -83,6 +83,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
             titleEle.size = StrCast(doc.title).length + 3;
             titleEle.value = doc.title;
+            titleEle.onkeydown = (e: KeyboardEvent) => {
+                e.stopPropagation();
+            }
             titleEle.onchange = undoBatch(action((e: any) => {
                 titleEle.size = e.currentTarget.value.length + 3;
                 Doc.GetProto(doc).title = e.currentTarget.value;
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 92f9b2f49..3582718a3 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -1,10 +1,10 @@
 import { action, computed } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from "react";
-import { Doc } from '../../../../fields/Doc';
+import { Doc, DocListCast } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnFalse } from '../../../../Utils';
+import { emptyFunction, returnFalse, returnTrue } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
@@ -194,11 +194,38 @@ export class CollectionMulticolumnView extends CollectionSubView() {
     @undoBatch
     @action
     onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
-        if (super.onInternalDrop(e, de)) {
+        let dropInd = -1;
+        if (de.complete.docDragData && this._mainCont) {
+            let curInd = -1;
             de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
-                d._dimUnit = "*";
-                d._dimMagnitude = 1;
+                curInd = this.childDocs.indexOf(d);
             }));
+            Array.from(this._mainCont.children).forEach((child, index) => {
+                const brect = child.getBoundingClientRect();
+                if (brect.x < de.x && brect.x + brect.width > de.x) {
+                    if (curInd !== -1 && curInd === Math.floor(index / 2)) {
+                        dropInd = curInd;
+                    }
+                    else if (child.className === "multiColumnResizer") {
+                        dropInd = Math.floor(index / 2);
+                    } else {
+                        dropInd = Math.ceil(index / 2 + (de.x - brect.x > brect.width / 2 ? 0 : -1));
+                    }
+                }
+            })
+            if (super.onInternalDrop(e, de)) {
+                de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
+                    d._dimUnit = "*";
+                    d._dimMagnitude = 1;
+                    if (dropInd !== curInd || dropInd === -1) {
+                        if (this.childDocs.includes(d)) {
+                            if (dropInd > this.childDocs.indexOf(d)) dropInd--;
+                        }
+                        Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d);
+                        Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1);
+                    }
+                }));
+            }
         }
         return false;
     }
@@ -214,6 +241,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
         }
         return this.props.addDocTab(doc, where);
     }
+    isContentActive = () => this.props.isSelected() || this.props.isContentActive();
     getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
         return <DocumentView
             Document={layout}
@@ -232,6 +260,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
             onClick={this.onChildClickHandler}
             onDoubleClick={this.onChildDoubleClickHandler}
             ScreenToLocalTransform={dxf}
+            isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
             focus={this.props.focus}
             docFilters={this.childDocFilters}
             docRangeFilters={this.childDocRangeFilters}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 4c4054b09..95456cf46 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -1,7 +1,7 @@
 import { action, computed } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from "react";
-import { Doc } from '../../../../fields/Doc';
+import { Doc, DocListCast } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
 import { emptyFunction, returnFalse } from '../../../../Utils';
@@ -190,14 +190,42 @@ export class CollectionMultirowView extends CollectionSubView() {
         return Transform.Identity(); // type coersion, this case should never be hit
     }
 
+
     @undoBatch
     @action
     onInternalDrop = (e: Event, de: DragManager.DropEvent) => {
-        if (super.onInternalDrop(e, de)) {
+        let dropInd = -1;
+        if (de.complete.docDragData && this._mainCont) {
+            let curInd = -1;
             de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
-                d._dimUnit = "*";
-                d._dimMagnitude = 1;
+                curInd = this.childDocs.indexOf(d);
             }));
+            Array.from(this._mainCont.children).forEach((child, index) => {
+                const brect = child.getBoundingClientRect();
+                if (brect.y < de.y && brect.y + brect.height > de.y) {
+                    if (curInd !== -1 && curInd === Math.floor(index / 2)) {
+                        dropInd = curInd;
+                    }
+                    else if (child.className === "multiColumnResizer") {
+                        dropInd = Math.floor(index / 2);
+                    } else {
+                        dropInd = Math.ceil(index / 2 + (de.y - brect.y > brect.height / 2 ? 0 : -1));
+                    }
+                }
+            })
+            if (super.onInternalDrop(e, de)) {
+                de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
+                    d._dimUnit = "*";
+                    d._dimMagnitude = 1;
+                    if (dropInd !== curInd || dropInd === -1) {
+                        if (this.childDocs.includes(d)) {
+                            if (dropInd > this.childDocs.indexOf(d)) dropInd--;
+                        }
+                        Doc.RemoveDocFromList(this.rootDoc, this.props.fieldKey, d);
+                        Doc.AddDocToList(this.rootDoc, this.props.fieldKey, d, DocListCast(this.rootDoc[this.props.fieldKey])[dropInd], undefined, dropInd === -1);
+                    }
+                }));
+            }
         }
         return false;
     }
@@ -213,6 +241,7 @@ export class CollectionMultirowView extends CollectionSubView() {
         }
         return this.props.addDocTab(doc, where);
     }
+    isContentActive = () => this.props.isSelected() || this.props.isContentActive();
     getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
         return <DocumentView
             Document={layout}
@@ -230,6 +259,7 @@ export class CollectionMultirowView extends CollectionSubView() {
             onClick={this.onChildClickHandler}
             onDoubleClick={this.onChildDoubleClickHandler}
             ScreenToLocalTransform={dxf}
+            isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
             focus={this.props.focus}
             docFilters={this.childDocFilters}
             isContentActive={emptyFunction}
-- 
cgit v1.2.3-70-g09d2


From ee1fa0ad22f1643888e4c467c6f8df837cc69178 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 17 May 2022 10:18:45 -0400
Subject: fixed pointerevents on treview open icon.  added browse mode for
 freeformcollections

---
 src/client/util/DragManager.ts                     | 24 ++++++++++++----------
 src/client/views/collections/TabDocView.tsx        |  2 +-
 src/client/views/collections/TreeView.tsx          | 13 ++++++++----
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 23 ++++++++++++++++-----
 .../CollectionMulticolumnView.tsx                  |  2 +-
 .../CollectionMultirowView.tsx                     |  2 +-
 6 files changed, 43 insertions(+), 23 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 037da132b..5a00e0c04 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -456,17 +456,19 @@ export namespace DragManager {
                 dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : dragData.defaultDropAction;
             }
             if (((e.target as any)?.className === "lm_tabs" || e?.shiftKey) && dragData.draggedDocuments.length === 1) {
-                if (!startWindowDragTimer) startWindowDragTimer = setTimeout(async () => {
-                    startWindowDragTimer = undefined;
-                    dragData.dropAction = dragData.userDropAction || "same";
-                    AbortDrag();
-                    await finishDrag?.(new DragCompleteEvent(true, dragData));
-                    DragManager.StartWindowDrag?.(e, dragData.droppedDocuments, (aborted) => {
-                        if (!aborted && (dragData.dropAction === "move" || dragData.dropAction === "same")) {
-                            dragData.removeDocument?.(dragData.draggedDocuments[0]);
-                        }
-                    });
-                }, 500);
+                if (!startWindowDragTimer) {
+                    startWindowDragTimer = setTimeout(async () => {
+                        startWindowDragTimer = undefined;
+                        dragData.dropAction = dragData.userDropAction || "same";
+                        AbortDrag();
+                        await finishDrag?.(new DragCompleteEvent(true, dragData));
+                        DragManager.StartWindowDrag?.(e, dragData.droppedDocuments, (aborted) => {
+                            if (!aborted && (dragData.dropAction === "move" || dragData.dropAction === "same")) {
+                                dragData.removeDocument?.(dragData.draggedDocuments[0]);
+                            }
+                        });
+                    }, 500);
+                }
             } else {
                 clearTimeout(startWindowDragTimer);
                 startWindowDragTimer = undefined;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 1310a582c..cebc3f779 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -85,7 +85,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             titleEle.value = doc.title;
             titleEle.onkeydown = (e: KeyboardEvent) => {
                 e.stopPropagation();
-            }
+            };
             titleEle.onchange = undoBatch(action((e: any) => {
                 titleEle.size = e.currentTarget.value.length + 3;
                 Doc.GetProto(doc).title = e.currentTarget.value;
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index d608f800c..c004b4d49 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -494,10 +494,15 @@ export class TreeView extends React.Component<TreeViewProps> {
         return <div className={`bullet${this.props.treeView.outlineMode ? "-outline" : ""}`} key={"bullet"}
             title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
             onClick={this.bulletClick}
-            style={this.props.treeView.outlineMode ? { opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity) } : {
-                color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"),
-                opacity: checked === "unchecked" || typeof iconType !== "string" ? undefined : 0.4
-            }}>
+            style={this.props.treeView.outlineMode ?
+                {
+                    opacity: this.titleStyleProvider?.(this.doc, this.props.treeView.props, StyleProp.Opacity)
+                } :
+                {
+                    pointerEvents: this.props.isContentActive() ? "all" : undefined,
+                    opacity: checked === "unchecked" || typeof iconType !== "string" ? undefined : 0.4,
+                    color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"),
+                }}>
             {this.props.treeView.outlineMode ?
                 !(this.doc.text as RichTextField)?.Text ? (null) :
                     <FontAwesomeIcon size="sm" icon={[this.childDocs?.length && !this.treeViewOpen ? "fas" : "far", "circle"]} /> :
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a60253914..68a51ef69 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -53,6 +53,7 @@ import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCurso
 import "./CollectionFreeFormView.scss";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
+import { ScriptingGlobals } from "../../../util/ScriptingGlobals";
 
 export const panZoomSchema = createSchema({
     _panX: "number",
@@ -154,7 +155,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action setKeyFrameEditing = (set: boolean) => this._keyframeEditing = set;
     getKeyFrameEditing = () => this._keyframeEditing;
-    onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
+    onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick, ScriptCast(this.layoutDoc.onBrowseClick));
     onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
     elementFunc = () => this._layoutElements;
     shrinkWrap = () => {
@@ -621,7 +622,13 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     }
 
     onClick = (e: React.MouseEvent) => {
-        if ((Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) {
+
+        if (this.layoutDoc.onBrowseClick) {
+            this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1);
+            e.stopPropagation();
+            e.preventDefault();
+        }
+        else if ((Math.abs(e.pageX - this._downX) < 3 && Math.abs(e.pageY - this._downY) < 3)) {
             if (e.shiftKey) {
                 if (Date.now() - this._lastTap < 300) { // reset zoom of freeform view to 1-to-1 on a shift + double click 
                     this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 1);
@@ -1127,7 +1134,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const screen = { left: cx - pw / 2, right: cx + pw / 2, top: cy - ph / 2, bot: cy + ph / 2 };
 
         if (scale) {
-            const maxZoom = 2; // sets the limit for how far we will zoom. this is useful for preventing small text boxes from filling the screen. So probably needs to be more sophisticated to consider more about the target and context
+            const maxZoom = 5; // sets the limit for how far we will zoom. this is useful for preventing small text boxes from filling the screen. So probably needs to be more sophisticated to consider more about the target and context
             return {
                 panX: (bounds.left + bounds.right) / 2,
                 panY: (bounds.top + bounds.bot) / 2,
@@ -1549,7 +1556,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
         const viewctrls = ContextMenu.Instance.findByDescription("UI Controls...");
         const viewCtrlItems = viewctrls && "subitems" in viewctrls ? viewctrls.subitems : [];
-
+        viewCtrlItems.push({ description: (this.layoutDoc.onChildClick ? "Leave" : "Enter") + " Browse Mode", event: () => this.layoutDoc.onBrowseClick = this.layoutDoc.onBrowseClick ? undefined : ScriptField.MakeScript("CollectionBrowseClick(documentView)", { documentView: "any" }), icon: "compress-arrows-alt" });
         !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null;
         !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null;
         !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" });
@@ -1973,4 +1980,10 @@ class CollectionFreeFormBackgroundGrid extends React.Component<CollectionFreeFor
                 }
             }} />;
     }
-}
\ No newline at end of file
+}
+
+export function CollectionBrowseClick(dv: DocumentView) {
+    dv.props.focus(dv.props.Document, { willZoom: true });
+    Doc.linkFollowHighlight(dv?.props.Document, false);
+}
+ScriptingGlobals.add(CollectionBrowseClick);
\ No newline at end of file
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index c18b4cec7..b6b59a2d6 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -212,7 +212,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                         dropInd = Math.ceil(index / 2 + (de.x - brect.x > brect.width / 2 ? 0 : -1));
                     }
                 }
-            })
+            });
             if (super.onInternalDrop(e, de)) {
                 de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
                     d._dimUnit = "*";
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 95456cf46..4074f8d69 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -212,7 +212,7 @@ export class CollectionMultirowView extends CollectionSubView() {
                         dropInd = Math.ceil(index / 2 + (de.y - brect.y > brect.height / 2 ? 0 : -1));
                     }
                 }
-            })
+            });
             if (super.onInternalDrop(e, de)) {
                 de.complete.docDragData?.droppedDocuments.forEach(action((d: Doc) => {
                     d._dimUnit = "*";
-- 
cgit v1.2.3-70-g09d2


From 51199aae80013073d4f1a0749a36051dcee591c1 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 20 May 2022 10:48:04 -0400
Subject: moved explore mode to topBar.  fixed highlighting of overlay toggle. 
 fixed pointerEvents on lockedPosition collectoins that are not children of a
 free form view.

---
 src/client/util/CurrentUserUtils.ts                | 10 ++++----
 src/client/views/MainView.tsx                      | 15 ++++++------
 src/client/views/StyleProvider.tsx                 | 20 +++++++---------
 src/client/views/collections/CollectionView.tsx    |  2 +-
 src/client/views/collections/TabDocView.tsx        |  4 +++-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  7 +-----
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/nodes/button/ButtonScripts.ts     |  4 +++-
 src/client/views/topbar/TopBar.tsx                 | 28 +++++++++++++++-------
 10 files changed, 50 insertions(+), 44 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 78bf531c6..8fed6e940 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1009,7 +1009,7 @@ export class CurrentUserUtils {
                 title: "Header Color", toolTip: "Header Color", btnType: ButtonType.ColorButton, ignoreClick: true, icon: "heading",
                 script: "setHeaderColor(value, _readOnly_)", hidden: 'selectedDocumentType()',
             }, // Only when a document is selected
-            { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", click: 'toggleOverlay(_readOnly_)', hidden: 'selectedDocumentType(undefined, "freeform", true)' }, // Only when floating document is selected in freeform
+            { title: "Overlay", toolTip: "Overlay", btnType: ButtonType.ToggleButton, icon: "layer-group", backgroundColor: 'toggleOverlay(true)', click: 'toggleOverlay()', hidden: 'selectedDocumentType(undefined, "freeform", true)' }, // Only when floating document is selected in freeform
             // { title: "Alias", btnType: ButtonType.ClickButton, icon: "copy", hidden: 'selectedDocumentType()' }, // Only when a document is selected 
             { title: "Text", type: "textTools", subMenu: true, expanded: 'selectedDocumentType("rtf")' }, // Always available
             { title: "Ink", type: "inkTools", subMenu: true, expanded: 'selectedDocumentType("ink")' }, // Always available
@@ -1023,7 +1023,7 @@ export class CurrentUserUtils {
         if (doc.contextMenuBtns === undefined) {
             const docList: Doc[] = [];
 
-            (await CurrentUserUtils.contextMenuTools(doc)).map(({ title, width, list, toolTip, ignoreClick, icon, type, btnType, click, script, subMenu, hidden, expanded }) => {
+            (await CurrentUserUtils.contextMenuTools(doc)).map(({ title, width, list, toolTip, backgroundColor, ignoreClick, icon, type, btnType, click, script, subMenu, hidden, expanded }) => {
                 const menuDocList: Doc[] = [];
                 if (subMenu) {
                     // default is textTools
@@ -1046,7 +1046,7 @@ export class CurrentUserUtils {
                             break;
                     }
                     tools.map(({ title, toolTip, icon, btnType, numBtnType, numBtnMax, numBtnMin, click, script, width, list, ignoreClick, switchToggle }) => {
-                        const computed = click ? ComputedField.MakeFunction(click) as any : "transparent";
+                        const backgroundColor = click ? ComputedField.MakeFunction(click) as any : "transparent";
                         menuDocList.push(Docs.Create.FontIconDocument({
                             _nativeWidth: width ? width : 25,
                             _nativeHeight: 25,
@@ -1069,7 +1069,7 @@ export class CurrentUserUtils {
                             title,
                             switchToggle,
                             color: Colors.WHITE,
-                            backgroundColor: computed,
+                            backgroundColor,
                             _dropAction: "alias",
                             _removeDropProperties: new List<string>(["dropAction", "_stayInCollection"]),
                             onClick: click ? ScriptField.MakeScript(click) : undefined
@@ -1105,7 +1105,7 @@ export class CurrentUserUtils {
                         dontUndo: true,
                         title,
                         color: Colors.WHITE,
-                        // backgroundColor: checkResult ? ComputedField.MakeFunction(checkResult, {}, {_readOnly_:true}) as any : "transparent",
+                        backgroundColor: backgroundColor ? ComputedField.MakeFunction(backgroundColor) as any : "transparent",
                         _dropAction: "alias",
                         hidden: hidden ? ComputedField.MakeFunction(hidden) as any : undefined,
                         _removeDropProperties: new List<string>(["dropAction", "_stayInCollection"]),
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 2e1d10955..9be00fa9e 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -273,6 +273,12 @@ export class MainView extends React.Component {
         Doc.AddDocToList(this.userDoc.myFilesystem as Doc, "data", folder);
     }
 
+    @observable _exploreMode = false;
+    @computed get exploreMode() {
+        return () => this._exploreMode ? ScriptField.MakeScript("CollectionBrowseClick(documentView, clientX, clientY)",
+            { documentView: "any", clientX: "number", clientY: "number" })! : undefined;
+    }
+
     @computed get mainDocView() {
         return <DocumentView key="main"
             Document={this.mainContainer!}
@@ -571,13 +577,6 @@ export class MainView extends React.Component {
         </svg>;
     }
 
-    @computed get topbar() {
-        TraceMobx();
-        return <div className="mainView-topbar">
-            <TopBar />
-        </div>;
-    }
-
     @computed get invisibleWebBox() { // see note under the makeLink method in HypothesisUtils.ts
         return !DocumentLinksButton.invisibleWebDoc ? null :
             <div className="mainView-invisibleWebRef" ref={DocumentLinksButton.invisibleWebRef}>
@@ -625,7 +624,7 @@ export class MainView extends React.Component {
             <GoogleAuthenticationManager />
             <DocumentDecorations boundsLeft={this.leftScreenOffsetOfMainDocView} boundsTop={this.topOfMainDoc} PanelWidth={this._windowWidth} PanelHeight={this._windowHeight} />
             <ComponentDecorations boundsLeft={this.leftScreenOffsetOfMainDocView} boundsTop={this.topOfMainDocContent} />
-            {this.topbar}
+            <TopBar />
             {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
             {DocumentLinksButton.LinkEditorDocView ? <LinkMenu clearLinkEditor={action(() => DocumentLinksButton.LinkEditorDocView = undefined)} docView={DocumentLinksButton.LinkEditorDocView} /> : (null)}
             {LinkDocPreview.LinkInfo ? <LinkDocPreview {...LinkDocPreview.LinkInfo} /> : (null)}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 93da2fa19..7ac40fc8e 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -156,15 +156,14 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                     if (StrCast(Doc.LayoutField(doc)).includes(SliderBox.name)) break;
                     docColor = docColor ||
                         (doc?._viewType === CollectionViewType.Pile || Doc.IsSystem(doc) ? (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY) : // system docs (seen in treeView) get a grayish background
-                            isBackground() ? "cyan" : // ?? is there a good default for a background collection
-                                doc.annotationOn ? "#00000015" : // faint interior for collections on PDFs, images, etc
-                                    (doc?._isGroup ? undefined :
-                                        StrCast((props?.renderDepth || 0) > 0 ?
-                                            Doc.UserDoc().activeCollectionNestedBackground :
-                                            Doc.UserDoc().activeCollectionBackground ?? (darkScheme() ?
-                                                Colors.BLACK :
-                                                "linear-gradient(#065fff, #85c1f9)"))
-                                    ));
+                            doc.annotationOn ? "#00000015" : // faint interior for collections on PDFs, images, etc
+                                (doc?._isGroup ? undefined :
+                                    StrCast((props?.renderDepth || 0) > 0 ?
+                                        Doc.UserDoc().activeCollectionNestedBackground :
+                                        Doc.UserDoc().activeCollectionBackground ?? (darkScheme() ?
+                                            Colors.BLACK :
+                                            "linear-gradient(#065fff, #85c1f9)"))
+                                ));
                     break;
                 //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)";
                 default: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE); break;
@@ -203,7 +202,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             return undefined;
         case StyleProp.Decorations:
             if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform || doc?.x !== undefined || doc?.y !== undefined) {
-                return doc && (isBackground() || selected) && (props?.renderDepth || 0) > 0 &&
+                return doc && (isBackground() || selected) && !Doc.IsSystem(doc) && (props?.renderDepth || 0) > 0 &&
                     ((doc.type === DocumentType.COL && doc._viewType !== CollectionViewType.Pile) || [DocumentType.RTF, DocumentType.IMG, DocumentType.INK].includes(doc.type as DocumentType)) ?
                     <div className="styleProvider-lock" onClick={() => toggleLockedPosition(doc)}>
                         <FontAwesomeIcon icon={isBackground() ? "lock" : "unlock"} style={{ color: isBackground() ? "red" : undefined }} size="lg" />
@@ -236,7 +235,6 @@ export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps
                         DocFocusOrOpen(doc, props?.ContainingCollectionDoc);
                     }
                 })}
-                {DashboardToggleButton(doc, "lockedPosition", "lock", "unlock")}
             </>;
     }
     return DefaultStyleProvider(doc, props, property);
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 7c5f49b42..19485a0eb 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -261,7 +261,7 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             CollectionView: this,
         };
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
-            style={{ pointerEvents: this.rootDoc._lockedPosition ? "none" : undefined }}>
+            style={{ pointerEvents: this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? "none" : undefined }}>
             {this.showIsTagged()}
             {this.renderSubView(this.collectionViewType, props)}
         </div>);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index cebc3f779..43f31813c 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -9,6 +9,7 @@ import { observer } from "mobx-react";
 import * as ReactDOM from 'react-dom';
 import { DataSym, Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
 import { Id } from '../../../fields/FieldSymbols';
+import { List } from '../../../fields/List';
 import { FieldId } from "../../../fields/RefField";
 import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
 import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
@@ -24,6 +25,7 @@ import { Transform } from '../../util/Transform';
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { Colors, Shadows } from '../global/globalEnums';
 import { LightboxView } from '../LightboxView';
+import { MainView } from '../MainView';
 import { DocFocusOptions, DocumentView, DocumentViewProps } from "../nodes/DocumentView";
 import { PinProps, PresBox, PresMovement } from '../nodes/trails';
 import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
@@ -33,7 +35,6 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TabDocView.scss";
 import React = require("react");
-import { List } from '../../../fields/List';
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
@@ -354,6 +355,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined}
+                onBrowseClick={MainView.Instance.exploreMode}
                 isContentActive={returnTrue}
                 PanelWidth={this.PanelWidth}
                 PanelHeight={this.PanelHeight}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 916cc9c05..df09569ef 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -624,10 +624,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     onClick = (e: React.MouseEvent) => {
         if (this.onBrowseClickHandler()) {
-            // if (this.Document[this.scaleFieldKey] !== 0.5) {
-            //     this.zoomSmoothlyAboutPt(this.getTransform().transformPoint(e.clientX, e.clientY), 0.5);
-            // }
-            // else 
             if (this.props.DocumentView?.()) {
                 this.onBrowseClickHandler().script.run({ documentView: this.props.DocumentView(), clientX: e.clientX, clientY: e.clientY });
             }
@@ -961,7 +957,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
-        if (this.layoutDoc._lockedTransform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === "outline") return;
+        if (this.layoutDoc._Transform || (this.layoutDoc._fitWidth && this.layoutDoc.nativeHeight) || CurrentUserUtils.OverlayDocs.includes(this.props.Document) || this.props.Document.treeViewOutlineMode === "outline") return;
         if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming
             e.stopPropagation();
         }
@@ -1564,7 +1560,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
         const viewctrls = ContextMenu.Instance.findByDescription("UI Controls...");
         const viewCtrlItems = viewctrls && "subitems" in viewctrls ? viewctrls.subitems : [];
-        viewCtrlItems.push({ description: (this.layoutDoc.onBrowseClick ? "Leave" : "Enter") + " Browse Mode", event: () => this.layoutDoc.onBrowseClick = this.layoutDoc.onBrowseClick ? undefined : ScriptField.MakeScript("CollectionBrowseClick(documentView, clientX, clientY)", { documentView: "any", clientX: "number", clientY: "number" }), icon: "compress-arrows-alt" });
         !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " Snap Lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }) : null;
         !Doc.UserDoc().noviceMode ? viewCtrlItems.push({ description: (this.Document._useClusters ? "Hide" : "Show") + " Clusters", event: () => this.updateClusters(!this.Document._useClusters), icon: "braille" }) : null;
         !viewctrls && ContextMenu.Instance.addItem({ description: "UI Controls...", subitems: viewCtrlItems, icon: "eye" });
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 1a74a4500..f5ad47ca7 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -177,7 +177,7 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
     onDoubleClick?: () => ScriptField;
     onPointerDown?: () => ScriptField;
     onPointerUp?: () => ScriptField;
-    onBrowseClick?: () => ScriptField;
+    onBrowseClick?: () => (ScriptField | undefined);
 }
 
 // these props are only available in DocumentViewIntenral
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 33ed8cd89..94937430e 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -24,7 +24,7 @@ export interface FieldViewProps extends DocumentViewSharedProps {
     isSelected: (outsideReaction?: boolean) => boolean;
     scaling?: () => number;
     setHeight?: (height: number) => void;
-    onBrowseClick?: () => ScriptField;
+    onBrowseClick?: () => (ScriptField | undefined);
 
     // properties intended to be used from within layout strings (otherwise use the function equivalents that work more efficiently with React)
     pointerEvents?: () => Opt<string>;
diff --git a/src/client/views/nodes/button/ButtonScripts.ts b/src/client/views/nodes/button/ButtonScripts.ts
index f3731b8f9..b4a382faf 100644
--- a/src/client/views/nodes/button/ButtonScripts.ts
+++ b/src/client/views/nodes/button/ButtonScripts.ts
@@ -1,5 +1,6 @@
 import { ScriptingGlobals } from "../../../util/ScriptingGlobals";
 import { SelectionManager } from "../../../util/SelectionManager";
+import { Colors } from "../../global/globalEnums";
 
 // toggle: Set overlay status of selected document
 ScriptingGlobals.add(function changeView(view: string) {
@@ -8,7 +9,8 @@ ScriptingGlobals.add(function changeView(view: string) {
 });
 
 // toggle: Set overlay status of selected document
-ScriptingGlobals.add(function toggleOverlay() {
+ScriptingGlobals.add(function toggleOverlay(readOnly?: boolean) {
     const selected = SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
+    if (readOnly) return selected?.Document.z ? Colors.MEDIUM_BLUE : "transparent";
     selected ? selected.props.CollectionFreeFormDocumentView?.().float() : console.log("failed");
 });
\ No newline at end of file
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index 0af7de6af..be248ab92 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -1,4 +1,6 @@
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Tooltip } from "@material-ui/core";
+import { action } from "mobx";
 import { observer } from "mobx-react";
 import * as React from 'react';
 import { Doc, DocListCast } from '../../../fields/Doc';
@@ -9,6 +11,7 @@ import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 import { SettingsManager } from "../../util/SettingsManager";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { Borders, Colors } from "../global/globalEnums";
+import { MainView } from "../MainView";
 import "./TopBar.scss";
 
 /**
@@ -40,20 +43,28 @@ export class TopBar extends React.Component {
                             </select>
                         </div>
                         <div className="topbar-dashboards">
-                            <div className="topbar-icon" onClick={async () => {
+                            <Tooltip title={<div className="dash-tooltip">Create a new dashboard </div>} placement="bottom"><div className="topbar-icon" onClick={async () => {
                                 const batch = UndoManager.StartBatch("new dash");
                                 await CurrentUserUtils.createNewDashboard(Doc.UserDoc());
                                 batch.end();
                             }}>
                                 {"New"}<FontAwesomeIcon icon="plus" />
                             </div>
-                            {<div className="topbar-icon" onClick={async () => {
-                                const batch = UndoManager.StartBatch("snapshot");
-                                await CurrentUserUtils.snapshotDashboard(Doc.UserDoc());
-                                batch.end();
-                            }}>
-                                {"Snapshot"}<FontAwesomeIcon icon="camera" />
-                            </div>}
+                            </Tooltip>
+                            <Tooltip title={<div className="dash-tooltip">Work on a copy of the dashboard layout</div>} placement="bottom">
+                                <div className="topbar-icon" onClick={async () => {
+                                    const batch = UndoManager.StartBatch("snapshot");
+                                    await CurrentUserUtils.snapshotDashboard(Doc.UserDoc());
+                                    batch.end();
+                                }}>
+                                    {"Snapshot"}<FontAwesomeIcon icon="camera" />
+                                </div>
+                            </Tooltip>
+                            <Tooltip title={<div className="dash-tooltip">Browsing mode for directly navigating to documents</div>} placement="bottom">
+                                <div className="topbar-icon" style={{ background: MainView.Instance._exploreMode ? Colors.LIGHT_BLUE : undefined }} onClick={action(() => MainView.Instance._exploreMode = !MainView.Instance._exploreMode)}>
+                                    {"Explore"}<FontAwesomeIcon icon="map" />
+                                </div>
+                            </Tooltip>
                         </div>
                     </div>
                     <div className="topbar-right" >
@@ -64,7 +75,6 @@ export class TopBar extends React.Component {
                         <div className="topbar-icon" onClick={() => SettingsManager.Instance.open()}>
                             {"Settings"}<FontAwesomeIcon icon="cog" />
                         </div>
-
                     </div>
                 </div>
             </div >
-- 
cgit v1.2.3-70-g09d2


From 414b56260c55f5ea7cac43dad83b41688fb924b5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 23 May 2022 20:34:07 -0400
Subject: added headerBar for closed tabs and other docs. extended multirow/col
 to support hiding chile doc decorations and for making child content/document
 active work better.  changed background style to work better for sub
 collections.

---
 src/client/util/CurrentUserUtils.ts                |   3 +
 src/client/views/DocumentDecorations.tsx           |   7 +-
 src/client/views/MainView.tsx                      | 115 +++++++++++++++------
 src/client/views/StyleProvider.tsx                 |   6 +-
 src/client/views/collections/CollectionMenu.tsx    |  17 ++-
 src/client/views/collections/CollectionView.tsx    |   6 +-
 src/client/views/collections/TabDocView.tsx        |   2 +
 .../CollectionMulticolumnView.tsx                  |  11 +-
 .../CollectionMultirowView.tsx                     |  11 +-
 src/client/views/nodes/DocumentView.tsx            |   6 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   1 -
 11 files changed, 125 insertions(+), 60 deletions(-)

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

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 1ebb5365a..1e42b9073 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -70,6 +70,7 @@ export class CurrentUserUtils {
     @observable public static GuestDashboard: Doc | undefined;
     @observable public static GuestMobile: Doc | undefined;
     @observable public static propertiesWidth: number = 0;
+    @observable public static headerBarHeight: number = 0;
     @observable public static searchPanelWidth: number = 0;
 
     // sets up the default User Templates - slideView,  headerView
@@ -1003,6 +1004,7 @@ export class CurrentUserUtils {
         doc.savedFilters = new List<Doc>();
         doc.filterDocCount = 0;
         doc.freezeChildren = "remove|add";
+        doc.myHeaderBarDoc = doc.myHeaderBarDoc ?? Docs.Create.MulticolumnDocument([], { title: "header bar", system: true });
         this.setupDefaultIconTemplates(doc);  // creates a set of icon templates triggered by the document deoration icon
         this.setupDocTemplates(doc); // sets up the template menu of templates
         this.setupImportSidebar(doc); // sets up the import sidebar
@@ -1210,6 +1212,7 @@ export class CurrentUserUtils {
     public static get DockedBtns() { return Cast(Doc.UserDoc().dockedBtns, Doc, null); }
     public static get MySearchPanelDoc() { return Cast(Doc.UserDoc().mySearchPanelDoc, Doc, null); }
     public static get ActiveDashboard() { return Cast(Doc.UserDoc().activeDashboard, Doc, null); }
+    public static get MyHeaderBarDoc() { return Cast(Doc.UserDoc().myHeaderBarDoc, Doc, null); }
     public static get ActivePresentation() { return Cast(Doc.UserDoc().activePresentation, Doc, null); }
     public static get MyRecentlyClosed() { return Cast(Doc.UserDoc().myRecentlyClosedDocs, Doc, null); }
     public static get MyDashboards() { return Cast(Doc.UserDoc().myDashboards, Doc, null); }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index ae3a91c4d..29e088143 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -511,11 +511,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                     <span className={`documentDecorations-titleSpan${colorScheme}`}>{`${this.selectionTitle}`}</span>
                 </div>;
 
-        let inMainMenuPanel = false;
-        for (let node = seldoc.ContentDiv; node && !inMainMenuPanel; node = node?.parentNode as any) {
-            if (node.className === "mainView-mainContent") inMainMenuPanel = true;
-        }
-        const leftBounds = inMainMenuPanel ? 0 : this.props.boundsLeft;
+
+        const leftBounds = this.props.boundsLeft;
         const topBounds = LightboxView.LightboxDoc ? 0 : this.props.boundsTop;
         bounds.x = Math.max(leftBounds, bounds.x - this._resizeBorderWidth / 2) + this._resizeBorderWidth / 2;
         bounds.y = Math.max(topBounds, bounds.y - this._resizeBorderWidth / 2 - this._titleHeight) + this._resizeBorderWidth / 2 + this._titleHeight;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 09a57843c..69e394790 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -33,7 +33,7 @@ import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOpti
 import { CollectionLinearView } from './collections/collectionLinear';
 import { CollectionMenu } from './collections/CollectionMenu';
 import { TreeViewType } from './collections/CollectionTreeView';
-import { CollectionViewType } from './collections/CollectionView';
+import { CollectionView, CollectionViewType } from './collections/CollectionView';
 import "./collections/TreeView.scss";
 import { ComponentDecorations } from './ComponentDecorations';
 import { ContextMenu } from './ContextMenu';
@@ -81,14 +81,19 @@ export class MainView extends React.Component {
 
     @computed private get dashboardTabHeight() { return 27; } //  27 comes form lm.config.defaultConfig.dimensions.headerHeight in goldenlayout.js
     @computed private get topOfDashUI() { return Number(DASHBOARD_SELECTOR_HEIGHT.replace("px", "")); }
-    @computed private get topOfMainDoc() { return this.topOfDashUI + this.topMenuHeight(); }
+    @computed private get topOfHeaderBarDoc() { return this.topOfDashUI + this.topMenuHeight(); }
+    @computed private get topOfSidebarDoc() { return this.topOfDashUI + this.topMenuHeight(); }
+    @computed private get topOfMainDoc() { return this.topOfDashUI + this.topMenuHeight() + this.headerBarDocHeight(); }
     @computed private get topOfMainDocContent() { return this.topOfMainDoc + this.dashboardTabHeight; }
     @computed private get leftScreenOffsetOfMainDocView() { return this.leftMenuWidth() - 2; }
     @computed private get userDoc() { return Doc.UserDoc(); }
     @computed private get colorScheme() { return StrCast(CurrentUserUtils.ActiveDashboard?.colorScheme); }
     @computed private get mainContainer() { return this.userDoc ? CurrentUserUtils.ActiveDashboard : CurrentUserUtils.GuestDashboard; }
+    @computed private get headerBarDoc() { return this.userDoc ? CurrentUserUtils.MyHeaderBarDoc : CurrentUserUtils.MyHeaderBarDoc; }
     @computed public get mainFreeform(): Opt<Doc> { return (docs => (docs?.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
 
+    headerBarDocWidth = () => this._dashUIWidth;
+    headerBarDocHeight = () => CurrentUserUtils.headerBarHeight ?? 0;
     topMenuHeight = () => 35;
     topMenuWidth = returnZero; // value is ignored ...
     leftMenuWidth = () => Number(LEFT_MENU_WIDTH.replace("px", ""));
@@ -98,7 +103,7 @@ export class MainView extends React.Component {
     propertiesWidth = () => Math.max(0, Math.min(this._dashUIWidth - 50, CurrentUserUtils.propertiesWidth || 0));
     propertiesHeight = () => this._dashUIHeight;
     mainDocViewWidth = () => this._dashUIWidth - this.propertiesWidth() - this.leftMenuWidth();
-    mainDocViewHeight = () => this._dashUIHeight;
+    mainDocViewHeight = () => this._dashUIHeight - this.headerBarDocHeight();
 
     componentDidMount() {
         document.getElementById("root")?.addEventListener("scroll", e => ((ele) => ele.scrollLeft = ele.scrollTop = 0)(document.getElementById("root")!));
@@ -177,8 +182,8 @@ export class MainView extends React.Component {
         fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faClipboard, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript,
         fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper as any,
         fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle, far.faCircle as any,
-        fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer as any, fa.faExpand, fa.faUndo, fa.faSlidersH, fa.faAngleDoubleLeft, fa.faAngleUp,
-        fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl,
+        fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, fa.faAngleDoubleDown, fa.faAngleDoubleLeft, fa.faAngleDoubleUp, faBuffer as any, fa.faExpand, fa.faUndo,
+        fa.faSlidersH, fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl,
         fa.faWindowMinimize, fa.faWindowRestore, fa.faTextWidth, fa.faTextHeight, fa.faClosedCaptioning, fa.faInfoCircle, fa.faTag, fa.faSyncAlt, fa.faPhotoVideo,
         fa.faArrowAltCircleDown, fa.faArrowAltCircleUp, fa.faArrowAltCircleLeft, fa.faArrowAltCircleRight, fa.faStopCircle, fa.faCheckCircle, fa.faGripVertical,
         fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload, fa.faBorderAll,
@@ -276,33 +281,67 @@ export class MainView extends React.Component {
         return () => this._exploreMode ? ScriptField.MakeScript("CollectionBrowseClick(documentView, clientX, clientY)",
             { documentView: "any", clientX: "number", clientY: "number" })! : undefined;
     }
-
+    headerBarScreenXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.headerBarDocHeight(), 1);
+
+    headerContentActive = () => SnappingManager.GetIsDragging() ? false : true;
+    @computed get headerBarDocView() {
+        console.log(this.headerBarDoc)
+        return <div style={{ height: this.headerBarDocHeight() }}>
+            <DocumentView key="headerBarDoc"
+                Document={this.headerBarDoc}
+                DataDoc={undefined}
+                addDocument={undefined}
+                addDocTab={this.addDocTabFunc}
+                pinToPres={emptyFunction}
+                docViewPath={returnEmptyDoclist}
+                styleProvider={DefaultStyleProvider}
+                rootSelected={returnTrue}
+                removeDocument={returnFalse}
+                fitContentsToDoc={returnTrue}
+                isContentActive={this.headerContentActive}
+                ScreenToLocalTransform={this.headerBarScreenXf}
+                hideResizeHandles={true}
+                PanelWidth={this.headerBarDocWidth}
+                PanelHeight={this.headerBarDocHeight}
+                renderDepth={0}
+                focus={DocUtils.DefaultFocus}
+                whenChildContentsActiveChanged={emptyFunction}
+                bringToFront={emptyFunction}
+                docFilters={returnEmptyFilter}
+                docRangeFilters={returnEmptyFilter}
+                searchFilterDocs={returnEmptyDoclist}
+                ContainingCollectionView={undefined}
+                ContainingCollectionDoc={undefined}
+            /></div>;
+    }
     @computed get mainDocView() {
-        return <DocumentView key="main"
-            Document={this.mainContainer!}
-            DataDoc={undefined}
-            addDocument={undefined}
-            addDocTab={this.addDocTabFunc}
-            pinToPres={emptyFunction}
-            docViewPath={returnEmptyDoclist}
-            styleProvider={undefined}
-            rootSelected={returnTrue}
-            isContentActive={returnTrue}
-            removeDocument={undefined}
-            ScreenToLocalTransform={Transform.Identity}
-            PanelWidth={this.mainDocViewWidth}
-            PanelHeight={this.mainDocViewHeight}
-            focus={DocUtils.DefaultFocus}
-            whenChildContentsActiveChanged={emptyFunction}
-            bringToFront={emptyFunction}
-            docFilters={returnEmptyFilter}
-            docRangeFilters={returnEmptyFilter}
-            searchFilterDocs={returnEmptyDoclist}
-            ContainingCollectionView={undefined}
-            ContainingCollectionDoc={undefined}
-            suppressSetHeight={true}
-            renderDepth={-1}
-        />;
+        return <>
+            {this.headerBarDocView}
+            <DocumentView key="main"
+                Document={this.mainContainer!}
+                DataDoc={undefined}
+                addDocument={undefined}
+                addDocTab={this.addDocTabFunc}
+                pinToPres={emptyFunction}
+                docViewPath={returnEmptyDoclist}
+                styleProvider={undefined}
+                rootSelected={returnTrue}
+                isContentActive={returnTrue}
+                removeDocument={undefined}
+                ScreenToLocalTransform={Transform.Identity}
+                PanelWidth={this.mainDocViewWidth}
+                PanelHeight={this.mainDocViewHeight}
+                focus={DocUtils.DefaultFocus}
+                whenChildContentsActiveChanged={emptyFunction}
+                bringToFront={emptyFunction}
+                docFilters={returnEmptyFilter}
+                docRangeFilters={returnEmptyFilter}
+                searchFilterDocs={returnEmptyDoclist}
+                ContainingCollectionView={undefined}
+                ContainingCollectionDoc={undefined}
+                suppressSetHeight={true}
+                renderDepth={-1}
+            /></>;
     }
 
     @computed get dockingContent() {
@@ -331,7 +370,7 @@ export class MainView extends React.Component {
             this.closeFlyout);
     }
 
-    sidebarScreenToLocal = () => new Transform(0, -this.topOfMainDoc, 1);
+    sidebarScreenToLocal = () => new Transform(0, -this.topOfSidebarDoc, 1);
     mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftScreenOffsetOfMainDocView, 0);
     addDocTabFunc = (doc: Doc, location: string): boolean => {
         const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":");
@@ -461,6 +500,16 @@ export class MainView extends React.Component {
         </>;
     }
 
+    @computed get headerBar() {
+        return !this.userDoc ? (null) :
+            <div className="mainView-dashboardArea" style={{
+                height: this.headerBarDocHeight(),
+                width: "100%",
+            }} >
+                {this.headerBarDocView}
+            </div>;
+    }
+
     @computed get mainDashboardArea() {
         return !this.userDoc ? (null) :
             <div className="mainView-dashboardArea" ref={r => {
@@ -620,7 +669,7 @@ export class MainView extends React.Component {
             <CaptureManager />
             <GroupManager />
             <GoogleAuthenticationManager />
-            <DocumentDecorations boundsLeft={this.leftScreenOffsetOfMainDocView} boundsTop={this.topOfMainDoc} PanelWidth={this._windowWidth} PanelHeight={this._windowHeight} />
+            <DocumentDecorations boundsLeft={this.leftScreenOffsetOfMainDocView} boundsTop={this.topOfHeaderBarDoc} PanelWidth={this._windowWidth} PanelHeight={this._windowHeight} />
             <ComponentDecorations boundsLeft={this.leftScreenOffsetOfMainDocView} boundsTop={this.topOfMainDocContent} />
             <TopBar />
             {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 7ac40fc8e..c44443264 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -158,12 +158,12 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                         (doc?._viewType === CollectionViewType.Pile || Doc.IsSystem(doc) ? (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY) : // system docs (seen in treeView) get a grayish background
                             doc.annotationOn ? "#00000015" : // faint interior for collections on PDFs, images, etc
                                 (doc?._isGroup ? undefined :
-                                    StrCast((props?.renderDepth || 0) > 0 ?
+                                    Cast((props?.renderDepth || 0) > 0 ?
                                         Doc.UserDoc().activeCollectionNestedBackground :
-                                        Doc.UserDoc().activeCollectionBackground ?? (darkScheme() ?
+                                        Doc.UserDoc().activeCollectionBackground, "string") ?? (darkScheme() ?
                                             Colors.BLACK :
                                             "linear-gradient(#065fff, #85c1f9)"))
-                                ));
+                        );
                     break;
                 //if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)";
                 default: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE); break;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index c322d9e16..96029a8e4 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -84,11 +84,11 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps>{
     }
 
     @action
-    toggleProperties = () => {
-        if (CurrentUserUtils.propertiesWidth > 0) {
-            CurrentUserUtils.propertiesWidth = 0;
+    toggleTopBar = () => {
+        if (CurrentUserUtils.headerBarHeight > 0) {
+            CurrentUserUtils.headerBarHeight = 0;
         } else {
-            CurrentUserUtils.propertiesWidth = 250;
+            CurrentUserUtils.headerBarHeight = 60;
         }
     }
 
@@ -137,14 +137,13 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps>{
 
     render() {
 
-        const propIcon = CurrentUserUtils.propertiesWidth > 0 ? "angle-double-right" : "angle-double-left";
-        const propTitle = CurrentUserUtils.propertiesWidth > 0 ? "Close Properties Panel" : "Open Properties Panel";
+        const propIcon = CurrentUserUtils.headerBarHeight > 0 ? "angle-double-up" : "angle-double-down";
+        const propTitle = CurrentUserUtils.headerBarHeight > 0 ? "Close Header Bar" : "Open Header Bar";
 
-        const prop = <Tooltip title={<div className="dash-tooltip">{propTitle}</div>} key="properties" placement="bottom">
+        const prop = <Tooltip title={<div className="dash-tooltip">{propTitle}</div>} key="topar" placement="bottom">
             <div className="collectionMenu-hardCodedButton"
                 style={{ backgroundColor: CurrentUserUtils.propertiesWidth > 0 ? Colors.MEDIUM_BLUE : undefined }}
-                key="properties"
-                onPointerDown={this.toggleProperties}>
+                onPointerDown={this.toggleTopBar}>
                 <FontAwesomeIcon icon={propIcon} size="lg" />
             </div>
         </Tooltip>;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 19485a0eb..4f92e305e 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -6,7 +6,7 @@ import { Doc, DocListCast } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { ObjectField } from '../../../fields/ObjectField';
 import { ScriptField } from '../../../fields/ScriptField';
-import { Cast, ScriptCast, StrCast } from '../../../fields/Types';
+import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
 import { returnEmptyString } from '../../../Utils';
 import { DocUtils } from '../../documents/Documents';
@@ -237,6 +237,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
 
     bodyPanelWidth = () => this.props.PanelWidth();
 
+    childHideResizeHandles = () => this.props.childHideResizeHandles?.() ?? BoolCast(this.Document.childHideResizeHandles);
+    childHideDecorationTitle = () => this.props.childHideDecorationTitle?.() ?? BoolCast(this.Document.childHideDecorationTitle);
     childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.rootDoc.childLayoutTemplate, Doc, null);
     @computed get childLayoutString() { return StrCast(this.rootDoc.childLayoutString); }
 
@@ -258,6 +260,8 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             ScreenToLocalTransform: this.screenToLocalTransform,
             childLayoutTemplate: this.childLayoutTemplate,
             childLayoutString: this.childLayoutString,
+            childHideResizeHandles: this.childHideResizeHandles,
+            childHideDecorationTitle: this.childHideDecorationTitle,
             CollectionView: this,
         };
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 43f31813c..0070d0b9d 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -104,6 +104,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 closeWrap.id = "lm_closeWrap";
                 closeWrap.onclick = (e: MouseEvent) => {
                     tab.header.parent.contentItem.remove();
+                    Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", tab.DashDoc);
                     Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", tab.DashDoc, undefined, true, true);
                 };
                 const docIcon = <FontAwesomeIcon onPointerDown={dragBtnDown} icon={iconType} />;
@@ -179,6 +180,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             tab.closeElement.off('click') //unbind the current click handler
                 .click(function () {
                     Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
+                    Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", doc);
                     Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", doc, undefined, true, true);
                     SelectionManager.DeselectAll();
                     UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab");
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index b6b59a2d6..66cc3613d 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -241,7 +241,9 @@ export class CollectionMulticolumnView extends CollectionSubView() {
         }
         return this.props.addDocTab(doc, where);
     }
-    isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+    isContentActive = () => this.props.isSelected() ? true : undefined;
+    isChildContentActive = () => this.props.isContentActive?.() === false ? false : undefined;
+    isChildDocumentActive = () => (this.props.childDocumentsActive?.() && this.props.isDocumentActive?.()) || this.isContentActive() || this.props.isContentActive();
     getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
         return <DocumentView
             Document={layout}
@@ -252,7 +254,11 @@ export class CollectionMulticolumnView extends CollectionSubView() {
             LayoutTemplateString={this.props.childLayoutString}
             freezeDimensions={this.props.childFreezeDimensions}
             renderDepth={this.props.renderDepth + 1}
-            isContentActive={emptyFunction}
+            isContentActive={this.isChildContentActive}
+            isDocumentActive={this.isChildDocumentActive}
+            hideResizeHandles={this.props.childHideResizeHandles?.()}
+            hideDecorationTitle={this.props.childHideDecorationTitle?.()}
+            fitContentsToDoc={this.props.fitContentsToDoc}
             PanelWidth={width}
             PanelHeight={height}
             rootSelected={this.rootSelected}
@@ -261,7 +267,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
             onDoubleClick={this.onChildDoubleClickHandler}
             suppressSetHeight={true}
             ScreenToLocalTransform={dxf}
-            isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
             focus={this.props.focus}
             docFilters={this.childDocFilters}
             docRangeFilters={this.childDocRangeFilters}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 4074f8d69..8218c49b5 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -241,7 +241,9 @@ export class CollectionMultirowView extends CollectionSubView() {
         }
         return this.props.addDocTab(doc, where);
     }
-    isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+    isContentActive = () => this.props.isSelected() ? true : undefined;
+    isChildContentActive = () => this.props.isContentActive?.() === false ? false : undefined;
+    isChildDocumentActive = () => (this.props.childDocumentsActive?.() && this.props.isDocumentActive?.()) || this.isContentActive() || this.props.isContentActive();
     getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
         return <DocumentView
             Document={layout}
@@ -259,10 +261,13 @@ export class CollectionMultirowView extends CollectionSubView() {
             onClick={this.onChildClickHandler}
             onDoubleClick={this.onChildDoubleClickHandler}
             ScreenToLocalTransform={dxf}
-            isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
+            isContentActive={this.isChildContentActive}
+            isDocumentActive={this.isChildDocumentActive}
+            hideResizeHandles={this.props.childHideResizeHandles?.()}
+            hideDecorationTitle={this.props.childHideDecorationTitle?.()}
+            fitContentsToDoc={this.props.fitContentsToDoc}
             focus={this.props.focus}
             docFilters={this.childDocFilters}
-            isContentActive={emptyFunction}
             docRangeFilters={this.childDocRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f7312e59c..54bb66f7f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -747,7 +747,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     const alias = Doc.MakeAlias(this.rootDoc);
                     alias.layout = FormattedTextBox.LayoutString("newfield");
                     alias.title = "newfield";
-                    alias._yMargin = 10;
                     alias._height = 35;
                     alias._width = 100;
                     alias.syncLayoutFieldWithTitle = true;
@@ -881,7 +880,10 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
         return <div className="documentView-contentsView"
             style={{
-                pointerEvents: this.props.pointerEvents?.() as any ?? this.rootDoc.layoutKey === "layout_icon" ? "none" : (this.rootDoc.type !== DocumentType.INK && ((this.props.contentPointerEvents as any) || (this.isContentActive())) ? "all" : "none"),
+                pointerEvents: this.props.pointerEvents?.() as any ?? this.rootDoc.layoutKey === "layout_icon" ? "none" :
+                    this.props.contentPointerEvents as any ? this.props.contentPointerEvents as any :
+                        this.rootDoc.type !== DocumentType.INK && this.isContentActive() ? "all" :
+                            "none",
                 height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
             }}>
             {!this._retryThumb || !this.thumbShown() ? (null) :
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 0e29461a6..822bc996b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -635,7 +635,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 }), icon: icon
             });
         });
-        !Doc.UserDoc().noviceMode && changeItems.push({ description: "FreeForm", event: () => DocUtils.makeCustomViewClicked(this.rootDoc, Docs.Create.FreeformDocument, "freeform"), icon: "eye" });
         const highlighting: ContextMenuProps[] = [];
         const noviceHighlighting = ["Audio Tags", "My Text", "Text from Others"];
         const expertHighlighting = [...noviceHighlighting, "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"];
-- 
cgit v1.2.3-70-g09d2


From d50b851d8e92797d214fc35cf243bfb29e970b36 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 23 May 2022 21:58:26 -0400
Subject: simplified dashboards by getting rid of confusing
 on-screen/off-screen tabs.  Now off screen tabs appear in the header bar
 which is not currently specific to a dashboard.

---
 src/client/documents/Documents.ts                  |  4 +-
 src/client/util/CurrentUserUtils.ts                | 33 +--------------
 src/client/views/MainView.tsx                      |  4 +-
 .../views/collections/CollectionDockingView.tsx    | 48 +++++++++++++++++-----
 src/client/views/collections/TabDocView.tsx        |  3 +-
 5 files changed, 43 insertions(+), 49 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 6fa467368..c3b6953b5 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -905,9 +905,7 @@ export namespace Docs {
         }
 
         export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
-            const tabs = TreeDocument(documents, { title: "On-Screen Tabs", childDontRegisterViews: true, freezeChildren: "remove|add", treeViewExpandedViewLock: true, treeViewExpandedView: "data", _fitWidth: true, system: true, isFolder: true });
-            const all = TreeDocument([], { title: "Off-Screen Tabs", childDontRegisterViews: true, freezeChildren: "add", treeViewExpandedViewLock: true, treeViewExpandedView: "data", system: true, isFolder: true });
-            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List([tabs, all]), { freezeChildren: "remove|add", ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
+            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { freezeChildren: "remove|add", ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
         }
 
         export function DirectoryImportDocument(options: DocumentOptions = {}) {
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 1e42b9073..9212d8ed9 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1172,22 +1172,8 @@ export class CurrentUserUtils {
         freeformDoc.context = dashboardDoc;
 
         // switching the tabs from the datadoc to the regular doc
-        const dashboardTabs = dashboardDoc[DataSym].data;
-        dashboardDoc[DataSym].data = new List<Doc>();
-        dashboardDoc.data = dashboardTabs;
-
-        // collating all docs on the dashboard to make a data-all field
-        const allDocs = new List<Doc>();
-        const allDocs2 = new List<Doc>(); // Array.from, spread, splice all cause so stack or acl issues for some reason
-        DocListCast(dashboardTabs).forEach(doc => {
-            const tabDocs = DocListCast(doc.data);
-            allDocs.push(...tabDocs);
-            allDocs2.push(...tabDocs);
-        });
-        dashboardDoc[DataSym]["data-all"] = allDocs;
-        dashboardDoc["data-all"] = allDocs2;
-        DocListCast(dashboardDoc.data).forEach(doc => doc.dashboard = dashboardDoc);
-        DocListCast(dashboardDoc.data)[1].data = ComputedField.MakeFunction(`dynamicOffScreenDocs(self.dashboard)`) as any;
+        const dashboardTabs = DocListCast(dashboardDoc[DataSym].data);
+        dashboardDoc.data = new List<Doc>(dashboardTabs);
 
         userDoc.activePresentation = presentation;
 
@@ -1258,21 +1244,6 @@ ScriptingGlobals.add(function addToDashboards(dashboard: Doc) {
 },
     "adds Dashboard to set of Dashboards");
 
-/**
- * Dynamically computes which docs should be rendered in the off-screen tabs tree of a dashboard.
- */
-ScriptingGlobals.add(function dynamicOffScreenDocs(dashboard: Doc) {
-    if (dashboard[DataSym] instanceof Doc) {
-        const allDocs = DocListCast(dashboard["data-all"]);
-        const onScreenTab = DocListCast(dashboard.data)[0];
-        const onScreenDocs = DocListCast(onScreenTab.data);
-        return new List<Doc>(allDocs.reduce((result: Doc[], doc) => {
-            !onScreenDocs.includes(doc) && !onScreenDocs.includes(doc.aliasOf as Doc) && (result.push(doc));
-            return result;
-        }, []));
-    }
-    return [];
-});
 ScriptingGlobals.add(function selectedDocumentType(docType?: DocumentType, colType?: CollectionViewType, checkParent?: boolean) {
     let selected = SelectionManager.Docs().length ? SelectionManager.Docs()[0] : undefined;
     if (selected && checkParent) {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 69e394790..f3dc2cf85 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -92,7 +92,7 @@ export class MainView extends React.Component {
     @computed private get headerBarDoc() { return this.userDoc ? CurrentUserUtils.MyHeaderBarDoc : CurrentUserUtils.MyHeaderBarDoc; }
     @computed public get mainFreeform(): Opt<Doc> { return (docs => (docs?.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
 
-    headerBarDocWidth = () => this._dashUIWidth;
+    headerBarDocWidth = () => this.mainDocViewWidth();
     headerBarDocHeight = () => CurrentUserUtils.headerBarHeight ?? 0;
     topMenuHeight = () => 35;
     topMenuWidth = returnZero; // value is ignored ...
@@ -102,7 +102,7 @@ export class MainView extends React.Component {
     leftMenuFlyoutHeight = () => this._dashUIHeight;
     propertiesWidth = () => Math.max(0, Math.min(this._dashUIWidth - 50, CurrentUserUtils.propertiesWidth || 0));
     propertiesHeight = () => this._dashUIHeight;
-    mainDocViewWidth = () => this._dashUIWidth - this.propertiesWidth() - this.leftMenuWidth();
+    mainDocViewWidth = () => this._dashUIWidth - this.propertiesWidth() - this.leftMenuWidth() - this.leftMenuFlyoutWidth();
     mainDocViewHeight = () => this._dashUIHeight - this.headerBarDocHeight();
 
     componentDidMount() {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 30f60bba6..1d65256a6 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -81,6 +81,8 @@ export class CollectionDockingView extends CollectionSubView() {
 
     tabItemDropped = () => DragManager.CompleteWindowDrag?.(false);
     tabDragStart = (proxy: any, finishDrag?: (aborted: boolean) => void) => {
+        const dashDoc = proxy?._contentItem?.tab?.DashDoc as Doc;
+        dashDoc && (DragManager.DocDragData = new DragManager.DocumentDragData([proxy._contentItem.tab.DashDoc]));
         DragManager.CompleteWindowDrag = (aborted: boolean) => {
             if (aborted) {
                 proxy._dragListener.AbortDrag();
@@ -90,6 +92,8 @@ export class CollectionDockingView extends CollectionSubView() {
                     this.setupGoldenLayout(); // restore golden layout to where it was before the drag (this is a no-op when using StartOtherDrag because the proxy dragged item was never in the golden layout)
                 }
                 DragManager.CompleteWindowDrag = undefined;
+            } else {
+                DragManager.DocDragData?.droppedDocuments.forEach(doc => this.addToTabDocList(doc));
             }
             finishDrag?.(aborted);
         };
@@ -100,12 +104,43 @@ export class CollectionDockingView extends CollectionSubView() {
         this.stateChanged();
     }
 
+    addToTabDocList = (document: Doc) => {
+        const instance = CollectionDockingView.Instance;
+        if (instance) {
+            const docList = DocListCast(instance.props.Document[DataSym].data);
+            // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases
+            !docList.includes(document) && !docList.includes(document.aliasOf as Doc) && Doc.AddDocToList(instance.props.Document[DataSym], "data", document);
+            // adds an alias of the doc to the data-all field of the layoutdocs of the aliases
+            DocListCast(instance.props.Document.aliases).forEach(alias => {
+                const aliasDocList = DocListCast(alias.data);
+                // if aliasDocList contains the alias, don't do anything
+                // otherwise add the original or an alias depending on whether the doc you're looking at is the current doc or a different alias
+                !DocListCast(document.aliases).some(a => aliasDocList.includes(a)) && Doc.AddDocToList(alias, "data", document);//alias !== instance.props.Document ? Doc.MakeAlias(document) : document);
+            });
+        }
+    }
+    removeFromTabDocList = (document: Doc) => {
+        const instance = CollectionDockingView.Instance;
+        if (instance) {
+            // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases
+            Doc.RemoveDocFromList(instance.props.Document[DataSym], "data", document);
+            // adds an alias of the doc to the data-all field of the layoutdocs of the aliases
+            DocListCast(instance.props.Document.aliases).forEach(alias => {
+                // if aliasDocList contains the alias, don't do anything
+                // otherwise add the original or an alias depending on whether the doc you're looking at is the current doc or a different alias
+                Doc.RemoveDocFromList(alias, "data", document);//alias !== instance.props.Document ? Doc.MakeAlias(document) : document);
+            });
+            document.type !== DocumentType.KVP && Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", document);
+        }
+    }
+
     @undoBatch
     public static CloseSplit(document: Opt<Doc>, panelName?: string): boolean {
         const tab = Array.from(CollectionDockingView.Instance.tabMap.keys()).find((tab) => panelName ? tab.contentItem.config.props.panelName === panelName : tab.DashDoc === document);
         if (tab) {
             const j = tab.header.parent.contentItems.indexOf(tab.contentItem);
             if (j !== -1) {
+                CollectionDockingView.Instance.removeFromTabDocList(tab.dashDoc as Doc);
                 tab.header.parent.contentItems[j].remove();
                 return CollectionDockingView.Instance.layoutChanged();
             }
@@ -185,16 +220,7 @@ export class CollectionDockingView extends CollectionSubView() {
         const instance = CollectionDockingView.Instance;
         if (!instance) return false;
         else {
-            const docList = DocListCast(instance.props.Document[DataSym]["data-all"]);
-            // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases
-            !docList.includes(document) && !docList.includes(document.aliasOf as Doc) && Doc.AddDocToList(instance.props.Document[DataSym], "data-all", document);
-            // adds an alias of the doc to the data-all field of the layoutdocs of the aliases
-            DocListCast(instance.props.Document[DataSym].aliases).forEach(alias => {
-                const aliasDocList = DocListCast(alias["data-all"]);
-                // if aliasDocList contains the alias, don't do anything
-                // otherwise add the original or an alias depending on whether the doc you're looking at is the current doc or a different alias
-                !DocListCast(document.aliases).some(a => aliasDocList.includes(a)) && Doc.AddDocToList(alias, "data-all", document);//alias !== instance.props.Document ? Doc.MakeAlias(document) : document);
-            });
+            instance.addToTabDocList(document);
         }
         const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
 
@@ -477,7 +503,7 @@ export class CollectionDockingView extends CollectionSubView() {
                 //if (confirm('really close this?')) {
                 if (!stack.parent.parent.isRoot || stack.parent.contentItems.length > 1) {
                     stack.remove();
-                    stack.contentItems.forEach((contentItem: any) => Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", contentItem.tab.DashDoc, undefined, true, true));
+                    stack.contentItems.forEach((contentItem: any) => CollectionDockingView.Instance.removeFromTabDocList(contentItem.tab.DashDoc));
                 } else {
                     alert('cant delete the last stack');
                 }
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 0070d0b9d..88d14fdfe 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -180,8 +180,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             tab.closeElement.off('click') //unbind the current click handler
                 .click(function () {
                     Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
-                    Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", doc);
-                    Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", doc, undefined, true, true);
+                    CollectionDockingView.Instance?.removeFromTabDocList(doc);
                     SelectionManager.DeselectAll();
                     UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab");
                 });
-- 
cgit v1.2.3-70-g09d2


From 097998abda6857a498f6cfc8a7214a18b09b8451 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 24 May 2022 13:10:33 -0400
Subject: fixed TabDocView's screenToLocal xf when headerBar opens/closes. 
 changed webBox to update thumbnails when native dims change.  cleaned up
 content dragging/activation for multiRow/col for headerBar

---
 src/client/views/MainView.tsx                      |  4 ++--
 src/client/views/collections/TabDocView.tsx        |  3 +++
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../CollectionMulticolumnView.tsx                  |  9 ++++----
 .../CollectionMultirowView.tsx                     | 11 +++++-----
 src/client/views/nodes/WebBox.tsx                  | 24 +++++++++++++++++-----
 6 files changed, 34 insertions(+), 19 deletions(-)

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

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 4b7b9fc23..183efc944 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -283,7 +283,6 @@ export class MainView extends React.Component {
     }
     headerBarScreenXf = () => new Transform(-this.leftScreenOffsetOfMainDocView - this.leftMenuFlyoutWidth(), -this.headerBarDocHeight(), 1);
 
-    headerContentActive = () => SnappingManager.GetIsDragging() && DocListCast(CurrentUserUtils.MyHeaderBarDoc.data).length ? false : true;
     @computed get headerBarDocView() {
         return <div style={{ height: this.headerBarDocHeight() }}>
             <DocumentView key="headerBarDoc"
@@ -297,7 +296,8 @@ export class MainView extends React.Component {
                 rootSelected={returnTrue}
                 removeDocument={returnFalse}
                 fitContentsToDoc={returnTrue}
-                isContentActive={this.headerContentActive}
+                isDocumentActive={returnTrue} // headerBar is always documentActive (ie, the docView gets pointer events)
+                isContentActive={returnTrue} // headerBar is awlays contentActive which means its items are always documentActive
                 ScreenToLocalTransform={this.headerBarScreenXf}
                 childHideResizeHandles={returnTrue}
                 hideResizeHandles={true}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 88d14fdfe..a2ba504dc 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -337,7 +337,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         }
     }
     active = () => this._isActive;
+    @observable _forceInvalidateScreenToLocal = 0;
     ScreenToLocalTransform = () => {
+        this._forceInvalidateScreenToLocal;
         const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont?.children?.[0] as HTMLElement);
         return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY);
     }
@@ -408,6 +410,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 if (this._mainCont = ref) {
                     (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
                     DocServer.GetRefField(this.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document)));
+                    new _global.ResizeObserver(action((entries: any) => this._forceInvalidateScreenToLocal++)).observe(ref);
                 }
             }} >
                 {this.docView}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3b32cf57d..dcff32d04 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1217,8 +1217,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             docFilters={this.childDocFilters}
             docRangeFilters={this.childDocRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
+            isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
             isContentActive={emptyFunction}
-            isDocumentActive={this.props.childDocumentsActive ? this.props.isDocumentActive : this.isContentActive}
             focus={this.focusDocument}
             addDocTab={this.addDocTab}
             addDocument={this.props.addDocument}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 345ac7854..e2dfb25e2 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -4,7 +4,7 @@ import * as React from "react";
 import { Doc, DocListCast } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnFalse, returnTrue } from '../../../../Utils';
+import { returnFalse } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
@@ -241,9 +241,8 @@ export class CollectionMulticolumnView extends CollectionSubView() {
         }
         return this.props.addDocTab(doc, where);
     }
-    isContentActive = () => this.props.isSelected() ? true : undefined;
-    isChildContentActive = () => this.props.isContentActive?.() === false ? false : undefined;
-    isChildDocumentActive = () => (this.props.childDocumentsActive?.() && this.props.isDocumentActive?.()) || this.isContentActive() || this.props.isContentActive();
+    isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+    isChildContentActive = () => this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
     getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
         return <DocumentView
             Document={layout}
@@ -255,7 +254,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
             freezeDimensions={this.props.childFreezeDimensions}
             renderDepth={this.props.renderDepth + 1}
             isContentActive={this.isChildContentActive}
-            isDocumentActive={this.isChildDocumentActive}
+            isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
             hideResizeHandles={this.props.childHideResizeHandles?.()}
             hideDecorationTitle={this.props.childHideDecorationTitle?.()}
             fitContentsToDoc={this.props.fitContentsToDoc}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 8218c49b5..3010e36aa 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -4,7 +4,7 @@ import * as React from "react";
 import { Doc, DocListCast } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
-import { emptyFunction, returnFalse } from '../../../../Utils';
+import { returnFalse } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
@@ -241,10 +241,9 @@ export class CollectionMultirowView extends CollectionSubView() {
         }
         return this.props.addDocTab(doc, where);
     }
-    isContentActive = () => this.props.isSelected() ? true : undefined;
-    isChildContentActive = () => this.props.isContentActive?.() === false ? false : undefined;
-    isChildDocumentActive = () => (this.props.childDocumentsActive?.() && this.props.isDocumentActive?.()) || this.isContentActive() || this.props.isContentActive();
-    getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
+    isContentActive = () => this.props.isSelected() || this.props.isContentActive();
+    isChildContentActive = () => this.props.isSelected() || this.props.isAnyChildContentActive() ? true : false;
+    getDisplayDoc = (layout: Doc, dxf: () => Transform, width: () => number, height: () => number) => {
         return <DocumentView
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
@@ -262,7 +261,7 @@ export class CollectionMultirowView extends CollectionSubView() {
             onDoubleClick={this.onChildDoubleClickHandler}
             ScreenToLocalTransform={dxf}
             isContentActive={this.isChildContentActive}
-            isDocumentActive={this.isChildDocumentActive}
+            isDocumentActive={this.props.childDocumentsActive?.() ? this.props.isDocumentActive : this.isContentActive}
             hideResizeHandles={this.props.childHideResizeHandles?.()}
             hideDecorationTitle={this.props.childHideDecorationTitle?.()}
             fitContentsToDoc={this.props.fitContentsToDoc}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 2112c1d44..dbbcdc9de 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -75,7 +75,12 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @computed get allAnnotations() { return DocListCast(this.dataDoc[this.annotationKey]); }
     @computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); }
     @computed get webField() { return Cast(this.dataDoc[this.props.fieldKey], WebField)?.url; }
-    @computed get webThumb() { return this.props.thumbShown?.() && ImageCast(this.layoutDoc["thumb-frozen"], ImageCast(this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop ? this.layoutDoc.thumb : undefined))?.url; }
+    @computed get webThumb() {
+        return this.props.thumbShown?.() &&
+            ImageCast(this.layoutDoc["thumb-frozen"],
+                ImageCast(this.layoutDoc.thumbScrollTop === this.layoutDoc._scrollTop && this.layoutDoc.thumbNativeWidth === NumCast(this.layoutDoc.nativeWidth) &&
+                    this.layoutDoc.thumbNativeHeight === NumCast(this.layoutDoc.nativeHeight) ? this.layoutDoc.thumb : undefined))?.url;
+    }
 
     constructor(props: any) {
         super(props);
@@ -114,20 +119,21 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     updateThumb = async () => {
         const imageBitmap = ImageCast(this.layoutDoc["thumb-frozen"])?.url.href;
         const scrollTop = NumCast(this.layoutDoc._scrollTop);
-        if (!this.lockout && this._iframe && !imageBitmap && scrollTop !== this.layoutDoc.thumbScrollTop) {
+        const nativeWidth = NumCast(this.layoutDoc.nativeWidth);
+        const nativeHeight = nativeWidth * this.props.PanelHeight() / this.props.PanelWidth();
+        if (!this.lockout && this._iframe && !imageBitmap && (scrollTop !== this.layoutDoc.thumbScrollTop || nativeWidth !== this.layoutDoc.thumbNativeWidth || nativeHeight !== this.layoutDoc.thumbNativeHeight)) {
             var htmlString = this._iframe.contentDocument && new XMLSerializer().serializeToString(this._iframe.contentDocument);
             if (!htmlString) {
                 htmlString = await (await fetch(Utils.CorsProxy(this.webField!.href))).text();
             }
             this.layoutDoc.thumb = undefined;
             this.lockout = true; // lock to prevent multiple thumb updates.
-            const nativeWidth = NumCast(this.layoutDoc.nativeWidth);
             CreateImage(
                 this._webUrl.endsWith("/") ? this._webUrl.substring(0, this._webUrl.length - 1) : this._webUrl,
                 this._iframe.contentDocument?.styleSheets ?? [],
                 htmlString,
                 nativeWidth,
-                nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(),
+                nativeHeight,
                 scrollTop
             ).then
                 ((data_url: any) => {
@@ -136,6 +142,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                             this.lockout = false;
                             this.layoutDoc.thumb = new ImageField(returnedfilename);
                             this.layoutDoc.thumbScrollTop = scrollTop;
+                            this.layoutDoc.thumbNativeWidth = nativeWidth;
+                            this.layoutDoc.thumbNativeHeight = nativeHeight;
                         }), 500));
                 })
                 .catch(function (error: any) {
@@ -387,6 +395,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()))) {
                 this.layoutDoc.thumb = undefined;
                 this.layoutDoc.thumbScrollTop = undefined;
+                this.layoutDoc.thumbNativeWidth = undefined;
+                this.layoutDoc.thumbNativeHeight = undefined;
                 this.layoutDoc.scrollTop = this._outerRef.current.scrollTop = newScrollTop;
             } else if (this._outerRef.current) this._outerRef.current.scrollTop = newScrollTop;
         }), timeout);
@@ -464,6 +474,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
                 if (this._webPageHasBeenRendered) {
                     this.layoutDoc.thumb = undefined;
                     this.layoutDoc.thumbScrollTop = undefined;
+                    this.layoutDoc.thumbNativeWidth = undefined;
+                    this.layoutDoc.thumbNativeHeight = undefined;
                 }
                 future && (future.length = 0);
             }
@@ -596,7 +608,9 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         }
         setTimeout(action(() => {
             this._scrollHeight = Math.max(this._scrollHeight, this._iframe && this._iframe.contentDocument && this._iframe.contentDocument.body ? this._iframe.contentDocument.body.scrollHeight : 0);
-            if (this._initialScroll === undefined && !this._webPageHasBeenRendered) this.setScrollPos(NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop)));
+            if (this._initialScroll === undefined && !this._webPageHasBeenRendered) {
+                this.setScrollPos(NumCast(this.layoutDoc.thumbScrollTop, NumCast(this.layoutDoc.scrollTop)));
+            }
             this._webPageHasBeenRendered = true;
         }));
         return view;
-- 
cgit v1.2.3-70-g09d2


From ddd38f923180efd0dc4f53a1c3caad4a1f9ed26f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 26 May 2022 17:40:54 -0400
Subject: removed more code relating to old version of dashboards with on and
 off screen tab lists.  fixed schema headers to not iconify when typing Enter
 in header field name.

---
 .../views/collections/CollectionDockingView.tsx    | 47 +---------------------
 src/client/views/collections/TabDocView.tsx        |  1 -
 .../collectionSchema/CollectionSchemaHeaders.tsx   |  5 ++-
 3 files changed, 6 insertions(+), 47 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index c60434d95..509da18cb 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -92,8 +92,6 @@ export class CollectionDockingView extends CollectionSubView() {
                     this.setupGoldenLayout(); // restore golden layout to where it was before the drag (this is a no-op when using StartOtherDrag because the proxy dragged item was never in the golden layout)
                 }
                 DragManager.CompleteWindowDrag = undefined;
-            } else {
-                DragManager.DocDragData?.droppedDocuments.forEach(doc => this.addToTabDocList(doc));
             }
             finishDrag?.(aborted);
         };
@@ -104,30 +102,12 @@ export class CollectionDockingView extends CollectionSubView() {
         this.stateChanged();
     }
 
-    addToTabDocList = (document: Doc) => {
-        const instance = CollectionDockingView.Instance;
-        if (instance) {
-            const docList = DocListCast(instance.props.Document[DataSym].data);
-            // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases
-            !docList.includes(document) && !docList.includes(document.aliasOf as Doc) && Doc.AddDocToList(instance.props.Document, "data", document);
-        }
-    }
-    removeFromTabDocList = (document: Doc) => {
-        const instance = CollectionDockingView.Instance;
-        if (instance) {
-            // adds the doc of the newly created tab to the data-all field if it doesn't already include that doc or one of its aliases
-            Doc.RemoveDocFromList(instance.props.Document, "data", document);
-            document.type !== DocumentType.KVP && Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", document);
-        }
-    }
-
     @undoBatch
     public static CloseSplit(document: Opt<Doc>, panelName?: string): boolean {
         const tab = Array.from(CollectionDockingView.Instance.tabMap.keys()).find((tab) => panelName ? tab.contentItem.config.props.panelName === panelName : tab.DashDoc === document);
         if (tab) {
             const j = tab.header.parent.contentItems.indexOf(tab.contentItem);
             if (j !== -1) {
-                CollectionDockingView.Instance.removeFromTabDocList(tab.dashDoc as Doc);
                 tab.header.parent.contentItems[j].remove();
                 return CollectionDockingView.Instance.layoutChanged();
             }
@@ -206,9 +186,6 @@ export class CollectionDockingView extends CollectionSubView() {
         }
         const instance = CollectionDockingView.Instance;
         if (!instance) return false;
-        else {
-            instance.addToTabDocList(document);
-        }
         const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
 
         if (!pullSide && stack) {
@@ -434,29 +411,10 @@ export class CollectionDockingView extends CollectionSubView() {
         const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g);
         const docids = matches?.map(m => m.replace("\"documentId\":\"", "").replace("\"", ""));
         const docs = !docids ? [] : docids.map(id => DocServer.GetCachedRefField(id)).filter(f => f).map(f => f as Doc);
-        const changesMade = this.props.Document.dockingConfig !== json;
+        const changesMade = this.props.Document.dockcingConfig !== json;
         if (changesMade && !this._flush) {
             this.props.Document.dockingConfig = json;
-            setTimeout(async () => {
-                const sublists = await DocListCastAsync(this.props.Document[this.props.fieldKey]);
-                const tabs = sublists && Cast(sublists[0], Doc, null);
-                // const other = sublists && Cast(sublists[1], Doc, null);
-                const tabdocs = await DocListCastAsync(tabs?.data);
-                // const otherdocs = await DocListCastAsync(other?.data);
-                if (tabs) {
-                    tabs.data = new List<Doc>(docs);
-                    // DocListCast(tabs.aliases).forEach(tab => tab !== tabs && (tab.data = new List<Doc>(docs)));
-                }
-                // const otherSet = new Set<Doc>();
-                // otherdocs?.filter(doc => !docs.includes(doc)).forEach(doc => otherSet.add(doc));
-                // tabdocs?.filter(doc => !docs.includes(doc) && doc.type !== DocumentType.KVP).forEach(doc => otherSet.add(doc));
-                // const vals = Array.from(otherSet.values()).filter(val => val instanceof Doc).map(d => d).filter(d => d.type !== DocumentType.KVP);
-                // this.props.Document[DataSym][this.props.fieldKey + "-all"] = new List<Doc>([...docs, ...vals]);
-                // if (other) {
-                //     other.data = new List<Doc>(vals);
-                //     // DocListCast(other.aliases).forEach(tab => tab !== other && (tab.data = new List<Doc>(vals)));
-                // }
-            }, 0);
+            this.props.Document.data = new List<Doc>(docs);
         }
         return changesMade;
     }
@@ -490,7 +448,6 @@ export class CollectionDockingView extends CollectionSubView() {
                 //if (confirm('really close this?')) {
                 if (!stack.parent.parent.isRoot || stack.parent.contentItems.length > 1) {
                     stack.remove();
-                    stack.contentItems.forEach((contentItem: any) => CollectionDockingView.Instance.removeFromTabDocList(contentItem.tab.DashDoc));
                 } else {
                     alert('cant delete the last stack');
                 }
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index a2ba504dc..2b78b20ea 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -180,7 +180,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             tab.closeElement.off('click') //unbind the current click handler
                 .click(function () {
                     Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
-                    CollectionDockingView.Instance?.removeFromTabDocList(doc);
                     SelectionManager.DeselectAll();
                     UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab");
                 });
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx
index dc35b5749..0875c80b3 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaHeaders.tsx
@@ -278,6 +278,7 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
     @undoBatch
     onKeyDown = (e: React.KeyboardEvent): void => {
         if (e.key === "Enter") {
+            e.stopPropagation();
             if (this._searchTerm.includes(":")) {
                 const colpos = this._searchTerm.indexOf(":");
                 const temp = this._searchTerm.slice(colpos + 1, this._searchTerm.length);
@@ -490,7 +491,9 @@ export class KeysDropdown extends React.Component<KeysDropdownProps> {
 
                 <div className="keys-dropdown" style={{ zIndex: 1, width: this.props.width, maxWidth: this.props.width }}>
                     <input className="keys-search" style={{ width: "100%" }}
-                        ref={this._inputRef} type="text" value={this._searchTerm} placeholder="Column key" onKeyDown={this.onKeyDown}
+                        ref={this._inputRef} type="text"
+                        value={this._searchTerm} placeholder="Column key"
+                        onKeyDown={this.onKeyDown}
                         onChange={e => this.onChange(e.target.value)}
                         onClick={(e) => { e.stopPropagation(); this._inputRef.current?.focus(); }}
                         onFocus={this.onFocus} ></input>
-- 
cgit v1.2.3-70-g09d2


From 58114c03252463b7386d16fc2aef61c361038bfa Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 2 Jun 2022 15:44:23 -0400
Subject: fixed previously introduced bug where pin doc added pres to first tab
 collection.  Highlight pres targets when following.  fixed videoBox to play
 regions properly.  adjusted labelBox for stackedTimeline views.  fixed
 stacked timelines to not stop keyboard events which was preventing text notes
 from being created on video boxes.

---
 src/Utils.ts                                         |  2 +-
 .../views/collections/CollectionStackedTimeline.tsx  |  9 +++++++--
 src/client/views/collections/TabDocView.tsx          |  4 +---
 src/client/views/nodes/LabelBox.tsx                  | 20 +++++++++++---------
 src/client/views/nodes/VideoBox.tsx                  |  2 ++
 src/client/views/nodes/trails/PresBox.tsx            |  1 +
 src/fields/Doc.ts                                    |  4 ++--
 src/fields/List.ts                                   |  1 +
 8 files changed, 26 insertions(+), 17 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index dbae0aa8c..e6aa0ad8b 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -209,7 +209,7 @@ export namespace Utils {
         if (scrollTop + contextHgt < Math.min(scrollHeight, targetY + minSpacing + targetHgt)) {
             return Math.ceil(targetY + minSpacing + targetHgt - contextHgt);
         }
-        if (scrollTop > Math.max(0, targetY - minSpacing - targetHgt)) {
+        if (scrollTop >= Math.max(0, targetY - minSpacing - targetHgt)) {
             return Math.max(0, Math.floor(targetY - minSpacing - targetHgt));
         }
     }
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 02b2248fb..5a1cc4ded 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -22,6 +22,7 @@ import {
     returnOne, returnTrue, setupMoveUpEvents, smoothScrollHorizontal, StopEvent
 } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
 import { DocumentManager } from "../../util/DocumentManager";
 import { DragManager } from "../../util/DragManager";
 import { LinkManager } from "../../util/LinkManager";
@@ -182,7 +183,6 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
         ) {
             // if shift pressed scrub 1 second otherwise 1/10th
             const jump = e.shiftKey ? 1 : 0.1;
-            e.stopPropagation();
             switch (e.key) {
                 case " ":
                     if (!CollectionStackedTimeline.SelectingRegion) {
@@ -202,18 +202,22 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                         this._markerEnd = undefined;
                         CollectionStackedTimeline.SelectingRegion = undefined;
                     }
+                    e.stopPropagation();
                     break;
                 case "Escape":
                     // abandons current trim
                     this._trimStart = this.clipStart;
                     this._trimStart = this.clipEnd;
                     this._trimming = TrimScope.None;
+                    e.stopPropagation();
                     break;
                 case "ArrowLeft":
                     this.props.setTime(Math.min(Math.max(this.clipStart, this.currentTime - jump), this.clipEnd));
+                    e.stopPropagation();
                     break;
                 case "ArrowRight":
                     this.props.setTime(Math.min(Math.max(this.clipStart, this.currentTime + jump), this.clipEnd));
+                    e.stopPropagation();
                     break;
             }
         }
@@ -788,6 +792,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
 
     // updates marker document title to reflect correct timecodes
     computeTitle = () => {
+        if (this.props.mark.type !== DocumentType.LABEL) return undefined;
         const start = Math.max(NumCast(this.props.mark[this.props.startTag]), this.props.trimStart) - this.props.trimStart;
         const end = Math.min(NumCast(this.props.mark[this.props.endTag]), this.props.trimEnd) - this.props.trimStart;
         return `#${formatTime(start)}-${formatTime(end)}`;
@@ -921,7 +926,7 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     DataDoc={undefined}
                     renderDepth={this.props.renderDepth + 1}
                     LayoutTemplate={undefined}
-                    LayoutTemplateString={LabelBox.LayoutStringWithTitle(LabelBox, "data", this.computeTitle())}
+                    LayoutTemplateString={LabelBox.LayoutStringWithTitle("data", this.computeTitle())}
                     isDocumentActive={this.props.isDocumentActive}
                     PanelWidth={width}
                     PanelHeight={height}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 2b78b20ea..be68e1001 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -236,9 +236,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
             const dview = CollectionDockingView.Instance.props.Document;
             const fieldKey = CollectionDockingView.Instance.props.fieldKey;
-            const sublists = DocListCast(dview[fieldKey]);
-            const tabs = Cast(sublists[0], Doc, null);
-            const tabdocs = await DocListCastAsync(tabs?.data);
+            const tabdocs = await DocListCastAsync(dview[fieldKey]);
             runInAction(() => {
                 if (!pinProps?.hidePresBox && !tabdocs?.includes(curPres)) {
                     tabdocs?.push(curPres);  // bcz: Argh! this is annoying.  if multiple documents are pinned, this will get called multiple times before the presentation view is drawn.  Thus it won't be in the tabdocs list and it will get created multple times.  so need to explicilty add the presbox to the list of open tabs
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index d0d61fd79..b0b050cea 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -23,8 +23,8 @@ export interface LabelBoxProps {
 @observer
 export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxProps)>() {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LabelBox, fieldKey); }
-    public static LayoutStringWithTitle(fieldType: { name: string }, fieldStr: string, label: string) {
-        return `<${fieldType.name} fieldKey={'${fieldStr}'} label={'${label}'} {...props} />`;  //e.g., "<ImageBox {...props} fieldKey={"data} />"
+    public static LayoutStringWithTitle(fieldStr: string, label?: string) {
+        return !label ? LabelBox.LayoutString(fieldStr) : `<LabelBox fieldKey={'${fieldStr}'} label={'${label}'} {...props} />`;  //e.g., "<ImageBox {...props} fieldKey={"data} />"
     }
     private dropDisposer?: DragManager.DragDropDisposer;
     private _timeout: any;
@@ -79,17 +79,18 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
     @computed get hoverColor() { return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : "unset"; }
 
     fitTextToBox = (r: any): any => {
+        const singleLine = BoolCast(this.rootDoc._singleLine, true);
         const params = {
             rotateText: null,
             fontSizeFactor: 1,
-            minimumFontSize: NumCast(this.rootDoc._minFontSize, 2),
+            minimumFontSize: NumCast(this.rootDoc._minFontSize, 8),
             maximumFontSize: NumCast(this.rootDoc._maxFontSize, 1000),
             limitingDimension: "both",
             horizontalAlign: "center",
             verticalAlign: "center",
             textAlign: "center",
-            singleLine: BoolCast(this.rootDoc._singleLine),
-            whiteSpace: this.rootDoc._singleLine ? "nowrap" : "pre-wrap"
+            singleLine,
+            whiteSpace: singleLine ? "nowrap" : "pre-wrap"
         };
         this._timeout = undefined;
         if (!r) return params;
@@ -99,15 +100,16 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
         parentStyle.display = "";
         parentStyle.alignItems = "";
         r.setAttribute("style", "");
-        r.style.width = this.rootDoc._singleLine ? "" : "100%";
+        r.style.width = singleLine ? "" : "100%";
 
         r.style.textOverflow = "ellipsis";
         r.style.overflow = "hidden";
         BigText(r, params);
+        return params;
     }
     // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")")
     render() {
-        this.fitTextToBox(null);// this causes mobx to trigger re-render when data changes
+        const boxParams = this.fitTextToBox(null);// this causes mobx to trigger re-render when data changes
         const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []);
         const missingParams = params?.filter(p => !this.paramsDoc[p]);
         params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ...
@@ -130,9 +132,9 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro
                     paddingBottom: NumCast(this.rootDoc._yPadding),
                     width: this.props.PanelWidth(),
                     height: this.props.PanelHeight(),
-                    whiteSpace: this.rootDoc._singleLine ? "pre" : "pre-wrap"
+                    whiteSpace: boxParams.singleLine ? "pre" : "pre-wrap"
                 }} >
-                    <span style={{ width: this.layoutDoc._singleLine ? "" : "100%" }} ref={action((r: any) => this.fitTextToBox(r))}>
+                    <span style={{ width: boxParams.singleLine ? "" : "100%" }} ref={action((r: any) => this.fitTextToBox(r))}>
                         {label.startsWith("#") ? (null) : label.replace(/([^a-zA-Z])/g, "$1\u200b")}
                     </span>
                 </div>
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index c350e3139..ac848fc2a 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -147,6 +147,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
 
     // plays video
     @action public Play = (update: boolean = true) => {
+        if (this._playRegionTimer) return;
         this._playing = true;
         const eleTime = this.player?.currentTime || 0;
         if (this.timeline) {
@@ -558,6 +559,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                         // removes from currently playing if playback has reached end of range marker
                         else this.removeCurrentlyPlaying();
                         this.Pause();
+                        this._playRegionTimer = undefined;
                     }, playRegionDuration * 1000);
             } else {
                 this.Pause();
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 9641b403f..077db9077 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -297,6 +297,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 this.startTempMedia(targetDoc, activeItem);
             }
             if (targetDoc) {
+                Doc.linkFollowHighlight((targetDoc.annotationOn instanceof Doc) ? [targetDoc, targetDoc.annotationOn] : targetDoc);
                 targetDoc && runInAction(() => {
                     if (activeItem.presMovement === PresMovement.Jump) targetDoc.focusSpeed = 0;
                     else targetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500;
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index b0a45091e..6abc27b23 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -1073,9 +1073,9 @@ export namespace Doc {
     }
 
     let _lastDate = 0;
-    export function linkFollowHighlight(destDoc: Doc, dataAndDisplayDocs = true) {
+    export function linkFollowHighlight(destDoc: Doc | Doc[], dataAndDisplayDocs = true) {
         linkFollowUnhighlight();
-        Doc.HighlightDoc(destDoc, dataAndDisplayDocs);
+        (destDoc instanceof Doc ? [destDoc] : destDoc).forEach(doc => Doc.HighlightDoc(doc, dataAndDisplayDocs));
         document.removeEventListener("pointerdown", linkFollowUnhighlight);
         document.addEventListener("pointerdown", linkFollowUnhighlight);
         const lastDate = _lastDate = Date.now();
diff --git a/src/fields/List.ts b/src/fields/List.ts
index 60bf442d4..b15548327 100644
--- a/src/fields/List.ts
+++ b/src/fields/List.ts
@@ -32,6 +32,7 @@ const listHandlers: any = {
     },
     push: action(function (this: any, ...items: any[]) {
         items = items.map(toObjectField);
+
         const list = this[Self];
         const length = list.__fields.length;
         for (let i = 0; i < items.length; i++) {
-- 
cgit v1.2.3-70-g09d2


From ba7824a91da113cc813c58b678719092c96d79a2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 3 Jun 2022 16:02:24 -0400
Subject: fixed opening closed tabs from Files sidebar to re-use best Alias
 before making a new alias.

---
 src/.DS_Store                                      | Bin 8196 -> 8196 bytes
 src/client/util/CurrentUserUtils.ts                |   2 +-
 src/client/util/DocumentManager.ts                 |  28 ++++++++++-----------
 src/client/views/LightboxView.tsx                  |   5 ++--
 src/client/views/collections/TabDocView.tsx        |  15 ++++++++++-
 src/client/views/collections/TreeView.tsx          |   4 +--
 src/client/views/nodes/DocumentIcon.tsx            |   4 +--
 src/client/views/nodes/DocumentView.tsx            |   4 ---
 src/client/views/nodes/button/FontIconBox.tsx      |  11 ++++----
 .../views/nodes/formattedText/DashFieldView.tsx    |   6 ++---
 .../views/nodes/formattedText/FormattedTextBox.tsx |   2 +-
 src/client/views/nodes/trails/PresBox.tsx          |  14 ++---------
 src/client/views/pdf/PDFViewer.tsx                 |   2 +-
 13 files changed, 48 insertions(+), 49 deletions(-)

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

diff --git a/src/.DS_Store b/src/.DS_Store
index b0987293b..4bf9cdac7 100644
Binary files a/src/.DS_Store and b/src/.DS_Store differ
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 2ed6c3cbe..85ad58726 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -869,7 +869,7 @@ export class CurrentUserUtils {
                             Doc.AddDocToList(menuBtnDoc, "data", newSubMenuBtnDoc, after, false, !prevSub);
                         }
                         prevSub = params.title;
-                    })
+                    });
                 }
                 prev = params.title;
             });
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index aeddc3249..a82f99d5a 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -16,7 +16,7 @@ import { SelectionManager } from './SelectionManager';
 export class DocumentManager {
 
     //global holds all of the nodes (regardless of which collection they're in)
-    @observable public DocumentViews: DocumentView[] = [];
+    @observable public DocumentViews = new Set<DocumentView>();
     @observable public LinkAnchorBoxViews: DocumentView[] = [];
     @observable public RecordingEvent = 0;
     @observable public LinkedDocumentViews: { a: DocumentView, b: DocumentView, l: Doc }[] = [];
@@ -46,7 +46,7 @@ export class DocumentManager {
             // this.LinkedDocumentViews.forEach(view => console.log("  LV = " + view.a.props.Document.title + "/" + view.a.props.LayoutTemplateString + " --> " +
             //     view.b.props.Document.title + "/" + view.b.props.LayoutTemplateString));
         } else {
-            this.DocumentViews.push(view);
+            this.DocumentViews.add(view);
         }
     }
     public RemoveView = action((view: DocumentView) => {
@@ -61,8 +61,7 @@ export class DocumentManager {
             const index = this.LinkAnchorBoxViews.indexOf(view);
             this.LinkAnchorBoxViews.splice(index, 1);
         } else {
-            const index = this.DocumentViews.indexOf(view);
-            index !== -1 && this.DocumentViews.splice(index, 1);
+            this.DocumentViews.delete(view);
         }
         SelectionManager.DeselectView(view);
     });
@@ -70,13 +69,13 @@ export class DocumentManager {
     //gets all views
     public getDocumentViewsById(id: string) {
         const toReturn: DocumentView[] = [];
-        DocumentManager.Instance.DocumentViews.map(view => {
+        Array.from(DocumentManager.Instance.DocumentViews).map(view => {
             if (view.rootDoc[Id] === id) {
                 toReturn.push(view);
             }
         });
         if (toReturn.length === 0) {
-            DocumentManager.Instance.DocumentViews.map(view => {
+            Array.from(DocumentManager.Instance.DocumentViews).map(view => {
                 const doc = view.rootDoc.proto;
                 if (doc && doc[Id] && doc[Id] === id) {
                     toReturn.push(view);
@@ -96,14 +95,14 @@ export class DocumentManager {
         const passes = preferredCollection ? [preferredCollection, undefined] : [undefined];
 
         for (const pass of passes) {
-            DocumentManager.Instance.DocumentViews.map(view => {
+            Array.from(DocumentManager.Instance.DocumentViews).map(view => {
                 if (view.rootDoc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
                     toReturn = view;
                     return;
                 }
             });
             if (!toReturn) {
-                DocumentManager.Instance.DocumentViews.map(view => {
+                Array.from(DocumentManager.Instance.DocumentViews).map(view => {
                     const doc = view.rootDoc.proto;
                     if (doc && doc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
                         toReturn = view;
@@ -122,9 +121,8 @@ export class DocumentManager {
     }
 
     public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
-        const docViews = DocumentManager.Instance.DocumentViews;
         const views: DocumentView[] = [];
-        docViews.map(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view));
+        Array.from(DocumentManager.Instance.DocumentViews).map(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.rootDoc, toFind) && views.push(view));
         return views?.find(view => view.ContentDiv?.getBoundingClientRect().width && view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined);
     }
     public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
@@ -133,8 +131,8 @@ export class DocumentManager {
     }
     public getDocumentViews(toFind: Doc): DocumentView[] {
         const toReturn: DocumentView[] = [];
-        const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.IsLightboxDocView(view.docViewPath));
-        const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.IsLightboxDocView(view.docViewPath));
+        const docViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => !LightboxView.IsLightboxDocView(view.docViewPath));
+        const lightViews = Array.from(DocumentManager.Instance.DocumentViews).filter(view => LightboxView.IsLightboxDocView(view.docViewPath));
 
         // heuristic to return the "best" documents first:
         //   choose a document in the lightbox first
@@ -290,7 +288,7 @@ export class DocumentManager {
         }
     }
 }
-export function DocFocusOrOpen(doc: any, collectionDoc?: Doc) {
+export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) {
     const cv = collectionDoc && DocumentManager.Instance.getDocumentView(collectionDoc);
     const dv = DocumentManager.Instance.getDocumentView(doc, (cv?.ComponentView as CollectionFreeFormView)?.props.CollectionView);
     if (dv && Doc.AreProtosEqual(dv.props.Document, doc)) {
@@ -300,7 +298,9 @@ export function DocFocusOrOpen(doc: any, collectionDoc?: Doc) {
     else {
         const context = doc.context !== Doc.UserDoc().myFilesystem && Cast(doc.context, Doc, null);
         const showDoc = context || doc;
-        CollectionDockingView.AddSplit(showDoc === Doc.GetProto(showDoc) ? Doc.MakeAlias(showDoc) : showDoc, "right") && context &&
+        const bestAlias = showDoc === Doc.GetProto(showDoc) ? DocListCast(showDoc.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail) : showDoc;
+
+        CollectionDockingView.AddSplit(bestAlias ? bestAlias : Doc.MakeAlias(showDoc), "right") && context &&
             setTimeout(() => DocumentManager.Instance.getDocumentView(Doc.GetProto(doc))?.focus(doc));
     }
 }
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index ddfc8b249..3d2769f66 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -275,9 +275,8 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                 <div className="lightboxView-tabBtn" title={"open in tab"}
                     onClick={e => {
                         e.stopPropagation();
-                        // CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, "");
-                        LightboxView.openInTabFunc(LightboxView._docTarget || LightboxView._doc!, "inPlace");
-                        console.log("lightbox to tab triggered")
+                        CollectionDockingView.AddSplit(LightboxView._docTarget || LightboxView._doc!, "");
+                        //LightboxView.openInTabFunc(LightboxView._docTarget || LightboxView._doc!, "inPlace");
                         SelectionManager.DeselectAll();
                         LightboxView.SetLightboxDoc(undefined);
                     }}>
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 8d84e9a56..d64cb2fd7 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -66,6 +66,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     get stack() { return (this.props as any).glContainer.parent.parent; }
     get tab() { return (this.props as any).glContainer.tab; }
     get view() { return this._view; }
+    _lastTab: any;
+    _lastView: DocumentView | undefined;
 
     @action
     init = (tab: any, doc: Opt<Doc>) => {
@@ -266,6 +268,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
     componentWillUnmount() {
         this._tabReaction?.();
+        this._view && DocumentManager.Instance.RemoveView(this._view);
         this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab);
 
         this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged);
@@ -353,7 +356,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
     @computed get docView() {
         return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
-            <><DocumentView key={this._document[Id]} ref={action((r: DocumentView) => this._view = r)}
+            <><DocumentView key={this._document[Id]} ref={action((r: DocumentView) => {
+                this._lastView && DocumentManager.Instance.RemoveView(this._lastView);
+                this._view = r;
+                this._lastView = this._view;
+            })}
                 renderDepth={0}
                 Document={this._document}
                 DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
@@ -409,6 +416,12 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 height: "100%", width: "100%"
             }} ref={ref => {
                 if (this._mainCont = ref) {
+                    if (this._lastTab) {
+                        console.log("DUP tab")
+                        this._view && DocumentManager.Instance.RemoveView(this._view);
+                        CollectionDockingView.Instance.tabMap.delete(this._lastTab);
+                    }
+                    this._lastTab = this.tab;
                     (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
                     DocServer.GetRefField(this.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document)));
                     new _global.ResizeObserver(action((entries: any) => this._forceInvalidateScreenToLocal++)).observe(ref);
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 661db7997..9de44fb00 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -183,7 +183,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             this.treeViewOpen = !this.treeViewOpen;
         } else {
             // choose an appropriate alias or make one. --- choose the first alias that (1) user owns,  (2) has no context field ... otherwise make a new alias
-            const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
+            const bestAlias = docView.props.Document.author === Doc.CurrentUserEmail && !Doc.IsPrototype(docView.props.Document) ? docView.props.Document : DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
             const nextBestAlias = DocListCast(this.props.document.aliases).find(doc => doc.author === Doc.CurrentUserEmail);
             this.props.addDocTab(bestAlias ?? nextBestAlias ?? Doc.MakeAlias(this.props.document), "lightbox");
         }
@@ -609,7 +609,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     // TODO: currently doc focus works, but can't seem to edit title
     // onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
     onChildClick = () => {
-        return this.props.onChildClick?.() ?? (ScriptField.MakeFunction(`DocFocusOrOpen(self)`)! || this._editTitleScript?.())
+        return this.props.onChildClick?.() ?? (ScriptField.MakeFunction(`DocFocusOrOpen(self)`)! || this._editTitleScript?.());
     }
 
     onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx
index a9c998757..56de2d1fc 100644
--- a/src/client/views/nodes/DocumentIcon.tsx
+++ b/src/client/views/nodes/DocumentIcon.tsx
@@ -52,7 +52,7 @@ export class DocumentIconContainer extends React.Component {
                 };
             },
             getVars() {
-                const docs = DocumentManager.Instance.DocumentViews;
+                const docs = Array.from(DocumentManager.Instance.DocumentViews);
                 const capturedVariables: { [name: string]: Field } = {};
                 usedDocuments.forEach(index => capturedVariables[`d${index}`] = docs[index].props.Document);
                 return { capturedVariables };
@@ -60,6 +60,6 @@ export class DocumentIconContainer extends React.Component {
         };
     }
     render() {
-        return DocumentManager.Instance.DocumentViews.map((dv, i) => <DocumentIcon key={i} index={i} view={dv} />);
+        return Array.from(DocumentManager.Instance.DocumentViews).map((dv, i) => <DocumentIcon key={i} index={i} view={dv} />);
     }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 14ededaf8..6e4d6a52e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -242,7 +242,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown); }
     @computed get onPointerUpHandler() { return this.props.onPointerUp?.() ?? ScriptCast(this.Document.onPointerUp); }
 
-
     componentWillUnmount() { this.cleanupHandlers(true); }
     componentDidMount() { this.setupHandlers(); }
     //componentDidUpdate() { this.setupHandlers(); }
@@ -1126,9 +1125,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     render() {
         TraceMobx();
         const highlightIndex = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : Doc.DocBrushStatus.unbrushed) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString
-        if (highlightIndex === 6) {
-            console.log("")
-        }
         const highlightColor = ["transparent", "rgb(68, 118, 247)", "rgb(68, 118, 247)", "orange", "lightBlue"][highlightIndex];
         const highlightStyle = ["solid", "dashed", "solid", "solid", "solid"][highlightIndex];
         const excludeTypes = !this.props.treeViewDoc ? [DocumentType.FONTICON, DocumentType.INK] : [DocumentType.FONTICON];
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index d29160458..b21a28d8e 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -231,7 +231,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
 
         const script = ScriptCast(this.rootDoc.script);
-        if (!script) { return null };
+        if (!script) { return null; }
 
         let noviceList: string[] = [];
         let text: string | undefined;
@@ -459,7 +459,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         const buttonText = StrCast(this.rootDoc.buttonText);
 
         // TODO:glr Add label of button type
-        let button = this.defaultButton;
+        let button: JSX.Element | null = this.defaultButton;
 
         switch (this.type) {
             case ButtonType.TextButton:
@@ -527,9 +527,10 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
         }
 
         return !this.layoutDoc.toolTip || this.type === ButtonType.DropdownList || this.type === ButtonType.ColorButton || this.type === ButtonType.NumberButton || this.type === ButtonType.EditableText ? button :
-            <Tooltip title={<div className="dash-tooltip">{StrCast(this.layoutDoc.toolTip)}</div>}>
-                {button}
-            </Tooltip>;
+            button !== null ?
+                <Tooltip title={<div className="dash-tooltip">{StrCast(this.layoutDoc.toolTip)}</div>}>
+                    {button}
+                </Tooltip > : null
     }
 }
 
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index 6a3f9ed00..bb3791f1e 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -86,7 +86,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     public static fieldContent(textBoxDoc: Doc, dashDoc: Doc, fieldKey: string) {
         const dashVal = dashDoc[fieldKey] ?? dashDoc[DataSym][fieldKey] ?? (fieldKey === "PARAMS" ? textBoxDoc[fieldKey] : "");
         const fval = dashVal instanceof List ? dashVal.join(DashFieldViewInternal.multiValueDelimeter) : StrCast(dashVal).startsWith(":=") || dashVal === "" ? Doc.Layout(textBoxDoc)[fieldKey] : dashVal;
-        return { boolVal: Cast(fval, "boolean", null), strVal: Field.toString(fval as Field) || "" }
+        return { boolVal: Cast(fval, "boolean", null), strVal: Field.toString(fval as Field) || "" };
     }
 
     // set the display of the field's value (checkbox for booleans, span of text for strings)
@@ -241,8 +241,8 @@ export class DashFieldViewMenu extends AntimodeMenu<AntimodeMenuProps> {
         const hideMenu = () => {
             this.fadeOut(true);
             document.removeEventListener("pointerdown", hideMenu);
-        }
-        document.addEventListener("pointerdown", hideMenu)
+        };
+        document.addEventListener("pointerdown", hideMenu);
     }
     render() {
         const buttons = [
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index ce82821b6..434fccf8d 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1202,7 +1202,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 const tr = this._editorView.state.tr.setStoredMarks(storedMarks).insertText(FormattedTextBox.SelectOnLoadChar, this._editorView.state.doc.content.size - 1, this._editorView.state.doc.content.size).setStoredMarks(storedMarks);
                 this._editorView.dispatch(tr.setSelection(new TextSelection(tr.doc.resolve(tr.doc.content.size))));
             } else if (this._editorView && curText && !FormattedTextBox.DontSelectInitialText) {
-                selectAll(this._editorView.state, this._editorView?.dispatch)
+                selectAll(this._editorView.state, this._editorView?.dispatch);
                 this.startUndoTypingBatch();
             } else if (this._editorView) {
                 this._editorView.dispatch(this._editorView.state.tr.addStoredMark(schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) })));
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index f4e792acd..0af7715fe 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -2435,9 +2435,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             indexNum += (index[i] * (10 ** (-i)));
         }
         this._treeViewMap.set(indexNum, treeViewDoc);
-        console.log(String(index), treeViewDoc)
         this.props.Document.presentationLinearizedDocuments = new List<Doc>(this.sort(this._treeViewMap)); // this is a flat array of Docs
-        console.log(this.props.Document.presentationLinearizedDocuments)
         return this.childDocs;
     }
 
@@ -2447,21 +2445,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             indexNum += (index[i] * (10 ** (-i)));
         }
         console.log(String(index), treeViewDoc)
-        this._treeViewMap.delete(indexNum)
+        this._treeViewMap.delete(indexNum);
         this.props.Document.presentationLinearizedDocuments = new List<Doc>(this.sort(this._treeViewMap));
         return this.childDocs;
     }
 
     // TODO: [AL] implement sort function for an array of numbers (e.g. arr[1,2,4] v arr[1,2,1])
-    sort = (treeViewMap: Map<number, Doc>): Doc[] => {
-        // TODO
-        const sortedMap = [...treeViewMap.entries()].sort();
-        var sortedDocs = [];
-        for (var kv of sortedMap) {
-            sortedDocs.push(kv[1]);
-        }
-        return sortedDocs;
-    }
+    sort = (treeViewMap: Map<number, Doc>) => [...treeViewMap.entries()].sort().map(kv => kv[1]);
 
     render() {
         // calling this method for keyEvents
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 6db36f36a..d5fd425ad 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -154,7 +154,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         if (doc !== this.props.rootDoc && mainCont) {
             const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1);
             const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, .1 * windowHeight, NumCast(this.props.Document.scrollHeight));
-            if (scrollTo !== undefined && scrollTo != this.props.layoutDoc._scrollTop) {
+            if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) {
                 focusSpeed = 500;
 
                 if (!this._pdfViewer) this._initialScroll = scrollTo;
-- 
cgit v1.2.3-70-g09d2


From 84e843ccb21dcb95dff11e34b749f4587fc0fd86 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 4 Jun 2022 23:21:17 -0400
Subject: fixed mini-pres view css, fixed interaction with mini-pres by fixing
 overlayView panelWidth/height, fixed tabMap to get updated properly to allow
 CloseSplit to work, etc.

---
 src/client/views/OverlayView.tsx            | 12 +++---
 src/client/views/StyleProvider.tsx          |  2 +-
 src/client/views/collections/TabDocView.tsx |  2 +-
 src/client/views/nodes/trails/PresBox.scss  |  7 +--
 src/client/views/nodes/trails/PresBox.tsx   | 67 ++++++++++++++++++++---------
 5 files changed, 58 insertions(+), 32 deletions(-)

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

diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index ebad2981d..18b87e3d5 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -2,10 +2,10 @@ import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
 import * as React from "react";
 import ReactLoading from 'react-loading';
-import { Doc } from "../../fields/Doc";
+import { Doc, HeightSym, WidthSym } from "../../fields/Doc";
 import { Id } from "../../fields/FieldSymbols";
 import { Cast, NumCast } from "../../fields/Types";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, setupMoveUpEvents, Utils } from "../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from "../../Utils";
 import { DocUtils } from "../documents/Documents";
 import { CurrentUserUtils } from "../util/CurrentUserUtils";
 import { DragManager } from "../util/DragManager";
@@ -186,12 +186,12 @@ export class OverlayView extends React.Component {
                     bringToFront={emptyFunction}
                     addDocument={undefined}
                     removeDocument={undefined}
-                    PanelWidth={returnOne}
-                    PanelHeight={returnOne}
+                    PanelWidth={d[WidthSym]}
+                    PanelHeight={d[HeightSym]}
                     ScreenToLocalTransform={Transform.Identity}
                     renderDepth={1}
-                    isDocumentActive={returnTrue}
-                    isContentActive={emptyFunction}
+                    isDocumentActive={returnFalse}
+                    isContentActive={returnTrue}
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={DocUtils.DefaultFocus}
                     styleProvider={DefaultStyleProvider}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 553f84a67..35415ae4e 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -136,7 +136,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                         StrCast(props?.Document.backgroundColor, isCaption ? "rgba(0,0,0,0.4)" : "")));
             switch (doc?.type) {
                 case DocumentType.PRESELEMENT: docColor = docColor || (darkScheme() ? "" : ""); break;
-                case DocumentType.PRES: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.WHITE); break;
+                case DocumentType.PRES: docColor = docColor || (darkScheme() ? "transparent" : "transparent"); break;
                 case DocumentType.FONTICON: docColor = docColor || Colors.DARK_GRAY; break;
                 case DocumentType.RTF: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : Colors.LIGHT_GRAY); break;
                 case DocumentType.FILTER: docColor = docColor || (darkScheme() ? Colors.DARK_GRAY : "rgba(105, 105, 105, 0.432)"); break;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index d64cb2fd7..ad01be3a3 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -76,7 +76,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             tab._disposers = {} as { [name: string]: IReactionDisposer };
             tab.contentItem.config.fixed && (tab.contentItem.parent.config.fixed = true);
             tab.DashDoc = doc;
-            CollectionDockingView.Instance.tabMap.add(tab);
             const iconType: IconProp = Doc.toIcon(doc);
             // setup the title element and set its size according to the # of chars in the title.  Show the full title when clicked.
             const titleEle = tab.titleElement[0];
@@ -186,6 +185,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab");
                 });
         }
+        CollectionDockingView.Instance.tabMap.add(tab);
     }
 
     /**
diff --git a/src/client/views/nodes/trails/PresBox.scss b/src/client/views/nodes/trails/PresBox.scss
index 06932d145..a0a2dd4f8 100644
--- a/src/client/views/nodes/trails/PresBox.scss
+++ b/src/client/views/nodes/trails/PresBox.scss
@@ -1078,11 +1078,13 @@
 .miniPres {
     cursor: grab;
     position: absolute;
-    right: 10;
-    top: 10;
+    top: 0;
+    left: 0;
     opacity: 0.1;
     transition: all 0.4s;
     color: $white;
+    width: 100%;
+    height: 100%;
 }
 
 .miniPres:hover {
@@ -1101,7 +1103,6 @@
     align-items: center;
     display: flex;
     position: absolute;
-    right: 10px;
     transition: all 0.2s;
 
     .presPanel-button-text {
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 0af7715fe..914d6ab15 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -12,7 +12,7 @@ import { PrefetchProxy } from "../../../../fields/Proxy";
 import { listSpec } from "../../../../fields/Schema";
 import { ScriptField } from "../../../../fields/ScriptField";
 import { BoolCast, Cast, NumCast, StrCast } from "../../../../fields/Types";
-import { emptyFunction, returnFalse, returnOne, returnTrue } from '../../../../Utils';
+import { emptyFunction, returnFalse, returnOne, returnTrue, setupMoveUpEvents } from '../../../../Utils';
 import { Docs } from "../../../documents/Documents";
 import { DocumentType } from "../../../documents/DocumentTypes";
 import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
@@ -604,27 +604,21 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
      * The method called to open the presentation as a minimized view
      */
     @action
-    updateMinimize = () => {
-        const docView = DocumentManager.Instance.getDocumentView(this.layoutDoc);
+    updateMinimize = async () => {
         if (CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
-            console.log("case 1");
             this.layoutDoc.presStatus = PresStatus.Edit;
             Doc.RemoveDocFromList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
             CollectionDockingView.AddSplit(this.rootDoc, "right");
-        } else if ((true || this.layoutDoc.context) && docView) {
-            console.log("case 2");
+        } else {
             this.layoutDoc.presStatus = PresStatus.Edit;
             clearTimeout(this._presTimer);
             const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
             this.rootDoc.x = pt[0] + (this.props.PanelWidth() - 250);
             this.rootDoc.y = pt[1] + 10;
-            this.rootDoc._height = 35;
-            this.rootDoc._width = 250;
-            docView.props.removeDocument?.(this.layoutDoc);
+            this.rootDoc._height = 30;
+            this.rootDoc._width = 248;
+            this.props.removeDocument?.(this.layoutDoc);
             Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
-        } else {
-            console.log("case 3");
-            // TODO glr: fix this case
         }
     }
 
@@ -2424,6 +2418,31 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         else this.pauseAutoPres();
     }
 
+    @action
+    prevClicked = (e: PointerEvent) => {
+        this.back();
+        if (this._presTimer) {
+            clearTimeout(this._presTimer);
+            this.layoutDoc.presStatus = PresStatus.Manual;
+        }
+    }
+
+    @action
+    nextClicked = (e: PointerEvent) => {
+        this.next();
+        if (this._presTimer) {
+            clearTimeout(this._presTimer);
+            this.layoutDoc.presStatus = PresStatus.Manual;
+        }
+    }
+    @undoBatch
+    @action
+    exitClicked = (e: PointerEvent) => {
+        this.updateMinimize();
+        this.layoutDoc.presStatus = PresStatus.Edit;
+        clearTimeout(this._presTimer);
+    }
+
     @action
     startMarqueeCreateSlide = () => {
         PresBox.startMarquee = true;
@@ -2465,28 +2484,34 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return CurrentUserUtils.OverlayDocs.includes(this.rootDoc) ?
             <div className="miniPres">
                 <div className="presPanelOverlay" style={{ display: "inline-flex", height: 30, background: '#323232', top: 0, zIndex: 3000000, boxShadow: presKeyEvents ? '0 0 0px 3px ' + Colors.MEDIUM_BLUE : undefined }}>
-                    <Tooltip title={<><div className="dash-tooltip">{"Loop"}</div></>}><div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : undefined }} onClick={() => this.layoutDoc.presLoop = !this.layoutDoc.presLoop}><FontAwesomeIcon icon={"redo-alt"} /></div></Tooltip>
+                    <Tooltip title={<><div className="dash-tooltip">{"Loop"}</div></>}><div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? Colors.MEDIUM_BLUE : undefined }}
+                        onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.layoutDoc.presLoop = !this.layoutDoc.presLoop, false, false)}><FontAwesomeIcon icon={"redo-alt"} /></div></Tooltip>
                     <div className="presPanel-divider"></div>
-                    <div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }} onClick={() => { this.back(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}><FontAwesomeIcon icon={"arrow-left"} /></div>
-                    <Tooltip title={<><div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? "Pause" : "Autoplay"}</div></>}><div className="presPanel-button" onClick={this.startOrPause}><FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div></Tooltip>
-                    <div className="presPanel-button" style={{ opacity: presEnd ? 0.4 : 1 }} onClick={() => { this.next(); if (this._presTimer) { clearTimeout(this._presTimer); this.layoutDoc.presStatus = PresStatus.Manual; } }}><FontAwesomeIcon icon={"arrow-right"} /></div>
+                    <div className="presPanel-button" style={{ opacity: presStart ? 0.4 : 1 }}
+                        onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.prevClicked, false, false)}><FontAwesomeIcon icon={"arrow-left"} /></div>
+                    <Tooltip title={<><div className="dash-tooltip">{this.layoutDoc.presStatus === PresStatus.Autoplay ? "Pause" : "Autoplay"}</div></>}><div className="presPanel-button"
+                        onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.startOrPause, false, false)}><FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div></Tooltip>
+                    <div className="presPanel-button" style={{ opacity: presEnd ? 0.4 : 1 }}
+                        onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, this.nextClicked, false, false)}><FontAwesomeIcon icon={"arrow-right"} /></div>
                     <div className="presPanel-divider"></div>
-                    <Tooltip title={<><div className="dash-tooltip">{"Click to return to 1st slide"}</div></>}><div className="presPanel-button" style={{ border: 'solid 1px white' }} onClick={() => this.gotoDocument(0, this.activeItem)}><b>1</b></div></Tooltip>
+                    <Tooltip title={<><div className="dash-tooltip">{"Click to return to 1st slide"}</div></>}><div className="presPanel-button" style={{ border: 'solid 1px white' }}
+                        onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, returnFalse, () => this.gotoDocument(0, this.activeItem), false, false)}><b>1</b></div></Tooltip>
                     <div className="presPanel-button-text">
                         Slide {this.itemIndex + 1} / {this.childDocs.length}
                         {this.playButtonFrames}
                     </div>
-                    <div className="presPanel-divider"></div>
-                    <div className="presPanel-button-text" onClick={undoBatch(action(() => { this.updateMinimize(); this.layoutDoc.presStatus = PresStatus.Edit; clearTimeout(this._presTimer); }))}>EXIT</div>
+                    <div className="presPanel-divider" />
+                    <div className="presPanel-button-text" onPointerDown={e =>
+                        setupMoveUpEvents(this, e, returnFalse, returnFalse, this.exitClicked, false, false)}>EXIT</div>
                 </div>
-            </div>
+            </div >
             :
             <div className="presBox-cont" style={{ minWidth: CurrentUserUtils.OverlayDocs.includes(this.layoutDoc) ? 240 : undefined }} >
                 {this.topPanel}
                 {this.toolbar}
                 {this.newDocumentToolbarDropdown}
                 <div className="presBox-listCont">
-                    <div className="Slide" style={{ height: `calc(100% - 100px)` }}>
+                    <div className="Slide" style={{ height: `calc(100% - 30px)` }}>
                         {mode !== CollectionViewType.Invalid ?
                             <CollectionView {...this.props}
                                 ContainingCollectionDoc={this.props.Document}
-- 
cgit v1.2.3-70-g09d2


From acf19e54a43d5b05c58ef3c80d27086dd64f8e8e Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Sun, 5 Jun 2022 16:38:46 +0100
Subject: updated and refactored pinWithView

Changed MarqueeView pinWithView so that it just calls TabDocView.PinDoc
---
 .vscode/settings.json                              |   2 +-
 src/client/views/collections/TabDocView.tsx        |  11 +-
 .../collections/collectionFreeForm/MarqueeView.tsx | 122 +++++----------------
 src/client/views/nodes/trails/PresBox.tsx          |  13 ++-
 4 files changed, 50 insertions(+), 98 deletions(-)

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

diff --git a/.vscode/settings.json b/.vscode/settings.json
index 27acfd1a2..a6e6ad360 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -6,7 +6,7 @@
         "**/CVS": true,
         "**/.DS_Store": true,
     },
-    "editor.formatOnSave": true,
+    "editor.formatOnSave": false,
     "editor.detectIndentation": false,
     "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false,
     "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces": true,
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index ad01be3a3..0cd3fb5a7 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -193,10 +193,12 @@ export class TabDocView extends React.Component<TabDocViewProps> {
      **/
     @action
     public static async PinDoc(doc: Doc, pinProps?: PinProps) {
-        if (pinProps?.unpin) console.log('TODO: Remove UNPIN from this location');
         //add this new doc to props.Document
+
+        // all docs will be added to the ActivePresentation as stored on CurrentUserUtils
         const curPres = CurrentUserUtils.ActivePresentation;
         if (curPres) {
+            // Edge Case 1: Cannot pin document to itself
             if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; }
             const batch = UndoManager.StartBatch("pinning doc");
             const pinDoc = Doc.MakeAlias(doc);
@@ -239,6 +241,13 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             const dview = CollectionDockingView.Instance.props.Document;
             const fieldKey = CollectionDockingView.Instance.props.fieldKey;
             const tabdocs = await DocListCastAsync(dview[fieldKey]);
+			if (pinProps?.pinWithView) {
+				const viewProps = pinProps.pinWithView;
+				pinDoc.presPinView = true;
+            	pinDoc.presPinViewX = viewProps.bounds.left + viewProps.bounds.width / 2;
+            	pinDoc.presPinViewY = viewProps.bounds.top + viewProps.bounds.height / 2;
+            	pinDoc.presPinViewScale = viewProps.scale;
+			}
             runInAction(() => {
                 if (!pinProps?.hidePresBox && !tabdocs?.includes(curPres)) {
                     tabdocs?.push(curPres);  // bcz: Argh! this is annoying.  if multiple documents are pinned, this will get called multiple times before the presentation view is drawn.  Thus it won't be in the tabdocs list and it will get created multple times.  so need to explicilty add the presbox to the list of open tabs
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 8ca7e160e..362117b19 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -20,7 +20,7 @@ import { Transform } from "../../../util/Transform";
 import { undoBatch, UndoManager } from "../../../util/UndoManager";
 import { ContextMenu } from "../../ContextMenu";
 import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
-import { PresBox } from "../../nodes/trails/PresBox";
+import { PinViewProps, PresBox } from "../../nodes/trails/PresBox";
 import { PresMovement } from "../../nodes/trails/PresEnums";
 import { VideoBox } from "../../nodes/VideoBox";
 import { pasteImageBitmap } from "../../nodes/WebBoxRenderer";
@@ -31,6 +31,7 @@ import { TreeView } from "../TreeView";
 import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
 import "./MarqueeView.scss";
 import React = require("react");
+import { TabDocView } from "../TabDocView";
 
 interface MarqueeViewProps {
     getContainerTransform: () => Transform;
@@ -44,6 +45,14 @@ interface MarqueeViewProps {
     ungroup?: () => void;
     setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void;
 }
+
+export interface MarqueeViewBounds {
+	left: number;
+	top: number;
+	width: number;
+	height: number;
+}
+
 @observer
 export class MarqueeView extends React.Component<SubCollectionViewProps & MarqueeViewProps>
 {
@@ -60,7 +69,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
     @computed get Bounds() {
         const topLeft = this.Transform.transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY);
         const size = this.Transform.transformDirection(this._lastX - this._downX, this._lastY - this._downY);
-        return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) };
+		const bounds:MarqueeViewBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }
+        return bounds;
     }
     get inkDoc() { return this.props.Document; }
     get ink() { return Cast(this.props.Document.ink, InkField); }
@@ -263,7 +273,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             document.removeEventListener("wheel", hideMarquee);
         };
         if (PresBox.startMarquee) {
-            this.pinMarqueeView();
+            this.pinWithView();
             PresBox.startMarquee = false;
         }
         if (!this._commandExecuted && (Math.abs(this.Bounds.height * this.Bounds.width) > 100) && !PresBox.startMarquee) {
@@ -385,98 +395,24 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         this.hideMarquee();
     }
 
+	/**
+	 * This triggers the TabDocView.PinDoc method which is the universal method
+	 * used to pin documents to the currently active presentation trail. 
+	 * 
+	 * This one is unique in that it includes the bounds associated with marquee view. 
+	 */
     @undoBatch
     @action
-    pinMarqueeView = async () => {
-        const doc = this.props.Document;
-        const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
-        if (curPres) {
-            console.log(curPres);
-            if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; }
-            const pinDoc = Doc.MakeAlias(doc);
-            pinDoc.presentationTargetDoc = doc;
-            pinDoc.presMovement = PresMovement.Zoom;
-            pinDoc.groupWithUp = false;
-            pinDoc.context = curPres;
-            pinDoc.title = doc.title + " - Slide";// 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.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
-            pinDoc.treeViewHeaderWidth = "100%"; // forces the header to grow to be the same size as its largest sibling.
-            pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc.
-            pinDoc.treeViewFieldKey = "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.treeViewExpandedView = "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.treeViewGrowsHorizontally = true;// the document expands horizontally when displayed as a tree view header  
-            pinDoc.treeViewHideHeaderIfTemplate = true;  // this will force the document to render itself as the tree view header
-
-            const presArray = PresBox.Instance?.sortArray();
-            const size = PresBox.Instance?._selectedArray.size;
-            const presSelected = presArray && size ? presArray[size - 1] : undefined;
-            Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
-            if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
-            const dview = CollectionDockingView.Instance.props.Document;
-            const fieldKey = CollectionDockingView.Instance.props.fieldKey;
-            const tabdocs = await DocListCastAsync(dview[fieldKey]);
-            if (!tabdocs?.includes(curPres)) {
-                tabdocs?.push(curPres);  // bcz: Argh! this is annoying.  if multiple documents are pinned, this will get called multiple times before the presentation view is drawn.  Thus it won't be in the tabdocs list and it will get created multple times.  so need to explicilty add the presbox to the list of open tabs
-                CollectionDockingView.AddSplit(curPres, "right");
-            }
-            PresBox.Instance?._selectedArray.clear();
-            pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Updates selected array
-            const index = PresBox.Instance?.childDocs.indexOf(pinDoc);
-            index && (curPres._itemIndex = index);
-            const scale = Math.min(this.props.PanelWidth() / this.Bounds.width, this.props.PanelHeight() / this.Bounds.height);
-            pinDoc.presPinView = true;
-            pinDoc.presPinViewX = this.Bounds.left + this.Bounds.width / 2;
-            pinDoc.presPinViewY = this.Bounds.top + this.Bounds.height / 2;
-            pinDoc.presPinViewScale = scale;
-        }
-        this.hideMarquee();
-    }
-
-    @undoBatch
-    @action
-    pinWithView = async (e: KeyboardEvent | React.PointerEvent | undefined) => {
-        const doc = this.props.Document;
-        const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
-        if (curPres) {
-            if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; }
-            const pinDoc = Doc.MakeAlias(doc);
-            pinDoc.presentationTargetDoc = doc;
-            pinDoc.presMovement = PresMovement.Zoom;
-            pinDoc.groupWithUp = false;
-            pinDoc.context = curPres;
-            pinDoc.title = doc.title + " - Slide";
-            pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
-            pinDoc.treeViewHeaderWidth = "100%"; // forces the header to grow to be the same size as its largest sibling.
-            pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc.
-            pinDoc.treeViewFieldKey = "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.treeViewExpandedView = "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.treeViewGrowsHorizontally = true;// the document expands horizontally when displayed as a tree view header  
-            pinDoc.treeViewHideHeaderIfTemplate = true;  // this will force the document to render itself as the tree view header
-
-            const presArray = PresBox.Instance?.sortArray();
-            const size = PresBox.Instance?._selectedArray.size;
-            const presSelected = presArray && size ? presArray[size - 1] : undefined;
-            Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
-            if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; const dview = CollectionDockingView.Instance.props.Document;
-            const fieldKey = CollectionDockingView.Instance.props.fieldKey;
-            const tabdocs = await DocListCastAsync(dview[fieldKey]);
-            if (!tabdocs?.includes(curPres)) {
-                tabdocs?.push(curPres);  // bcz: Argh! this is annoying.  if multiple documents are pinned, this will get called multiple times before the presentation view is drawn.  Thus it won't be in the tabdocs list and it will get created multple times.  so need to explicilty add the presbox to the list of open tabs
-                CollectionDockingView.AddSplit(curPres, "right");
-            }
-            PresBox.Instance?._selectedArray.clear();
-            pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Updates selected array
-            const index = PresBox.Instance?.childDocs.indexOf(pinDoc);
-            index && (curPres._itemIndex = index);
-            if (e instanceof KeyboardEvent ? e.key === "c" : true) {
-                const scale = Math.min(this.props.PanelWidth() / this.Bounds.width, this.props.PanelHeight() / this.Bounds.height);
-                pinDoc.presPinView = true;
-                pinDoc.presPinViewX = this.Bounds.left + this.Bounds.width / 2;
-                pinDoc.presPinViewY = this.Bounds.top + this.Bounds.height / 2;
-                pinDoc.presPinViewScale = scale;
-            }
-        }
-        MarqueeOptionsMenu.Instance.fadeOut(true);
+    pinWithView = async () => {
+		console.log("pinWithView");
+        const scale = Math.min(this.props.PanelWidth() / this.Bounds.width, this.props.PanelHeight() / this.Bounds.height);
+		const doc = this.props.Document;
+		const viewOptions:PinViewProps = {
+			bounds: this.Bounds,
+			scale: scale
+		};
+		TabDocView.PinDoc(doc, {pinWithView: viewOptions});
+		MarqueeOptionsMenu.Instance.fadeOut(true);
         this.hideMarquee();
     }
 
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index ab5382581..3a29d9adf 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -30,14 +30,21 @@ import { CollectionFreeFormDocumentView } from "../CollectionFreeFormDocumentVie
 import { FieldView, FieldViewProps } from '../FieldView';
 import "./PresBox.scss";
 import { PresEffect, PresMovement, PresStatus } from "./PresEnums";
+import { MarqueeViewBounds } from "../../collections/collectionFreeForm";
 
-export class PinProps {
+export interface PinProps {
     audioRange?: boolean;
-    unpin?: boolean;
     setPosition?: boolean;
     hidePresBox?: boolean;
+    pinWithView?: PinViewProps;
 }
 
+export interface PinViewProps {
+  bounds: MarqueeViewBounds;
+  scale: number;
+}
+
+
 @observer
 export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); }
@@ -2543,7 +2550,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
 // this func communicates with PresBoxElement to send information of the doc
 ScriptingGlobals.add(function lookupPresBoxField(presBoxDoc: Doc, field: string, presEleDoc: Doc) {
     if (field === 'indexInPres') return DocListCast(presBoxDoc._viewType === CollectionViewType.Tree ? presBoxDoc.presentationLinearizedDocuments : presBoxDoc[StrCast(presBoxDoc.presentationFieldKey)]).indexOf(presEleDoc);
-    if (field === 'presCollapsedHeight') return [CollectionViewType.Tree || CollectionViewType.Stacking].includes(presBoxDoc._viewType as any) ? 35 : 31;
+    if (field === 'presCollapsedHeight') return [CollectionViewType.Tree, CollectionViewType.Stacking].includes(presBoxDoc._viewType as any) ? 35 : 31;
     if (field === 'presStatus') return presBoxDoc.presStatus;
     if (field === '_itemIndex') return presBoxDoc._itemIndex;
     if (field === 'presBox') return presBoxDoc;
-- 
cgit v1.2.3-70-g09d2


From d939e83f1279cb010b3573f0ac02ba4dc7c3cb37 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Sun, 5 Jun 2022 17:11:22 +0100
Subject: updates and attempts at debugging

---
 src/client/views/collections/TabDocView.tsx | 15 ++++++++-------
 src/client/views/nodes/trails/PresBox.tsx   |  5 +++++
 2 files changed, 13 insertions(+), 7 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 0cd3fb5a7..004032282 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -220,6 +220,14 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             const size: number = PresBox.Instance?._selectedArray.size;
             const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
             const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], null);
+			// If pinWithView option set then update scale and x / y props of slide
+			if (pinProps?.pinWithView) {
+				const viewProps = pinProps.pinWithView;
+				pinDoc.presPinView = true;
+            	pinDoc.presPinViewX = viewProps.bounds.left + viewProps.bounds.width / 2;
+            	pinDoc.presPinViewY = viewProps.bounds.top + viewProps.bounds.height / 2;
+            	pinDoc.presPinViewScale = viewProps.scale;
+			}
             Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
             if (!pinProps?.audioRange && duration !== undefined) {
                 pinDoc.mediaStart = "manual";
@@ -241,13 +249,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             const dview = CollectionDockingView.Instance.props.Document;
             const fieldKey = CollectionDockingView.Instance.props.fieldKey;
             const tabdocs = await DocListCastAsync(dview[fieldKey]);
-			if (pinProps?.pinWithView) {
-				const viewProps = pinProps.pinWithView;
-				pinDoc.presPinView = true;
-            	pinDoc.presPinViewX = viewProps.bounds.left + viewProps.bounds.width / 2;
-            	pinDoc.presPinViewY = viewProps.bounds.top + viewProps.bounds.height / 2;
-            	pinDoc.presPinViewScale = viewProps.scale;
-			}
             runInAction(() => {
                 if (!pinProps?.hidePresBox && !tabdocs?.includes(curPres)) {
                     tabdocs?.push(curPres);  // bcz: Argh! this is annoying.  if multiple documents are pinned, this will get called multiple times before the presentation view is drawn.  Thus it won't be in the tabdocs list and it will get created multple times.  so need to explicilty add the presbox to the list of open tabs
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 3a29d9adf..ca71c76a9 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -335,7 +335,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     navigateToView = (targetDoc: Doc, activeItem: Doc) => {
         clearTimeout(this._navTimer);
         const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
+        if (bestTarget) console.log(bestTarget.title, bestTarget.type);
+        else console.log("no best target");
         bestTarget && runInAction(() => {
+            console.log(bestTarget.title, bestTarget.type);
             if (bestTarget.type === DocumentType.PDF || bestTarget.type === DocumentType.WEB || bestTarget.type === DocumentType.RTF || bestTarget._viewType === CollectionViewType.Stacking) {
                 bestTarget._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
                 bestTarget._scrollTop = activeItem.presPinViewScroll;
@@ -417,6 +420,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
         // After navigating to the document, if it is added as a presPinView then it will
         // adjust the pan and scale to that of the pinView when it was added.
         if (activeItem.presPinView) {
+            console.log(targetDoc.title);
+            console.log("presPinView in PresBox.tsx:420");
             // if targetDoc is not displayed but one of its aliases is, then we need to modify that alias, not the original target
             this.navigateToView(targetDoc, activeItem);
         }
-- 
cgit v1.2.3-70-g09d2


From 0371242941dfdd1d689d0097140b203bb0b24dea Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 5 Jun 2022 20:16:02 -0400
Subject: fixed presentations to allow pinning a clip of audio.  fixed
 TabDocViews to be added properly to DocumentManager.  fixed presentations to
 allow groupWithUp to work in tree/stacking view modes.  f

---
 src/client/views/collections/TabDocView.tsx | 3 +++
 src/client/views/nodes/AudioBox.tsx         | 1 -
 src/client/views/nodes/trails/PresBox.tsx   | 4 ++--
 3 files changed, 5 insertions(+), 3 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 ad01be3a3..dab3d490d 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -265,6 +265,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         //     ({ selected, title }) => title && (title.style.backgroundColor = selected ? "white" : ""),
         //     { fireImmediately: true });
     }
+    componentDidUpdate() {
+        this._view && DocumentManager.Instance.AddView(this._view);
+    }
 
     componentWillUnmount() {
         this._tabReaction?.();
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index d97cb6f84..85dfd1e9a 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -611,7 +611,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 renderDepth={this.props.renderDepth + 1}
                 startTag={"_timecodeToShow" /* audioStart */}
                 endTag={"_timecodeToHide" /* audioEnd */}
-                focus={DocUtils.DefaultFocus}
                 bringToFront={emptyFunction}
                 CollectionView={undefined}
                 playFrom={this.playFrom}
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 18344a11d..e32f2826f 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -319,7 +319,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             }
             if (!group) this._selectedArray.clear();
             this.childDocs[index] && this._selectedArray.set(this.childDocs[index], undefined); //Update selected array
-            if ([CollectionViewType.Stacking, CollectionViewType.Tree].includes(this.layoutDoc._viewType as any) && !group) this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
+            this.navigateToElement(this.childDocs[index]); //Handles movement to element only when presTrail is list
             this.onHideDocument(); //Handles hide after/before
         }
     });
@@ -357,7 +357,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
     navigateToElement = async (curDoc: Doc) => {
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
-        const srcContext = Cast(targetDoc.context, Doc, null);
+        const srcContext = Cast(targetDoc.context, Doc, null) ?? Cast(Cast(targetDoc.annotationOn, Doc, null)?.context, Doc, null);
         const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
         const collectionDocView = presCollection ? DocumentManager.Instance.getDocumentView(presCollection) : undefined;
         const includesDoc: boolean = DocListCast(presCollection?.data).includes(targetDoc);
-- 
cgit v1.2.3-70-g09d2


From f8840672a7bcb3f337d8e50098f374a1b2d441ce Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 8 Jun 2022 01:17:24 -0400
Subject: added ability to make thumbnails of dashboards. started to cleanup
 dockingView/goldenlayout undo event handling.  cleaned up tab doc list in
 docking view.  made titles editable again in treeview.  fixed overlay view to
 work with image docs etc by setting top/left in css

---
 src/client/documents/Documents.ts                  |  6 +--
 src/client/goldenLayout.js                         |  2 +-
 src/client/util/CurrentUserUtils.ts                | 26 ++++++++---
 src/client/views/DocumentButtonBar.tsx             | 53 ++++++++++------------
 src/client/views/MainView.tsx                      | 12 +----
 src/client/views/OverlayView.scss                  |  2 +
 src/client/views/OverlayView.tsx                   |  2 +-
 .../views/collections/CollectionDockingView.tsx    | 21 ++++++---
 src/client/views/collections/TabDocView.tsx        | 28 ++++--------
 src/client/views/collections/TreeView.tsx          |  4 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 45 ++++++++++--------
 src/client/views/nodes/WebBoxRenderer.js           |  4 +-
 src/client/views/topbar/TopBar.tsx                 |  6 +--
 13 files changed, 108 insertions(+), 103 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 817478b2f..acc1e341a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -671,9 +671,9 @@ export namespace Docs {
             return viewDoc;
         }
 
-        export function ImageDocument(url: string, options: DocumentOptions = {}) {
-            const imgField = new ImageField(url);
-            return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(url), ...options });
+        export function ImageDocument(url: string|ImageField, options: DocumentOptions = {}) {
+            const imgField =  url instanceof ImageField ? url : new ImageField(url);
+            return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(imgField.url.href), ...options });
         }
 
         export function PresDocument(options: DocumentOptions = {}) {
diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js
index 82b10608d..4735f216f 100644
--- a/src/client/goldenLayout.js
+++ b/src/client/goldenLayout.js
@@ -1431,7 +1431,7 @@
             this.root.callDownwards('_$init');
 
             if (config.maximisedItemId === '__glMaximised') {
-                this.root.getItemsById(config.maximisedItemId)[0].toggleMaximise();
+                this.root.getItemsById(config.maximisedItemId)[0]?.toggleMaximise();
             }
         },
 
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 51bfdbbd2..885679b64 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -8,7 +8,7 @@ import { PrefetchProxy } from "../../fields/Proxy";
 import { RichTextField } from "../../fields/RichTextField";
 import { ComputedField, ScriptField } from "../../fields/ScriptField";
 import { BoolCast, Cast, DateCast, NumCast, PromiseValue, StrCast } from "../../fields/Types";
-import { nullAudio } from "../../fields/URLField";
+import { ImageField, nullAudio } from "../../fields/URLField";
 import { SharingPermissions } from "../../fields/util";
 import { Utils } from "../../Utils";
 import { DocServer } from "../DocServer";
@@ -22,11 +22,10 @@ import { TreeView } from "../views/collections/TreeView";
 import { Colors } from "../views/global/globalEnums";
 import { MainView } from "../views/MainView";
 import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox";
-import { LabelBox } from "../views/nodes/LabelBox";
 import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView";
 import { OverlayView } from "../views/OverlayView";
 import { DocumentManager } from "./DocumentManager";
-import { DragManager, dropActionType } from "./DragManager";
+import { DragManager } from "./DragManager";
 import { makeTemplate, MakeTemplate } from "./DropConverter";
 import { HistoryUtil } from "./History";
 import { LinkManager } from "./LinkManager";
@@ -1185,9 +1184,24 @@ export class CurrentUserUtils {
     }
 
     public static async snapshotDashboard(userDoc: Doc) {
-        const copy = await CollectionDockingView.Copy(CurrentUserUtils.ActiveDashboard);
-        Doc.AddDocToList(Cast(userDoc.myDashboards, Doc, null), "data", copy);
-        CurrentUserUtils.openDashboard(userDoc, copy);
+        const docView = CollectionDockingView.Instance.props.DocumentView?.();
+        const content = docView?.ContentDiv;
+        if (docView && content) {
+            const _width = Number(getComputedStyle(content).width.replace("px",""));
+            const _height = Number(getComputedStyle(content).height.replace("px",""));
+            CollectionFreeFormView.UpdateIcon(
+                docView.layoutDoc[Id] + "-icon" + (new Date()).getTime(),
+                content,
+                _width, _height,
+                _width, _height, 0,
+                (iconFile, _nativeWidth, _nativeHeight) => {
+                    const img = Docs.Create.ImageDocument(new ImageField(iconFile), { title: docView.rootDoc.title+"-icon", _width, _height, _nativeWidth, _nativeHeight});
+                    const proto = Cast(img.proto, Doc, null)!;
+                    proto["data-nativeWidth"] = _width;
+                    proto["data-nativeHeight"] = _height;
+                    docView.dataDoc.thumb = img;
+                });
+        }
     }
 
     public static createNewDashboard = async (userDoc: Doc, id?: string) => {
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index c0645f0ab..103734b9b 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -213,34 +213,31 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
     @undoBatch
     @action
     pinWithView = (targetDoc: Doc) => {
-        if (targetDoc) {
-            TabDocView.PinDoc(targetDoc);
-            setTimeout(() => {
-                const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
-                const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetDoc.type as any) || targetDoc._viewType === CollectionViewType.Stacking;
-                const pannable: boolean = ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG);
-                if (scrollable) {
-                    const scroll = targetDoc._scrollTop;
-                    activeDoc.presPinView = true;
-                    activeDoc.presPinViewScroll = scroll;
-                } else if ([DocumentType.AUDIO, DocumentType.VID].includes(targetDoc.type as any)) {
-                    activeDoc.presPinView = true;
-                    activeDoc.presStartTime = targetDoc._currentTimecode;
-                    activeDoc.presEndTime = NumCast(targetDoc._currentTimecode) + 0.1;
-                } else if (pannable) {
-                    const x = targetDoc._panX;
-                    const y = targetDoc._panY;
-                    const scale = targetDoc._viewScale;
-                    activeDoc.presPinView = true;
-                    activeDoc.presPinViewX = x;
-                    activeDoc.presPinViewY = y;
-                    activeDoc.presPinViewScale = scale;
-                } else if (targetDoc.type === DocumentType.COMPARISON) {
-                    const width = targetDoc._clipWidth;
-                    activeDoc.presPinClipWidth = width;
-                    activeDoc.presPinView = true;
-                }
-            });
+        const activeDoc = targetDoc && TabDocView.PinDoc(targetDoc);
+        if (activeDoc) {
+            const scrollable = [DocumentType.PDF, DocumentType.RTF, DocumentType.WEB].includes(targetDoc.type as any) || targetDoc._viewType === CollectionViewType.Stacking;
+            const pannable: boolean = ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG);
+            if (scrollable) {
+                const scroll = targetDoc._scrollTop;
+                activeDoc.presPinView = true;
+                activeDoc.presPinViewScroll = scroll;
+            } else if ([DocumentType.AUDIO, DocumentType.VID].includes(targetDoc.type as any)) {
+                activeDoc.presPinView = true;
+                activeDoc.presStartTime = targetDoc._currentTimecode;
+                activeDoc.presEndTime = NumCast(targetDoc._currentTimecode) + 0.1;
+            } else if (pannable) {
+                const x = targetDoc._panX;
+                const y = targetDoc._panY;
+                const scale = targetDoc._viewScale;
+                activeDoc.presPinView = true;
+                activeDoc.presPinViewX = x;
+                activeDoc.presPinViewY = y;
+                activeDoc.presPinViewScale = scale;
+            } else if (targetDoc.type === DocumentType.COMPARISON) {
+                const width = targetDoc._clipWidth;
+                activeDoc.presPinClipWidth = width;
+                activeDoc.presPinView = true;
+            }
         }
     }
 
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index cdf85c905..a30db66e4 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -226,17 +226,7 @@ export class MainView extends React.Component {
         if (received && !this.userDoc) {
             reaction(() => CurrentUserUtils.GuestTarget, target => target && CurrentUserUtils.createNewDashboard(Doc.UserDoc()), { fireImmediately: true });
         } else {
-            if (received && CurrentUserUtils._urlState.sharing) {
-                reaction(() => CollectionDockingView.Instance && CollectionDockingView.Instance.initialized,
-                    initialized => initialized && received && DocServer.GetRefField(received).then(docField => {
-                        if (docField instanceof Doc && docField._viewType !== CollectionViewType.Docking) {
-                            CollectionDockingView.AddSplit(docField, "right");
-                        }
-                    }),
-                );
-            }
-            const activeDash = PromiseValue(this.userDoc.activeDashboard);
-            activeDash.then(dash => {
+            PromiseValue(this.userDoc.activeDashboard).then(dash => {
                 if (dash instanceof Doc) CurrentUserUtils.openDashboard(this.userDoc, dash);
                 else CurrentUserUtils.createNewDashboard(this.userDoc);
             });
diff --git a/src/client/views/OverlayView.scss b/src/client/views/OverlayView.scss
index 555f4298d..f22e68ff5 100644
--- a/src/client/views/OverlayView.scss
+++ b/src/client/views/OverlayView.scss
@@ -46,4 +46,6 @@
 .overlayView-doc {
     z-index: 9002; //so that it appears above chroma 
     position: absolute;
+    top: 0;
+    left: 0;
 }
\ No newline at end of file
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index c3c103b50..f5e686473 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -200,7 +200,7 @@ export class OverlayView extends React.Component {
                     ScreenToLocalTransform={this.docScreenToLocalXf(d)}
                     renderDepth={1}
                     isDocumentActive={returnTrue}
-                    isContentActive={retu}
+                    isContentActive={returnTrue}
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={DocUtils.DefaultFocus}
                     styleProvider={DefaultStyleProvider}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index de2106e4a..5af72b7d1 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -26,6 +26,7 @@ import { CollectionSubView, SubCollectionViewProps } from "./CollectionSubView";
 import { CollectionViewType } from './CollectionView';
 import { TabDocView } from './TabDocView';
 import React = require("react");
+import { SelectionManager } from '../../util/SelectionManager';
 const _global = (window /* browser */ || global /* node */) as any;
 
 @observer
@@ -50,9 +51,8 @@ export class CollectionDockingView extends CollectionSubView() {
     public _flush: UndoManager.Batch | undefined;
     private _ignoreStateChange = "";
     public tabMap: Set<any> = new Set();
-    public get initialized() { return this._goldenLayout !== null; }
     public get HasFullScreen() { return this._goldenLayout._maximisedItem !== null; }
-    @observable private _goldenLayout: any = null;
+    private _goldenLayout: any = null;
 
     constructor(props: SubCollectionViewProps) {
         super(props);
@@ -118,6 +118,7 @@ export class CollectionDockingView extends CollectionSubView() {
 
     @undoBatch
     public static OpenFullScreen(doc: Doc) {
+        SelectionManager.DeselectAll();
         const instance = CollectionDockingView.Instance;
         if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") {
             return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc);
@@ -271,7 +272,7 @@ export class CollectionDockingView extends CollectionSubView() {
         return true;
     }
 
-    async setupGoldenLayout() {
+    setupGoldenLayout = async () => {
         const config = StrCast(this.props.Document.dockingConfig);
         if (config) {
             const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g);
@@ -291,7 +292,7 @@ export class CollectionDockingView extends CollectionSubView() {
             }
             this.tabMap.clear();
             this._goldenLayout?.destroy();
-            runInAction(() => this._goldenLayout = new GoldenLayout(JSON.parse(config)));
+            this._goldenLayout = new GoldenLayout(JSON.parse(config));
             this._goldenLayout.on('tabCreated', this.tabCreated);
             this._goldenLayout.on('tabDestroyed', this.tabDestroyed);
             this._goldenLayout.on('stackCreated', this.stackCreated);
@@ -322,7 +323,7 @@ export class CollectionDockingView extends CollectionSubView() {
                     }
                     this._ignoreStateChange = "";
                 });
-            setTimeout(() => this.setupGoldenLayout(), 0);
+            setTimeout(this.setupGoldenLayout);
             //window.addEventListener('resize', this.onResize); // bcz: would rather add this event to the parent node, but resize events only come from Window
         }
     }
@@ -413,19 +414,25 @@ export class CollectionDockingView extends CollectionSubView() {
         const docs = !docids ? [] : docids.map(id => DocServer.GetCachedRefField(id)).filter(f => f).map(f => f as Doc);
         const changesMade = this.props.Document.dockcingConfig !== json;
         if (changesMade && !this._flush) {
-            this.props.Document.dockingConfig = json;
-            this.props.Document.data = new List<Doc>(docs);
+            UndoManager.RunInBatch(() => {
+                this.props.Document.dockingConfig = json;
+                this.props.Document.data = new List<Doc>(docs);
+            }, "state changed");
         }
         return changesMade;
     }
 
     tabDestroyed = (tab: any) => {
+        const dview = CollectionDockingView.Instance.props.Document;
+        const fieldKey = CollectionDockingView.Instance.props.fieldKey;
+        Doc.RemoveDocFromList(dview, fieldKey, tab.DashDoc);
         this.tabMap.delete(tab);
         tab._disposers && Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
         tab.reactComponents?.forEach((ele: any) => ReactDOM.unmountComponentAtNode(ele));
         this.stateChanged();
     }
     tabCreated = (tab: any) => {
+        this.tabMap.add(tab);
         tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab?.(tab);  // have to explicitly initialize tabs that reuse contents from previous tabs (ie, when dragging a tab around a new tab is created for the old content)
     }
 
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 0141724ea..75a8207dd 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -82,7 +82,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             const iconWrap = document.createElement("div");
             const closeWrap = document.createElement("div");
 
-
             titleEle.size = StrCast(doc.title).length + 3;
             titleEle.value = doc.title;
             titleEle.onkeydown = (e: KeyboardEvent) => {
@@ -185,14 +184,13 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab");
                 });
         }
-        CollectionDockingView.Instance.tabMap.add(tab);
     }
 
     /**
      * Adds a document to the presentation view
      **/
     @action
-    public static async PinDoc(doc: Doc, pinProps?: PinProps) {
+    public static PinDoc(doc: Doc, pinProps?: PinProps) {
         //add this new doc to props.Document
 
         // all docs will be added to the ActivePresentation as stored on CurrentUserUtils
@@ -246,19 +244,14 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 pinDoc.presMovement = PresMovement.None;
             }
             if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
-            const dview = CollectionDockingView.Instance.props.Document;
-            const fieldKey = CollectionDockingView.Instance.props.fieldKey;
-            const tabdocs = await DocListCastAsync(dview[fieldKey]);
-            runInAction(() => {
-                if (!pinProps?.hidePresBox && !tabdocs?.includes(curPres)) {
-                    tabdocs?.push(curPres);  // bcz: Argh! this is annoying.  if multiple documents are pinned, this will get called multiple times before the presentation view is drawn.  Thus it won't be in the tabdocs list and it will get created multple times.  so need to explicilty add the presbox to the list of open tabs
-                    CollectionDockingView.AddSplit(curPres, "right");
-                }
-                PresBox.Instance?._selectedArray.clear();
-                pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array
-                DocumentManager.Instance.jumpToDocument(doc, false, undefined, []);
-                batch.end();
-            });
+            if (!Array.from(CollectionDockingView.Instance.tabMap).map(d => d.DashDoc).includes(curPres)) {
+                CollectionDockingView.AddSplit(curPres, "right");
+                setTimeout(() => DocumentManager.Instance.jumpToDocument(doc, false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things
+            }
+            PresBox.Instance?._selectedArray.clear();
+            pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array
+            setTimeout(batch.end, 500); // need to wait until dockingview (goldenlayout) updates all its structurs
+            return pinDoc;
         }
     }
 
@@ -282,7 +275,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     componentWillUnmount() {
         this._tabReaction?.();
         this._view && DocumentManager.Instance.RemoveView(this._view);
-        this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab);
 
         this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged);
     }
@@ -430,9 +422,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             }} ref={ref => {
                 if (this._mainCont = ref) {
                     if (this._lastTab) {
-                        console.log("DUP tab")
                         this._view && DocumentManager.Instance.RemoveView(this._view);
-                        CollectionDockingView.Instance.tabMap.delete(this._lastTab);
                     }
                     this._lastTab = this.tab;
                     (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index befd2020c..09f05f69a 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -609,10 +609,8 @@ export class TreeView extends React.Component<TreeViewProps> {
         return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
     }
 
-    // TODO: currently doc focus works, but can't seem to edit title
-    // onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptCast(this.doc.treeChildClick));
     onChildClick = () => {
-        return this.props.onChildClick?.() ?? (ScriptField.MakeFunction(`DocFocusOrOpen(self)`)! || this._editTitleScript?.());
+        return this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!);
     }
 
     onChildDoubleClick = () => (!this.props.treeView.outlineMode && this._openScript?.()) || ScriptCast(this.doc.treeChildDoubleClick);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 77cf0fc84..5f927a2a9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1489,7 +1489,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         }));
     }
 
-    replaceCanvases = (oldDiv: HTMLElement, newDiv: HTMLElement) => {
+    static replaceCanvases(oldDiv: HTMLElement, newDiv: HTMLElement) {
         if (oldDiv.childNodes && newDiv) {
             for (let i = 0; i < oldDiv.childNodes.length; i++) {
                 this.replaceCanvases(oldDiv.childNodes[i] as HTMLElement, newDiv.childNodes[i] as HTMLElement);
@@ -1508,32 +1508,39 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         }
     }
 
-    updateIcon = () => {
-        const docViewContent = this.props.docViewPath().lastElement().ContentDiv!;
+    updateIcon = () => CollectionFreeFormView.UpdateIcon(
+        this.layoutDoc[Id] + "-icon" + (new Date()).getTime(),
+        this.props.docViewPath().lastElement().ContentDiv!,
+        this.layoutDoc[WidthSym](), this.layoutDoc[HeightSym](), 
+        this.props.PanelWidth(), this.props.PanelHeight(), 0, 
+        (iconFile, nativeWidth, nativeHeight) => {
+                    this.dataDoc.icon = new ImageField(iconFile);
+                    this.dataDoc["icon-nativeWidth"] = nativeWidth;
+                    this.dataDoc["icon-nativeHeight"] = nativeHeight;
+        });
+
+    public static UpdateIcon(filename:string, docViewContent:HTMLElement, width: number, height: number, 
+        panelWidth:number, panelHeight: number, scrollTop:number, cb:(iconFile:string, nativeWidth:number, nativeHeight:number) => any) {
         const newDiv = docViewContent.cloneNode(true) as HTMLDivElement;
-        newDiv.style.width = (this.layoutDoc[WidthSym]()).toString();
-        newDiv.style.height = (this.layoutDoc[HeightSym]()).toString();
+        newDiv.style.width = width.toString();
+        newDiv.style.height = height.toString();
         this.replaceCanvases(docViewContent, newDiv);
-        const htmlString = this._mainCont && new XMLSerializer().serializeToString(newDiv);
-        const nativeWidth = this.layoutDoc[WidthSym]();
-        const nativeHeight = this.layoutDoc[HeightSym]();
-
+        const htmlString = new XMLSerializer().serializeToString(newDiv);
+        const nativeWidth = width;
+        const nativeHeight = height;
         CreateImage(
-            "",
+            Utils.prepend(""),
             document.styleSheets,
             htmlString,
             nativeWidth,
-            nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(),
-            NumCast(this.layoutDoc._scrollTop)
+            nativeWidth * panelHeight / panelWidth,
+            scrollTop
         ).then
             ((data_url: any) => {
-                VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true, this.layoutDoc[Id] + "-icon").then(
-                    returnedfilename => setTimeout(action(() => {
-
-                        this.dataDoc.icon = new ImageField(returnedfilename);
-                        this.dataDoc["icon-nativeWidth"] = nativeWidth;
-                        this.dataDoc["icon-nativeHeight"] = nativeHeight;
-                    }), 500));
+                VideoBox.convertDataUri(data_url, filename).then(
+                    returnedfilename => setTimeout(() => {
+                        cb(returnedfilename as string, nativeWidth, nativeHeight);
+                    }, 500));
             })
             .catch(function (error: any) {
                 console.error('oops, something went wrong!', error);
diff --git a/src/client/views/nodes/WebBoxRenderer.js b/src/client/views/nodes/WebBoxRenderer.js
index d9524dd6e..f3f1bcf5c 100644
--- a/src/client/views/nodes/WebBoxRenderer.js
+++ b/src/client/views/nodes/WebBoxRenderer.js
@@ -214,8 +214,8 @@ var ForeignHtmlRenderer = function (styleSheets) {
                 .replace(/noscript/g, "div").replace(/<div class="mediaset"><\/div>/g, "")  // when scripting isn't available (ie, rendering web pages here), <noscript> tags should become <div>'s.  But for Brown CS, there's a layout problem if you leave the empty <mediaset> tag
                 .replace(/<link[^>]*>/g, "")  // don't need to keep any linked style sheets because we've already processed all style sheets above
                 .replace(/srcset="([^ "]*)[^"]*"/g, "src=\"$1\""); // instead of converting each item in the srcset to a data url, just convert the first one and use that
-            let urlsFoundInHtml = getImageUrlsFromFromHtml(contentHtml);
-            const fetchedResources = await getMultipleResourcesAsBase64(webUrl, urlsFoundInHtml);
+            let urlsFoundInHtml = getImageUrlsFromFromHtml(contentHtml).filter(url => !url.startsWith("data:"));
+            const fetchedResources = webUrl ? await getMultipleResourcesAsBase64(webUrl, urlsFoundInHtml) : [];
             for (let i = 0; i < fetchedResources.length; i++) {
                 const r = fetchedResources[i];
                 if (r.resourceUrl) {
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index be248ab92..e486bcb52 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -48,7 +48,7 @@ export class TopBar extends React.Component {
                                 await CurrentUserUtils.createNewDashboard(Doc.UserDoc());
                                 batch.end();
                             }}>
-                                {"New"}<FontAwesomeIcon icon="plus" />
+                                New<FontAwesomeIcon icon="plus" />
                             </div>
                             </Tooltip>
                             <Tooltip title={<div className="dash-tooltip">Work on a copy of the dashboard layout</div>} placement="bottom">
@@ -57,12 +57,12 @@ export class TopBar extends React.Component {
                                     await CurrentUserUtils.snapshotDashboard(Doc.UserDoc());
                                     batch.end();
                                 }}>
-                                    {"Snapshot"}<FontAwesomeIcon icon="camera" />
+                                    Snapshot<FontAwesomeIcon icon="camera" />
                                 </div>
                             </Tooltip>
                             <Tooltip title={<div className="dash-tooltip">Browsing mode for directly navigating to documents</div>} placement="bottom">
                                 <div className="topbar-icon" style={{ background: MainView.Instance._exploreMode ? Colors.LIGHT_BLUE : undefined }} onClick={action(() => MainView.Instance._exploreMode = !MainView.Instance._exploreMode)}>
-                                    {"Explore"}<FontAwesomeIcon icon="map" />
+                                    Explore<FontAwesomeIcon icon="map" />
                                 </div>
                             </Tooltip>
                         </div>
-- 
cgit v1.2.3-70-g09d2


From 58c2085ceb20cd2527ac69088efb7a46b20f8434 Mon Sep 17 00:00:00 2001
From: Jenny Yu <jennyyu212@outlook.com>
Date: Wed, 8 Jun 2022 00:49:12 -0700
Subject: styling: pres element box

---
 src/client/views/DocumentDecorations.tsx          |  44 +-
 src/client/views/collections/TabDocView.tsx       | 904 +++++++++++-----------
 src/client/views/nodes/trails/PresElementBox.scss | 338 ++++----
 src/client/views/nodes/trails/PresElementBox.tsx  |  20 +-
 4 files changed, 656 insertions(+), 650 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 0e9bf50fc..b666b5977 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -153,29 +153,29 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
       _deleteAfterIconify = false;
       _iconifyBatch: UndoManager.Batch | undefined;
       onCloseClick = (forceDeleteOrIconify: boolean | undefined) => {
-            if (this.canDelete) {
-                  const views = SelectionManager.Views().slice().filter(v => v);
-                  if (forceDeleteOrIconify === false && this._iconifyBatch) return;
-                  this._deleteAfterIconify = forceDeleteOrIconify || this._iconifyBatch ? true : false;
-                  if (!this._iconifyBatch) {
-                        this._iconifyBatch = UndoManager.StartBatch("iconifying");
-                  } else {
-                        forceDeleteOrIconify = false; // can't force immediate close in the middle of iconifying -- have to wait until iconifying completes
-                  }
-                  var iconifyingCount = views.length;
-                  const finished = action((force?: boolean) => {
-                        if ((force || --iconifyingCount === 0) && this._iconifyBatch) {
-                              if (this._deleteAfterIconify) {
-                                    views.forEach(iconView => iconView.props.removeDocument?.(iconView.props.Document));
-                                    SelectionManager.DeselectAll();
-                              }
-                              this._iconifyBatch?.end();
-                              this._iconifyBatch = undefined;
-                        }
-                  });
-                  if (forceDeleteOrIconify) finished(forceDeleteOrIconify);
-                  else if (!this._deleteAfterIconify) views.forEach(dv => dv.iconify(finished));
+
+            const views = SelectionManager.Views().slice().filter(v => v);
+            if (forceDeleteOrIconify === false && this._iconifyBatch) return;
+            this._deleteAfterIconify = forceDeleteOrIconify || this._iconifyBatch ? true : false;
+            if (!this._iconifyBatch) {
+                  this._iconifyBatch = UndoManager.StartBatch("iconifying");
+            } else {
+                  forceDeleteOrIconify = false; // can't force immediate close in the middle of iconifying -- have to wait until iconifying completes
             }
+            var iconifyingCount = views.length;
+            const finished = action((force?: boolean) => {
+                  if ((force || --iconifyingCount === 0) && this._iconifyBatch) {
+                        if (this._deleteAfterIconify) {
+                              views.forEach(iconView => iconView.props.removeDocument?.(iconView.props.Document));
+                              SelectionManager.DeselectAll();
+                        }
+                        this._iconifyBatch?.end();
+                        this._iconifyBatch = undefined;
+                  }
+            });
+            if (forceDeleteOrIconify) finished(forceDeleteOrIconify);
+            else if (!this._deleteAfterIconify) views.forEach(dv => dv.iconify(finished));
+
       }
       onMaximizeDown = (e: React.PointerEvent) => {
             setupMoveUpEvents(this, e, () => {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 2b78b20ea..39add0534 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -38,490 +38,490 @@ import React = require("react");
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
-    documentId: FieldId;
-    glContainer: any;
+      documentId: FieldId;
+      glContainer: any;
 }
 @observer
 export class TabDocView extends React.Component<TabDocViewProps> {
-    _mainCont: HTMLDivElement | null = null;
-    _tabReaction: IReactionDisposer | undefined;
-    @observable _activated: boolean = false;
-    @observable _panelWidth = 0;
-    @observable _panelHeight = 0;
-    @observable _isActive: boolean = false;
-    @observable _document: Doc | undefined;
-    @observable _view: DocumentView | undefined;
+      _mainCont: HTMLDivElement | null = null;
+      _tabReaction: IReactionDisposer | undefined;
+      @observable _activated: boolean = false;
+      @observable _panelWidth = 0;
+      @observable _panelHeight = 0;
+      @observable _isActive: boolean = false;
+      @observable _document: Doc | undefined;
+      @observable _view: DocumentView | undefined;
 
-    @computed get layoutDoc() { return this._document && Doc.Layout(this._document); }
-    @computed get tabColor() { return StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor))); }
-    @computed get tabTextColor() { return this._document?.type === DocumentType.PRES ? "black" : StrCast(this._document?._color, StrCast(this._document?.color, DefaultStyleProvider(this._document, undefined, StyleProp.Color))); }
-    // @computed get renderBounds() {
-    //     const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0];
-    //     const xbounds = bounds[2] - bounds[0];
-    //     const ybounds = bounds[3] - bounds[1];
-    //     const dim = Math.max(xbounds, ybounds);
-    //     return { l: bounds[0] + xbounds / 2 - dim / 2, t: bounds[1] + ybounds / 2 - dim / 2, cx: bounds[0] + xbounds / 2, cy: bounds[1] + ybounds / 2, dim };
-    // }
+      @computed get layoutDoc() { return this._document && Doc.Layout(this._document); }
+      @computed get tabColor() { return StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, DefaultStyleProvider(this._document, undefined, StyleProp.BackgroundColor))); }
+      @computed get tabTextColor() { return this._document?.type === DocumentType.PRES ? "black" : StrCast(this._document?._color, StrCast(this._document?.color, DefaultStyleProvider(this._document, undefined, StyleProp.Color))); }
+      // @computed get renderBounds() {
+      //     const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0];
+      //     const xbounds = bounds[2] - bounds[0];
+      //     const ybounds = bounds[3] - bounds[1];
+      //     const dim = Math.max(xbounds, ybounds);
+      //     return { l: bounds[0] + xbounds / 2 - dim / 2, t: bounds[1] + ybounds / 2 - dim / 2, cx: bounds[0] + xbounds / 2, cy: bounds[1] + ybounds / 2, dim };
+      // }
 
-    get stack() { return (this.props as any).glContainer.parent.parent; }
-    get tab() { return (this.props as any).glContainer.tab; }
-    get view() { return this._view; }
+      get stack() { return (this.props as any).glContainer.parent.parent; }
+      get tab() { return (this.props as any).glContainer.tab; }
+      get view() { return this._view; }
 
-    @action
-    init = (tab: any, doc: Opt<Doc>) => {
-        if (tab.contentItem === tab.header.parent.getActiveContentItem()) this._activated = true;
-        if (tab.DashDoc !== doc && doc && tab.hasOwnProperty("contentItem") && tab.contentItem.config.type !== "stack") {
-            tab._disposers = {} as { [name: string]: IReactionDisposer };
-            tab.contentItem.config.fixed && (tab.contentItem.parent.config.fixed = true);
-            tab.DashDoc = doc;
-            CollectionDockingView.Instance.tabMap.add(tab);
-            const iconType: IconProp = Doc.toIcon(doc);
-            // setup the title element and set its size according to the # of chars in the title.  Show the full title when clicked.
-            const titleEle = tab.titleElement[0];
-            const iconWrap = document.createElement("div");
-            const closeWrap = document.createElement("div");
+      @action
+      init = (tab: any, doc: Opt<Doc>) => {
+            if (tab.contentItem === tab.header.parent.getActiveContentItem()) this._activated = true;
+            if (tab.DashDoc !== doc && doc && tab.hasOwnProperty("contentItem") && tab.contentItem.config.type !== "stack") {
+                  tab._disposers = {} as { [name: string]: IReactionDisposer };
+                  tab.contentItem.config.fixed && (tab.contentItem.parent.config.fixed = true);
+                  tab.DashDoc = doc;
+                  CollectionDockingView.Instance.tabMap.add(tab);
+                  const iconType: IconProp = Doc.toIcon(doc);
+                  // setup the title element and set its size according to the # of chars in the title.  Show the full title when clicked.
+                  const titleEle = tab.titleElement[0];
+                  const iconWrap = document.createElement("div");
+                  const closeWrap = document.createElement("div");
 
 
-            titleEle.size = StrCast(doc.title).length + 3;
-            titleEle.value = doc.title;
-            titleEle.onkeydown = (e: KeyboardEvent) => {
-                e.stopPropagation();
-            };
-            titleEle.onchange = undoBatch(action((e: any) => {
-                titleEle.size = e.currentTarget.value.length + 3;
-                Doc.GetProto(doc).title = e.currentTarget.value;
-            }));
+                  titleEle.size = StrCast(doc.title).length + 3;
+                  titleEle.value = doc.title;
+                  titleEle.onkeydown = (e: KeyboardEvent) => {
+                        e.stopPropagation();
+                  };
+                  titleEle.onchange = undoBatch(action((e: any) => {
+                        titleEle.size = e.currentTarget.value.length + 3;
+                        Doc.GetProto(doc).title = e.currentTarget.value;
+                  }));
 
-            const dragBtnDown = (e: React.PointerEvent) => {
-                setupMoveUpEvents(this, e, e => !e.defaultPrevented && DragManager.StartDocumentDrag([iconWrap], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY), returnFalse, emptyFunction);
-            };
+                  const dragBtnDown = (e: React.PointerEvent) => {
+                        setupMoveUpEvents(this, e, e => !e.defaultPrevented && DragManager.StartDocumentDrag([iconWrap], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY), returnFalse, emptyFunction);
+                  };
 
 
-            if (tab.element[0].children[1].children.length === 1) {
-                iconWrap.className = "lm_iconWrap";
-                iconWrap.id = "lm_iconWrap";
-                closeWrap.className = "lm_iconWrap";
-                closeWrap.id = "lm_closeWrap";
-                closeWrap.onclick = (e: MouseEvent) => {
-                    tab.header.parent.contentItem.remove();
-                    Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", tab.DashDoc);
-                    Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", tab.DashDoc, undefined, true, true);
-                };
-                const docIcon = <FontAwesomeIcon onPointerDown={dragBtnDown} icon={iconType} />;
-                const closeIcon = <FontAwesomeIcon icon={"times"} />;
-                ReactDOM.render(docIcon, iconWrap);
-                ReactDOM.render(closeIcon, closeWrap);
-                // tab.element[0].append(closeWrap);
-                tab.element[0].prepend(iconWrap);
-                tab._disposers.layerDisposer = reaction(() => ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }),
-                    ({ layer, color }) => {
-                        // console.log("TabDocView: " + this.tabColor);
-                        // console.log("lightOrDark: " + lightOrDark(this.tabColor));
-                        const textColor = lightOrDark(this.tabColor); //not working with StyleProp.Color
-                        titleEle.style.color = textColor;
-                        titleEle.style.backgroundColor = "transparent";
-                        iconWrap.style.color = textColor;
-                        closeWrap.style.color = textColor;
-                        moreInfoDrag.style.backgroundColor = textColor;
-                        tab.element[0].style.background = !layer ? color : "dimgrey";
-                    }, { fireImmediately: true });
-            }
-            // shifts the focus to this tab when another tab is dragged over it
-            tab.element[0].onmouseenter = (e: MouseEvent) => {
-                if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) {
-                    tab.header.parent.setActiveContentItem(tab.contentItem);
-                    tab.setActive(true);
-                }
-            };
-
+                  if (tab.element[0].children[1].children.length === 1) {
+                        iconWrap.className = "lm_iconWrap";
+                        iconWrap.id = "lm_iconWrap";
+                        closeWrap.className = "lm_iconWrap";
+                        closeWrap.id = "lm_closeWrap";
+                        closeWrap.onclick = (e: MouseEvent) => {
+                              tab.header.parent.contentItem.remove();
+                              Doc.AddDocToList(CurrentUserUtils.MyHeaderBarDoc, "data", tab.DashDoc);
+                              Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", tab.DashDoc, undefined, true, true);
+                        };
+                        const docIcon = <FontAwesomeIcon onPointerDown={dragBtnDown} icon={iconType} />;
+                        const closeIcon = <FontAwesomeIcon icon={"times"} />;
+                        ReactDOM.render(docIcon, iconWrap);
+                        ReactDOM.render(closeIcon, closeWrap);
+                        // tab.element[0].append(closeWrap);
+                        tab.element[0].prepend(iconWrap);
+                        tab._disposers.layerDisposer = reaction(() => ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }),
+                              ({ layer, color }) => {
+                                    // console.log("TabDocView: " + this.tabColor);
+                                    // console.log("lightOrDark: " + lightOrDark(this.tabColor));
+                                    const textColor = lightOrDark(this.tabColor); //not working with StyleProp.Color
+                                    titleEle.style.color = textColor;
+                                    titleEle.style.backgroundColor = "transparent";
+                                    iconWrap.style.color = textColor;
+                                    closeWrap.style.color = textColor;
+                                    moreInfoDrag.style.backgroundColor = textColor;
+                                    tab.element[0].style.background = !layer ? color : "dimgrey";
+                              }, { fireImmediately: true });
+                  }
+                  // shifts the focus to this tab when another tab is dragged over it
+                  tab.element[0].onmouseenter = (e: MouseEvent) => {
+                        if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) {
+                              tab.header.parent.setActiveContentItem(tab.contentItem);
+                              tab.setActive(true);
+                        }
+                  };
 
-            // 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);
-                    else this._activated = true;
-                    if (Date.now() - titleEle.lastClick < 1000) titleEle.select();
-                    titleEle.lastClick = Date.now();
-                    (document.activeElement !== titleEle) && titleEle.focus();
-                }
-            });
-            tab._disposers.selectionDisposer = reaction(() => SelectionManager.Views().some(v => v.topMost && v.props.Document === doc),
-                action((selected) => {
-                    if (selected) this._activated = true;
-                    const toggle = tab.element[0].children[1].children[0] as HTMLInputElement;
-                    selected && tab.contentItem !== tab.header.parent.getActiveContentItem() &&
-                        UndoManager.RunInBatch(() => tab.header.parent.setActiveContentItem(tab.contentItem), "tab switch");
-                    // toggle.style.fontWeight = selected ? "bold" : "";
-                    // toggle.style.textTransform = selected ? "uppercase" : "";
-                }));
 
-            //attach the selection doc buttons menu to the drag handle
-            const stack: HTMLDivElement = tab.contentItem.parent;
-            const header: HTMLDivElement = tab;
-            stack.onscroll = action((e: any) => {
-                console.log('scrolling...');
-            });
-            const moreInfoDrag = document.createElement("div");
-            moreInfoDrag.className = "lm_iconWrap";
-            tab._disposers.buttonDisposer = reaction(() => this.view, view =>
-                view && [ReactDOM.render(<span><CollectionDockingViewMenu views={() => [view]} Stack={stack} /></span>, moreInfoDrag), tab._disposers.buttonDisposer?.()],
-                { fireImmediately: true });
-            // tab.reactComponents = [moreInfoDrag];
-            // tab.element[0].children[3].before(moreInfoDrag);
+                  // 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);
+                              else this._activated = true;
+                              if (Date.now() - titleEle.lastClick < 1000) titleEle.select();
+                              titleEle.lastClick = Date.now();
+                              (document.activeElement !== titleEle) && titleEle.focus();
+                        }
+                  });
+                  tab._disposers.selectionDisposer = reaction(() => SelectionManager.Views().some(v => v.topMost && v.props.Document === doc),
+                        action((selected) => {
+                              if (selected) this._activated = true;
+                              const toggle = tab.element[0].children[1].children[0] as HTMLInputElement;
+                              selected && tab.contentItem !== tab.header.parent.getActiveContentItem() &&
+                                    UndoManager.RunInBatch(() => tab.header.parent.setActiveContentItem(tab.contentItem), "tab switch");
+                              // toggle.style.fontWeight = selected ? "bold" : "";
+                              // toggle.style.textTransform = selected ? "uppercase" : "";
+                        }));
 
-            // highlight the tab when the tab document is brushed in any part of the UI
-            tab._disposers.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => {
-                //titleEle.value = title;
-                // titleEle.style.padding = degree ? 0 : 2;
-                // titleEle.style.border = `${["gray", "gray", "gray"][degree]} ${["none", "dashed", "solid"][degree]} 2px`;
-            }, { fireImmediately: true });
+                  //attach the selection doc buttons menu to the drag handle
+                  const stack: HTMLDivElement = tab.contentItem.parent;
+                  const header: HTMLDivElement = tab;
+                  stack.onscroll = action((e: any) => {
+                        console.log('scrolling...');
+                  });
+                  const moreInfoDrag = document.createElement("div");
+                  moreInfoDrag.className = "lm_iconWrap";
+                  tab._disposers.buttonDisposer = reaction(() => this.view, view =>
+                        view && [ReactDOM.render(<span><CollectionDockingViewMenu views={() => [view]} Stack={stack} /></span>, moreInfoDrag), tab._disposers.buttonDisposer?.()],
+                        { fireImmediately: true });
+                  // tab.reactComponents = [moreInfoDrag];
+                  // tab.element[0].children[3].before(moreInfoDrag);
 
-            // clean up the tab when it is closed
-            tab.closeElement.off('click') //unbind the current click handler
-                .click(function () {
-                    Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
-                    SelectionManager.DeselectAll();
-                    UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab");
-                });
-        }
-    }
+                  // highlight the tab when the tab document is brushed in any part of the UI
+                  tab._disposers.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => {
+                        //titleEle.value = title;
+                        // titleEle.style.padding = degree ? 0 : 2;
+                        // titleEle.style.border = `${["gray", "gray", "gray"][degree]} ${["none", "dashed", "solid"][degree]} 2px`;
+                  }, { fireImmediately: true });
 
-    /**
-     * Adds a document to the presentation view
-     **/
-    @action
-    public static async PinDoc(doc: Doc, pinProps?: PinProps) {
-        if (pinProps?.unpin) console.log('TODO: Remove UNPIN from this location');
-        //add this new doc to props.Document
-        const curPres = CurrentUserUtils.ActivePresentation;
-        if (curPres) {
-            if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; }
-            const batch = UndoManager.StartBatch("pinning doc");
-            const pinDoc = Doc.MakeAlias(doc);
-            pinDoc.presentationTargetDoc = doc;
-            pinDoc.title = doc.title + " - Slide";
-            pinDoc.data = new List<Doc>();  // the children of the alias' layout are the presentation slide children.  the alias' 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.presMovement = PresMovement.Zoom;
-            pinDoc.groupWithUp = false;
-            pinDoc.context = 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.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
-            pinDoc.treeViewHeaderWidth = "100%"; // forces the header to grow to be the same size as its largest sibling.
-            pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc.
-            pinDoc.treeViewFieldKey = "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.treeViewExpandedView = "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.treeViewGrowsHorizontally = true;// the document expands horizontally when displayed as a tree view header  
-            pinDoc.treeViewHideHeaderIfTemplate = true;  // this will force the document to render itself as the tree view header
-            const presArray: Doc[] = PresBox.Instance?.sortArray();
-            const size: number = PresBox.Instance?._selectedArray.size;
-            const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
-            const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], null);
-            Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
-            if (!pinProps?.audioRange && duration !== undefined) {
-                pinDoc.mediaStart = "manual";
-                pinDoc.mediaStop = "manual";
-                pinDoc.presStartTime = NumCast(doc.clipStart);
-                pinDoc.presEndTime = NumCast(doc.clipEnd, duration);
+                  // clean up the tab when it is closed
+                  tab.closeElement.off('click') //unbind the current click handler
+                        .click(function () {
+                              Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
+                              SelectionManager.DeselectAll();
+                              UndoManager.RunInBatch(() => tab.contentItem.remove(), "delete tab");
+                        });
             }
-            //save position
-            if (pinProps?.setPosition || pinDoc.isInkMask) {
-                pinDoc.setPosition = true;
-                pinDoc.y = doc.y;
-                pinDoc.x = doc.x;
-                pinDoc.presHideAfter = true;
-                pinDoc.presHideBefore = true;
-                pinDoc.title = doc.title + " (move)";
-                pinDoc.presMovement = PresMovement.None;
-            }
-            if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
-            const dview = CollectionDockingView.Instance.props.Document;
-            const fieldKey = CollectionDockingView.Instance.props.fieldKey;
-            const sublists = DocListCast(dview[fieldKey]);
-            const tabs = Cast(sublists[0], Doc, null);
-            const tabdocs = await DocListCastAsync(tabs?.data);
-            runInAction(() => {
-                if (!pinProps?.hidePresBox && !tabdocs?.includes(curPres)) {
-                    tabdocs?.push(curPres);  // bcz: Argh! this is annoying.  if multiple documents are pinned, this will get called multiple times before the presentation view is drawn.  Thus it won't be in the tabdocs list and it will get created multple times.  so need to explicilty add the presbox to the list of open tabs
-                    CollectionDockingView.AddSplit(curPres, "right");
-                }
-                PresBox.Instance?._selectedArray.clear();
-                pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array
-                DocumentManager.Instance.jumpToDocument(doc, false, undefined, []);
-                batch.end();
-            });
-        }
-    }
+      }
 
-    componentDidMount() {
-        new _global.ResizeObserver(action((entries: any) => {
-            for (const entry of entries) {
-                this._panelWidth = entry.contentRect.width;
-                this._panelHeight = entry.contentRect.height;
+      /**
+       * Adds a document to the presentation view
+       **/
+      @action
+      public static async PinDoc(doc: Doc, pinProps?: PinProps) {
+            if (pinProps?.unpin) console.log('TODO: Remove UNPIN from this location');
+            //add this new doc to props.Document
+            const curPres = CurrentUserUtils.ActivePresentation;
+            if (curPres) {
+                  if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; }
+                  const batch = UndoManager.StartBatch("pinning doc");
+                  const pinDoc = Doc.MakeAlias(doc);
+                  pinDoc.presentationTargetDoc = doc;
+                  pinDoc.title = doc.title;
+                  pinDoc.data = new List<Doc>();  // the children of the alias' layout are the presentation slide children.  the alias' 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.presMovement = PresMovement.Zoom;
+                  pinDoc.groupWithUp = false;
+                  pinDoc.context = 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.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area
+                  pinDoc.treeViewHeaderWidth = "100%"; // forces the header to grow to be the same size as its largest sibling.
+                  pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc.
+                  pinDoc.treeViewFieldKey = "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.treeViewExpandedView = "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.treeViewGrowsHorizontally = true;// the document expands horizontally when displayed as a tree view header  
+                  pinDoc.treeViewHideHeaderIfTemplate = true;  // this will force the document to render itself as the tree view header
+                  const presArray: Doc[] = PresBox.Instance?.sortArray();
+                  const size: number = PresBox.Instance?._selectedArray.size;
+                  const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
+                  const duration = NumCast(doc[`${Doc.LayoutFieldKey(pinDoc)}-duration`], null);
+                  Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
+                  if (!pinProps?.audioRange && duration !== undefined) {
+                        pinDoc.mediaStart = "manual";
+                        pinDoc.mediaStop = "manual";
+                        pinDoc.presStartTime = NumCast(doc.clipStart);
+                        pinDoc.presEndTime = NumCast(doc.clipEnd, duration);
+                  }
+                  //save position
+                  if (pinProps?.setPosition || pinDoc.isInkMask) {
+                        pinDoc.setPosition = true;
+                        pinDoc.y = doc.y;
+                        pinDoc.x = doc.x;
+                        pinDoc.presHideAfter = true;
+                        pinDoc.presHideBefore = true;
+                        pinDoc.title = doc.title + " (move)";
+                        pinDoc.presMovement = PresMovement.None;
+                  }
+                  if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
+                  const dview = CollectionDockingView.Instance.props.Document;
+                  const fieldKey = CollectionDockingView.Instance.props.fieldKey;
+                  const sublists = DocListCast(dview[fieldKey]);
+                  const tabs = Cast(sublists[0], Doc, null);
+                  const tabdocs = await DocListCastAsync(tabs?.data);
+                  runInAction(() => {
+                        if (!pinProps?.hidePresBox && !tabdocs?.includes(curPres)) {
+                              tabdocs?.push(curPres);  // bcz: Argh! this is annoying.  if multiple documents are pinned, this will get called multiple times before the presentation view is drawn.  Thus it won't be in the tabdocs list and it will get created multple times.  so need to explicilty add the presbox to the list of open tabs
+                              CollectionDockingView.AddSplit(curPres, "right");
+                        }
+                        PresBox.Instance?._selectedArray.clear();
+                        pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Update selected array
+                        DocumentManager.Instance.jumpToDocument(doc, false, undefined, []);
+                        batch.end();
+                  });
             }
-        })).observe(this.props.glContainer._element[0]);
-        this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged);
-        this.props.glContainer.tab?.isActive && this.onActiveContentItemChanged(undefined);
-        // this._tabReaction = reaction(() => ({ selected: this.active(), title: this.tab?.titleElement[0] }),
-        //     ({ selected, title }) => title && (title.style.backgroundColor = selected ? "white" : ""),
-        //     { fireImmediately: true });
-    }
+      }
 
-    componentWillUnmount() {
-        this._tabReaction?.();
-        this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab);
+      componentDidMount() {
+            new _global.ResizeObserver(action((entries: any) => {
+                  for (const entry of entries) {
+                        this._panelWidth = entry.contentRect.width;
+                        this._panelHeight = entry.contentRect.height;
+                  }
+            })).observe(this.props.glContainer._element[0]);
+            this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged);
+            this.props.glContainer.tab?.isActive && this.onActiveContentItemChanged(undefined);
+            // this._tabReaction = reaction(() => ({ selected: this.active(), title: this.tab?.titleElement[0] }),
+            //     ({ selected, title }) => title && (title.style.backgroundColor = selected ? "white" : ""),
+            //     { fireImmediately: true });
+      }
 
-        this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged);
-    }
+      componentWillUnmount() {
+            this._tabReaction?.();
+            this.tab && CollectionDockingView.Instance.tabMap.delete(this.tab);
 
-    @action.bound
-    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;
-            !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.
-        }
-    }
+            this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged);
+      }
+
+      @action.bound
+      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;
+                  !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.
+            }
+      }
 
-    // adds a tab to the layout based on the locaiton parameter which can be:
-    //  close[:{left,right,top,bottom}]  - e.g., "close" will close the tab, "close:left" will close the left tab,
-    //  add[:{left,right,top,bottom}] - e.g., "add" will add a tab to the current stack, "add:right" will add a tab on the right
-    //  replace[:{left,right,top,bottom,<any string>}] - e.g., "replace" will replace the current stack contents,
-    //                                  "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name,
-    //                                   "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right
-    //  inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack
-    addDocTab = (doc: Doc, location: string) => {
-        SelectionManager.DeselectAll();
-        const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":");
-        const locationParams = locationFields.length > 1 ? locationFields[1] : "";
-        switch (locationFields[0]) {
-            case "dashboard": return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc);
-            case "close": return CollectionDockingView.CloseSplit(doc, locationParams);
-            case "fullScreen": return CollectionDockingView.OpenFullScreen(doc);
-            case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack);
-            case "lightbox": return LightboxView.AddDocTab(doc, location);
-            case "toggle": return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack);
-            case "inPlace":
-            case "add":
-            default:
-                return CollectionDockingView.AddSplit(doc, locationParams, this.stack);
-        }
-    }
-    remDocTab = (doc: Doc | Doc[]) => {
-        if (doc === this._document) {
+      // adds a tab to the layout based on the locaiton parameter which can be:
+      //  close[:{left,right,top,bottom}]  - e.g., "close" will close the tab, "close:left" will close the left tab,
+      //  add[:{left,right,top,bottom}] - e.g., "add" will add a tab to the current stack, "add:right" will add a tab on the right
+      //  replace[:{left,right,top,bottom,<any string>}] - e.g., "replace" will replace the current stack contents,
+      //                                  "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name,
+      //                                   "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right
+      //  inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack
+      addDocTab = (doc: Doc, location: string) => {
             SelectionManager.DeselectAll();
-            CollectionDockingView.CloseSplit(this._document);
-            return true;
-        }
-        return false;
-    }
+            const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":");
+            const locationParams = locationFields.length > 1 ? locationFields[1] : "";
+            switch (locationFields[0]) {
+                  case "dashboard": return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc);
+                  case "close": return CollectionDockingView.CloseSplit(doc, locationParams);
+                  case "fullScreen": return CollectionDockingView.OpenFullScreen(doc);
+                  case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack);
+                  case "lightbox": return LightboxView.AddDocTab(doc, location);
+                  case "toggle": return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack);
+                  case "inPlace":
+                  case "add":
+                  default:
+                        return CollectionDockingView.AddSplit(doc, locationParams, this.stack);
+            }
+      }
+      remDocTab = (doc: Doc | Doc[]) => {
+            if (doc === this._document) {
+                  SelectionManager.DeselectAll();
+                  CollectionDockingView.CloseSplit(this._document);
+                  return true;
+            }
+            return false;
+      }
 
-    getCurrentFrame = () => {
-        return NumCast(Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null)._currentFrame);
-    }
-    @action
-    focusFunc = (doc: Doc, options?: DocFocusOptions) => {
-        const shrinkwrap = options?.originalTarget === this._document && this.view?.ComponentView?.shrinkWrap;
-        if (shrinkwrap && this._document) {
-            const focusSpeed = 1000;
-            shrinkwrap();
-            this._document._viewTransition = `transform ${focusSpeed}ms`;
-            setTimeout(action(() => {
-                this._document!._viewTransition = undefined;
-                options?.afterFocus?.(false);
-            }), focusSpeed);
-        } else {
-            options?.afterFocus?.(false);
-        }
-        if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) {
-            this.tab.header.parent.setActiveContentItem(this.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)
-        }
-    }
-    active = () => this._isActive;
-    @observable _forceInvalidateScreenToLocal = 0;
-    ScreenToLocalTransform = () => {
-        this._forceInvalidateScreenToLocal;
-        const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont?.children?.[0] as HTMLElement);
-        return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY);
-    }
-    PanelWidth = () => this._panelWidth;
-    PanelHeight = () => this._panelHeight;
-    miniMapColor = () => this.tabColor;
-    tabView = () => this._view;
-    disableMinimap = () => !this._document || (this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform);
-    hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.hideMinimap);
+      getCurrentFrame = () => {
+            return NumCast(Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null)._currentFrame);
+      }
+      @action
+      focusFunc = (doc: Doc, options?: DocFocusOptions) => {
+            const shrinkwrap = options?.originalTarget === this._document && this.view?.ComponentView?.shrinkWrap;
+            if (shrinkwrap && this._document) {
+                  const focusSpeed = 1000;
+                  shrinkwrap();
+                  this._document._viewTransition = `transform ${focusSpeed}ms`;
+                  setTimeout(action(() => {
+                        this._document!._viewTransition = undefined;
+                        options?.afterFocus?.(false);
+                  }), focusSpeed);
+            } else {
+                  options?.afterFocus?.(false);
+            }
+            if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) {
+                  this.tab.header.parent.setActiveContentItem(this.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)
+            }
+      }
+      active = () => this._isActive;
+      @observable _forceInvalidateScreenToLocal = 0;
+      ScreenToLocalTransform = () => {
+            this._forceInvalidateScreenToLocal;
+            const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont?.children?.[0] as HTMLElement);
+            return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY);
+      }
+      PanelWidth = () => this._panelWidth;
+      PanelHeight = () => this._panelHeight;
+      miniMapColor = () => this.tabColor;
+      tabView = () => this._view;
+      disableMinimap = () => !this._document || (this._document.layout !== CollectionView.LayoutString(Doc.LayoutFieldKey(this._document)) || this._document?._viewType !== CollectionViewType.Freeform);
+      hideMinimap = () => this.disableMinimap() || BoolCast(this._document?.hideMinimap);
 
-    @computed get docView() {
-        return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
-            <><DocumentView key={this._document[Id]} ref={action((r: DocumentView) => this._view = r)}
-                renderDepth={0}
-                Document={this._document}
-                DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
-                ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
-                onBrowseClick={MainView.Instance.exploreMode}
-                isContentActive={returnTrue}
-                PanelWidth={this.PanelWidth}
-                PanelHeight={this.PanelHeight}
-                styleProvider={DefaultStyleProvider}
-                docFilters={CollectionDockingView.Instance.childDocFilters}
-                docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters}
-                searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
-                addDocument={undefined}
-                removeDocument={this.remDocTab}
-                addDocTab={this.addDocTab}
-                ScreenToLocalTransform={this.ScreenToLocalTransform}
-                dontCenter={"y"}
-                rootSelected={returnTrue}
-                whenChildContentsActiveChanged={emptyFunction}
-                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.hideMinimap ? "Open minimap" : "Close minimap"}</div>}>
-                    <div className="miniMap-hidden"
-                        style={{
-                            display: this.disableMinimap() || this._document._viewType !== "freeform" ? "none" : undefined,
-                            color: this._document.hideMinimap ? Colors.BLACK : Colors.WHITE,
-                            backgroundColor: this._document.hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,
-                            boxShadow: this._document.hideMinimap ? Shadows.STANDARD_SHADOW : undefined
-                        }}
-                        onPointerDown={e => e.stopPropagation()}
-                        onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
-                        <FontAwesomeIcon icon={"globe-asia"} size="lg" />
-                    </div>
-                </Tooltip>
-            </>;
-    }
+      @computed get docView() {
+            return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
+                  <><DocumentView key={this._document[Id]} ref={action((r: DocumentView) => this._view = r)}
+                        renderDepth={0}
+                        Document={this._document}
+                        DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
+                        ContainingCollectionView={undefined}
+                        ContainingCollectionDoc={undefined}
+                        onBrowseClick={MainView.Instance.exploreMode}
+                        isContentActive={returnTrue}
+                        PanelWidth={this.PanelWidth}
+                        PanelHeight={this.PanelHeight}
+                        styleProvider={DefaultStyleProvider}
+                        docFilters={CollectionDockingView.Instance.childDocFilters}
+                        docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters}
+                        searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
+                        addDocument={undefined}
+                        removeDocument={this.remDocTab}
+                        addDocTab={this.addDocTab}
+                        ScreenToLocalTransform={this.ScreenToLocalTransform}
+                        dontCenter={"y"}
+                        rootSelected={returnTrue}
+                        whenChildContentsActiveChanged={emptyFunction}
+                        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.hideMinimap ? "Open minimap" : "Close minimap"}</div>}>
+                              <div className="miniMap-hidden"
+                                    style={{
+                                          display: this.disableMinimap() || this._document._viewType !== "freeform" ? "none" : undefined,
+                                          color: this._document.hideMinimap ? Colors.BLACK : Colors.WHITE,
+                                          backgroundColor: this._document.hideMinimap ? Colors.LIGHT_GRAY : Colors.MEDIUM_BLUE,
+                                          boxShadow: this._document.hideMinimap ? Shadows.STANDARD_SHADOW : undefined
+                                    }}
+                                    onPointerDown={e => e.stopPropagation()}
+                                    onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
+                                    <FontAwesomeIcon icon={"globe-asia"} size="lg" />
+                              </div>
+                        </Tooltip>
+                  </>;
+      }
 
-    render() {
-        return (
-            <div className="collectionDockingView-content" style={{
-                fontFamily: Doc.UserDoc().renderStyle === "comic" ? "Comic Sans MS" : undefined,
-                height: "100%", width: "100%"
-            }} ref={ref => {
-                if (this._mainCont = ref) {
-                    (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
-                    DocServer.GetRefField(this.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document)));
-                    new _global.ResizeObserver(action((entries: any) => this._forceInvalidateScreenToLocal++)).observe(ref);
-                }
-            }} >
-                {this.docView}
-            </div >
-        );
-    }
+      render() {
+            return (
+                  <div className="collectionDockingView-content" style={{
+                        fontFamily: Doc.UserDoc().renderStyle === "comic" ? "Comic Sans MS" : undefined,
+                        height: "100%", width: "100%"
+                  }} ref={ref => {
+                        if (this._mainCont = ref) {
+                              (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
+                              DocServer.GetRefField(this.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document)));
+                              new _global.ResizeObserver(action((entries: any) => this._forceInvalidateScreenToLocal++)).observe(ref);
+                        }
+                  }} >
+                        {this.docView}
+                  </div >
+            );
+      }
 }
 
 interface TabMinimapViewProps {
-    document: Doc;
-    hideMinimap: () => boolean;
-    tabView: () => DocumentView | undefined;
-    addDocTab: (doc: Doc, where: string) => boolean;
-    PanelWidth: () => number;
-    PanelHeight: () => number;
-    background: () => string;
+      document: Doc;
+      hideMinimap: () => boolean;
+      tabView: () => DocumentView | undefined;
+      addDocTab: (doc: Doc, where: string) => boolean;
+      PanelWidth: () => number;
+      PanelHeight: () => number;
+      background: () => string;
 }
 @observer
 export class TabMinimapView extends React.Component<TabMinimapViewProps> {
-    static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
-        if (doc) {
-            switch (property.split(":")[0]) {
-                default: return DefaultStyleProvider(doc, props, property);
-                case StyleProp.PointerEvents: return "none";
-                case StyleProp.DocContents:
-                    const background = ((type: DocumentType) => {
-                        switch (type) {
-                            case DocumentType.PDF: return "pink";
-                            case DocumentType.AUDIO: return "lightgreen";
-                            case DocumentType.WEB: return "brown";
-                            case DocumentType.IMG: return "blue";
-                            case DocumentType.MAP: return "orange";
-                            case DocumentType.VID: return "purple";
-                            case DocumentType.RTF: return "yellow";
-                            case DocumentType.COL: return undefined;
-                            default: return "gray";
-                        }
-                    })(doc.type as DocumentType);
-                    return !background ?
-                        undefined :
-                        <div style={{ width: doc[WidthSym](), height: doc[HeightSym](), position: "absolute", display: "block", background }} />;
+      static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
+            if (doc) {
+                  switch (property.split(":")[0]) {
+                        default: return DefaultStyleProvider(doc, props, property);
+                        case StyleProp.PointerEvents: return "none";
+                        case StyleProp.DocContents:
+                              const background = ((type: DocumentType) => {
+                                    switch (type) {
+                                          case DocumentType.PDF: return "pink";
+                                          case DocumentType.AUDIO: return "lightgreen";
+                                          case DocumentType.WEB: return "brown";
+                                          case DocumentType.IMG: return "blue";
+                                          case DocumentType.MAP: return "orange";
+                                          case DocumentType.VID: return "purple";
+                                          case DocumentType.RTF: return "yellow";
+                                          case DocumentType.COL: return undefined;
+                                          default: return "gray";
+                                    }
+                              })(doc.type as DocumentType);
+                              return !background ?
+                                    undefined :
+                                    <div style={{ width: doc[WidthSym](), height: doc[HeightSym](), position: "absolute", display: "block", background }} />;
+                  }
             }
-        }
-    }
-    @computed get renderBounds() {
-        const compView = this.props.tabView()?.ComponentView as CollectionFreeFormView;
-        const bounds = compView?.freeformData?.(true)?.bounds;
-        if (!bounds) return undefined;
-        const xbounds = bounds.r - bounds.x;
-        const ybounds = bounds.b - bounds.y;
-        const dim = Math.max(xbounds, ybounds);
-        return { l: bounds.x + xbounds / 2 - dim / 2, t: bounds.y + ybounds / 2 - dim / 2, cx: bounds.x + xbounds / 2, cy: bounds.y + ybounds / 2, dim };
-    }
-    childLayoutTemplate = () => Cast(this.props.document.childLayoutTemplate, Doc, null);
-    returnMiniSize = () => NumCast(this.props.document._miniMapSize, 150);
-    miniDown = (e: React.PointerEvent) => {
-        const doc = this.props.document;
-        const renderBounds = this.renderBounds ?? { l: 0, r: 0, t: 0, b: 0, dim: 1 };
-        const miniSize = this.returnMiniSize();
-        doc && setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
-            doc._panX = clamp(NumCast(doc._panX) + delta[0] / miniSize * renderBounds.dim, renderBounds.l, renderBounds.l + renderBounds.dim);
-            doc._panY = clamp(NumCast(doc._panY) + delta[1] / miniSize * renderBounds.dim, renderBounds.t, renderBounds.t + renderBounds.dim);
-            return false;
-        }), emptyFunction, emptyFunction);
-    }
-    render() {
-        if (!this.renderBounds) return (null);
-        const miniWidth = this.props.PanelWidth() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim * 100;
-        const miniHeight = this.props.PanelHeight() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim * 100;
-        const miniLeft = 50 + (NumCast(this.props.document._panX) - this.renderBounds.cx) / this.renderBounds.dim * 100 - miniWidth / 2;
-        const miniTop = 50 + (NumCast(this.props.document._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}
-                    CollectionView={undefined}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
-                    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}
-                    dropAction={undefined}
-                    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={DocUtils.DefaultFocus}
-                    styleProvider={TabMinimapView.miniStyleProvider}
-                    addDocTab={this.props.addDocTab}
-                    pinToPres={TabDocView.PinDoc}
-                    docFilters={CollectionDockingView.Instance.childDocFilters}
-                    docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters}
-                    searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
-                    fitContentsToDoc={returnTrue}
-                />
-                <div className="miniOverlay" onPointerDown={this.miniDown} >
-                    <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% `, }} />
-                </div>
-            </div>;
-    }
+      }
+      @computed get renderBounds() {
+            const compView = this.props.tabView()?.ComponentView as CollectionFreeFormView;
+            const bounds = compView?.freeformData?.(true)?.bounds;
+            if (!bounds) return undefined;
+            const xbounds = bounds.r - bounds.x;
+            const ybounds = bounds.b - bounds.y;
+            const dim = Math.max(xbounds, ybounds);
+            return { l: bounds.x + xbounds / 2 - dim / 2, t: bounds.y + ybounds / 2 - dim / 2, cx: bounds.x + xbounds / 2, cy: bounds.y + ybounds / 2, dim };
+      }
+      childLayoutTemplate = () => Cast(this.props.document.childLayoutTemplate, Doc, null);
+      returnMiniSize = () => NumCast(this.props.document._miniMapSize, 150);
+      miniDown = (e: React.PointerEvent) => {
+            const doc = this.props.document;
+            const renderBounds = this.renderBounds ?? { l: 0, r: 0, t: 0, b: 0, dim: 1 };
+            const miniSize = this.returnMiniSize();
+            doc && setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
+                  doc._panX = clamp(NumCast(doc._panX) + delta[0] / miniSize * renderBounds.dim, renderBounds.l, renderBounds.l + renderBounds.dim);
+                  doc._panY = clamp(NumCast(doc._panY) + delta[1] / miniSize * renderBounds.dim, renderBounds.t, renderBounds.t + renderBounds.dim);
+                  return false;
+            }), emptyFunction, emptyFunction);
+      }
+      render() {
+            if (!this.renderBounds) return (null);
+            const miniWidth = this.props.PanelWidth() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim * 100;
+            const miniHeight = this.props.PanelHeight() / NumCast(this.props.document._viewScale, 1) / this.renderBounds.dim * 100;
+            const miniLeft = 50 + (NumCast(this.props.document._panX) - this.renderBounds.cx) / this.renderBounds.dim * 100 - miniWidth / 2;
+            const miniTop = 50 + (NumCast(this.props.document._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}
+                              CollectionView={undefined}
+                              ContainingCollectionView={undefined}
+                              ContainingCollectionDoc={undefined}
+                              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}
+                              dropAction={undefined}
+                              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={DocUtils.DefaultFocus}
+                              styleProvider={TabMinimapView.miniStyleProvider}
+                              addDocTab={this.props.addDocTab}
+                              pinToPres={TabDocView.PinDoc}
+                              docFilters={CollectionDockingView.Instance.childDocFilters}
+                              docRangeFilters={CollectionDockingView.Instance.childDocRangeFilters}
+                              searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
+                              fitContentsToDoc={returnTrue}
+                        />
+                        <div className="miniOverlay" onPointerDown={this.miniDown} >
+                              <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% `, }} />
+                        </div>
+                  </div>;
+      }
 }
diff --git a/src/client/views/nodes/trails/PresElementBox.scss b/src/client/views/nodes/trails/PresElementBox.scss
index a178be910..1919071df 100644
--- a/src/client/views/nodes/trails/PresElementBox.scss
+++ b/src/client/views/nodes/trails/PresElementBox.scss
@@ -5,155 +5,157 @@ $slide-background: #d5dce2;
 $slide-active: #5B9FDD;
 
 .presItem-container {
-    cursor: grab;
-    display: grid;
-    grid-template-columns: 20px auto;
-    font-family: Roboto;
-    letter-spacing: normal;
-    position: relative;
-    pointer-events: all;
-    width: 100%;
-    height: 100%;
-    font-weight: 400;
-    -webkit-touch-callout: none;
-    -webkit-user-select: none;
-    -khtml-user-select: none;
-    -moz-user-select: none;
-    -ms-user-select: none;
-    user-select: none;
-    align-items: center;
-
-    .presItem-number {
-        margin-top: 3.5px;
-        font-size: 12px;
-        font-weight: 700;
-        text-align: center;
-        justify-self: center;
-        align-self: flex-start;
-        position: relative;
-        display: inline-block;
-        overflow: hidden;
-    }
+      cursor: grab;
+      display: flex;
+      grid-template-columns: 20px auto;
+      font-family: Roboto;
+      letter-spacing: normal;
+      position: relative;
+      pointer-events: all;
+      width: 100%;
+      height: 100%;
+      font-weight: 400;
+      -webkit-touch-callout: none;
+      -webkit-user-select: none;
+      -khtml-user-select: none;
+      -moz-user-select: none;
+      -ms-user-select: none;
+      user-select: none;
+      align-items: center;
+
+      //     .presItem-number {
+      //         margin-top: 3.5px;
+      //         font-size: 12px;
+      //         font-weight: 700;
+      //         text-align: center;
+      //         justify-self: center;
+      //         align-self: flex-start;
+      //         position: relative;
+      //         display: inline-block;
+      //         overflow: hidden;
+      //     }
 
 }
 
 .presItem-slide {
-    position: relative;
-    background-color: #d5dce2;
-    border-radius: 5px;
-    height: calc(100% - 7px);
-    width: 100%;
-    display: grid;
-    grid-template-rows: 16px 10px auto;
-    grid-template-columns: max-content max-content max-content max-content auto;
-
-    .presItem-name {
-        min-width: 20px;
-        z-index: 300;
-        top: 2px;
-        align-self: center;
-        font-size: 11px;
-        font-family: Roboto;
-        font-weight: 500;
-        position: relative;
-        padding-left: 10px;
-        padding-right: 10px;
-        letter-spacing: normal;
-        width: max-content;
-        text-overflow: ellipsis;
-        overflow: hidden;
-        white-space: pre;
-    }
-
-    .presItem-docName {
-        min-width: 20px;
-        z-index: 300;
-        align-self: center;
-        font-size: 9px;
-        font-family: Roboto;
-        font-weight: 300;
-        position: relative;
-        padding-left: 10px;
-        padding-right: 10px;
-        letter-spacing: normal;
-        width: max-content;
-        text-overflow: ellipsis;
-        overflow: hidden;
-        white-space: pre;
-        grid-row: 2;
-        grid-column: 1/6;
-    }
-
-    .presItem-time {
-        align-self: center;
-        position: relative;
-        padding-right: 10px;
-        top: 1px;
-        font-size: 10;
-        font-weight: 300;
-        font-family: Roboto;
-        z-index: 300;
-        letter-spacing: normal;
-    }
-
-    .presItem-embedded {
-        overflow: hidden;
-        grid-row: 3;
-        grid-column: 1/8;
-        position: relative;
-        display: flex;
-        width: auto;
-        justify-content: center;
-        margin: auto;
-        margin-bottom: 2px;
-        border-bottom-left-radius: 5px;
-        border-bottom-right-radius: 5px;
-    }
-
-    .presItem-embeddedMask {
-        width: 100%;
-        height: 100%;
-        position: absolute;
-        border-radius: 3px;
-        top: 0;
-        left: 0;
-        z-index: 1;
-        overflow: hidden;
-    }
-
-
-    .presItem-slideButtons {
-        display: flex;
-        grid-column: 7;
-        grid-row: 1/3;
-        width: max-content;
-        justify-self: right;
-        justify-content: flex-end;
-
-        .slideButton {
-            cursor: pointer;
+      position: relative;
+      height: 100%;
+      width: 100%;
+      border-bottom: .5px solid grey;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      grid-template-rows: 16px 10px auto;
+      grid-template-columns: max-content max-content max-content max-content auto;
+
+      .presItem-name {
+            display: flex;
+            min-width: 20px;
+            z-index: 300;
+            top: 2px;
+            align-self: center;
+            font-size: 11px;
+            font-family: Roboto;
+            font-weight: 500;
             position: relative;
-            border-radius: 100px;
+            padding-left: 10px;
+            padding-right: 10px;
+            letter-spacing: normal;
+            width: max-content;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            white-space: pre;
+      }
+
+      .presItem-docName {
+            min-width: 20px;
             z-index: 300;
-            width: 18px;
-            height: 18px;
-            display: flex;
-            font-size: 12px;
-            justify-self: center;
             align-self: center;
-            background-color: rgba(0, 0, 0, 0.5);
-            color: white;
+            font-size: 9px;
+            font-family: Roboto;
+            font-weight: 300;
+            position: relative;
+            padding-left: 10px;
+            padding-right: 10px;
+            letter-spacing: normal;
+            width: max-content;
+            text-overflow: ellipsis;
+            overflow: hidden;
+            white-space: pre;
+            grid-row: 2;
+            grid-column: 1/6;
+      }
+
+      .presItem-time {
+            align-self: center;
+            position: relative;
+            padding-right: 10px;
+            top: 1px;
+            font-size: 10;
+            font-weight: 300;
+            font-family: Roboto;
+            z-index: 300;
+            letter-spacing: normal;
+      }
+
+      .presItem-embedded {
+            overflow: hidden;
+            grid-row: 3;
+            grid-column: 1/8;
+            position: relative;
+            display: flex;
+            width: auto;
             justify-content: center;
-            align-items: center;
-            transition: 0.2s;
-            margin-right: 3px;
-        }
-
-        .slideButton:hover {
-            background-color: rgba(0, 0, 0, 1);
-            transform: scale(1.2);
-        }
-    }
+            margin: auto;
+            margin-bottom: 2px;
+            border-bottom-left-radius: 5px;
+            border-bottom-right-radius: 5px;
+      }
+
+      .presItem-embeddedMask {
+            width: 100%;
+            height: 100%;
+            position: absolute;
+            border-radius: 3px;
+            top: 0;
+            left: 0;
+            z-index: 1;
+            overflow: hidden;
+      }
+
+
+      .presItem-slideButtons {
+            display: flex;
+            grid-column: 7;
+            grid-row: 1/3;
+            width: max-content;
+            justify-self: right;
+            justify-content: flex-end;
+
+            .slideButton {
+                  cursor: pointer;
+                  position: relative;
+                  border-radius: 100px;
+                  z-index: 300;
+                  width: 18px;
+                  height: 18px;
+                  display: flex;
+                  font-size: 12px;
+                  justify-self: center;
+                  align-self: center;
+                  background-color: rgba(0, 0, 0, 0.5);
+                  color: white;
+                  justify-content: center;
+                  align-items: center;
+                  transition: 0.2s;
+                  margin-right: 3px;
+            }
+
+            .slideButton:hover {
+                  background-color: rgba(0, 0, 0, 1);
+                  transform: scale(1.2);
+            }
+      }
 }
 
 // .presItem-slide:hover {
@@ -192,42 +194,42 @@ $slide-active: #5B9FDD;
 // }
 
 .presItem-slide.active {
-    box-shadow: 0 0 0px 1.5px $dark-blue;
+      box-shadow: 0 0 0px 1.5px $dark-blue;
 }
 
 .presItem-multiDrag {
-    font-family: Roboto;
-    font-weight: 600;
-    color: white;
-    text-align: center;
-    justify-content: center;
-    align-content: center;
-    width: 100px;
-    height: 30px;
-    position: absolute;
-    background-color: $dark-blue;
-    z-index: 4000;
-    border-radius: 10px;
-    box-shadow: black 0.4vw 0.4vw 0.8vw;
-    line-height: 30px;
+      font-family: Roboto;
+      font-weight: 600;
+      color: white;
+      text-align: center;
+      justify-content: center;
+      align-content: center;
+      width: 100px;
+      height: 30px;
+      position: absolute;
+      background-color: $dark-blue;
+      z-index: 4000;
+      border-radius: 10px;
+      box-shadow: black 0.4vw 0.4vw 0.8vw;
+      line-height: 30px;
 }
 
 .presItem-miniSlide {
-    font-weight: 700;
-    font-size: 12;
-    grid-column: 1/8;
-    align-self: center;
-    justify-self: center;
-    background-color: #d5dce2;
-    width: 26px;
-    text-align: center;
-    height: 26px;
-    line-height: 28px;
-    border-radius: 100%;
+      font-weight: 700;
+      font-size: 12;
+      grid-column: 1/8;
+      align-self: center;
+      justify-self: center;
+      background-color: #d5dce2;
+      width: 26px;
+      text-align: center;
+      height: 26px;
+      line-height: 28px;
+      border-radius: 100%;
 }
 
 .presItem-miniSlide.active {
-    box-shadow: 0 0 0px 1.5px $dark-blue;
+      box-shadow: 0 0 0px 1.5px $dark-blue;
 }
 
 // .presItem-slide:hover {
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index f1144b32d..acdf9c43f 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -329,7 +329,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         hideDocumentButtonBar: true,
                         hideDecorationTitle: true,
                         hideOpenButton: true,
-                        hideDeleteButton: true,
+                        // hideDeleteButton: true,
                         cloneFieldFilter:
                               new List<string>(["system"])
                   });
@@ -387,7 +387,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         onPointerDown={this.headerDown}
                         onPointerUp={this.headerUp}
                   >
-                        {miniView ?
+                        {/* {miniView ?
                               // when width is LESS than 110 px 
                               <div className={`presItem-miniSlide ${isSelected ? "active" : ""}`} ref={miniView ? this._dragRef : null}>
                                     {`${this.indexInPres + 1}.`}
@@ -396,13 +396,17 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                               // when width is MORE than 110 px 
                               <div className="presItem-number">
                                     {`${this.indexInPres + 1}.`}
-                              </div>}
+                              </div>} */}
+                        {/* <div className="presItem-number">
+                              {`${this.indexInPres + 1}.`}
+                        </div> */}
                         {miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`}
                               style={{
                                     backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BackgroundColor),
                                     boxShadow: presBoxColor && presBoxColor !== "white" && presBoxColor !== "transparent" ? isSelected ? "0 0 0px 1.5px" + presBoxColor : undefined : undefined
                               }}>
                               <div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}>
+                                    <div>{`${this.indexInPres + 1}.  `}</div>
                                     <EditableView
                                           ref={this._titleRef}
                                           editing={!isSelected ? false : undefined}
@@ -412,8 +416,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                           SetValue={this.onSetValue}
                                     />
                               </div>
-                              <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.transition}</div></Tooltip>
-                              <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.duration}</div></Tooltip>
+                              {/* <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.transition}</div></Tooltip> */}
+                              {/* <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presItem-time" style={{ display: showMore ? "block" : "none" }}>{this.duration}</div></Tooltip> */}
                               <div className={"presItem-slideButtons"}>
                                     <Tooltip title={<><div className="dash-tooltip">{"Update view"}</div></>}>
                                           <div className="slideButton"
@@ -439,7 +443,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                     }
 
 
-                                    {this.indexInPres === 0 ? (null) : <Tooltip title={<><div className="dash-tooltip">{activeItem.groupWithUp ? "Ungroup" : "Group with up"}</div></>}>
+                                    {/* {this.indexInPres === 0 ? (null) : <Tooltip title={<><div className="dash-tooltip">{activeItem.groupWithUp ? "Ungroup" : "Group with up"}</div></>}>
                                           <div className="slideButton"
                                                 onClick={() => activeItem.groupWithUp = !activeItem.groupWithUp}
                                                 style={{
@@ -453,7 +457,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                                       <FontAwesomeIcon icon={"arrow-up"} onPointerDown={e => e.stopPropagation()} />
                                                 </div>
                                           </div>
-                                    </Tooltip>}
+                                    </Tooltip>} */}
                                     {/* <Tooltip title={<><div className="dash-tooltip">{this.rootDoc.presExpandInlineButton ? "Minimize" : "Expand"}</div></>}><div className={"slideButton"} onClick={e => { e.stopPropagation(); this.presExpandDocumentClick(); }}>
                                           <FontAwesomeIcon icon={this.rootDoc.presExpandInlineButton ? "eye-slash" : "eye"} onPointerDown={e => e.stopPropagation()} />
                                     </div></Tooltip> */}
@@ -463,7 +467,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                           <FontAwesomeIcon icon={"trash"} onPointerDown={e => e.stopPropagation()} />
                                     </div></Tooltip>
                               </div>
-                              <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div>
+                              {/* <div className="presItem-docName" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105 }}>{activeItem.presPinView ? (<><i>View of </i> {targetDoc.title}</>) : targetDoc.title}</div> */}
                               {this.renderEmbeddedInline}
                         </div>}
                   </div >);
-- 
cgit v1.2.3-70-g09d2


From 5157f0c500b01a635c373cc661a2588ef7506d79 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 8 Jun 2022 12:44:36 -0400
Subject: added context menu back to tab's via the doc icon.  made docicon
 draggable and clickable. removed collectiondockingviewmenu.

---
 src/client/goldenLayout.js                         |  5 ++-
 .../views/collections/CollectionDockingView.tsx    |  3 +-
 .../collections/CollectionDockingViewMenu.scss     | 34 ---------------
 .../collections/CollectionDockingViewMenu.tsx      | 48 --------------------
 src/client/views/collections/TabDocView.tsx        | 51 +++++++++++-----------
 5 files changed, 31 insertions(+), 110 deletions(-)
 delete mode 100644 src/client/views/collections/CollectionDockingViewMenu.scss
 delete mode 100644 src/client/views/collections/CollectionDockingViewMenu.tsx

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

diff --git a/src/client/goldenLayout.js b/src/client/goldenLayout.js
index 4735f216f..012ee163c 100644
--- a/src/client/goldenLayout.js
+++ b/src/client/goldenLayout.js
@@ -458,8 +458,9 @@
                 if (this._bDragging === true) {
                     this._bDragging = false;
                     this.emit('dragStop', oEvent, this._nOriginalX + this._nX);
-                } else if (oEvent.target) { // make title receive pointer events to allow setting insertion position or selecting texst range
-                    if (oEvent.target.className.includes("lm_title_wrap")) {
+                } else  { // make title receive pointer events to allow setting insertion position or selecting texst range
+                    const classname = typeof oEvent.target?.className === "string" ? oEvent.target.className : "";
+                    if (classname.includes("lm_title_wrap")) {
                         oEvent.target.children[0].style.pointerEvents = "all";
                         oEvent.target.children[0].focus();
                     }
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 745565ff5..476ffaf81 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -362,7 +362,8 @@ export class CollectionDockingView extends CollectionSubView() {
             const htmlTarget = e.target as HTMLElement;
             window.addEventListener("mouseup", this.onPointerUp);
             if (!htmlTarget.closest("*.lm_content") && (htmlTarget.closest("*.lm_tab") || htmlTarget.closest("*.lm_stack"))) {
-                if (!htmlTarget.className.includes("lm_close") && !htmlTarget.className.includes("lm_maximise")) {
+                const className = typeof htmlTarget.className === "string" ? htmlTarget.className : "";
+                if (!className.includes("lm_close") && !className.includes("lm_maximise")) {
                     this._flush = UndoManager.StartBatch("golden layout edit");
                 }
             }
diff --git a/src/client/views/collections/CollectionDockingViewMenu.scss b/src/client/views/collections/CollectionDockingViewMenu.scss
deleted file mode 100644
index 4157f0f7e..000000000
--- a/src/client/views/collections/CollectionDockingViewMenu.scss
+++ /dev/null
@@ -1,34 +0,0 @@
-
-.dockingViewButtonSelector {
-    div {
-        overflow: visible !important;
-    }
-
-    display: inline-block;
-    width:100%;
-    height:100%;
-}
-.dockingViewButtonSelector-flyout {
-    position: relative;
-    z-index: 9999;
-    background-color: #eeeeee;
-    box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
-    color: black;
-
-    padding: 10px;
-    border-radius: 3px;
-    display: inline-block;
-    height: 100%;
-    width: 100%;
-    border-radius: 3px;
-
-    hr {
-        height: 1px;
-        margin: 0px;
-        background-color: gray;
-        border-top: 0px;
-        border-bottom: 0px;
-        border-right: 0px;
-        border-left: 0px;
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionDockingViewMenu.tsx b/src/client/views/collections/CollectionDockingViewMenu.tsx
deleted file mode 100644
index 1cab293a8..000000000
--- a/src/client/views/collections/CollectionDockingViewMenu.tsx
+++ /dev/null
@@ -1,48 +0,0 @@
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Tooltip } from "@material-ui/core";
-import { action, computed, observable } from "mobx";
-import { observer } from "mobx-react";
-import * as React from "react";
-import { DocumentButtonBar } from "../DocumentButtonBar";
-import { DocumentView } from "../nodes/DocumentView";
-const higflyout = require("@hig/flyout");
-export const { anchorPoints } = higflyout;
-export const Flyout = higflyout.default;
-
-@observer
-export class CollectionDockingViewMenu extends React.Component<{ views: () => DocumentView[], Stack: any }> {
-    customStylesheet(styles: any) {
-        return {
-            ...styles,
-            panel: {
-                ...styles.panel,
-                minWidth: "100px"
-            },
-        };
-    }
-    _ref = React.createRef<HTMLDivElement>();
-
-    @computed get flyout() {
-        return (
-            <div className="dockingViewButtonSelector-flyout" title=" " ref={this._ref}>
-                <DocumentButtonBar views={this.props.views} stack={this.props.Stack} />
-            </div>
-        );
-    }
-
-    @observable _tooltipOpen: boolean = false;
-    render() {
-        return <Tooltip open={this._tooltipOpen} onClose={action(() => this._tooltipOpen = false)} title={<><div className="dash-tooltip">Tap for toolbar, drag to create alias in another pane</div></>} placement="bottom">
-            <span className="dockingViewButtonSelector"
-                onPointerEnter={action(() => !this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true))}
-                onPointerDown={action(e => {
-                    this.props.views()[0]?.select(false);
-                    this._tooltipOpen = false;
-                })} >
-                <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.flyout} stylesheet={this.customStylesheet}>
-                    <FontAwesomeIcon icon={"arrows-alt"} size={"sm"} />
-                </Flyout>
-            </span>
-        </Tooltip >;
-    }
-}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 75a8207dd..91c6975ea 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -4,15 +4,15 @@ import { Tooltip } from '@material-ui/core';
 import 'golden-layout/src/css/goldenlayout-base.css';
 import 'golden-layout/src/css/goldenlayout-dark-theme.css';
 import { clamp } from 'lodash';
-import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
 import * as ReactDOM from 'react-dom';
-import { DataSym, Doc, DocListCast, DocListCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
+import { DataSym, Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { FieldId } from "../../../fields/RefField";
 import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
+import { emptyFunction, lightOrDark, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { DocUtils } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -27,10 +27,10 @@ import { Colors, Shadows } from '../global/globalEnums';
 import { LightboxView } from '../LightboxView';
 import { MainView } from '../MainView';
 import { DocFocusOptions, DocumentView, DocumentViewProps } from "../nodes/DocumentView";
+import { DashFieldView } from '../nodes/formattedText/DashFieldView';
 import { PinProps, PresBox, PresMovement } from '../nodes/trails';
 import { DefaultStyleProvider, StyleProp } from '../StyleProvider';
 import { CollectionDockingView } from './CollectionDockingView';
-import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TabDocView.scss";
@@ -92,14 +92,28 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 Doc.GetProto(doc).title = e.currentTarget.value;
             }));
 
-            const dragBtnDown = (e: React.PointerEvent) => {
-                setupMoveUpEvents(this, e, e => !e.defaultPrevented && DragManager.StartDocumentDrag([iconWrap], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY), returnFalse, emptyFunction);
-            };
-
-
             if (tab.element[0].children[1].children.length === 1) {
-                iconWrap.className = "lm_iconWrap";
-                iconWrap.id = "lm_iconWrap";
+                iconWrap.className = "lm_iconWrap lm_moreInfo";
+                const dragBtnDown = (e: React.PointerEvent) => {
+                    setupMoveUpEvents(this, e, e => !e.defaultPrevented && DragManager.StartDocumentDrag([iconWrap], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY), returnFalse, action(e => {
+                        if (this.view) {
+                            SelectionManager.SelectView(this.view, false);
+                            let child = this.view.ContentDiv!.children[0];
+                            while (child.children.length) {
+                                const next = Array.from(child.children).find(c => c.className?.toString().includes("SVGAnimatedString") || typeof (c.className) === "string");
+                                if (next?.className?.toString().includes(DocumentView.ROOT_DIV)) break;
+                                if (next?.className?.toString().includes(DashFieldView.name)) break;
+                                if (next) child = next;
+                                else break;
+                            }
+                            simulateMouseClick(child, e.clientX, e.clientY + 30, e.screenX, e.screenY + 30);
+                        }
+                        else { this._activated = true;
+                              setTimeout(() =>this.view && SelectionManager.SelectView(this.view, false));
+                        }
+                    }));
+                };
+
                 closeWrap.className = "lm_iconWrap";
                 closeWrap.id = "lm_closeWrap";
                 closeWrap.onclick = (e: MouseEvent) => {
@@ -111,6 +125,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 const closeIcon = <FontAwesomeIcon icon={"times"} />;
                 ReactDOM.render(docIcon, iconWrap);
                 ReactDOM.render(closeIcon, closeWrap);
+                tab.reactComponents = [iconWrap, closeWrap];
                 // tab.element[0].append(closeWrap);
                 tab.element[0].prepend(iconWrap);
                 tab._disposers.layerDisposer = reaction(() => ({ layer: tab.DashDoc.activeLayer, color: this.tabColor }),
@@ -122,7 +137,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                         titleEle.style.backgroundColor = "transparent";
                         iconWrap.style.color = textColor;
                         closeWrap.style.color = textColor;
-                        moreInfoDrag.style.backgroundColor = textColor;
                         tab.element[0].style.background = !layer ? color : "dimgrey";
                     }, { fireImmediately: true });
             }
@@ -155,19 +169,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     // toggle.style.textTransform = selected ? "uppercase" : "";
                 }));
 
-            //attach the selection doc buttons menu to the drag handle
-            const stack: HTMLDivElement = tab.contentItem.parent;
-            const header: HTMLDivElement = tab;
-            stack.onscroll = action((e: any) => {
-                console.log('scrolling...');
-            });
-            const moreInfoDrag = document.createElement("div");
-            moreInfoDrag.className = "lm_iconWrap";
-            tab._disposers.buttonDisposer = reaction(() => this.view, view =>
-                view && [ReactDOM.render(<span><CollectionDockingViewMenu views={() => [view]} Stack={stack} /></span>, moreInfoDrag), tab._disposers.buttonDisposer?.()],
-                { fireImmediately: true });
-            // tab.reactComponents = [moreInfoDrag];
-            // tab.element[0].children[3].before(moreInfoDrag);
 
             // highlight the tab when the tab document is brushed in any part of the UI
             tab._disposers.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => {
-- 
cgit v1.2.3-70-g09d2


From 94975954fbd1ce9b68f6545b16a4eabe4b41cca0 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 8 Jun 2022 14:30:18 -0400
Subject: fixed bug with adding to pres when in miniview mode.

---
 .../views/collections/CollectionDockingView.tsx    | 69 ++++++++++------------
 src/client/views/collections/TabDocView.tsx        |  3 +
 src/client/views/nodes/trails/PresBox.tsx          |  4 +-
 3 files changed, 37 insertions(+), 39 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 476ffaf81..a790a0475 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -172,12 +172,6 @@ export class CollectionDockingView extends CollectionSubView() {
     @undoBatch
     @action
     public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) {
-        if (document.type === DocumentType.PRES) {
-            const docs = Cast(Cast(Doc.UserDoc().myOverlayDocs, Doc, null).data, listSpec(Doc), []);
-            if (docs.includes(document)) {
-                docs.splice(docs.indexOf(document), 1);
-            }
-        }
         if (document._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), document);
 
         const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document);
@@ -186,6 +180,7 @@ export class CollectionDockingView extends CollectionSubView() {
             return true;
         }
         const instance = CollectionDockingView.Instance;
+        const glayRoot = instance._goldenLayout.root;
         if (!instance) return false;
         const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
 
@@ -194,29 +189,29 @@ export class CollectionDockingView extends CollectionSubView() {
             stack.setActiveContentItem(stack.contentItems[stack.contentItems.length - 1]);
         } else {
             const newItemStackConfig = { type: 'stack', content: [docContentConfig] };
-            const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
-            if (instance._goldenLayout.root.contentItems.length === 0) { // if no rows / columns
-                instance._goldenLayout.root.addChild(newContentItem);
-            } else if (instance._goldenLayout.root.contentItems[0].isStack) {
-                instance._goldenLayout.root.contentItems[0].addChild(docContentConfig);
+            const newContentItem = glayRoot.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
+            if (glayRoot.contentItems.length === 0) { // if no rows / columns
+                glayRoot.addChild(newContentItem);
+            } else if (glayRoot.contentItems[0].isStack) {
+                glayRoot.contentItems[0].addChild(docContentConfig);
             } else if (
-                instance._goldenLayout.root.contentItems.length === 1 &&
-                instance._goldenLayout.root.contentItems[0].contentItems.length === 1 &&
-                instance._goldenLayout.root.contentItems[0].contentItems[0].contentItems.length === 0) {
-                instance._goldenLayout.root.contentItems[0].contentItems[0].addChild(docContentConfig);
+                glayRoot.contentItems.length === 1 &&
+                glayRoot.contentItems[0].contentItems.length === 1 &&
+                glayRoot.contentItems[0].contentItems[0].contentItems.length === 0) {
+                glayRoot.contentItems[0].contentItems[0].addChild(docContentConfig);
             }
             else if (instance._goldenLayout.root.contentItems[0].isRow) { // if row
                 switch (pullSide) {
                     default:
-                    case "right": instance._goldenLayout.root.contentItems[0].addChild(newContentItem); break;
-                    case "left": instance._goldenLayout.root.contentItems[0].addChild(newContentItem, 0); break;
+                    case "right": glayRoot.contentItems[0].addChild(newContentItem); break;
+                    case "left": glayRoot.contentItems[0].addChild(newContentItem, 0); break;
                     case "top":
                     case "bottom":
                         // if not going in a row layout, must add already existing content into column
-                        const rowlayout = instance._goldenLayout.root.contentItems[0];
+                        const rowlayout = glayRoot.contentItems[0];
                         const newColumn = rowlayout.layoutManager.createContentItem({ type: "column" }, instance._goldenLayout);
 
-                        CollectionDockingView.Instance._goldenLayout.saveScrollTops(rowlayout.element);
+                        instance._goldenLayout.saveScrollTops(rowlayout.element);
                         rowlayout.parent.replaceChild(rowlayout, newColumn);
                         if (pullSide === "top") {
                             newColumn.addChild(rowlayout, undefined, true);
@@ -225,23 +220,23 @@ export class CollectionDockingView extends CollectionSubView() {
                             newColumn.addChild(newContentItem, undefined, true);
                             newColumn.addChild(rowlayout, 0, true);
                         }
-                        CollectionDockingView.Instance._goldenLayout.restoreScrollTops(rowlayout.element);
+                        instance._goldenLayout.restoreScrollTops(rowlayout.element);
 
                         rowlayout.config.height = 50;
                         newContentItem.config.height = 50;
                 }
             } else {// if (instance._goldenLayout.root.contentItems[0].isColumn) { // if column
                 switch (pullSide) {
-                    case "top": instance._goldenLayout.root.contentItems[0].addChild(newContentItem, 0); break;
-                    case "bottom": instance._goldenLayout.root.contentItems[0].addChild(newContentItem); break;
+                    case "top": glayRoot.contentItems[0].addChild(newContentItem, 0); break;
+                    case "bottom": glayRoot.contentItems[0].addChild(newContentItem); break;
                     case "left":
                     case "right":
                     default:
                         // if not going in a row layout, must add already existing content into column
-                        const collayout = instance._goldenLayout.root.contentItems[0];
+                        const collayout = glayRoot.contentItems[0];
                         const newRow = collayout.layoutManager.createContentItem({ type: "row" }, instance._goldenLayout);
 
-                        CollectionDockingView.Instance._goldenLayout.saveScrollTops(collayout.element);
+                        instance._goldenLayout.saveScrollTops(collayout.element);
                         collayout.parent.replaceChild(collayout, newRow);
                         if (pullSide === "left") {
                             newRow.addChild(collayout, undefined, true);
@@ -250,7 +245,7 @@ export class CollectionDockingView extends CollectionSubView() {
                             newRow.addChild(newContentItem, undefined, true);
                             newRow.addChild(collayout, 0, true);
                         }
-                        CollectionDockingView.Instance._goldenLayout.restoreScrollTops(collayout.element);
+                        instance._goldenLayout.restoreScrollTops(collayout.element);
 
                         collayout.config.width = 50;
                         newContentItem.config.width = 50;
@@ -289,19 +284,19 @@ export class CollectionDockingView extends CollectionSubView() {
                         this._goldenLayout.unbind('stackCreated', this.stackCreated);
                     } catch (e) { }
                 }
+                this.tabMap.clear();
+                this._goldenLayout.destroy();
             }
-            this.tabMap.clear();
-            this._goldenLayout?.destroy();
-            this._goldenLayout = new GoldenLayout(JSON.parse(config));
-            this._goldenLayout.on('tabCreated', this.tabCreated);
-            this._goldenLayout.on('tabDestroyed', this.tabDestroyed);
-            this._goldenLayout.on('stackCreated', this.stackCreated);
-            this._goldenLayout.registerComponent('DocumentFrameRenderer', TabDocView);
-            this._goldenLayout.container = this._containerRef.current;
-            this._goldenLayout.init();
-            this._goldenLayout.root.layoutManager.on('itemDropped', this.tabItemDropped);
-            this._goldenLayout.root.layoutManager.on('dragStart', this.tabDragStart);
-            this._goldenLayout.root.layoutManager.on('activeContentItemChanged', this.stateChanged);
+            const glay = this._goldenLayout = new GoldenLayout(JSON.parse(config));
+            glay.on('tabCreated', this.tabCreated);
+            glay.on('tabDestroyed', this.tabDestroyed);
+            glay.on('stackCreated', this.stackCreated);
+            glay.registerComponent('DocumentFrameRenderer', TabDocView);
+            glay.container = this._containerRef.current;
+            glay.init();
+            glay.root.layoutManager.on('itemDropped', this.tabItemDropped);
+            glay.root.layoutManager.on('dragStart', this.tabDragStart);
+            glay.root.layoutManager.on('activeContentItemChanged', this.stateChanged);
         }
     }
 
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 91c6975ea..34fe572e3 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -35,6 +35,7 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TabDocView.scss";
 import React = require("react");
+import { listSpec } from '../../../fields/Schema';
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
@@ -246,6 +247,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             }
             if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
             if (!Array.from(CollectionDockingView.Instance.tabMap).map(d => d.DashDoc).includes(curPres)) {
+                const docs = Cast(Cast(Doc.UserDoc().myOverlayDocs, Doc, null).data, listSpec(Doc), []);
+                if (docs.includes(curPres)) docs.splice(docs.indexOf(curPres), 1);
                 CollectionDockingView.AddSplit(curPres, "right");
                 setTimeout(() => DocumentManager.Instance.jumpToDocument(doc, false, undefined, []), 100); // keeps the pinned doc in view since the sidebar shifts things
             }
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 1a4be8e0c..591480023 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -403,11 +403,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             // openInTab(targetDoc);
         } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
             LightboxView.SetLightboxDoc(undefined);
-            await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, [srcContext], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right
+            await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext ? [srcContext]:[], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true); // documents open in new tab instead of on right
         } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
             LightboxView.SetLightboxDoc(undefined);
             //awaiting jump so that new scale can be found, since jumping is async     
-            await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, [srcContext], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right    
+            await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext ? [srcContext]:[], undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection, undefined, true, NumCast(curDoc.presZoom)); // documents open in new tab instead of on right    
         }
         // After navigating to the document, if it is added as a presPinView then it will
         // adjust the pan and scale to that of the pinView when it was added.
-- 
cgit v1.2.3-70-g09d2

