From df23545cff9c612a91272c16fa819f8b53c310d0 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 3 Feb 2021 10:35:29 -0500
Subject: fixed webBox forward/backward and in lightbox.

---
 src/client/views/collections/CollectionMenu.tsx | 157 +++++-------------------
 1 file changed, 32 insertions(+), 125 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5670d45f5..4e2d81e61 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -5,7 +5,7 @@ import { Tooltip } from "@material-ui/core";
 import { action, computed, Lambda, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { ColorState } from "react-color";
-import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
+import { Doc, DocListCast, Opt } from "../../../fields/Doc";
 import { Document } from "../../../fields/documentSchemas";
 import { Id } from "../../../fields/FieldSymbols";
 import { InkTool } from "../../../fields/InkField";
@@ -15,7 +15,6 @@ import { RichTextField } from "../../../fields/RichTextField";
 import { listSpec } from "../../../fields/Schema";
 import { ScriptField } from "../../../fields/ScriptField";
 import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
-import { WebField } from "../../../fields/URLField";
 import { emptyFunction, setupMoveUpEvents, Utils } from "../../../Utils";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
@@ -549,17 +548,13 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     @computed get dataField() {
         return this.document[this.props.docView.LayoutFieldKey + (this.props.isOverlay ? "-annotations" : "")];
     }
-    @computed get childDocs() {
-        return DocListCast(this.dataField);
-    }
-
-    @computed get selectedDocumentView() {
-        return SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined;
-    }
+    @computed get childDocs() { return DocListCast(this.dataField); }
+    @computed get selectedDocumentView() { return SelectionManager.Views().length ? SelectionManager.Views()[0] : undefined; }
     @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
     @computed get isText() {
         return this.selectedDoc?.type === DocumentType.RTF || (RichTextMenu.Instance?.view as any) ? true : false;
     }
+    @computed get webBoxUrl() { return this.selectedDocumentView?.ComponentView?.url?.(); }
 
     @undoBatch
     @action
@@ -591,20 +586,17 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     private _draw = ["∿", "⎯", "→", "↔︎", "ロ", "O"];
     private _head = ["", "", "", "arrow", "", ""];
     private _end = ["", "", "arrow", "arrow", "", ""];
-    private _shape = ["", "line", "line", "line", "rectangle", "circle"];
+    private _shapePrims = ["", "line", "line", "line", "rectangle", "circle"];
     private _title = ["pen", "line", "line with arrow", "line with double arrows", "square", "circle",];
     private _faName = ["pen-fancy", "minus", "long-arrow-alt-right", "arrows-alt-h", "square", "circle"];
-    @observable _shapesNum = this._shape.length;
-    @observable _selected = this._shapesNum;
-
-    @observable _keepMode = false;
+    @observable _selectedPrimitive = this._shapePrims.length;
+    @observable _keepPrimitiveMode = false; // for whether primitive selection enters a one-shot or persistent mode
 
     @observable _colorBtn = false;
     @observable _widthBtn = false;
     @observable _fillBtn = false;
 
-    @action
-    clearKeep() { this._selected = this._shapesNum; }
+    @action clearKeepPrimitiveMode() { this._selectedPrimitive = this._shapePrims.length; }
 
     @action
     changeColor = (color: string, type: string) => {
@@ -636,17 +628,17 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
 
     @computed get drawButtons() {
         const func = action((i: number, keep: boolean) => {
-            this._keepMode = keep;
-            if (this._selected !== i) {
-                this._selected = i;
+            this._keepPrimitiveMode = keep;
+            if (this._selectedPrimitive !== i) {
+                this._selectedPrimitive = i;
                 Doc.SetSelectedTool(InkTool.Pen);
                 SetActiveArrowStart(this._head[i]);
                 SetActiveArrowEnd(this._end[i]);
                 SetActiveBezierApprox("300");
 
-                GestureOverlay.Instance.InkShape = this._shape[i];
+                GestureOverlay.Instance.InkShape = this._shapePrims[i];
             } else {
-                this._selected = this._shapesNum;
+                this._selectedPrimitive = this._shapePrims.length;
                 Doc.SetSelectedTool(InkTool.None);
                 SetActiveArrowStart("");
                 SetActiveArrowEnd("");
@@ -660,7 +652,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
                     <button className="antimodeMenu-button"
                         onPointerDown={() => func(i, false)}
                         onDoubleClick={() => func(i, true)}
-                        style={{ backgroundColor: i === this._selected ? "525252" : "", fontSize: "20" }}>
+                        style={{ backgroundColor: i === this._selectedPrimitive ? "525252" : "", fontSize: "20" }}>
                         <FontAwesomeIcon icon={this._faName[i] as IconProp} size="sm" />
                     </button>
                 </Tooltip>)}
@@ -729,120 +721,35 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
             </div>;
     }
 
-    onUrlDrop = (e: React.DragEvent) => {
+    onWebUrlDrop = (e: React.DragEvent) => {
         const { dataTransfer } = e;
         const html = dataTransfer.getData("text/html");
         const uri = dataTransfer.getData("text/uri-list");
-        const url = uri || html || this._url;
+        const url = uri || html || this.webBoxUrl || "";
         const newurl = url.startsWith(window.location.origin) ?
-            url.replace(window.location.origin, this._url.match(/http[s]?:\/\/[^\/]*/)?.[0] || "") : url;
-        this.submitURL(newurl);
+            url.replace(window.location.origin, this.webBoxUrl?.match(/http[s]?:\/\/[^\/]*/)?.[0] || "") : url;
+        this.submitWebUrl(newurl);
         e.stopPropagation();
     }
-    onUrlDragover = (e: React.DragEvent) => {
-        e.preventDefault();
-    }
-
-    @computed get _url() {
-        return this.selectedDoc?.data instanceof WebField ? Cast(this.selectedDoc.data, WebField, null)?.url.toString() : Field.toString(this.selectedDoc?.data as Field);
-    }
-
-    set _url(value) {
-        if (this.selectedDoc) {
-            Doc.GetProto(this.selectedDoc).data = new WebField(value);
-            Doc.SetInPlace(this.selectedDoc, "title", value, true);
-            const annots = Doc.GetProto(this.selectedDoc)["data-annotations-" + this.urlHash(value)];
-            Doc.GetProto(this.selectedDoc)["data-annotations"] = annots instanceof ObjectField ? ObjectField.MakeCopy(annots) : new List<Doc>([]);
-        }
-    }
-
-    @action
-    submitURL = (url: string) => {
-        if (!url.startsWith("http")) url = "http://" + url;
-        try {
-            const selectedDoc = this.selectedDoc;
-            if (selectedDoc) {
-                const URLy = new URL(url);
-                const future = Cast(selectedDoc["data-future"], listSpec("string"), null);
-                const history = Cast(selectedDoc["data-history"], listSpec("string"), null);
-                const annos = DocListCast(selectedDoc["data-annotations"]);
-                if (Field.toString(selectedDoc.data as Field) === Field.toString(new WebField(URLy))) {
-                    Doc.GetProto(selectedDoc).data = new WebField(new URL("http://cs.brown.edu/~avd"));
-                    setTimeout(action(() => Doc.GetProto(selectedDoc).data = new WebField(URLy)), 100);
-                } else {
-                    if (url) {
-                        Doc.GetProto(selectedDoc)["data-annotations-" + this.urlHash(this._url)] = new List<Doc>(annos);
-                        if (history === undefined) {
-                            selectedDoc["data-history"] = new List<string>([this._url]);
-                        } else {
-                            history.push(this._url);
-                        }
-                        this.props.docView.props.Document._scrollTop = 0;
-                        future && (future.length = 0);
-                    }
-                    this._url = url;
-                }
-            }
-        } catch (e) {
-            console.log("WebBox URL error:" + url);
-        }
-    }
-
-    urlHash(s: string) {
-        return s.split('').reduce((a: any, b: any) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0);
-    }
-
-    onValueKeyDown = async (e: React.KeyboardEvent) => {
-        e.key === "Enter" && this.submitURL(this._keyInput.current!.value);
+    onWebUrlValueKeyDown = (e: React.KeyboardEvent) => {
+        e.key === "Enter" && this.submitWebUrl(this._keyInput.current!.value);
         e.stopPropagation();
     }
-
-    @action
-    forward = () => {
-        const selectedDoc = this.selectedDoc;
-        if (selectedDoc) {
-            const future = Cast(selectedDoc["data-future"], listSpec("string"), null);
-            const history = Cast(selectedDoc["data-history"], listSpec("string"), null);
-            if (future?.length) {
-                history?.push(this._url);
-                Doc.GetProto(selectedDoc)["data-annotations-" + this.urlHash(this._url)] = new List<Doc>(DocListCast(selectedDoc["data-annotations"]));
-                const newurl = future.pop()!;
-                Doc.GetProto(selectedDoc).data = new WebField(new URL(this._url = newurl));
-                Doc.GetProto(selectedDoc)["data-annotations"] = new List<Doc>(DocListCast(selectedDoc["data-annotations-" + this.urlHash(newurl)]));
-            }
-        }
-    }
-
-    @action
-    back = () => {
-        const selectedDoc = this.selectedDoc;
-        if (selectedDoc) {
-            const future = Cast(selectedDoc["data-future"], listSpec("string"), null);
-            const history = Cast(selectedDoc["data-history"], listSpec("string"), null);
-            if (history?.length) {
-                if (future === undefined) selectedDoc["data-future"] = new List<string>([this._url]);
-                else future.push(this._url);
-                Doc.GetProto(selectedDoc)["data-annotations-" + this.urlHash(this._url)] = new List<Doc>(DocListCast(selectedDoc["data-annotations"]));
-                const newurl = history.pop()!;
-                Doc.GetProto(selectedDoc).data = new WebField(new URL(this._url = newurl));
-                Doc.GetProto(selectedDoc)["data-annotations"] = new List<Doc>(DocListCast(selectedDoc["data-annotations-" + this.urlHash(newurl)]));
-            }
-        }
-    }
+    submitWebUrl = (url: string) => this.selectedDocumentView?.ComponentView?.submitURL?.(url);
+    webUrlForward = () => this.selectedDocumentView?.ComponentView?.forward?.();
+    webUrlBack = () => this.selectedDocumentView?.ComponentView?.back?.();
 
     private _keyInput = React.createRef<HTMLInputElement>();
 
     @computed get urlEditor() {
         return (
-            <div className="webBox-buttons"
-                onDrop={this.onUrlDrop}
-                onDragOver={this.onUrlDragover} style={{ display: "flex" }}>
-                <input className="webpage-urlInput" key={this._url}
+            <div className="collectionMenu-webUrlButtons" onDrop={this.onWebUrlDrop} onDragOver={e => e.preventDefault()} >
+                <input className="collectionMenu-urlInput" key={this.webBoxUrl}
                     placeholder="ENTER URL"
-                    defaultValue={this._url}
-                    onDrop={this.onUrlDrop}
-                    onDragOver={this.onUrlDragover}
-                    onKeyDown={this.onValueKeyDown}
+                    defaultValue={this.webBoxUrl}
+                    onDrop={this.onWebUrlDrop}
+                    onDragOver={e => e.preventDefault()}
+                    onKeyDown={this.onWebUrlValueKeyDown}
                     onClick={(e) => {
                         this._keyInput.current!.select();
                         e.stopPropagation();
@@ -850,13 +757,13 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
                     ref={this._keyInput}
                 />
                 <div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", maxWidth: "250px", }}>
-                    <button className="submitUrl" onClick={() => this.submitURL(this._keyInput.current!.value)} onDragOver={this.onUrlDragover} onDrop={this.onUrlDrop}>
+                    <button className="submitUrl" onClick={() => this.submitWebUrl(this._keyInput.current!.value)} onDragOver={e => e.stopPropagation()} onDrop={this.onWebUrlDrop}>
                         GO
                     </button>
-                    <button className="submitUrl" onClick={this.back}>
+                    <button className="submitUrl" onClick={this.webUrlBack}>
                         <FontAwesomeIcon icon="caret-left" size="lg"></FontAwesomeIcon>
                     </button>
-                    <button className="submitUrl" onClick={this.forward}>
+                    <button className="submitUrl" onClick={this.webUrlForward}>
                         <FontAwesomeIcon icon="caret-right" size="lg"></FontAwesomeIcon>
                     </button>
                 </div>
-- 
cgit v1.2.3-70-g09d2


From a774d7f55755703faa316401dd8724dd82a9ee98 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 3 Feb 2021 12:08:27 -0500
Subject: added linkRelationship to linkEditor.  fixed warnings.

---
 src/client/views/GestureOverlay.tsx                | 18 +----
 src/client/views/collections/CollectionMenu.tsx    | 11 ++-
 src/client/views/linking/LinkEditor.tsx            | 84 +++++++++++++++-------
 src/client/views/nodes/WebBox.tsx                  |  1 +
 .../views/nodes/formattedText/FormattedTextBox.tsx |  4 +-
 5 files changed, 71 insertions(+), 47 deletions(-)

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

diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 0cf958681..ae27e78d5 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -32,10 +32,6 @@ export class GestureOverlay extends Touchable {
     @observable public InkShape: string = "";
     @observable public SavedColor?: string;
     @observable public SavedWidth?: string;
-    @observable public SavedFill?: string;
-    @observable public SavedArrowStart: string = "none";
-    @observable public SavedArrowEnd: string = "none";
-    @observable public SavedDash: String = "0";
     @observable public Tool: ToolglassTools = ToolglassTools.None;
 
     @observable private _thumbX?: number;
@@ -653,15 +649,7 @@ export class GestureOverlay extends Touchable {
         } else {
             this._points = [];
         }
-        //get out of ink mode after each stroke=
-        if (CollectionFreeFormViewChrome.Instance && !CollectionFreeFormViewChrome.Instance?._keepPrimitiveMode) {
-            Doc.SetSelectedTool(InkTool.None);
-            CollectionFreeFormViewChrome.Instance._selectedPrimitive = CollectionFreeFormViewChrome.Instance._shapesPrimNum;
-            SetActiveArrowStart("none");
-            GestureOverlay.Instance.SavedArrowStart = ActiveArrowStart();
-            SetActiveArrowEnd("none");
-            GestureOverlay.Instance.SavedArrowEnd = ActiveArrowEnd();
-        }
+        CollectionFreeFormViewChrome.Instance.primCreated();
     }
 
     makePolygon = (shape: string, gesture: boolean) => {
@@ -969,13 +957,9 @@ Scripting.addGlobal(function setPen(width: any, color: any, fill: any, arrowStar
         SetActiveInkColor(color);
         GestureOverlay.Instance.SavedWidth = ActiveInkWidth();
         SetActiveInkWidth(width);
-        GestureOverlay.Instance.SavedFill = ActiveFillColor();
         SetActiveFillColor(fill);
-        GestureOverlay.Instance.SavedArrowStart = ActiveArrowStart();
         SetActiveArrowStart(arrowStart);
-        GestureOverlay.Instance.SavedArrowEnd = ActiveArrowEnd();
         SetActiveArrowStart(arrowEnd);
-        GestureOverlay.Instance.SavedDash = ActiveDash();
         SetActiveDash(dash);
     });
 });
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 4e2d81e61..7ba857449 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -25,7 +25,7 @@ import { undoBatch } from "../../util/UndoManager";
 import { AntimodeMenu, AntimodeMenuProps } from "../AntimodeMenu";
 import { EditableView } from "../EditableView";
 import { GestureOverlay } from "../GestureOverlay";
-import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from "../InkingStroke";
+import { ActiveFillColor, ActiveInkColor, SetActiveArrowEnd, SetActiveArrowStart, SetActiveBezierApprox, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth, ActiveArrowStart, ActiveArrowEnd } from "../InkingStroke";
 import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
 import { DocumentView } from "../nodes/DocumentView";
 import { RichTextMenu } from "../nodes/formattedText/RichTextMenu";
@@ -591,12 +591,19 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     private _faName = ["pen-fancy", "minus", "long-arrow-alt-right", "arrows-alt-h", "square", "circle"];
     @observable _selectedPrimitive = this._shapePrims.length;
     @observable _keepPrimitiveMode = false; // for whether primitive selection enters a one-shot or persistent mode
-
     @observable _colorBtn = false;
     @observable _widthBtn = false;
     @observable _fillBtn = false;
 
     @action clearKeepPrimitiveMode() { this._selectedPrimitive = this._shapePrims.length; }
+    @action primCreated() {
+        if (!this._keepPrimitiveMode) { //get out of ink mode after each stroke=
+            Doc.SetSelectedTool(InkTool.None);
+            this._selectedPrimitive = this._shapePrims.length;
+            SetActiveArrowStart("none");
+            SetActiveArrowEnd("none");
+        }
+    }
 
     @action
     changeColor = (color: string, type: string) => {
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index 435b9d904..f74b422d3 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -4,7 +4,6 @@ import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
 import { Doc } from "../../../fields/Doc";
 import { DateCast, StrCast } from "../../../fields/Types";
-import { Utils } from "../../../Utils";
 import { LinkManager } from "../../util/LinkManager";
 import { undoBatch } from "../../util/UndoManager";
 import './LinkEditor.scss';
@@ -21,31 +20,41 @@ interface LinkEditorProps {
 export class LinkEditor extends React.Component<LinkEditorProps> {
 
     @observable description = StrCast(LinkManager.currentLink?.description);
+    @observable relationship = StrCast(LinkManager.currentLink?.linkRelationship);
     @observable openDropdown: boolean = false;
     @observable showInfo: boolean = false;
     @computed get infoIcon() { if (this.showInfo) { return "chevron-up"; } return "chevron-down"; }
     @observable private buttonColor: string = "";
-
+    @observable private relationshipButtonColor: string = "";
 
     //@observable description = this.props.linkDoc.description ? StrCast(this.props.linkDoc.description) : "DESCRIPTION";
 
-    @undoBatch @action
+    @undoBatch
     deleteLink = (): void => {
         LinkManager.Instance.deleteLink(this.props.linkDoc);
         this.props.showLinks();
     }
 
-    @undoBatch @action
-    setDescripValue = (value: string) => {
+    @undoBatch
+    setRelationshipValue = action((value: string) => {
+        if (LinkManager.currentLink) {
+            LinkManager.currentLink.linkRelationship = value;
+            this.relationshipButtonColor = "rgb(62, 133, 55)";
+            setTimeout(action(() => this.relationshipButtonColor = ""), 750);
+            return true;
+        }
+    });
+
+    @undoBatch
+    setDescripValue = action((value: string) => {
         if (LinkManager.currentLink) {
             LinkManager.currentLink.description = value;
             this.buttonColor = "rgb(62, 133, 55)";
             setTimeout(action(() => this.buttonColor = ""), 750);
             return true;
         }
-    }
+    });
 
-    @action
     onKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.key === "Enter") {
             this.setDescripValue(this.description);
@@ -53,22 +62,48 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
         }
     }
 
-    @action
-    onDown = () => {
-        this.setDescripValue(this.description);
+    onRelationshipKey = (e: React.KeyboardEvent<HTMLInputElement>) => {
+        if (e.key === "Enter") {
+            this.setRelationshipValue(this.relationship);
+            document.getElementById('input')?.blur();
+        }
     }
 
+    onDown = () => this.setDescripValue(this.description);
+    onRelationshipDown = () => this.setRelationshipValue(this.description);
+
     @action
-    handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
-        this.description = e.target.value;
-    }
+    handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.target.value; }
+    @action
+    handleRelationshipChange = (e: React.ChangeEvent<HTMLInputElement>) => { this.relationship = e.target.value; }
 
+    @computed
+    get editRelationship() {
+        return <div className="linkEditor-description">
+            <div className="linkEditor-description-label">Link Relationship:</div>
+            <div className="linkEditor-description-input">
+                <div className="linkEditor-description-editing">
+                    <input
+                        style={{ width: "100%" }}
+                        id="input"
+                        value={this.relationship}
+                        placeholder={"enter link label"}
+                        // color={"rgb(88, 88, 88)"}
+                        onKeyDown={this.onRelationshipKey}
+                        onChange={this.handleRelationshipChange}
+                    ></input>
+                </div>
+                <div className="linkEditor-description-add-button"
+                    style={{ background: this.relationshipButtonColor }}
+                    onPointerDown={this.onRelationshipDown}>Set</div>
+            </div>
+        </div>;
+    }
 
     @computed
     get editDescription() {
         return <div className="linkEditor-description">
-            <div className="linkEditor-description-label">
-                Link Label:</div>
+            <div className="linkEditor-description-label">Link Description:</div>
             <div className="linkEditor-description-input">
                 <div className="linkEditor-description-editing">
                     <input
@@ -84,13 +119,12 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                 <div className="linkEditor-description-add-button"
                     style={{ background: this.buttonColor }}
                     onPointerDown={this.onDown}>Set</div>
-            </div></div>;
+            </div>
+        </div>;
     }
 
     @action
-    changeDropdown = () => {
-        this.openDropdown = !this.openDropdown;
-    }
+    changeDropdown = () => { this.openDropdown = !this.openDropdown; }
 
     @undoBatch
     changeFollowBehavior = action((follow: string) => {
@@ -101,8 +135,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     @computed
     get followingDropdown() {
         return <div className="linkEditor-followingDropdown">
-            <div className="linkEditor-followingDropdown-label">
-                Follow Behavior:</div>
+            <div className="linkEditor-followingDropdown-label">Follow Behavior:</div>
             <div className="linkEditor-followingDropdown-dropdown">
                 <div className="linkEditor-followingDropdown-header"
                     onPointerDown={this.changeDropdown}>
@@ -157,9 +190,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
     }
 
     @action
-    changeInfo = () => {
-        this.showInfo = !this.showInfo;
-    }
+    changeInfo = () => { this.showInfo = !this.showInfo; }
 
     render() {
         const destination = LinkManager.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
@@ -186,8 +217,9 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                         {DateCast(this.props.linkDoc.creationDate).toString()}</div> : null}</div>
                 </div> : null}
 
-                <div>{this.editDescription}</div>
-                <div>{this.followingDropdown}</div>
+                {this.editDescription}
+                {this.editRelationship}
+                {this.followingDropdown}
             </div>
 
         );
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 438395ab0..352abd1e7 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -256,6 +256,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
         } catch (e) {
             console.log("WebBox URL error:" + this._url);
         }
+        return true;
     }
 
     editToggleBtn() {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 8b1e58ceb..b3abcf90a 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -67,7 +67,7 @@ import { StyleProp } from '../../StyleProvider';
 import { AnchorMenu } from '../../pdf/AnchorMenu';
 import { CurrentUserUtils } from '../../../util/CurrentUserUtils';
 import { DocumentManager } from '../../../util/DocumentManager';
-const translateGoogleApi = require("translate-google-api")
+const translateGoogleApi = require("translate-google-api");
 
 export interface FormattedTextBoxProps {
     makeLink?: () => Opt<Doc>;  // bcz: hack: notifies the text document when the container has made a link.  allows the text doc to react and setup a hyeprlink for any selected text
@@ -947,7 +947,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                             this.tryUpdateHeight();
                         }
                     } else if (incomingValue?.str) {
-                        selectAll(this._editorView!.state, tx => this._editorView?.dispatch(tx.insertText(incomingValue.str)));
+                        selectAll(this._editorView.state, tx => this._editorView?.dispatch(tx.insertText(incomingValue.str)));
                     }
                 }
             },
-- 
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/CollectionMenu.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 919483d4222de685c1062a1e715f57c09442b676 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 5 Feb 2021 13:57:34 -0500
Subject: from last

---
 src/client/views/DocumentDecorations.tsx        | 15 ++++++++++-----
 src/client/views/collections/CollectionMenu.tsx |  2 +-
 2 files changed, 11 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 0dfa0f8b2..77b43db9b 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -175,7 +175,10 @@ 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(() => LightboxView.LightboxDoc = selectedDocs[0].props.Document);
+                    runInAction(() => {
+                        LightboxView.LightboxDoc = selectedDocs[0].props.Document;
+                        LightboxView.LightboxFuture = selectedDocs.slice(1).map(view => view.props.Document);
+                    });
                 }
             }
         }
@@ -572,10 +575,12 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
                     <FontAwesomeIcon className="documentdecorations-times" icon={"times"} size="lg" />
                 </div></Tooltip>);
 
-        const openIcon = !canOpen ? (null) : <Tooltip key="open" title={<div className="dash-tooltip">Open in Tab (ctrl: as alias, shift: in new collection)</div>} placement="top"><div className="documentDecorations-openInTab" onContextMenu={e => { e.preventDefault(); e.stopPropagation(); }} onPointerDown={this.onMaximizeDown}>
-            {SelectionManager.Views().length === 1 ? <FontAwesomeIcon icon="external-link-alt" className="documentView-minimizedIcon" /> : "..."}
-        </div>
-        </Tooltip>;
+        const openIcon = !canOpen ? (null) :
+            <Tooltip key="open" title={<div className="dash-tooltip">Open in Tab (ctrl: as alias, shift: in new collection)</div>} placement="top">
+                <div className="documentDecorations-openInTab" onContextMenu={e => { e.preventDefault(); e.stopPropagation(); }} onPointerDown={this.onMaximizeDown}>
+                    <FontAwesomeIcon icon="external-link-alt" className="documentView-minimizedIcon" />
+                </div>
+            </Tooltip>;
 
         const titleArea = this._edtingTitle ?
             <input ref={this._keyinput} className="documentDecorations-title" type="text" name="dynbox" autoComplete="on" value={this._accumulatedTitle}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 3f0b8eb3e..d6e4b01c4 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -493,7 +493,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                 const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
                 if (docs.length) {
                     LightboxView.LightboxDoc = docs[0];
-                    LightboxView.LightboxFuture = docs;
+                    LightboxView.LightboxFuture = docs.slice(1);
                 }
             })}>
                 <FontAwesomeIcon className="documentdecorations-icon" icon="desktop" size="lg" />
-- 
cgit v1.2.3-70-g09d2

