From 2e26c14fe82fa7dfdeb51398558101a0047743e6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 2 Feb 2021 13:53:50 -0500
Subject: playing with a general lightbox for Dash documents.

---
 src/client/views/collections/TabDocView.tsx | 5 ++++-
 1 file changed, 4 insertions(+), 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 c66734556..d291a703b 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -33,6 +33,7 @@ import { CollectionViewType } from './CollectionView';
 import "./TabDocView.scss";
 import React = require("react");
 import Color = require('color');
+import { MainView } from '../MainView';
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
@@ -279,7 +280,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack);
             case "inPlace":
             case "add":
-            default: return CollectionDockingView.AddSplit(doc, locationParams, this.stack);
+            default: runInAction(() => MainView.Instance.LightboxDoc = doc);
+                if (MainView.Instance.LightboxDoc) return true;
+                return CollectionDockingView.AddSplit(doc, locationParams, this.stack);
         }
     }
 
-- 
cgit v1.2.3-70-g09d2


From 7c1dd332dc444d2d34cc9cc142de5998ca4622b5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 4 Feb 2021 14:32:38 -0500
Subject: fixed scrolling animations in view bounds for webbox and pdfBox's
 particualrly for lightbox views.   added a docViewPath prop for docuentViews.

---
 src/client/util/DocumentManager.ts                 | 19 ++++++++++++----
 src/client/util/LinkManager.ts                     |  2 +-
 src/client/views/MainView.tsx                      | 25 +++++++++++++++++++---
 .../views/collections/CollectionStackingView.tsx   |  2 ++
 .../views/collections/CollectionTreeView.tsx       |  2 ++
 src/client/views/collections/TabDocView.tsx        |  5 ++++-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  9 +++++---
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  3 ++-
 src/client/views/nodes/DocumentContentsView.tsx    |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  9 ++++++--
 src/client/views/nodes/WebBox.tsx                  | 11 ++++++++--
 src/client/views/pdf/PDFViewer.tsx                 | 12 +++++------
 12 files changed, 77 insertions(+), 24 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 41c7a1409..08efdb36c 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,4 +1,4 @@
-import { action, observable } from 'mobx';
+import { action, observable, runInAction } from 'mobx';
 import { Doc, DocListCast, DocListCastAsync, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { Cast, NumCast } from '../../fields/Types';
@@ -9,6 +9,7 @@ import { CollectionView } from '../views/collections/CollectionView';
 import { DocumentView } from '../views/nodes/DocumentView';
 import { LinkManager } from './LinkManager';
 import { Scripting } from './Scripting';
+import { MainView } from '../views/MainView';
 
 export type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void;
 
@@ -116,6 +117,7 @@ export class DocumentManager {
         // heuristic to return the "best" documents first:
         //   choose an exact match over an alias match
         //   choose documents that have a PanelWidth() over those that don't (the treeview documents have no panelWidth)
+        docViews.map(view => view.docViewPath.includes(MainView.Instance.lightboxDocView.current!) && view.props.Document === toFind && toReturn.push(view));
         docViews.map(view => view.props.PanelWidth() > 1 && view.props.Document === toFind && toReturn.push(view));
         docViews.map(view => view.props.PanelWidth() <= 1 && view.props.Document === toFind && toReturn.push(view));
         docViews.map(view => view.props.PanelWidth() > 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view));
@@ -139,7 +141,10 @@ export class DocumentManager {
         originatingDoc: Opt<Doc> = undefined, // doc that initiated the display of the target odoc
         finished?: () => void,
     ): Promise<void> => {
-        const getFirstDocView = DocumentManager.Instance.getFirstDocumentView;
+        const getFirstDocView = (toFind: Doc, originatingDoc?: Doc) => {
+            const docView = DocumentManager.Instance.getFirstDocumentView(toFind, originatingDoc);
+            return (!MainView.Instance.LightboxDoc || docView?.docViewPath.includes(MainView.Instance.lightboxDocView.current!)) ? docView : undefined;
+        }
         const focusAndFinish = () => { finished?.(); return false; };
         const highlight = () => {
             const finalDocView = getFirstDocView(targetDoc);
@@ -214,8 +219,14 @@ export class DocumentManager {
                         findView(0);
                     }
                 } else {  // there's no context view so we need to create one first and try again when that finishes
-                    createViewFunc(targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target
-                        () => this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished));
+                    const finishFunc = () => this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished);
+                    if (MainView.Instance.LightboxDoc) {
+                        runInAction(() => MainView.Instance.LightboxDoc = annotatedDoc ? annotatedDoc : targetDoc);
+                        setTimeout(() => finishFunc, 250);
+                    } else {
+                        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/LinkManager.ts b/src/client/util/LinkManager.ts
index 3dabe0ec0..000017ebb 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -147,7 +147,7 @@ export class LinkManager {
                     doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number") :
                         (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number")));
                 if (target) {
-                    if (MainView.Instance.LightboxDoc) {
+                    if (MainView.Instance.LightboxDoc && doc.annotationOn !== MainView.Instance.LightboxDoc) { // following a link should replace an existing lightboxDoc unless the target is an annotation on the lightbox document
                         runInAction(() => MainView.Instance.LightboxDoc = (target.annotationOn as Doc) ?? target);
                         finished?.();
                     } else {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index d72b2b409..9d9698c9c 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -13,7 +13,7 @@ import { List } from '../../fields/List';
 import { PrefetchProxy } from '../../fields/Proxy';
 import { BoolCast, PromiseValue, StrCast } from '../../fields/Types';
 import { TraceMobx } from '../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils, emptyPath } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs } from '../documents/Documents';
@@ -248,6 +248,9 @@ export class MainView extends React.Component {
             addDocument={undefined}
             addDocTab={this.addDocTabFunc}
             pinToPres={emptyFunction}
+            docViewPath={emptyPath}
+            layerProvider={undefined}
+            styleProvider={undefined}
             rootSelected={returnTrue}
             removeDocument={undefined}
             ScreenToLocalTransform={Transform.Identity}
@@ -336,6 +339,9 @@ export class MainView extends React.Component {
                         addDocument={undefined}
                         addDocTab={this.addDocTabFunc}
                         pinToPres={emptyFunction}
+                        docViewPath={emptyPath}
+                        layerProvider={undefined}
+                        styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards ? this.DashboardStyleProvider : DefaultStyleProvider}
                         rootSelected={returnTrue}
                         removeDocument={returnFalse}
                         ScreenToLocalTransform={this.mainContainerXf}
@@ -344,7 +350,6 @@ export class MainView extends React.Component {
                         renderDepth={0}
                         scriptContext={CollectionDockingView.Instance.props.Document}
                         focus={emptyFunction}
-                        styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards ? this.DashboardStyleProvider : DefaultStyleProvider}
                         parentActive={returnTrue}
                         whenActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
@@ -373,8 +378,10 @@ export class MainView extends React.Component {
                 PanelWidth={this.menuPanelWidth}
                 PanelHeight={this.getContentsHeight}
                 renderDepth={0}
+                docViewPath={emptyPath}
                 focus={emptyFunction}
                 styleProvider={DefaultStyleProvider}
+                layerProvider={undefined}
                 parentActive={returnTrue}
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
@@ -476,11 +483,13 @@ export class MainView extends React.Component {
                     dropAction={"alias"}
                     parentActive={returnFalse}
                     styleProvider={DefaultStyleProvider}
+                    layerProvider={undefined}
                     rootSelected={returnTrue}
                     bringToFront={emptyFunction}
                     select={emptyFunction}
                     active={returnFalse}
                     isSelected={returnFalse}
+                    docViewPath={emptyPath}
                     moveDocument={this.moveButtonDoc}
                     CollectionView={undefined}
                     addDocument={this.addButtonDoc}
@@ -547,12 +556,14 @@ export class MainView extends React.Component {
                 pinToPres={emptyFunction}
                 rootSelected={returnTrue}
                 styleProvider={DefaultStyleProvider}
+                layerProvider={undefined}
                 removeDocument={undefined}
                 ScreenToLocalTransform={Transform.Identity}
                 PanelWidth={this.getPWidth}
                 PanelHeight={this.getPHeight}
                 renderDepth={0}
                 focus={emptyFunction}
+                docViewPath={emptyPath}
                 parentActive={returnFalse}
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
@@ -573,6 +584,8 @@ export class MainView extends React.Component {
                     ContainingCollectionDoc={undefined}
                     Document={DocumentLinksButton.invisibleWebDoc}
                     dropAction={"move"}
+                    layerProvider={undefined}
+                    styleProvider={undefined}
                     isSelected={returnFalse}
                     select={returnFalse}
                     rootSelected={returnFalse}
@@ -585,6 +598,7 @@ export class MainView extends React.Component {
                     active={returnFalse}
                     whenActiveChanged={returnFalse}
                     focus={returnFalse}
+                    docViewPath={emptyPath}
                     PanelWidth={() => 500}
                     PanelHeight={() => 800}
                     docFilters={returnEmptyFilter}
@@ -599,6 +613,7 @@ export class MainView extends React.Component {
     lightboxScreenToLocal = () => new Transform(-Math.min(window.innerWidth / 4, 200), -Math.min(window.innerHeight / 4, 100), 1);
     lightboxHistory: (Opt<Doc>)[] = [];
     lightboxFuture: (Opt<Doc>)[] = [];
+    lightboxDocView = React.createRef<DocumentView>();
     @computed get lightboxView() {
         if (this.lightboxHistory.lastElement() !== this.LightboxDoc) this.lightboxHistory.push(this.LightboxDoc);
         let downx = 0, downy = 0;
@@ -618,13 +633,14 @@ export class MainView extends React.Component {
                     width: window.innerWidth - Math.min(window.innerWidth / 4, 200) * 2,
                     height: window.innerHeight - Math.min(window.innerHeight / 4, 100) * 2
                 }}>
-                    <DocumentView
+                    <DocumentView ref={this.lightboxDocView}
                         Document={this.LightboxDoc}
                         DataDoc={undefined}
                         addDocument={undefined}
                         addDocTab={this.addDocTabFunc}
                         pinToPres={emptyFunction}
                         rootSelected={returnTrue}
+                        docViewPath={emptyPath}
                         removeDocument={undefined}
                         styleProvider={DefaultStyleProvider}
                         layerProvider={DefaultLayerProvider(this.LightboxDoc)}
@@ -710,9 +726,12 @@ export class MainView extends React.Component {
                             Document={invisibleDoc}
                             dropAction={"move"}
                             isSelected={returnFalse}
+                            docViewPath={emptyPath}
                             select={returnFalse}
                             rootSelected={returnFalse}
                             renderDepth={0}
+                            layerProvider={undefined}
+                            styleProvider={undefined}
                             addDocTab={returnFalse}
                             pinToPres={returnFalse}
                             ScreenToLocalTransform={Transform.Identity}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d8a8723cd..745987780 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -207,6 +207,8 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
             PanelWidth={width}
             PanelHeight={height}
             styleProvider={styleProvider}
+            layerProvider={this.props.layerProvider}
+            docViewPath={this.props.docViewPath}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
             freezeDimensions={this.props.childFreezeDimensions}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 564939270..bbe6cfdcb 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -164,7 +164,9 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                 renderDepth={this.props.renderDepth + 1}
                 rootSelected={returnTrue}
                 //dontRegisterView={true}
+                docViewPath={this.props.docViewPath}
                 styleProvider={this.props.styleProvider}
+                layerProvider={this.props.layerProvider}
                 PanelWidth={this.rtfWidth}
                 PanelHeight={this.rtfOutlineHeight}
                 focus={this.props.focus}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index d291a703b..e8162c0ed 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -12,7 +12,7 @@ import { FieldId } from "../../../fields/RefField";
 import { listSpec } from '../../../fields/Schema';
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
+import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, Utils, returnEmptyDoclist, emptyPath } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { DocumentType } from '../../documents/DocumentTypes';
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
@@ -314,6 +314,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined}
                     parentActive={returnFalse}
+                    docViewPath={emptyPath}
                     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
                     active={returnTrue}
@@ -334,6 +335,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     whenActiveChanged={emptyFunction}
                     focus={emptyFunction}
                     styleProvider={TabDocView.miniStyleProvider}
+                    layerProvider={undefined}
                     addDocTab={this.addDocTab}
                     pinToPres={TabDocView.PinDoc}
                     docFilters={CollectionDockingView.Instance.docFilters}
@@ -408,6 +410,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 parentActive={this.active}
                 whenActiveChanged={emptyFunction}
                 focus={this.focusFunc}
+                docViewPath={emptyPath}
                 bringToFront={emptyFunction}
                 pinToPres={TabDocView.PinDoc} />
                 {this._document._viewType !== CollectionViewType.Freeform ? (null) :
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 6c7512f7c..e25a46a5d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -904,13 +904,14 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         }
         SelectionManager.DeselectAll();
         if (this.props.Document.scrollHeight) {
-            const annotOn = Cast(doc.annotationOn, Doc) as Doc;
+            // only consider the document to be an annotation if it's an annotation on this collection's document (ignore annotations on some other document that are somehow being focused on here)
+            const annotOn = Doc.AreProtosEqual(doc.annotationOn as Doc, this.props.Document) ? Cast(doc.annotationOn, Doc) as Doc : undefined;
             let delay = 1000;
             if (!annotOn) {
                 !dontCenter && this.props.focus(doc);
                 afterFocus && setTimeout(afterFocus, delay);
             } else {
-                const contextHgt = NumCast(annotOn._height);
+                const contextHgt = this.props.PanelHeight();
                 const curScroll = NumCast(this.props.Document._scrollTop);
                 let scrollTo = curScroll;
                 if (curScroll + contextHgt < NumCast(doc.y)) {
@@ -922,7 +923,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                     this.props.Document._scrollPreviewY = this.props.Document._scrollY = scrollTo;
                     delay = Math.abs(scrollTo - curScroll) > 5 ? 1000 : 0;
                     !dontCenter && this.props.focus(this.props.Document);
-                    afterFocus && setTimeout(afterFocus, delay);
+                    afterFocus && setTimeout(() => afterFocus?.(delay ? true : false), delay);
                 } else {
                     !dontCenter && delay && this.props.focus(this.props.Document);
                     afterFocus?.(!dontCenter && delay ? true : false);
@@ -988,6 +989,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             pinToPres: this.props.pinToPres,
             whenActiveChanged: this.props.whenActiveChanged,
             parentActive: this.parentActive,
+            docViewPath: this.props.docViewPath,
             DataDoc: childData,
             Document: childLayout,
             ContainingCollectionView: this.props.CollectionView,
@@ -1005,6 +1007,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             searchFilterDocs: this.searchFilterDocs,
             focus: this.focusDocument,
             styleProvider: this.getClusterColor,
+            layerProvider: this.props.layerProvider,
             freezeDimensions: this.props.childFreezeDimensions,
             dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
             bringToFront: this.bringToFront,
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 09d89170c..d2dab4157 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -23,7 +23,7 @@ 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;
+    layerProvider: ((doc: Doc, assign?: boolean) => boolean) | undefined
     zIndex?: number;
     highlight?: boolean;
     jitterRotation: number;
@@ -162,6 +162,7 @@ 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/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index f969bee85..6ecd70330 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -207,7 +207,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
         return (this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc || GetEffectiveAcl(this.layoutDoc) === AclPrivate) ? (null) :
             <ObserverJsxParser
                 key={42}
-                blacklistedAttrs={[]}
+                blacklistedAttrs={emptyPath}
                 renderInWrapper={false}
                 components={{
                     FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, SliderBox, FieldView,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 099433168..4e2eadd4b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -62,8 +62,9 @@ export interface DocumentViewSharedProps {
     CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
     PanelWidth: () => number;
     PanelHeight: () => number;
-    layerProvider?: (doc: Doc, assign?: boolean) => boolean;
-    styleProvider?: StyleProviderFunc;
+    docViewPath: DocumentView[];
+    layerProvider: undefined | ((doc: Doc, assign?: boolean) => boolean);
+    styleProvider: Opt<StyleProviderFunc>;
     focus: DocFocusFunc;
     docFilters: () => string[];
     docRangeFilters: () => string[];
@@ -113,6 +114,7 @@ export interface DocumentViewInternalProps extends DocumentViewProps {
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (ctrlPressed: boolean) => void;
     DocumentView: any;
+    viewPath: DocumentView[];
 }
 
 @observer
@@ -720,6 +722,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
             }}>
             <DocumentContentsView key={1} {...this.props}
+                docViewPath={this.props.viewPath}
                 setContentView={this.setContentView}
                 scaling={this.contentScaling}
                 PanelHeight={this.panelHeight}
@@ -875,6 +878,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     get allLinks() { return this.docView?.allLinks || []; }
     get LayoutFieldKey() { return this.docView?.LayoutFieldKey || "layout"; }
 
+    @computed get docViewPath() { return this.props.docViewPath ? [...this.props.docViewPath, this] : [this]; }
     @computed get layoutDoc() { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); }
     @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); }
     @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions) || 0); }
@@ -965,6 +969,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         const internalProps = {
             ...this.props,
             DocumentView: this,
+            viewPath: this.docViewPath,
             PanelWidth: this.PanelWidth,
             PanelHeight: this.PanelHeight,
             NativeWidth: this.NativeWidth,
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index a3afc96d4..e80a78b87 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -92,12 +92,14 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                 const duration = durationStr ? Number(durationStr[1]) : 1000;
                 if (scrollY !== undefined) {
                     this._forceSmoothScrollUpdate = true;
-                    this.layoutDoc._scrollY = undefined;
+                    setTimeout(() => this.layoutDoc._scrollY = undefined, duration);
+                    setTimeout(() => this.webpage && smoothScroll(duration, this.webpage as any as HTMLElement, Math.abs(scrollY || 0)), delay);
                     setTimeout(() => this._outerRef.current && smoothScroll(duration, this._outerRef.current, Math.abs(scrollY || 0), () => this.layoutDoc._scrollTop = scrollY), delay);
                 }
                 if (scrollX !== undefined) {
                     this._forceSmoothScrollUpdate = true;
-                    this.layoutDoc._scrollX = undefined;
+                    setTimeout(() => this.layoutDoc._scrollX = undefined, duration);
+                    setTimeout(() => this.webpage && smoothScroll(duration, this.webpage as any as HTMLElement, Math.abs(scrollX || 0)), delay);
                     setTimeout(() => this._outerRef.current && smoothScroll(duration, this._outerRef.current, Math.abs(scrollX || 0), () => this.layoutDoc._scrollLeft = scrollX), delay);
                 }
             },
@@ -108,6 +110,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                 const durationStr = StrCast(this.Document._viewTransition).match(/([0-9]*)ms/);
                 const duration = durationStr ? Number(durationStr[1]) : 1000;
                 if (scrollTop !== this._outerRef.current?.scrollTop && scrollTop !== undefined && this._forceSmoothScrollUpdate) {
+                    this.webpage!.scrollTop = scrollTop;
                     this._outerRef.current && smoothScroll(duration, this._outerRef.current, Math.abs(scrollTop || 0), () => this._forceSmoothScrollUpdate = true);
                 } else this._forceSmoothScrollUpdate = true;
             },
@@ -447,6 +450,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
         this.props.select(true);
     }
 
+    panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
+    panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
     scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc._scrollLeft), NumCast(this.layoutDoc._scrollTop));
     render() {
         const inactiveLayer = this.props.layerProvider?.(this.layoutDoc) === false;
@@ -490,6 +495,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                             fieldKey={this.annotationKey}
                             isAnnotationOverlay={true}
                             scaling={returnOne}
+                            PanelWidth={this.panelWidth}
+                            PanelHeight={this.panelHeight}
                             ScreenToLocalTransform={this.scrollXf}
                             removeDocument={this.removeDocument}
                             moveDocument={this.moveDocument}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index fa97bde3f..cffa9686b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -150,8 +150,8 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                         const delay = this._mainCont.current ? 0 : 250; // wait for mainCont and try again to scroll
                         const durationStr = StrCast(this.Document._viewTransition).match(/([0-9]*)ms/);
                         const duration = durationStr ? Number(durationStr[1]) : 1000;
-                        setTimeout(() => this._mainCont.current && smoothScroll(duration, this._mainCont.current, Math.abs(scrollY || 0)), delay);
-                        setTimeout(() => { this.Document._scrollTop = scrollY; this.Document._scrollY = undefined; }, duration + delay);
+                        setTimeout(() => this.Document._scrollY = undefined, duration + delay);
+                        setTimeout(() => this._mainCont.current && smoothScroll(duration, this._mainCont.current, Math.abs(scrollY || 0), () => this.layoutDoc._scrollTop = scrollY), delay);
                     }
                 }
             },
@@ -518,8 +518,8 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
 
     showInfo = action((anno: Opt<Doc>) => this._overlayAnnoInfo = anno);
     overlayTransform = () => this.scrollXf().scale(1 / this._zoomed);
-    panelWidth = () => (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
-    panelHeight = () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
+    panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
+    panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
     @computed get overlayLayer() {
         return <div className={`pdfViewerDash-overlay${Doc.GetSelectedTool() !== InkTool.None || SnappingManager.GetIsDragging() ? "-inking" : ""}`}
             style={{
@@ -531,8 +531,8 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                 isAnnotationOverlay={true}
                 fieldKey={this.annotationKey}
                 setPreviewCursor={this.setPreviewCursor}
-                PanelHeight={this.panelWidth}
-                PanelWidth={this.panelHeight}
+                PanelHeight={this.panelHeight}
+                PanelWidth={this.panelWidth}
                 dropAction={"alias"}
                 select={emptyFunction}
                 active={this.annotationsActive}
-- 
cgit v1.2.3-70-g09d2


From d5bda76f901c27771715f2443392ff7d54f99693 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 5 Feb 2021 13:52:32 -0500
Subject: cleaned up lightbox.  replaced old npm lightbox.

---
 src/client/util/DocumentManager.ts                 |  12 +--
 src/client/util/LinkManager.ts                     |  10 +-
 src/client/views/DocumentDecorations.tsx           |   4 +-
 src/client/views/GestureOverlay.tsx                |   4 +-
 src/client/views/GlobalKeyHandler.ts               |   5 +-
 src/client/views/LightboxView.scss                 |  26 ++++++
 src/client/views/LightboxView.tsx                  | 103 +++++++++++++++++++++
 src/client/views/MainView.scss                     |  24 -----
 src/client/views/MainView.tsx                      |  82 +---------------
 src/client/views/OverlayView.tsx                   |   4 +-
 src/client/views/Palette.tsx                       |   4 +-
 src/client/views/PropertiesView.tsx                |   4 +-
 src/client/views/TemplateMenu.tsx                  |   6 +-
 .../views/collections/CollectionLinearView.tsx     |   4 +-
 src/client/views/collections/CollectionMenu.tsx    |  11 ++-
 .../views/collections/CollectionSchemaView.tsx     |   4 +-
 src/client/views/collections/CollectionView.tsx    |  41 +-------
 src/client/views/collections/SchemaTable.tsx       |   6 +-
 src/client/views/collections/TabDocView.tsx        |   5 +-
 src/client/views/collections/TreeView.tsx          |  10 +-
 .../CollectionMulticolumnView.tsx                  |   4 +-
 .../CollectionMultirowView.tsx                     |   4 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |   2 +-
 src/client/views/nodes/DocHolderBox.tsx            |   4 +
 src/client/views/nodes/DocumentView.tsx            |   2 +-
 src/client/views/nodes/FilterBox.tsx               |   2 +
 src/client/views/nodes/KeyValuePair.tsx            |   6 +-
 src/client/views/nodes/LinkDocPreview.tsx          |   7 +-
 .../views/nodes/formattedText/DashDocView.tsx      |   4 +-
 .../formattedText/FormattedTextBoxComment.tsx      |   6 +-
 .../views/nodes/formattedText/RichTextSchema.tsx   |   1 +
 .../views/presentationview/PresElementBox.tsx      |   4 +-
 src/mobile/AudioUpload.tsx                         |   4 +-
 src/mobile/MobileInterface.tsx                     |   2 +
 34 files changed, 241 insertions(+), 180 deletions(-)
 create mode 100644 src/client/views/LightboxView.scss
 create mode 100644 src/client/views/LightboxView.tsx

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 08efdb36c..7af16ed6e 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -6,10 +6,10 @@ import { returnFalse } from '../../Utils';
 import { DocumentType } from '../documents/DocumentTypes';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
 import { CollectionView } from '../views/collections/CollectionView';
+import { LightboxView } from '../views/LightboxView';
 import { DocumentView } from '../views/nodes/DocumentView';
 import { LinkManager } from './LinkManager';
 import { Scripting } from './Scripting';
-import { MainView } from '../views/MainView';
 
 export type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void;
 
@@ -117,7 +117,7 @@ export class DocumentManager {
         // heuristic to return the "best" documents first:
         //   choose an exact match over an alias match
         //   choose documents that have a PanelWidth() over those that don't (the treeview documents have no panelWidth)
-        docViews.map(view => view.docViewPath.includes(MainView.Instance.lightboxDocView.current!) && view.props.Document === toFind && toReturn.push(view));
+        docViews.map(view => view.docViewPath.includes(LightboxView.LightboxDocView.current!) && view.props.Document === toFind && toReturn.push(view));
         docViews.map(view => view.props.PanelWidth() > 1 && view.props.Document === toFind && toReturn.push(view));
         docViews.map(view => view.props.PanelWidth() <= 1 && view.props.Document === toFind && toReturn.push(view));
         docViews.map(view => view.props.PanelWidth() > 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view));
@@ -143,8 +143,8 @@ export class DocumentManager {
     ): Promise<void> => {
         const getFirstDocView = (toFind: Doc, originatingDoc?: Doc) => {
             const docView = DocumentManager.Instance.getFirstDocumentView(toFind, originatingDoc);
-            return (!MainView.Instance.LightboxDoc || docView?.docViewPath.includes(MainView.Instance.lightboxDocView.current!)) ? docView : undefined;
-        }
+            return (!LightboxView.LightboxDoc || docView?.docViewPath.includes(LightboxView.LightboxDocView.current!)) ? docView : undefined;
+        };
         const focusAndFinish = () => { finished?.(); return false; };
         const highlight = () => {
             const finalDocView = getFirstDocView(targetDoc);
@@ -220,8 +220,8 @@ export class DocumentManager {
                     }
                 } else {  // there's no context view so we need to create one first and try again when that finishes
                     const finishFunc = () => this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished);
-                    if (MainView.Instance.LightboxDoc) {
-                        runInAction(() => MainView.Instance.LightboxDoc = annotatedDoc ? annotatedDoc : targetDoc);
+                    if (LightboxView.LightboxDoc) {
+                        runInAction(() => LightboxView.LightboxDoc = annotatedDoc ? annotatedDoc : targetDoc);
                         setTimeout(() => finishFunc, 250);
                     } else {
                         createViewFunc(targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 000017ebb..afc0e76be 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -1,14 +1,14 @@
+import { runInAction } from "mobx";
 import { computedFn } from "mobx-utils";
 import { Doc, DocListCast, Opt } from "../../fields/Doc";
 import { BoolCast, Cast, StrCast } from "../../fields/Types";
-import { DocFocusFunc, DocumentViewSharedProps } from "../views/nodes/DocumentView";
+import { LightboxView } from "../views/LightboxView";
+import { DocumentViewSharedProps } from "../views/nodes/DocumentView";
 import { FormattedTextBoxComment } from "../views/nodes/formattedText/FormattedTextBoxComment";
 import { LinkDocPreview } from "../views/nodes/LinkDocPreview";
 import { CreateViewFunc, DocumentManager } from "./DocumentManager";
 import { SharingManager } from "./SharingManager";
 import { UndoManager } from "./UndoManager";
-import { MainView } from "../views/MainView";
-import { runInAction } from "mobx";
 
 /* 
  * link doc: 
@@ -147,8 +147,8 @@ export class LinkManager {
                     doc === linkDoc.anchor2 ? Cast(linkDoc.anchor1_timecode, "number") :
                         (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number")));
                 if (target) {
-                    if (MainView.Instance.LightboxDoc && doc.annotationOn !== MainView.Instance.LightboxDoc) { // following a link should replace an existing lightboxDoc unless the target is an annotation on the lightbox document
-                        runInAction(() => MainView.Instance.LightboxDoc = (target.annotationOn as Doc) ?? target);
+                    if (LightboxView.LightboxDoc && doc.annotationOn !== LightboxView.LightboxDoc) { // following a link should replace an existing lightboxDoc unless the target is an annotation on the lightbox document
+                        runInAction(() => LightboxView.LightboxDoc = (target.annotationOn as Doc) ?? target);
                         finished?.();
                     } else {
                         const containerDoc = (await Cast(target.annotationOn, Doc)) || target;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 226eef658..0dfa0f8b2 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -23,10 +23,10 @@ import { DocumentButtonBar } from './DocumentButtonBar';
 import './DocumentDecorations.scss';
 import { KeyManager } from './GlobalKeyHandler';
 import { InkStrokeProperties } from './InkStrokeProperties';
+import { LightboxView } from './LightboxView';
 import { DocumentView } from "./nodes/DocumentView";
 import React = require("react");
 import e = require('express');
-import { MainView } from './MainView';
 
 @observer
 export class DocumentDecorations extends React.Component<{ boundsLeft: number, boundsTop: number }, { value: string }> {
@@ -175,7 +175,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
                 } else if (e.altKey) {    // open same document in new tab
                     CollectionDockingView.ToggleSplit(Cast(selectedDocs[0].props.Document._fullScreenView, Doc, null) || selectedDocs[0].props.Document, "right");
                 } else {
-                    runInAction(() => MainView.Instance.LightboxDoc = selectedDocs[0].props.Document);
+                    runInAction(() => LightboxView.LightboxDoc = selectedDocs[0].props.Document);
                 }
             }
         }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index ae27e78d5..76cb0112e 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -8,7 +8,7 @@ import { Cast, FieldValue, NumCast } from "../../fields/Types";
 import MobileInkOverlay from "../../mobile/MobileInkOverlay";
 import { GestureUtils } from "../../pen-gestures/GestureUtils";
 import { MobileInkOverlayContent } from "../../server/Message";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from "../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents, emptyPath } from "../../Utils";
 import { CognitiveServices } from "../cognitive_services/CognitiveServices";
 import { DocUtils } from "../documents/Documents";
 import { CurrentUserUtils } from "../util/CurrentUserUtils";
@@ -886,6 +886,8 @@ export class GestureOverlay extends Touchable {
                 PanelHeight={this.return300}
                 renderDepth={0}
                 styleProvider={returnEmptyString}
+                layerProvider={undefined}
+                docViewPath={emptyPath}
                 focus={emptyFunction}
                 parentActive={returnTrue}
                 whenActiveChanged={emptyFunction}
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 78905bfb2..e70dea0f6 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -19,12 +19,13 @@ import { SnappingManager } from "../util/SnappingManager";
 import { undoBatch, UndoManager } from "../util/UndoManager";
 import { CollectionDockingView } from "./collections/CollectionDockingView";
 import { CollectionFreeFormViewChrome } from "./collections/CollectionMenu";
+import { CollectionStackedTimeline } from "./collections/CollectionStackedTimeline";
 import { ContextMenu } from "./ContextMenu";
 import { DocumentDecorations } from "./DocumentDecorations";
 import { InkStrokeProperties } from "./InkStrokeProperties";
+import { LightboxView } from "./LightboxView";
 import { MainView } from "./MainView";
 import { DocumentLinksButton } from "./nodes/DocumentLinksButton";
-import { CollectionStackedTimeline } from "./collections/CollectionStackedTimeline";
 import { AnchorMenu } from "./pdf/AnchorMenu";
 import { SearchBox } from "./search/SearchBox";
 
@@ -114,7 +115,7 @@ export class KeyManager {
                 DocumentLinksButton.StartLink = undefined;
                 DocumentLinksButton.StartLinkView = undefined;
                 InkStrokeProperties.Instance && (InkStrokeProperties.Instance._controlBtn = false);
-                MainView.Instance.LightboxDoc = undefined;
+                LightboxView.LightboxDoc = undefined;
 
                 Doc.SetSelectedTool(InkTool.None);
                 var doDeselect = true;
diff --git a/src/client/views/LightboxView.scss b/src/client/views/LightboxView.scss
new file mode 100644
index 000000000..9847966bf
--- /dev/null
+++ b/src/client/views/LightboxView.scss
@@ -0,0 +1,26 @@
+.lightboxView-frame {
+    position: absolute; 
+    top: 0; left: 0;
+    width: 100%;
+    height: 100%;
+    background: #000000bb;
+    z-index: 10000;
+    .lightboxView-contents {
+        position: absolute;
+    }
+    .lightboxView-navBtn-frame {
+        position: absolute;
+        .lightboxView-navBtn {
+            margin: auto;
+            position: relative;
+            background: transparent;
+            border-radius: 8;
+            color:white;
+            opacity: 0.7;
+            width: 30;
+            &:hover {
+                opacity: 1;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
new file mode 100644
index 000000000..263117437
--- /dev/null
+++ b/src/client/views/LightboxView.tsx
@@ -0,0 +1,103 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, observable } from 'mobx';
+import { observer } from 'mobx-react';
+import "normalize.css";
+import * as React from 'react';
+import { Doc, Opt } from '../../fields/Doc';
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../../Utils';
+import { Transform } from '../util/Transform';
+import "./LightboxView.scss";
+import { DocumentView } from './nodes/DocumentView';
+import { DefaultStyleProvider } from './StyleProvider';
+
+interface LightboxViewProps {
+    PanelWidth: number;
+    PanelHeight: number;
+    minBorder: number[];
+}
+
+@observer
+export class LightboxView extends React.Component<LightboxViewProps> {
+    @observable public static LightboxDoc: Opt<Doc>;
+    public static LightboxHistory: (Opt<Doc>)[] = [];
+    public static LightboxFuture: (Opt<Doc>)[] = [];
+    public static LightboxDocView = React.createRef<DocumentView>();
+    public LightboxDocView = React.createRef<DocumentView>();
+    lightboxWidth = () => this.props.PanelWidth - Math.min(this.props.PanelWidth / 4, this.props.minBorder[0]) * 2;
+    lightboxHeight = () => this.props.PanelHeight - Math.min(this.props.PanelHeight / 4, this.props.minBorder[1]) * 2;
+    lightboxScreenToLocal = () => new Transform(-Math.min(this.props.PanelWidth / 4, this.props.minBorder[0]), -Math.min(this.props.PanelHeight / 4, this.props.minBorder[1]), 1);
+    navBtn = (left: Opt<number>, icon: string, display: () => string, click: (e: React.MouseEvent) => void) => {
+        return <div className="lightboxView-navBtn-frame" style={{
+            display: display(),
+            left,
+            width: Math.min(this.props.PanelWidth / 4, this.props.minBorder[0])
+        }}>
+            <div className="lightboxView-navBtn" style={{ top: this.props.PanelHeight / 2 - 12.50 }}
+                onClick={click}>
+                <FontAwesomeIcon icon={icon as any} size="3x" />
+            </div>
+        </div>;
+    }
+
+    render() {
+        if (LightboxView.LightboxHistory.lastElement() !== LightboxView.LightboxDoc) LightboxView.LightboxHistory.push(LightboxView.LightboxDoc);
+        let downx = 0, downy = 0;
+        return !LightboxView.LightboxDoc ? (null) :
+            <div className="lightboxView-frame"
+                onPointerDown={e => { downx = e.clientX; downy = e.clientY; }}
+                onClick={action(e => {
+                    if (Math.abs(downx - e.clientX) < 4 && Math.abs(downy - e.clientY) < 4) {
+                        LightboxView.LightboxHistory = [];
+                        LightboxView.LightboxFuture = [];
+                        LightboxView.LightboxDoc = undefined;
+                    }
+                })}  >
+                <div className="lightboxView-contents" style={{
+                    left: Math.min(this.props.PanelWidth / 4, this.props.minBorder[0]),
+                    top: Math.min(this.props.PanelHeight / 4, this.props.minBorder[1]),
+                    width: this.props.PanelWidth - Math.min(this.props.PanelWidth / 4, this.props.minBorder[0]) * 2,
+                    height: this.props.PanelHeight - Math.min(this.props.PanelHeight / 4, this.props.minBorder[1]) * 2
+                }}>
+                    <DocumentView ref={this.LightboxDocView}
+                        Document={LightboxView.LightboxDoc}
+                        DataDoc={undefined}
+                        addDocument={undefined}
+                        addDocTab={returnFalse}
+                        pinToPres={emptyFunction}
+                        rootSelected={returnTrue}
+                        docViewPath={emptyPath}
+                        removeDocument={undefined}
+                        styleProvider={DefaultStyleProvider}
+                        layerProvider={undefined}
+                        ScreenToLocalTransform={this.lightboxScreenToLocal}
+                        PanelWidth={this.lightboxWidth}
+                        PanelHeight={this.lightboxHeight}
+                        focus={emptyFunction}
+                        parentActive={returnTrue}
+                        whenActiveChanged={emptyFunction}
+                        bringToFront={emptyFunction}
+                        docFilters={returnEmptyFilter}
+                        docRangeFilters={returnEmptyFilter}
+                        searchFilterDocs={returnEmptyDoclist}
+                        ContainingCollectionView={undefined}
+                        ContainingCollectionDoc={undefined}
+                        renderDepth={0} />
+                </div>
+                {this.navBtn(undefined, "chevron-left",
+                    () => LightboxView.LightboxDoc && LightboxView.LightboxHistory.length ? "" : "none",
+                    action(e => {
+                        e.stopPropagation();
+                        const popped = LightboxView.LightboxHistory.pop();
+                        if (LightboxView.LightboxHistory.lastElement() !== LightboxView.LightboxFuture.lastElement()) LightboxView.LightboxFuture.push(popped);
+                        LightboxView.LightboxDoc = LightboxView.LightboxHistory.lastElement();
+                    }))}
+                {this.navBtn(this.props.PanelWidth - Math.min(this.props.PanelWidth / 4, this.props.minBorder[0]), "chevron-right",
+                    () => LightboxView.LightboxDoc && LightboxView.LightboxFuture.length ? "" : "none",
+                    action(e => {
+                        e.stopPropagation();
+                        LightboxView.LightboxDoc = LightboxView.LightboxFuture.pop();
+                    }))}
+
+            </div>;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index 971e8f2ac..8ccb64744 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -67,30 +67,6 @@
         background: #cacaca;
         color: black;
     }
-
-    .mainView-lightBox-frame {
-        position: absolute; 
-        top: 0; left: 0;
-        width: 100%;
-        height: 100%;
-        background: #000000bb;
-        z-index: 10000;
-        .mainView-lightBox-contents {
-            position: absolute;
-        }
-        .mainView-lightBox-navBtn {
-            margin: auto;
-            position: relative;
-            background: transparent;
-            border-radius: 8;
-            color:white;
-            opacity: 0.7;
-            width: 30;
-            &:hover {
-                opacity: 1;
-            }
-        }
-    }
 }
 
 .mainView-container-dark {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 5873ce650..b3f5cc54f 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -13,7 +13,7 @@ import { List } from '../../fields/List';
 import { PrefetchProxy } from '../../fields/Proxy';
 import { BoolCast, PromiseValue, StrCast } from '../../fields/Types';
 import { TraceMobx } from '../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils, emptyPath } from '../../Utils';
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs } from '../documents/Documents';
@@ -42,6 +42,7 @@ import { GestureOverlay } from './GestureOverlay';
 import { MENU_PANEL_WIDTH, SEARCH_PANEL_HEIGHT } from './globalCssVariables.scss';
 import { KeyManager } from './GlobalKeyHandler';
 import { InkStrokeProperties } from './InkStrokeProperties';
+import { LightboxView } from './LightboxView';
 import { LinkMenu } from './linking/LinkMenu';
 import "./MainView.scss";
 import { AudioBox } from './nodes/AudioBox';
@@ -59,7 +60,7 @@ import { AnchorMenu } from './pdf/AnchorMenu';
 import { PreviewCursor } from './PreviewCursor';
 import { PropertiesView } from './PropertiesView';
 import { SearchBox } from './search/SearchBox';
-import { DefaultStyleProvider, StyleProp, DefaultLayerProvider } from './StyleProvider';
+import { DefaultStyleProvider, StyleProp } from './StyleProvider';
 const _global = (window /* browser */ || global /* node */) as any;
 
 @observer
@@ -68,7 +69,6 @@ export class MainView extends React.Component {
     private _docBtnRef = React.createRef<HTMLDivElement>();
     private _mainViewRef = React.createRef<HTMLDivElement>();
     @observable public LastButton: Opt<Doc>;
-    @observable public LightboxDoc: Opt<Doc>;
     @observable private _panelWidth: number = 0;
     @observable private _panelHeight: number = 0;
     @observable private _panelContent: string = "none";
@@ -608,80 +608,6 @@ export class MainView extends React.Component {
             </div>;
     }
 
-    lightboxWidth = () => window.innerWidth - Math.min(window.innerWidth / 4, 200) * 2;
-    lightboxHeight = () => window.innerHeight - Math.min(window.innerHeight / 4, 100) * 2;
-    lightboxScreenToLocal = () => new Transform(-Math.min(window.innerWidth / 4, 200), -Math.min(window.innerHeight / 4, 100), 1);
-    lightboxHistory: (Opt<Doc>)[] = [];
-    lightboxFuture: (Opt<Doc>)[] = [];
-    lightboxDocView = React.createRef<DocumentView>();
-    @computed get lightboxView() {
-        if (this.lightboxHistory.lastElement() !== this.LightboxDoc) this.lightboxHistory.push(this.LightboxDoc);
-        let downx = 0, downy = 0;
-        return !this.LightboxDoc ? (null) :
-            <div className="mainView-lightBox-frame"
-                onPointerDown={e => { downx = e.clientX; downy = e.clientY; }}
-                onClick={action(e => {
-                    if (Math.abs(downx - e.clientX) < 4 && Math.abs(downy - e.clientY) < 4) {
-                        this.lightboxHistory = [];
-                        this.lightboxFuture = [];
-                        this.LightboxDoc = undefined;
-                    }
-                })}  >
-                <div className="mainView-lightBox-contents" style={{
-                    left: Math.min(window.innerWidth / 4, 200),
-                    top: Math.min(window.innerHeight / 4, 100),
-                    width: window.innerWidth - Math.min(window.innerWidth / 4, 200) * 2,
-                    height: window.innerHeight - Math.min(window.innerHeight / 4, 100) * 2
-                }}>
-                    <DocumentView ref={this.lightboxDocView}
-                        Document={this.LightboxDoc}
-                        DataDoc={undefined}
-                        addDocument={undefined}
-                        addDocTab={this.addDocTabFunc}
-                        pinToPres={emptyFunction}
-                        rootSelected={returnTrue}
-                        docViewPath={emptyPath}
-                        removeDocument={undefined}
-                        styleProvider={DefaultStyleProvider}
-                        layerProvider={DefaultLayerProvider(this.LightboxDoc)}
-                        ScreenToLocalTransform={this.lightboxScreenToLocal}
-                        PanelWidth={this.lightboxWidth}
-                        PanelHeight={this.lightboxHeight}
-                        focus={emptyFunction}
-                        parentActive={returnTrue}
-                        whenActiveChanged={emptyFunction}
-                        bringToFront={emptyFunction}
-                        docFilters={returnEmptyFilter}
-                        docRangeFilters={returnEmptyFilter}
-                        searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
-                        renderDepth={0} />
-                </div>
-                <div style={{ position: "absolute", display: this.LightboxDoc && this.lightboxHistory.length ? "" : "none", width: Math.min(window.innerWidth / 4, 200) }}>
-                    <div className="mainView-lightBox-navBtn" style={{ top: window.innerHeight / 2 - 12.50 }}
-                        onClick={action(e => {
-                            e.stopPropagation();
-                            const popped = this.lightboxHistory.pop();
-                            if (this.lightboxHistory.lastElement() !== this.lightboxFuture.lastElement()) this.lightboxFuture.push(popped);
-                            this.LightboxDoc = this.lightboxHistory.lastElement();
-                        })}>
-                        <FontAwesomeIcon icon={"chevron-left"} size="3x" />
-                    </div>
-                </div>
-                <div style={{ position: "absolute", display: this.LightboxDoc && this.lightboxFuture.length ? "" : "none", left: window.innerWidth - Math.min(window.innerWidth / 4, 200), width: Math.min(window.innerWidth / 4, 200) }}>
-                    <div className="mainView-lightBox-navBtn" style={{ top: window.innerHeight / 2 - 12.50 }}
-                        onClick={action(e => {
-                            e.stopPropagation();
-                            this.LightboxDoc = this.lightboxFuture.pop();
-                        })}>
-                        <FontAwesomeIcon icon={"chevron-right"} size="3x" />
-                    </div>
-                </div>
-            </div>;
-    }
-
-
     render() {
         return (<div className={"mainView-container" + (this.darkScheme ? "-dark" : "")} onScroll={() => ((ele) => ele.scrollTop = ele.scrollLeft = 0)(document.getElementById("root")!)} ref={this._mainViewRef}>
             {this.inkResources}
@@ -710,7 +636,7 @@ export class MainView extends React.Component {
             <TimelineMenu />
             {this.snapLines}
             <div className="mainView-webRef" ref={this.makeWebRef} />
-            {this.lightboxView}
+            <LightboxView PanelWidth={this._panelWidth} PanelHeight={this._panelHeight} minBorder={[200, 100]} />
         </div>);
     }
 
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 78053be92..628003391 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -5,7 +5,7 @@ import ReactLoading from 'react-loading';
 import { Doc } 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, setupMoveUpEvents, Utils, emptyPath } from "../../Utils";
 import { CurrentUserUtils } from "../util/CurrentUserUtils";
 import { DragManager } from "../util/DragManager";
 import { Scripting } from "../util/Scripting";
@@ -193,6 +193,8 @@ export class OverlayView extends React.Component {
                     whenActiveChanged={emptyFunction}
                     focus={emptyFunction}
                     styleProvider={DefaultStyleProvider}
+                    layerProvider={undefined}
+                    docViewPath={emptyPath}
                     addDocTab={returnFalse}
                     pinToPres={emptyFunction}
                     docFilters={returnEmptyFilter}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index d181c7651..6268be31c 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
 import * as React from "react";
 import { Doc } from "../../fields/Doc";
 import { NumCast } from "../../fields/Types";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue } from "../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { DocumentView } from "./nodes/DocumentView";
 import "./Palette.scss";
@@ -50,7 +50,9 @@ export default class Palette extends React.Component<PaletteProps> {
                             PanelHeight={() => window.screen.height}
                             renderDepth={0}
                             focus={emptyFunction}
+                            docViewPath={emptyPath}
                             styleProvider={returnEmptyString}
+                            layerProvider={undefined}
                             parentActive={returnTrue}
                             whenActiveChanged={emptyFunction}
                             bringToFront={emptyFunction}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 4aeb4e63a..a5ddf8044 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -11,7 +11,7 @@ import { InkField } from "../../fields/InkField";
 import { ComputedField } from "../../fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../fields/Types";
 import { denormalizeEmail, GetEffectiveAcl, SharingPermissions } from "../../fields/util";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse } from "../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, emptyPath } from "../../Utils";
 import { DocumentType } from "../documents/DocumentTypes";
 import { DocumentManager } from "../util/DocumentManager";
 import { SelectionManager } from "../util/SelectionManager";
@@ -270,6 +270,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     renderDepth={1}
                     rootSelected={returnFalse}
                     styleProvider={DefaultStyleProvider}
+                    layerProvider={undefined}
+                    docViewPath={emptyPath}
                     freezeDimensions={true}
                     dontCenter={"y"}
                     NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 841e8aef9..f9aae64f1 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -5,13 +5,14 @@ import { List } from "../../fields/List";
 import { ScriptField } from "../../fields/ScriptField";
 import { Cast, StrCast } from "../../fields/Types";
 import { TraceMobx } from "../../fields/util";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../Utils";
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from "../../Utils";
 import { Docs, DocUtils } from "../documents/Documents";
 import { Scripting } from "../util/Scripting";
 import { Transform } from "../util/Transform";
 import { undoBatch } from "../util/UndoManager";
 import { CollectionTreeView } from "./collections/CollectionTreeView";
 import { DocumentView } from "./nodes/DocumentView";
+import { DefaultStyleProvider } from "./StyleProvider";
 import './TemplateMenu.scss';
 import React = require("react");
 
@@ -130,6 +131,9 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 CollectionView={undefined}
                 ContainingCollectionDoc={undefined}
                 ContainingCollectionView={undefined}
+                styleProvider={DefaultStyleProvider}
+                layerProvider={undefined}
+                docViewPath={emptyPath}
                 docFilters={returnEmptyFilter}
                 docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 756346356..79cc1719c 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -7,7 +7,7 @@ import { documentSchema } from '../../../fields/documentSchemas';
 import { Id } from '../../../fields/FieldSymbols';
 import { makeInterface } from '../../../fields/Schema';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, returnTrue, Utils } from '../../../Utils';
+import { emptyFunction, returnTrue, Utils, emptyPath } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { Transform } from '../../util/Transform';
 import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
@@ -152,6 +152,8 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 renderDepth={this.props.renderDepth + 1}
                                 focus={emptyFunction}
                                 styleProvider={this.props.styleProvider}
+                                layerProvider={this.props.layerProvider}
+                                docViewPath={emptyPath}
                                 parentActive={returnTrue}
                                 whenActiveChanged={emptyFunction}
                                 bringToFront={emptyFunction}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 7ba857449..3f0b8eb3e 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -33,6 +33,7 @@ import { PresBox } from "../nodes/PresBox";
 import "./CollectionMenu.scss";
 import { CollectionViewType, COLLECTION_BORDER_WIDTH } from "./CollectionView";
 import { TabDocView } from "./TabDocView";
+import { LightboxView } from "../LightboxView";
 
 @observer
 export class CollectionMenu extends AntimodeMenu<AntimodeMenuProps> {
@@ -487,8 +488,14 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
 
     @computed get lightboxButton() {
         const targetDoc = this.selectedDoc;
-        return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Show Lightbox of Images"}</div>} placement="top">
-            <button className="antimodeMenu-button" onPointerDown={action(() => targetDoc._isLightboxOpen = true)}>
+        return !targetDoc ? (null) : <Tooltip title={<div className="dash-tooltip">{"Show Lightbox of Documents"}</div>} placement="top">
+            <button className="antimodeMenu-button" onPointerDown={action(() => {
+                const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
+                if (docs.length) {
+                    LightboxView.LightboxDoc = docs[0];
+                    LightboxView.LightboxFuture = docs;
+                }
+            })}>
                 <FontAwesomeIcon className="documentdecorations-icon" icon="desktop" size="lg" />
             </button>
         </Tooltip>;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index c39f8b255..e246dc020 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -11,7 +11,7 @@ import { listSpec } from "../../../fields/Schema";
 import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
 import { Cast, NumCast } from "../../../fields/Types";
 import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, setupMoveUpEvents } from "../../../Utils";
 import { SelectionManager } from "../../util/SelectionManager";
 import { SnappingManager } from "../../util/SnappingManager";
 import { Transform } from "../../util/Transform";
@@ -414,6 +414,8 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                     docRangeFilters={this.docRangeFilters}
                     searchFilterDocs={this.searchFilterDocs}
                     styleProvider={DefaultStyleProvider}
+                    layerProvider={undefined}
+                    docViewPath={emptyPath}
                     ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                     ContainingCollectionView={this.props.CollectionView}
                     moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 03d8606d7..9ae469930 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,17 +1,16 @@
 import { action, computed, observable } from 'mobx';
 import { observer } from "mobx-react";
 import * as React from 'react';
-import Lightbox from 'react-image-lightbox-with-rotate';
 import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
 import { DateField } from '../../../fields/DateField';
-import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, DocListCast, Field } from '../../../fields/Doc';
+import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, DocListCast } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
 import { ObjectField } from '../../../fields/ObjectField';
-import { BoolCast, Cast, ScriptCast, StrCast } from '../../../fields/Types';
-import { ImageField } from '../../../fields/URLField';
+import { ScriptField } from '../../../fields/ScriptField';
+import { Cast, ScriptCast, StrCast } from '../../../fields/Types';
 import { denormalizeEmail, distributeAcls, GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
-import { returnFalse, Utils } from '../../../Utils';
+import { returnFalse } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
@@ -38,7 +37,6 @@ import { SubCollectionViewProps } from './CollectionSubView';
 import { CollectionTimeView } from './CollectionTimeView';
 import { CollectionTreeView } from "./CollectionTreeView";
 import './CollectionView.scss';
-import { ScriptField } from '../../../fields/ScriptField';
 export const COLLECTION_BORDER_WIDTH = 2;
 const path = require('path');
 
@@ -85,8 +83,6 @@ export class CollectionView extends Touchable<CollectionViewProps> {
     public static LayoutString(fieldStr: string) { return FieldView.LayoutString(CollectionView, fieldStr); }
 
     _isChildActive = false;   //TODO should this be observable?
-    get _isLightboxOpen() { return BoolCast(this.props.Document._isLightboxOpen); }
-    set _isLightboxOpen(value) { this.props.Document._isLightboxOpen = value; }
     @observable private _curLightboxImg = 0;
     @observable private static _safeMode = false;
     public static SetSafeMode(safeMode: boolean) { this._safeMode = safeMode; }
@@ -280,7 +276,6 @@ export class CollectionView extends Touchable<CollectionViewProps> {
         !Doc.UserDoc().noviceMode && subItems.push({ description: "Pivot/Time", event: () => func(CollectionViewType.Time), icon: "columns" });
         !Doc.UserDoc().noviceMode && subItems.push({ description: "Map", event: () => func(CollectionViewType.Map), icon: "globe-americas" });
         subItems.push({ description: "Grid", event: () => func(CollectionViewType.Grid), icon: "th-list" });
-        subItems.push({ description: "lightbox", event: action(() => this._isLightboxOpen = true), icon: "eye" });
 
         if (!Doc.IsSystem(this.props.Document) && !this.props.Document.annotationOn) {
             const existingVm = ContextMenu.Instance.findByDescription(category);
@@ -342,27 +337,6 @@ export class CollectionView extends Touchable<CollectionViewProps> {
         }
     }
 
-    lightbox = (images: { image: string, title: string, caption: string }[]) => {
-        if (!images.length) return (null);
-        const mainPath = path.extname(images[this._curLightboxImg].image);
-        const nextPath = path.extname(images[(this._curLightboxImg + 1) % images.length].image);
-        const prevPath = path.extname(images[(this._curLightboxImg + images.length - 1) % images.length].image);
-        const main = images[this._curLightboxImg].image.replace(mainPath, "_o" + mainPath);
-        const title = images[this._curLightboxImg].title;
-        const caption = images[this._curLightboxImg].caption;
-        const next = images[(this._curLightboxImg + 1) % images.length].image.replace(nextPath, "_o" + nextPath);
-        const prev = images[(this._curLightboxImg + images.length - 1) % images.length].image.replace(prevPath, "_o" + prevPath);
-        return !this._isLightboxOpen ? (null) : (<Lightbox key="lightbox"
-            mainSrc={main}
-            nextSrc={next}
-            prevSrc={prev}
-            imageTitle={title}
-            imageCaption={caption}
-            onCloseRequest={action(() => this._isLightboxOpen = false)}
-            onMovePrevRequest={action(() => this._curLightboxImg = (this._curLightboxImg + images.length - 1) % images.length)}
-            onMoveNextRequest={action(() => this._curLightboxImg = (this._curLightboxImg + 1) % images.length)} />);
-    }
-
     bodyPanelWidth = () => this.props.PanelWidth();
 
     childLayoutTemplate = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
@@ -389,13 +363,6 @@ export class CollectionView extends Touchable<CollectionViewProps> {
             style={{ pointerEvents: this.props.layerProvider?.(this.props.Document) === false ? "none" : undefined }}>
             {this.showIsTagged()}
             {this.collectionViewType !== undefined ? this.SubView(this.collectionViewType, props) : (null)}
-            {this.lightbox(DocListCast(this.props.Document[this.props.fieldKey]).filter(d => Cast(d.data, ImageField, null)).map(d =>
-                ({
-                    image: (Cast(d.data, ImageField)!.url.href.indexOf(window.location.origin) === -1) ?
-                        Utils.CorsProxy(Cast(d.data, ImageField)!.url.href) : Cast(d.data, ImageField)!.url.href,
-                    title: StrCast(d.title),
-                    caption: Field.toString(d.caption as Field)
-                })))}
         </div>);
     }
 }
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index d77f70607..3c83c241b 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -15,7 +15,7 @@ import { ComputedField } from "../../../fields/ScriptField";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
 import { ImageField } from "../../../fields/URLField";
 import { GetEffectiveAcl } from "../../../fields/util";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse } from "../../../Utils";
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse } from "../../../Utils";
 import { Docs, DocumentOptions } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { CompileScript, Transformer, ts } from "../../util/Scripting";
@@ -25,6 +25,7 @@ import { COLLECTION_BORDER_WIDTH, SCHEMA_DIVIDER_WIDTH } from '../../views/globa
 import { ContextMenu } from "../ContextMenu";
 import '../DocumentDecorations.scss';
 import { DocumentView } from "../nodes/DocumentView";
+import { DefaultStyleProvider } from "../StyleProvider";
 import { CellProps, CollectionSchemaButtons, CollectionSchemaCell, CollectionSchemaCheckboxCell, CollectionSchemaDateCell, CollectionSchemaDocCell, CollectionSchemaImageCell, CollectionSchemaListCell, CollectionSchemaNumberCell, CollectionSchemaStringCell } from "./CollectionSchemaCells";
 import { CollectionSchemaAddColumnHeader, KeysDropdown } from "./CollectionSchemaHeaders";
 import { MovableColumn, MovableRow } from "./CollectionSchemaMovableTableHOC";
@@ -570,6 +571,9 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                     ref="overlay"><DocumentView
                         Document={this._showDoc}
                         DataDoc={this._showDataDoc}
+                        styleProvider={DefaultStyleProvider}
+                        layerProvider={undefined}
+                        docViewPath={emptyPath}
                         freezeDimensions={true}
                         focus={emptyFunction}
                         renderDepth={this.props.renderDepth}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index e8162c0ed..1026da64c 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -34,6 +34,7 @@ import "./TabDocView.scss";
 import React = require("react");
 import Color = require('color');
 import { MainView } from '../MainView';
+import { LightboxView } from '../LightboxView';
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
@@ -278,10 +279,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             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 runInAction(() => LightboxView.LightboxDoc = doc) ? true : false;
             case "inPlace":
             case "add":
-            default: runInAction(() => MainView.Instance.LightboxDoc = doc);
-                if (MainView.Instance.LightboxDoc) return true;
+            default:
                 return CollectionDockingView.AddSplit(doc, locationParams, this.stack);
         }
     }
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index c4934cf45..5deeb6997 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -1,7 +1,6 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
-import { TREE_BULLET_WIDTH } from '../globalCssVariables.scss';
 import { DataSym, Doc, DocListCast, DocListCastOrNull, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc';
 import { Id } from '../../../fields/FieldSymbols';
 import { List } from '../../../fields/List';
@@ -10,7 +9,7 @@ import { listSpec } from '../../../fields/Schema';
 import { ComputedField, ScriptField } from '../../../fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from "../../documents/DocumentTypes";
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
@@ -21,17 +20,18 @@ import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
 import { undoBatch, UndoManager } from '../../util/UndoManager';
 import { EditableView } from "../EditableView";
+import { TREE_BULLET_WIDTH } from '../globalCssVariables.scss';
 import { DocumentView, DocumentViewProps, StyleProviderFunc } from '../nodes/DocumentView';
 import { FieldViewProps } from '../nodes/FieldView';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import { RichTextMenu } from '../nodes/formattedText/RichTextMenu';
 import { KeyValueBox } from '../nodes/KeyValueBox';
+import { SliderBox } from '../nodes/SliderBox';
 import { StyleProp, testDocProps } from '../StyleProvider';
 import { CollectionTreeView } from './CollectionTreeView';
 import { CollectionView, CollectionViewType } from './CollectionView';
 import "./TreeView.scss";
 import React = require("react");
-import { SliderBox } from '../nodes/SliderBox';
 
 export interface TreeViewProps {
     document: Doc;
@@ -549,6 +549,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                 Document={this.doc}
                 DataDoc={undefined}
                 styleProvider={this.titleStyleProvider}
+                layerProvider={undefined}
+                docViewPath={emptyPath}
                 treeViewDoc={this.props.treeView.props.Document}
                 addDocument={undefined}
                 addDocTab={this.props.addDocTab}
@@ -639,6 +641,8 @@ export class TreeView extends React.Component<TreeViewProps> {
             renderDepth={this.props.renderDepth + 1}
             rootSelected={returnTrue}
             styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
+            layerProvider={undefined}
+            docViewPath={emptyPath}
             docFilters={returnEmptyFilter}
             docRangeFilters={returnEmptyFilter}
             searchFilterDocs={returnEmptyDoclist}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 85013b960..3d9673438 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -6,7 +6,7 @@ import { documentSchema } from '../../../../fields/documentSchemas';
 import { List } from '../../../../fields/List';
 import { makeInterface } from '../../../../fields/Schema';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
-import { returnFalse } from '../../../../Utils';
+import { returnFalse, emptyPath } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
@@ -217,6 +217,8 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
             styleProvider={this.props.styleProvider}
+            layerProvider={undefined}
+            docViewPath={emptyPath}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
             freezeDimensions={this.props.childFreezeDimensions}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 4f5c8af95..278ca20c1 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -6,7 +6,7 @@ import { documentSchema } from '../../../../fields/documentSchemas';
 import { List } from '../../../../fields/List';
 import { makeInterface } from '../../../../fields/Schema';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
-import { returnFalse } from '../../../../Utils';
+import { returnFalse, emptyPath } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
@@ -217,6 +217,8 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
             styleProvider={this.props.styleProvider}
+            layerProvider={undefined}
+            docViewPath={emptyPath}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
             freezeDimensions={this.props.childFreezeDimensions}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index d2dab4157..4b0422ed3 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -23,7 +23,7 @@ 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
+    layerProvider: ((doc: Doc, assign?: boolean) => boolean) | undefined;
     zIndex?: number;
     highlight?: boolean;
     jitterRotation: number;
diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx
index 533a4931a..765751a65 100644
--- a/src/client/views/nodes/DocHolderBox.tsx
+++ b/src/client/views/nodes/DocHolderBox.tsx
@@ -124,6 +124,8 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
                     ContainingCollectionView={this as any} // bcz: hack!  need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked.  currently, the up selector allows only a containing collection to be selected
                     ContainingCollectionDoc={undefined}
                     styleProvider={this.props.styleProvider}
+                    layerProvider={this.props.layerProvider}
+                    docViewPath={this.props.docViewPath}
                     LayoutTemplateString={layoutTemplate}
                     LayoutTemplate={this.layoutTemplateDoc}
                     rootSelected={this.props.isSelected}
@@ -150,6 +152,8 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
                     ContainingCollectionView={this as any} // bcz: hack!  need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked.  currently, the up selector allows only a containing collection to be selected
                     ContainingCollectionDoc={undefined}
                     styleProvider={this.props.styleProvider}
+                    layerProvider={this.props.layerProvider}
+                    docViewPath={this.props.docViewPath}
                     ignoreAutoHeight={true}
                     LayoutTemplateString={layoutTemplate}
                     LayoutTemplate={this.layoutTemplateDoc}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 4e2eadd4b..2f56f5b00 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -401,7 +401,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                         if (this.props.Document.type !== DocumentType.LABEL) {
                             UndoManager.RunInBatch(() => {
                                 const fullScreenDoc = Cast(this.props.Document._fullScreenView, Doc, null) || this.props.Document;
-                                this.props.addDocTab(fullScreenDoc, "add");
+                                this.props.addDocTab(fullScreenDoc, "lightbox");
                             }, "double tap");
                             SelectionManager.DeselectAll();
                         }
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 71196ea19..cc924ff7a 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -211,6 +211,8 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
                     onCheckedClick={this.scriptField}
                     dontRegisterView={true}
                     styleProvider={this.props.styleProvider}
+                    layerProvider={this.props.layerProvider}
+                    docViewPath={this.props.docViewPath}
                     scriptContext={this.props.scriptContext}
                     moveDocument={returnFalse}
                     removeDocument={returnFalse}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 3c10cc5fe..6f222d53b 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -1,7 +1,7 @@
 import { action, observable } from 'mobx';
 import { observer } from "mobx-react";
 import { Doc, Field, Opt } from '../../../fields/Doc';
-import { emptyFunction, returnFalse, returnOne, returnZero, returnEmptyFilter, returnEmptyDoclist } from '../../../Utils';
+import { emptyFunction, returnFalse, returnOne, returnZero, returnEmptyFilter, returnEmptyDoclist, emptyPath } from '../../../Utils';
 import { Docs } from '../../documents/Documents';
 import { Transform } from '../../util/Transform';
 import { undoBatch } from '../../util/UndoManager';
@@ -12,6 +12,7 @@ import { KeyValueBox } from './KeyValueBox';
 import "./KeyValueBox.scss";
 import "./KeyValuePair.scss";
 import React = require("react");
+import { DefaultStyleProvider } from '../StyleProvider';
 
 // Represents one row in a key value plane
 
@@ -58,6 +59,9 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             docFilters: returnEmptyFilter,
             docRangeFilters: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
+            styleProvider: DefaultStyleProvider,
+            layerProvider: undefined,
+            docViewPath: emptyPath,
             ContainingCollectionView: undefined,
             ContainingCollectionDoc: undefined,
             fieldKey: this.props.keyName,
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 7934dba8e..75ca6059e 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -4,7 +4,7 @@ import wiki from "wikijs";
 import { Doc, DocCastAsync, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
 import { Id } from '../../../fields/FieldSymbols';
 import { Cast, FieldValue, NumCast } from "../../../fields/Types";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse } from "../../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, emptyPath } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { LinkManager } from '../../util/LinkManager';
 import { Transform } from "../../util/Transform";
@@ -111,7 +111,10 @@ export class LinkDocPreview extends React.Component<Props> {
                 focus={emptyFunction}
                 whenActiveChanged={returnFalse}
                 bringToFront={returnFalse}
-                styleProvider={this.props.docprops?.styleProvider} />;
+                styleProvider={this.props.docprops?.styleProvider}
+                layerProvider={this.props.docprops?.layerProvider}
+                docViewPath={emptyPath}
+            />;
     }
 
     render() {
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 1fbd3af5c..91d123efe 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -236,7 +236,9 @@ export class DashDocView extends React.Component<IDashDocView> {
                             PanelWidth={finalLayout[WidthSym]}
                             PanelHeight={finalLayout[HeightSym]}
                             focus={this.outerFocus}
-                            styleProvider={returnEmptyString}
+                            styleProvider={self._textBox.props.styleProvider}
+                            layerProvider={self._textBox.props.layerProvider}
+                            docViewPath={self._textBox.props.docViewPath}
                             parentActive={returnFalse}
                             whenActiveChanged={returnFalse}
                             bringToFront={emptyFunction}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 5371bd10a..9508f8034 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -8,7 +8,7 @@ import * as ReactDOM from 'react-dom';
 import wiki from "wikijs";
 import { Doc, DocCastAsync, DocListCast, Opt } from "../../../../fields/Doc";
 import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, Utils } from "../../../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, Utils, emptyPath } from "../../../../Utils";
 import { DocServer } from "../../../DocServer";
 import { Docs } from "../../../documents/Documents";
 import { DocumentType } from "../../../documents/DocumentTypes";
@@ -22,6 +22,7 @@ import { FormattedTextBox } from "./FormattedTextBox";
 import './FormattedTextBoxComment.scss';
 import { schema } from "./schema_rts";
 import React = require("react");
+import { DefaultStyleProvider } from "../../StyleProvider";
 
 export let formattedTextBoxCommentPlugin = new Plugin({
     view(editorView) { return new FormattedTextBoxComment(editorView); }
@@ -298,6 +299,9 @@ export class FormattedTextBoxComment {
                                             Document={target}
                                             moveDocument={returnFalse}
                                             rootSelected={returnFalse}
+                                            styleProvider={DefaultStyleProvider}
+                                            layerProvider={undefined}
+                                            docViewPath={emptyPath}
                                             ScreenToLocalTransform={Transform.Identity}
                                             parentActive={returnFalse}
                                             addDocument={returnFalse}
diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx
index abbb89780..2252de3d6 100644
--- a/src/client/views/nodes/formattedText/RichTextSchema.tsx
+++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx
@@ -138,6 +138,7 @@ export class DashDocView {
                     removeDocument={removeDoc}
                     layerProvider={this._textBox.props.layerProvider}
                     styleProvider={this._textBox.props.styleProvider}
+                    docViewPath={this._textBox.props.docViewPath}
                     ScreenToLocalTransform={this.getDocTransform}
                     addDocTab={this._textBox.props.addDocTab}
                     pinToPres={returnFalse}
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index c07e137c4..9f9200fa4 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -7,7 +7,7 @@ import { documentSchema } from '../../../fields/documentSchemas';
 import { Id } from "../../../fields/FieldSymbols";
 import { createSchema, makeInterface } from '../../../fields/Schema';
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents } from "../../../Utils";
+import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, emptyPath } from "../../../Utils";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 import { DocumentManager } from "../../util/DocumentManager";
@@ -92,6 +92,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     Document={this.targetDoc}
                     DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
                     styleProvider={this.styleProvider}
+                    layerProvider={this.props.layerProvider}
+                    docViewPath={emptyPath}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index d32e19ee1..fe3595181 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -12,7 +12,7 @@ import { Doc } from '../fields/Doc';
 import { listSpec } from '../fields/Schema';
 import { Cast, FieldValue } from '../fields/Types';
 import { nullAudio } from '../fields/URLField';
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue } from '../Utils';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, emptyPath } from '../Utils';
 import "./ImageUpload.scss";
 import { MobileInterface } from './MobileInterface';
 import React = require('react');
@@ -94,7 +94,9 @@ export class AudioUpload extends React.Component {
                         PanelHeight={() => 400}
                         renderDepth={0}
                         focus={emptyFunction}
+                        layerProvider={undefined}
                         styleProvider={() => "rgba(0,0,0,0)"}
+                        docViewPath={emptyPath}
                         parentActive={returnTrue}
                         whenActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index c7e2d02cb..f6c283c3a 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -212,6 +212,8 @@ export class MobileInterface extends React.Component {
                     renderDepth={0}
                     focus={emptyFunction}
                     styleProvider={this.whitebackground}
+                    layerProvider={undefined}
+                    docViewPath={emptyPath}
                     parentActive={returnTrue}
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-- 
cgit v1.2.3-70-g09d2


From 5e9faf9fc5a2aeb3b5c0377b756a746934097619 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 10 Feb 2021 11:41:26 -0500
Subject: changed docViewPath to be a function to avoid mobx invalidations

---
 src/client/views/GestureOverlay.tsx                        |  2 +-
 src/client/views/LightboxView.tsx                          |  2 +-
 src/client/views/MainView.tsx                              | 14 +++++++-------
 src/client/views/OverlayView.tsx                           |  2 +-
 src/client/views/Palette.tsx                               |  2 +-
 src/client/views/PropertiesView.tsx                        |  4 ++--
 src/client/views/TemplateMenu.tsx                          |  2 +-
 src/client/views/collections/CollectionLinearView.tsx      |  4 ++--
 src/client/views/collections/CollectionSchemaView.tsx      |  4 ++--
 src/client/views/collections/SchemaTable.tsx               |  2 +-
 src/client/views/collections/TabDocView.tsx                |  4 ++--
 src/client/views/collections/TreeView.tsx                  |  4 ++--
 .../collectionMulticolumn/CollectionMulticolumnView.tsx    |  4 ++--
 .../collectionMulticolumn/CollectionMultirowView.tsx       |  4 ++--
 src/client/views/nodes/DocumentView.tsx                    |  9 +++++----
 src/client/views/nodes/KeyValuePair.tsx                    |  2 +-
 src/client/views/nodes/LinkDocPreview.tsx                  |  2 +-
 src/client/views/nodes/formattedText/FormattedTextBox.tsx  |  2 +-
 src/client/views/presentationview/PresElementBox.tsx       |  4 ++--
 src/mobile/AudioUpload.tsx                                 |  2 +-
 src/mobile/MobileInterface.tsx                             |  2 +-
 21 files changed, 39 insertions(+), 38 deletions(-)

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

diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 9306cf9ae..d7e7e055f 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -872,7 +872,7 @@ export class GestureOverlay extends Touchable {
                 renderDepth={0}
                 styleProvider={returnEmptyString}
                 layerProvider={undefined}
-                docViewPath={emptyPath}
+                docViewPath={returnEmptyDoclist}
                 focus={emptyFunction}
                 parentActive={returnTrue}
                 whenActiveChanged={emptyFunction}
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index aa6e4d909..f19aff5f0 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -66,7 +66,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                         addDocTab={returnFalse}
                         pinToPres={emptyFunction}
                         rootSelected={returnTrue}
-                        docViewPath={emptyPath}
+                        docViewPath={returnEmptyDoclist}
                         removeDocument={undefined}
                         styleProvider={DefaultStyleProvider}
                         layerProvider={returnTrue}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index d09b0269f..4c164b85b 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -249,7 +249,7 @@ export class MainView extends React.Component {
             addDocument={undefined}
             addDocTab={this.addDocTabFunc}
             pinToPres={emptyFunction}
-            docViewPath={emptyPath}
+            docViewPath={returnEmptyDoclist}
             layerProvider={undefined}
             styleProvider={undefined}
             rootSelected={returnTrue}
@@ -340,7 +340,7 @@ export class MainView extends React.Component {
                         addDocument={undefined}
                         addDocTab={this.addDocTabFunc}
                         pinToPres={emptyFunction}
-                        docViewPath={emptyPath}
+                        docViewPath={returnEmptyDoclist}
                         layerProvider={undefined}
                         styleProvider={this._sidebarContent.proto === Doc.UserDoc().myDashboards ? this.DashboardStyleProvider : DefaultStyleProvider}
                         rootSelected={returnTrue}
@@ -379,7 +379,7 @@ export class MainView extends React.Component {
                 PanelWidth={this.menuPanelWidth}
                 PanelHeight={this.getContentsHeight}
                 renderDepth={0}
-                docViewPath={emptyPath}
+                docViewPath={returnEmptyDoclist}
                 focus={emptyFunction}
                 styleProvider={DefaultStyleProvider}
                 layerProvider={undefined}
@@ -490,7 +490,7 @@ export class MainView extends React.Component {
                     select={emptyFunction}
                     active={returnFalse}
                     isSelected={returnFalse}
-                    docViewPath={emptyPath}
+                    docViewPath={returnEmptyDoclist}
                     moveDocument={this.moveButtonDoc}
                     CollectionView={undefined}
                     addDocument={this.addButtonDoc}
@@ -564,7 +564,7 @@ export class MainView extends React.Component {
                 PanelHeight={this.getPHeight}
                 renderDepth={0}
                 focus={emptyFunction}
-                docViewPath={emptyPath}
+                docViewPath={returnEmptyDoclist}
                 parentActive={returnFalse}
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
@@ -599,7 +599,7 @@ export class MainView extends React.Component {
                     active={returnFalse}
                     whenActiveChanged={returnFalse}
                     focus={returnFalse}
-                    docViewPath={emptyPath}
+                    docViewPath={returnEmptyDoclist}
                     PanelWidth={() => 500}
                     PanelHeight={() => 800}
                     docFilters={returnEmptyFilter}
@@ -657,7 +657,7 @@ export class MainView extends React.Component {
                             Document={invisibleDoc}
                             dropAction={"move"}
                             isSelected={returnFalse}
-                            docViewPath={emptyPath}
+                            docViewPath={returnEmptyDoclist}
                             select={returnFalse}
                             rootSelected={returnFalse}
                             renderDepth={0}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 628003391..64f907f4c 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -194,7 +194,7 @@ export class OverlayView extends React.Component {
                     focus={emptyFunction}
                     styleProvider={DefaultStyleProvider}
                     layerProvider={undefined}
-                    docViewPath={emptyPath}
+                    docViewPath={returnEmptyDoclist}
                     addDocTab={returnFalse}
                     pinToPres={emptyFunction}
                     docFilters={returnEmptyFilter}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 6268be31c..fbf67f0a0 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -50,7 +50,7 @@ export default class Palette extends React.Component<PaletteProps> {
                             PanelHeight={() => window.screen.height}
                             renderDepth={0}
                             focus={emptyFunction}
-                            docViewPath={emptyPath}
+                            docViewPath={returnEmptyDoclist}
                             styleProvider={returnEmptyString}
                             layerProvider={undefined}
                             parentActive={returnTrue}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index a5ddf8044..6ee5e4d8c 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -11,7 +11,7 @@ import { InkField } from "../../fields/InkField";
 import { ComputedField } from "../../fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../fields/Types";
 import { denormalizeEmail, GetEffectiveAcl, SharingPermissions } from "../../fields/util";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, emptyPath } from "../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse } from "../../Utils";
 import { DocumentType } from "../documents/DocumentTypes";
 import { DocumentManager } from "../util/DocumentManager";
 import { SelectionManager } from "../util/SelectionManager";
@@ -271,7 +271,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     rootSelected={returnFalse}
                     styleProvider={DefaultStyleProvider}
                     layerProvider={undefined}
-                    docViewPath={emptyPath}
+                    docViewPath={returnEmptyDoclist}
                     freezeDimensions={true}
                     dontCenter={"y"}
                     NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index f9aae64f1..cdaf1bd0c 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -133,7 +133,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 ContainingCollectionView={undefined}
                 styleProvider={DefaultStyleProvider}
                 layerProvider={undefined}
-                docViewPath={emptyPath}
+                docViewPath={returnEmptyDoclist}
                 docFilters={returnEmptyFilter}
                 docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 79cc1719c..ead0ce6c4 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -7,7 +7,7 @@ import { documentSchema } from '../../../fields/documentSchemas';
 import { Id } from '../../../fields/FieldSymbols';
 import { makeInterface } from '../../../fields/Schema';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
-import { emptyFunction, returnTrue, Utils, emptyPath } from '../../../Utils';
+import { emptyFunction, returnTrue, Utils, emptyPath, returnEmptyDoclist } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { Transform } from '../../util/Transform';
 import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
@@ -153,7 +153,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 focus={emptyFunction}
                                 styleProvider={this.props.styleProvider}
                                 layerProvider={this.props.layerProvider}
-                                docViewPath={emptyPath}
+                                docViewPath={returnEmptyDoclist}
                                 parentActive={returnTrue}
                                 whenActiveChanged={emptyFunction}
                                 bringToFront={emptyFunction}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index e246dc020..66064e354 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -11,7 +11,7 @@ import { listSpec } from "../../../fields/Schema";
 import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField";
 import { Cast, NumCast } from "../../../fields/Types";
 import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, emptyPath, returnFalse, setupMoveUpEvents } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, setupMoveUpEvents, returnEmptyDoclist } from "../../../Utils";
 import { SelectionManager } from "../../util/SelectionManager";
 import { SnappingManager } from "../../util/SnappingManager";
 import { Transform } from "../../util/Transform";
@@ -415,7 +415,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                     searchFilterDocs={this.searchFilterDocs}
                     styleProvider={DefaultStyleProvider}
                     layerProvider={undefined}
-                    docViewPath={emptyPath}
+                    docViewPath={returnEmptyDoclist}
                     ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                     ContainingCollectionView={this.props.CollectionView}
                     moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 3c83c241b..d4b4cf333 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -573,7 +573,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         DataDoc={this._showDataDoc}
                         styleProvider={DefaultStyleProvider}
                         layerProvider={undefined}
-                        docViewPath={emptyPath}
+                        docViewPath={returnEmptyDoclist}
                         freezeDimensions={true}
                         focus={emptyFunction}
                         renderDepth={this.props.renderDepth}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 1026da64c..86276b693 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -315,7 +315,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined}
                     parentActive={returnFalse}
-                    docViewPath={emptyPath}
+                    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
                     active={returnTrue}
@@ -411,7 +411,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 parentActive={this.active}
                 whenActiveChanged={emptyFunction}
                 focus={this.focusFunc}
-                docViewPath={emptyPath}
+                docViewPath={returnEmptyDoclist}
                 bringToFront={emptyFunction}
                 pinToPres={TabDocView.PinDoc} />
                 {this._document._viewType !== CollectionViewType.Freeform ? (null) :
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 5deeb6997..6b7911b13 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -550,7 +550,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 DataDoc={undefined}
                 styleProvider={this.titleStyleProvider}
                 layerProvider={undefined}
-                docViewPath={emptyPath}
+                docViewPath={returnEmptyDoclist}
                 treeViewDoc={this.props.treeView.props.Document}
                 addDocument={undefined}
                 addDocTab={this.props.addDocTab}
@@ -642,7 +642,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             rootSelected={returnTrue}
             styleProvider={asText ? this.titleStyleProvider : this.embeddedStyleProvider}
             layerProvider={undefined}
-            docViewPath={emptyPath}
+            docViewPath={returnEmptyDoclist}
             docFilters={returnEmptyFilter}
             docRangeFilters={returnEmptyFilter}
             searchFilterDocs={returnEmptyDoclist}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 3d9673438..e51417f64 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -6,7 +6,7 @@ import { documentSchema } from '../../../../fields/documentSchemas';
 import { List } from '../../../../fields/List';
 import { makeInterface } from '../../../../fields/Schema';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
-import { returnFalse, emptyPath } from '../../../../Utils';
+import { returnFalse, emptyPath, returnEmptyDoclist } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
@@ -218,7 +218,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             DataDoc={layout.resolvedDataDoc as Doc}
             styleProvider={this.props.styleProvider}
             layerProvider={undefined}
-            docViewPath={emptyPath}
+            docViewPath={returnEmptyDoclist}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
             freezeDimensions={this.props.childFreezeDimensions}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 278ca20c1..d61a2bb72 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -6,7 +6,7 @@ import { documentSchema } from '../../../../fields/documentSchemas';
 import { List } from '../../../../fields/List';
 import { makeInterface } from '../../../../fields/Schema';
 import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
-import { returnFalse, emptyPath } from '../../../../Utils';
+import { returnFalse, emptyPath, returnEmptyDoclist } from '../../../../Utils';
 import { DragManager, dropActionType } from '../../../util/DragManager';
 import { Transform } from '../../../util/Transform';
 import { undoBatch } from '../../../util/UndoManager';
@@ -218,7 +218,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             DataDoc={layout.resolvedDataDoc as Doc}
             styleProvider={this.props.styleProvider}
             layerProvider={undefined}
-            docViewPath={emptyPath}
+            docViewPath={returnEmptyDoclist}
             LayoutTemplate={this.props.childLayoutTemplate}
             LayoutTemplateString={this.props.childLayoutString}
             freezeDimensions={this.props.childFreezeDimensions}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8afa53eac..190dfd6be 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -65,7 +65,7 @@ export interface DocumentViewSharedProps {
     CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
     PanelWidth: () => number;
     PanelHeight: () => number;
-    docViewPath: DocumentView[];
+    docViewPath: () => DocumentView[];
     layerProvider: undefined | ((doc: Doc, assign?: boolean) => boolean);
     styleProvider: Opt<StyleProviderFunc>;
     focus: DocFocusFunc;
@@ -117,7 +117,7 @@ export interface DocumentViewInternalProps extends DocumentViewProps {
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (ctrlPressed: boolean) => void;
     DocumentView: any;
-    viewPath: DocumentView[];
+    viewPath: () => DocumentView[];
 }
 
 @observer
@@ -884,7 +884,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     get allLinks() { return this.docView?.allLinks || []; }
     get LayoutFieldKey() { return this.docView?.LayoutFieldKey || "layout"; }
 
-    @computed get docViewPath() { return this.props.docViewPath ? [...this.props.docViewPath, this] : [this]; }
+    @computed get docViewPath() { return this.props.docViewPath ? [...this.props.docViewPath(), this] : [this]; }
     @computed get layoutDoc() { return Doc.Layout(this.Document, this.props.LayoutTemplate?.()); }
     @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions)); }
     @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, this.props.DataDoc, this.props.freezeDimensions) || 0); }
@@ -955,6 +955,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         }), 400);
     });
 
+    docViewPathFunc = () => this.docViewPath;
     isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
     select = (ctrlPressed: boolean) => SelectionManager.SelectView(this, ctrlPressed);
     NativeWidth = () => this.nativeWidth;
@@ -978,7 +979,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         const internalProps = {
             ...this.props,
             DocumentView: this,
-            viewPath: this.docViewPath,
+            viewPath: this.docViewPathFunc,
             PanelWidth: this.PanelWidth,
             PanelHeight: this.PanelHeight,
             NativeWidth: this.NativeWidth,
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 6f222d53b..ce9d8bed5 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -61,7 +61,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             layerProvider: undefined,
-            docViewPath: emptyPath,
+            docViewPath: returnEmptyDoclist,
             ContainingCollectionView: undefined,
             ContainingCollectionDoc: undefined,
             fieldKey: this.props.keyName,
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index eb27a6241..6155ed493 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -145,7 +145,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             rootSelected={returnFalse}
                             styleProvider={this.props.docProps?.styleProvider}
                             layerProvider={this.props.docProps?.layerProvider}
-                            docViewPath={emptyPath}
+                            docViewPath={returnEmptyDoclist}
                             ScreenToLocalTransform={Transform.Identity}
                             parentActive={returnFalse}
                             addDocument={returnFalse}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index a91157519..9e2e8f1be 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1245,7 +1245,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             (this._editorView as any).TextView = this;
         }
 
-        const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad && (!LightboxView.LightboxDoc || this.props.docViewPath.includes(LightboxView.LightboxDocView.current!));
+        const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad && (!LightboxView.LightboxDoc || this.props.docViewPath().includes(LightboxView.LightboxDocView.current!));
         if (selectOnLoad && !this.props.dontRegisterView && !this.props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
             FormattedTextBox.SelectOnLoad = "";
             this.props.select(false);
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 9f9200fa4..01a55660a 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -7,7 +7,7 @@ import { documentSchema } from '../../../fields/documentSchemas';
 import { Id } from "../../../fields/FieldSymbols";
 import { createSchema, makeInterface } from '../../../fields/Schema';
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, emptyPath } from "../../../Utils";
+import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, emptyPath, returnEmptyDoclist } from "../../../Utils";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 import { DocumentManager } from "../../util/DocumentManager";
@@ -93,7 +93,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
                     styleProvider={this.styleProvider}
                     layerProvider={this.props.layerProvider}
-                    docViewPath={emptyPath}
+                    docViewPath={returnEmptyDoclist}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index fe3595181..cbae71270 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -96,7 +96,7 @@ export class AudioUpload extends React.Component {
                         focus={emptyFunction}
                         layerProvider={undefined}
                         styleProvider={() => "rgba(0,0,0,0)"}
-                        docViewPath={emptyPath}
+                        docViewPath={returnEmptyDoclist}
                         parentActive={returnTrue}
                         whenActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index f6c283c3a..058c61a6d 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -213,7 +213,7 @@ export class MobileInterface extends React.Component {
                     focus={emptyFunction}
                     styleProvider={this.whitebackground}
                     layerProvider={undefined}
-                    docViewPath={emptyPath}
+                    docViewPath={returnEmptyDoclist}
                     parentActive={returnTrue}
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
-- 
cgit v1.2.3-70-g09d2


From f240c85ff0adee914b43d9d169fa31260e03265d Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 10 Feb 2021 19:06:53 -0500
Subject: fixed following link to document in another context to work in
 LightboxView

---
 src/client/util/DocumentManager.ts                      | 17 +++++++----------
 src/client/util/LinkManager.ts                          |  3 ---
 src/client/views/LightboxView.tsx                       |  1 +
 src/client/views/collections/TabDocView.tsx             |  9 ++++-----
 .../views/nodes/formattedText/FormattedTextBox.tsx      |  2 +-
 5 files changed, 13 insertions(+), 19 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index d7335c8c6..9a8b662e7 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -104,7 +104,7 @@ export class DocumentManager {
     public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
         const docViews = DocumentManager.Instance.DocumentViews;
         const views: DocumentView[] = [];
-        docViews.map(view => view.docViewPath.includes(LightboxView.LightboxDocView.current!) && view.rootDoc === toFind && views.push(view));
+        docViews.map(view => LightboxView.IsLightboxDocView(view.docViewPath) && 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 => {
@@ -113,14 +113,14 @@ export class DocumentManager {
     }
     public getDocumentViews(toFind: Doc): DocumentView[] {
         const toReturn: DocumentView[] = [];
-        const docViews = DocumentManager.Instance.DocumentViews.filter(view => !view.docViewPath.includes(LightboxView.LightboxDocView.current!));
-        const lightboxViews = DocumentManager.Instance.DocumentViews.filter(view => view.docViewPath.includes(LightboxView.LightboxDocView.current!));
+        const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.IsLightboxDocView(view.docViewPath));
+        const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.IsLightboxDocView(view.docViewPath));
 
         // heuristic to return the "best" documents first:
         //   choose a document in the lightbox first
         //   choose an exact match over an alias match
-        lightboxViews.map(view => view.rootDoc === toFind && toReturn.push(view));
-        lightboxViews.map(view => view.rootDoc !== toFind && Doc.AreProtosEqual(view.rootDoc, toFind) && toReturn.push(view));
+        lightViews.map(view => view.rootDoc === toFind && toReturn.push(view));
+        lightViews.map(view => view.rootDoc !== toFind && Doc.AreProtosEqual(view.rootDoc, toFind) && toReturn.push(view));
         docViews.map(view => view.rootDoc === toFind && toReturn.push(view));
         docViews.map(view => view.rootDoc !== toFind && Doc.AreProtosEqual(view.rootDoc, toFind) && toReturn.push(view));
 
@@ -142,10 +142,7 @@ export class DocumentManager {
         originatingDoc: Opt<Doc> = undefined, // doc that initiated the display of the target odoc
         finished?: () => void,
     ): Promise<void> => {
-        const getFirstDocView = (toFind: Doc, originatingDoc?: Doc) => {
-            const docView = DocumentManager.Instance.getFirstDocumentView(toFind, originatingDoc);
-            return (!LightboxView.LightboxDoc || docView?.docViewPath.includes(LightboxView.LightboxDocView.current!)) ? docView : undefined;
-        };
+        const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView;
         const focusAndFinish = () => { finished?.(); return false; };
         const highlight = () => {
             const finalDocView = getFirstDocView(targetDoc);
@@ -218,7 +215,7 @@ export class DocumentManager {
                 } else {  // there's no context view so we need to create one first and try again when that finishes
                     const finishFunc = () => this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished);
                     if (LightboxView.LightboxDoc) {
-                        runInAction(() => LightboxView.LightboxDoc = annotatedDoc ? annotatedDoc : targetDoc);
+                        runInAction(() => LightboxView.LightboxDoc = targetDocContext);
                         setTimeout(() => finishFunc, 250);
                     } else {
                         createViewFunc(targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 7ad37f059..9034484d3 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -4,8 +4,6 @@ import { Doc, DocListCast, Opt } from "../../fields/Doc";
 import { BoolCast, Cast, StrCast } from "../../fields/Types";
 import { LightboxView } from "../views/LightboxView";
 import { DocumentViewSharedProps } from "../views/nodes/DocumentView";
-import { FormattedTextBoxComment } from "../views/nodes/formattedText/FormattedTextBoxComment";
-import { LinkDocPreview } from "../views/nodes/LinkDocPreview";
 import { CreateViewFunc, DocumentManager } from "./DocumentManager";
 import { SharingManager } from "./SharingManager";
 import { UndoManager } from "./UndoManager";
@@ -146,7 +144,6 @@ export class LinkManager {
                         (Doc.AreProtosEqual(doc, linkDoc.anchor1 as Doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc) ? Cast(linkDoc.anchor2_timecode, "number") : Cast(linkDoc.anchor1_timecode, "number")));
                 if (target) {
                     if (LightboxView.LightboxDoc && !DocumentManager.Instance.getLightboxDocumentView(doc)) {
-                        //doc.annotationOn !== LightboxView.LightboxDoc) { // following a link should replace an existing lightboxDoc unless the target is an annotation on the lightbox document
                         runInAction(() => LightboxView.LightboxDoc = (target.annotationOn as Doc) ?? target);
                         finished?.();
                     } else {
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index f19aff5f0..4e9491ec6 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -19,6 +19,7 @@ interface LightboxViewProps {
 @observer
 export class LightboxView extends React.Component<LightboxViewProps> {
     @observable public static LightboxDoc: Opt<Doc>;
+    public static IsLightboxDocView(path: DocumentView[]) { return path.includes(LightboxView.LightboxDocView.current!); }
     public static LightboxHistory: (Opt<Doc>)[] = [];
     public static LightboxFuture: (Opt<Doc>)[] = [];
     public static LightboxDocView = React.createRef<DocumentView>();
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 86276b693..38e1551e6 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -12,7 +12,7 @@ import { FieldId } from "../../../fields/RefField";
 import { listSpec } from '../../../fields/Schema';
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, returnFalse, returnTrue, setupMoveUpEvents, Utils, returnEmptyDoclist, emptyPath } from "../../../Utils";
+import { emptyFunction, returnEmptyDoclist, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { DocumentType } from '../../documents/DocumentTypes';
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
@@ -22,9 +22,10 @@ import { SelectionManager } from '../../util/SelectionManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
 import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { DocumentView, DocAfterFocusFunc, DocumentViewProps } from "../nodes/DocumentView";
+import { LightboxView } from '../LightboxView';
+import { DocAfterFocusFunc, DocumentView, DocumentViewProps } from "../nodes/DocumentView";
 import { FieldViewProps } from '../nodes/FieldView';
-import { PresBox, PresMovement, PinProps } from '../nodes/PresBox';
+import { PinProps, PresBox, PresMovement } from '../nodes/PresBox';
 import { DefaultLayerProvider, DefaultStyleProvider, StyleLayers, StyleProp } from '../StyleProvider';
 import { CollectionDockingView } from './CollectionDockingView';
 import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
@@ -33,8 +34,6 @@ import { CollectionViewType } from './CollectionView';
 import "./TabDocView.scss";
 import React = require("react");
 import Color = require('color');
-import { MainView } from '../MainView';
-import { LightboxView } from '../LightboxView';
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 81e385e95..c15c30803 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1246,7 +1246,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             (this._editorView as any).TextView = this;
         }
 
-        const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad && (!LightboxView.LightboxDoc || this.props.docViewPath().includes(LightboxView.LightboxDocView.current!));
+        const selectOnLoad = this.rootDoc[Id] === FormattedTextBox.SelectOnLoad && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(this.props.docViewPath()));
         if (selectOnLoad && !this.props.dontRegisterView && !this.props.dontSelectOnLoad && this.isActiveTab(this.ProseRef)) {
             FormattedTextBox.SelectOnLoad = "";
             this.props.select(false);
-- 
cgit v1.2.3-70-g09d2


From c86cb3966ecb905c2dc6a6236b71d7ce9c8fb80f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 11 Feb 2021 00:54:52 -0500
Subject: playing with trying to improve chaining of nested focus() method
 calls.

---
 src/Utils.ts                                       |  4 +-
 src/client/util/DocumentManager.ts                 | 51 +++++++++++---------
 src/client/views/collections/TabDocView.tsx        |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 56 ++++++++++++----------
 src/client/views/nodes/DocumentView.tsx            |  5 +-
 src/client/views/nodes/WebBox.tsx                  |  4 +-
 6 files changed, 67 insertions(+), 55 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 061c74611..770cef283 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -192,8 +192,8 @@ export namespace Utils {
     }
 
     export function scrollIntoView(targetY: number, targetHgt: number, scrollTop: number, contextHgt: number) {
-        if (scrollTop + contextHgt < targetY + Math.max(targetHgt * 1.1, 100)) {
-            return Math.min(scrollTop, targetY + Math.max(targetHgt * 1.1, 100) - contextHgt);
+        if (scrollTop + contextHgt < targetY + targetHgt * 1.1) {
+            return targetY + targetHgt * 1.1 - contextHgt;
         } else if (scrollTop > targetY - targetHgt * .1) {
             return Math.max(0, targetY - targetHgt * .1);
         }
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index ac7710d34..e5ef924d6 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -143,45 +143,52 @@ export class DocumentManager {
         finished?: () => void,
     ): Promise<void> => {
         const getFirstDocView = LightboxView.LightboxDoc ? DocumentManager.Instance.getLightboxDocumentView : DocumentManager.Instance.getFirstDocumentView;
-        const focusAndFinish = () => { finished?.(); return false; };
+        const docView = getFirstDocView(targetDoc, originatingDoc);
+        const focusAndFinish = (didFocus: boolean) => {
+            if (originatingDoc?.isPushpin) {
+                if (!didFocus || targetDoc.hidden) {
+                    targetDoc.hidden = !targetDoc.hidden;
+                }
+            } else {
+                targetDoc.hidden && (targetDoc.hidden = undefined);
+                docView?.select(false);
+            }
+            finished?.();
+            return false;
+        };
         const highlight = () => {
             const finalDocView = getFirstDocView(targetDoc);
             finalDocView && Doc.linkFollowHighlight(finalDocView.rootDoc);
         };
-        const docView = getFirstDocView(targetDoc, originatingDoc);
         let annotatedDoc = Cast(targetDoc.annotationOn, Doc, null);
+        const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined;
+        const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext : undefined;
+        const targetDocContext = contextDoc || annotatedDoc;
+        const targetDocContextView = targetDocContext && getFirstDocView(targetDocContext);
         if (!docView && annotatedDoc && annotatedDoc !== originatingDoc?.context && targetDoc.type === DocumentType.TEXTANCHOR) {
             const first = getFirstDocView(annotatedDoc);
             if (first) {
                 annotatedDoc = first.rootDoc;
                 first.focus(targetDoc, false);
             }
-        } else if (docView) {  // we have a docView already and aren't forced to create a new one ... just focus on the document.  TODO move into view if necessary otherwise just highlight?
-            if (originatingDoc?.isPushpin) {
-                docView.props.focus(docView.rootDoc, willZoom, undefined, (didFocus: boolean) => {
-                    if (!didFocus || docView.rootDoc.hidden) {
-                        docView.rootDoc.hidden = !docView.rootDoc.hidden;
-                    }
-                    return focusAndFinish();
-                });
-            }
-            else {
-                docView.select(false);
-                docView.rootDoc.hidden && (docView.rootDoc.hidden = undefined);
-                // @ts-ignore
-                docView.props.focus(docView.rootDoc, willZoom, undefined, focusAndFinish);
-            }
+        } else if (docView && (targetDocContextView || !targetDocContext)) {  // we have a docView already and aren't forced to create a new one ... just focus on the document.  TODO move into view if necessary otherwise just highlight?      
+            const first = annotatedDoc && getFirstDocView(annotatedDoc);
+            const targetFocus = (outFocus?: boolean) => docView.props.focus(docView.rootDoc, willZoom, undefined, (didFocus: boolean) => focusAndFinish(outFocus || didFocus));
+            const annoFocus = (outFocus?: boolean) => first?.props.focus(first.rootDoc, false, undefined, (didFocus: boolean) => {
+                targetFocus(outFocus || didFocus);
+                return false;
+            });
+            const contextFocus = targetDocContext === annotatedDoc ? undefined : (outFocus?: boolean) => targetDocContextView?.props.focus(targetDocContext, false, undefined, (didFocus: boolean) => {
+                annoFocus(outFocus || didFocus);
+                return false;
+            });
+            (contextFocus || annoFocus || targetFocus)();
             highlight();
         } else {
-            const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined;
-            const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc) || Doc.AreProtosEqual(doc, annotatedDoc)) ? docContext : undefined;
-            const targetDocContext = contextDoc || annotatedDoc;
-
             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)));
                 highlight();
             } else {  // otherwise try to get a view of the context of the target
-                const targetDocContextView = getFirstDocView(targetDocContext);
                 if (targetDocContextView) { // we found a context view and aren't forced to create a new one ... focus on the context first..
                     targetDocContext._viewTransition = "transform 500ms";
                     targetDocContextView.props.focus(targetDocContextView.rootDoc, willZoom);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 38e1551e6..e1e1c8656 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -356,7 +356,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             </Tooltip>
         </>;
     }
-    focusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, dontCenter?: boolean, notFocused?: boolean) => {
+    focusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc) => {
         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)
         }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 68a65dfe7..6fdd569da 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -907,53 +907,59 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         } else {
             const layoutdoc = Doc.Layout(doc);
             const savedState = { px: NumCast(this.Document._panX), py: NumCast(this.Document._panY), s: this.Document[this.scaleFieldKey], pt: this.Document._viewTransition };
-
             const newState = HistoryUtil.getState();
-            let newPanX = savedState.px;
-            let newPanY = savedState.py;
+            const { px, py } = layoutdoc.annotationOn ? savedState : willZoom ? this.setZoomToDoc(layoutdoc, scale) : this.setPanIntoView(doc);
             if (!layoutdoc.annotationOn) {   // only pan and zoom to focus on a document if the document is not an annotation in an annotation overlay collection
-                willZoom && this.setScaleToZoom(layoutdoc, scale);
-                const cx = NumCast(this.props.Document._panX);
-                const cy = NumCast(this.props.Document._panY);
-                const pwid = this.props.PanelWidth() / NumCast(this.props.Document._viewScale, 1);
-                const phgt = this.props.PanelHeight() / NumCast(this.props.Document._viewScale, 1);
-                const screen = { left: cx - pwid / 2, right: cx + pwid / 2, top: cy - phgt / 2, bot: cy + phgt / 2 };
-                const bounds = { left: NumCast(doc.x) - pwid / 10, right: NumCast(doc.x) + doc[WidthSym]() + pwid / 10, top: NumCast(doc.y) - phgt / 10, bot: NumCast(doc.y) + doc[HeightSym]() + phgt / 10 };
-                newPanX = cx + Math.min(0, bounds.left - screen.left) + Math.max(0, bounds.right - screen.right);
-                newPanY = cy + Math.min(0, bounds.top - screen.top) + Math.max(0, bounds.bot - screen.bot);
-                newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY };
+                newState.initializers![this.Document[Id]] = { panX: px, panY: py };
                 HistoryUtil.pushState(newState);
             }
 
             if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) {
                 // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
-                if (!doc.z) this.setPan(newPanX, newPanY, doc.focusSpeed || doc.focusSpeed === 0 ? `transform ${doc.focusSpeed}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
+                if (!doc.z) this.setPan(px, py, doc.focusSpeed || doc.focusSpeed === 0 ? `transform ${doc.focusSpeed}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
             }
             Doc.BrushDoc(this.props.Document);
 
-            const newAfterFocus = (didFocus: boolean) => {
-                afterFocus && setTimeout(() => {
-                    // @ts-ignore
-                    if (afterFocus?.(didFocus || (newPanX !== savedState.px || newPanY !== savedState.py))) {
+            !doc.hidden && Doc.linkFollowHighlight(doc);
+            this.props.focus(this.props.Document, undefined, undefined, (didFocus: boolean) => {
+                setTimeout(() => {
+                    if (afterFocus?.(didFocus || (px !== savedState.px || py !== savedState.py))) {
                         this.Document._panX = savedState.px;
                         this.Document._panY = savedState.py;
                         this.Document[this.scaleFieldKey] = savedState.s;
                         this.Document._viewTransition = savedState.pt;
                     }
                     doc.hidden && Doc.UnHighlightDoc(doc);
-                }, newPanX !== savedState.px || newPanY !== savedState.py ? 500 : 0);
+                }, px !== savedState.px || py !== savedState.py ? 500 : 0);
                 return false;
-            };
-            this.props.focus(this.props.Document, undefined, undefined, newAfterFocus);
-            !doc.hidden && Doc.linkFollowHighlight(doc);
+            });
         }
+    }
 
+    setPanIntoView = (doc: Doc) => {
+        const cx = NumCast(this.props.Document._panX);
+        const cy = NumCast(this.props.Document._panY);
+        const pwid = this.props.PanelWidth() / NumCast(this.props.Document._viewScale, 1);
+        const phgt = this.props.PanelHeight() / NumCast(this.props.Document._viewScale, 1);
+        const screen = { left: cx - pwid / 2, right: cx + pwid / 2, top: cy - phgt / 2, bot: cy + phgt / 2 };
+        const bounds = { left: NumCast(doc.x) - pwid / 10, right: NumCast(doc.x) + doc[WidthSym]() + pwid / 10, top: NumCast(doc.y) - phgt / 10, bot: NumCast(doc.y) + doc[HeightSym]() + phgt / 10 };
+        return {
+            px: cx + Math.min(0, bounds.left - screen.left) + Math.max(0, bounds.right - screen.right),
+            py: cy + Math.min(0, bounds.top - screen.top) + Math.max(0, bounds.bot - screen.bot)
+        };
     }
 
-    setScaleToZoom = (doc: Doc, scale: number = 0.75) => {
-        const pw = this.isAnnotationOverlay ? Doc.NativeWidth(this.props.Document) : this.props.PanelWidth();
-        const ph = this.isAnnotationOverlay ? Doc.NativeHeight(this.props.Document) : this.props.PanelHeight();
+    setZoomToDoc = (doc: Doc, scale: number = 0.75) => {
+        const pw = this.props.PanelWidth();
+        const ph = this.props.PanelHeight();
         pw && ph && (this.Document[this.scaleFieldKey] = scale * Math.min(pw / NumCast(doc._width), ph / NumCast(doc._height)));
+        const pwid = pw / NumCast(this.props.Document._viewScale, 1);
+        const phgt = ph / NumCast(this.props.Document._viewScale, 1);
+        const bounds = { left: NumCast(doc.x) - pwid / 10, right: NumCast(doc.x) + doc[WidthSym]() + pwid / 10, top: NumCast(doc.y) - phgt / 10, bot: NumCast(doc.y) + doc[HeightSym]() + phgt / 10 };
+        return {
+            px: (bounds.left + bounds.right) / 2,
+            py: (bounds.top + bounds.bot) / 2
+        };
     }
 
     onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a5698e138..d20866f94 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -41,7 +41,6 @@ import { PresBox } from './PresBox';
 import { RadialMenu } from './RadialMenu';
 import React = require("react");
 import { LinkDocPreview } from "./LinkDocPreview";
-import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment";
 
 export type DocAfterFocusFunc = (notFocused: boolean) => boolean;
 export type DocFocusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc) => void;
@@ -919,8 +918,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
 
     toggleNativeDimensions = () => this.docView && Doc.toggleNativeDimensions(this.layoutDoc, this.docView.ContentScale, this.props.PanelWidth(), this.props.PanelHeight());
     contentsActive = () => this.docView?.contentsActive();
-    focus = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, focused?: boolean) => {
-        return this.docView?.focus(doc, willZoom, scale, afterFocus, focused);
+    focus = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc) => {
+        return this.docView?.focus(doc, willZoom, scale, afterFocus);
     }
     getBounds = () => {
         if (!this.docView || !this.docView.ContentDiv || this.docView.props.renderDepth === 0 || this.docView.props.treeViewDoc || Doc.AreProtosEqual(this.props.Document, Doc.UserDoc())) {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index d3d58b2f8..ef0df25b6 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -4,7 +4,7 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction
 import { observer } from "mobx-react";
 import { Dictionary } from "typescript-collections";
 import * as WebRequest from 'web-request';
-import { Doc, DocListCast, HeightSym, WidthSym, Opt } from "../../../fields/Doc";
+import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
 import { documentSchema } from "../../../fields/documentSchemas";
 import { Id } from "../../../fields/FieldSymbols";
 import { HtmlField } from "../../../fields/HtmlField";
@@ -26,10 +26,10 @@ import { ViewBoxAnnotatableComponent } from "../DocComponent";
 import { DocumentDecorations } from "../DocumentDecorations";
 import { MarqueeAnnotator } from "../MarqueeAnnotator";
 import { Annotation } from "../pdf/Annotation";
+import { DocAfterFocusFunc } from "./DocumentView";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./WebBox.scss";
 import React = require("react");
-import { DocFocusFunc, DocAfterFocusFunc, DocumentView } from "./DocumentView";
 const htmlToText = require("html-to-text");
 
 type WebDocument = makeInterface<[typeof documentSchema]>;
-- 
cgit v1.2.3-70-g09d2

