From 51f9da2bb6529c102c300a1ceb4ccd23065a76fc Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 29 Aug 2020 17:58:32 -0400
Subject: split out TabDocView from CollectionDockingView (where it had been
 called DockedFrameRenderer)

---
 src/client/views/collections/TabDocView.tsx | 379 ++++++++++++++++++++++++++++
 1 file changed, 379 insertions(+)
 create mode 100644 src/client/views/collections/TabDocView.tsx

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

diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
new file mode 100644
index 000000000..36959f254
--- /dev/null
+++ b/src/client/views/collections/TabDocView.tsx
@@ -0,0 +1,379 @@
+import 'golden-layout/src/css/goldenlayout-base.css';
+import 'golden-layout/src/css/goldenlayout-dark-theme.css';
+import { clamp } from 'lodash';
+import { action, computed, IReactionDisposer, observable, reaction } from "mobx";
+import { observer } from "mobx-react";
+import * as ReactDOM from 'react-dom';
+import { DataSym, Doc, DocListCast, Opt } from "../../../fields/Doc";
+import { Id } from '../../../fields/FieldSymbols';
+import { FieldId } from "../../../fields/RefField";
+import { listSpec } from '../../../fields/Schema';
+import { Cast, NumCast, StrCast } from "../../../fields/Types";
+import { TraceMobx } from '../../../fields/util';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from "../../../Utils";
+import { DocServer } from "../../DocServer";
+import { CurrentUserUtils } from '../../util/CurrentUserUtils';
+import { DocumentManager } from '../../util/DocumentManager';
+import { DragManager, dropActionType } from "../../util/DragManager";
+import { SelectionManager } from '../../util/SelectionManager';
+import { SnappingManager } from '../../util/SnappingManager';
+import { Transform } from '../../util/Transform';
+import { undoBatch } from "../../util/UndoManager";
+import { DocumentView } from "../nodes/DocumentView";
+import { PresBox } from '../nodes/PresBox';
+import { CollectionDockingView } from './CollectionDockingView';
+import "./TabDocView.scss";
+import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
+import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
+import { CollectionViewType } from './CollectionView';
+import React = require("react");
+const _global = (window /* browser */ || global /* node */) as any;
+
+interface TabDocViewProps {
+    documentId: FieldId;
+    glContainer: any;
+}
+@observer
+export class TabDocView extends React.Component<TabDocViewProps> {
+    _mainCont: HTMLDivElement | null = null;
+    _tabReaction: IReactionDisposer | undefined;
+    @observable private _panelWidth = 0;
+    @observable private _panelHeight = 0;
+    @observable private _isActive: boolean = false;
+    @observable private _document: Doc | undefined;
+    @observable private _view: DocumentView | undefined;
+
+    get stack(): any { return (this.props as any).glContainer.parent.parent; }
+    get tab() { return (this.props as any).glContainer.tab; }
+    get view() { return this._view; }
+
+    @action
+    init = (tab: any, doc: Opt<Doc>) => {
+        if (tab.DashDoc !== doc && doc && tab.hasOwnProperty("contentItem") && tab.contentItem.config.type !== "stack") {
+            tab._disposers = {} as { [name: string]: IReactionDisposer };
+            tab.contentItem.config.fixed && (tab.contentItem.parent.config.fixed = true);
+            tab.DashDoc = doc;
+
+            CollectionDockingView.Instance.tabMap.add(tab);
+            tab.titleElement[0].onclick = (e: any) => {
+                if (Date.now() - tab.titleElement[0].lastClick < 1000) tab.titleElement[0].select();
+                tab.titleElement[0].lastClick = Date.now();
+                tab.titleElement[0].focus();
+            };
+            tab.titleElement[0].onchange = (e: any) => {
+                tab.titleElement[0].size = e.currentTarget.value.length + 1;
+                Doc.GetProto(doc).title = e.currentTarget.value;
+            };
+            tab.titleElement[0].size = StrCast(doc.title).length + 1;
+            tab.titleElement[0].value = doc.title;
+            tab.titleElement[0].style["max-width"] = "100px";
+            const gearSpan = document.createElement("span");
+            gearSpan.className = "collectionDockingView-gear";
+            gearSpan.style.position = "relative";
+            gearSpan.style.paddingLeft = "0px";
+            gearSpan.style.paddingRight = "12px";
+            const stack = tab.contentItem.parent;
+            tab.element[0].onpointerdown = (e: any) => {
+                e.target.className !== "lm_close_tab" && this.view && SelectionManager.SelectDoc(this.view, false);
+            };
+            // shifts the focus to this tab when another tab is dragged over it
+            tab.element[0].onmouseenter = (e: MouseEvent) => {
+                if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) {
+                    tab.header.parent.setActiveContentItem(tab.contentItem);
+                }
+                tab.setActive(true);
+            };
+            const onDown = (e: React.PointerEvent) => {
+                setupMoveUpEvents(this, e, (e) => {
+                    !e.defaultPrevented && DragManager.StartDocumentDrag([gearSpan], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY);
+                    return !e.defaultPrevented;
+                }, returnFalse, emptyFunction);
+            };
+
+            tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.props.Document === doc),
+                (selected) => {
+                    selected && tab.contentItem !== tab.header.parent.getActiveContentItem() && tab.header.parent.setActiveContentItem(tab.contentItem);
+                }
+            );
+            tab._disposers.buttonDisposer = reaction(() => this.view,
+                (view) => {
+                    if (view) {
+                        ReactDOM.render(<span title="Drag as document" className="collectionDockingView-dragAsDocument" onPointerDown={onDown} >
+                            <CollectionDockingViewMenu views={() => [view]} Stack={stack} />
+                        </span>,
+                            gearSpan);
+                        tab._disposers.buttonDisposer?.();
+                    }
+                }, { fireImmediately: true });
+
+            tab.reactComponents = [gearSpan];
+            tab.element.append(gearSpan);
+            tab._disposers.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => {
+                tab.titleElement[0].value = title;
+                tab.titleElement[0].style.padding = degree ? 0 : 2;
+                tab.titleElement[0].style.border = `${["gray", "gray", "gray"][degree]} ${["none", "dashed", "solid"][degree]} 2px`;
+            }, { fireImmediately: true });
+            tab.closeElement.off('click') //unbind the current click handler
+                .click(function () {
+                    Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
+                    Doc.AddDocToList(CurrentUserUtils.MyRecentlyClosed, "data", doc, undefined, true, true);
+                    SelectionManager.DeselectAll();
+                    tab.contentItem.remove();
+                });
+        }
+    }
+    /**
+     * Adds a document to the presentation view
+     **/
+    @undoBatch
+    @action
+    public static PinDoc(doc: Doc, unpin = false) {
+        if (unpin) TabDocView.UnpinDoc(doc);
+        else {
+            //add this new doc to props.Document
+            const curPres = CurrentUserUtils.ActivePresentation;
+            if (curPres) {
+                const pinDoc = Doc.MakeAlias(doc);
+                pinDoc.presentationTargetDoc = doc;
+                pinDoc.presZoomButton = true;
+                pinDoc.context = curPres;
+                Doc.AddDocToList(curPres, "data", pinDoc);
+                if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
+                if (!DocumentManager.Instance.getDocumentView(curPres)) {
+                    CollectionDockingView.AddSplit(curPres, "right");
+                }
+                DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null));
+            }
+        }
+    }
+    /**
+     * Adds a document to the presentation view
+     **/
+    @undoBatch
+    @action
+    public static UnpinDoc(doc: Doc) {
+        //add this new doc to props.Document
+        const curPres = CurrentUserUtils.ActivePresentation;
+        if (curPres) {
+            const ind = DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc));
+            ind !== -1 && Doc.RemoveDocFromList(curPres, "data", DocListCast(curPres.data)[ind]);
+        }
+    }
+
+    componentDidMount() {
+        const color = () => StrCast(this._document?._backgroundColor, this._document && CollectionDockingView.Instance?.props.backgroundColor?.(this._document, 0) || "white");
+        const selected = () => SelectionManager.SelectedDocuments().some(v => v.props.Document === this._document);
+        const updateTabColor = () => this.tab?.titleElement[0] && (this.tab.titleElement[0].style.backgroundColor = selected() ? color() : "");
+        const observer = new _global.ResizeObserver(action((entries: any) => {
+            for (const entry of entries) {
+                this._panelWidth = entry.contentRect.width;
+                this._panelHeight = entry.contentRect.height;
+            }
+            updateTabColor();
+        }));
+        observer.observe(this.props.glContainer._element[0]);
+        this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged);
+        this.props.glContainer.tab?.isActive && this.onActiveContentItemChanged();
+        this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: color() }), updateTabColor, { fireImmediately: true });
+    }
+
+    componentWillUnmount() {
+        this._tabReaction?.();
+        this.props.glContainer.layoutManager.off("activeContentItemChanged", this.onActiveContentItemChanged);
+    }
+
+    @action.bound
+    private onActiveContentItemChanged() {
+        if (this.props.glContainer.tab && this._isActive !== this.props.glContainer.tab.isActive) {
+            this._isActive = this.props.glContainer.tab.isActive;
+            this._isActive && setTimeout(() => this.view && SelectionManager.SelectDoc(this.view, false), 0);
+            (CollectionDockingView.Instance as any)._goldenLayout.isInitialised && CollectionDockingView.Instance.stateChanged();
+            !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one.
+        }
+    }
+
+    get layoutDoc() { return this._document && Doc.Layout(this._document); }
+    nativeAspect = () => this.nativeWidth() ? this.nativeWidth() / this.nativeHeight() : 0;
+    panelWidth = () => this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) :
+        (this.nativeAspect() && this.nativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.nativeAspect() : this._panelWidth)
+    panelHeight = () => this.nativeAspect() && this.nativeAspect() > this._panelWidth / this._panelHeight ? this._panelWidth / this.nativeAspect() : this._panelHeight;
+    nativeWidth = () => !this.layoutDoc?._fitWidth ? NumCast(this.layoutDoc?._nativeWidth) || this._panelWidth : 0;
+    nativeHeight = () => !this.layoutDoc?._fitWidth ? NumCast(this.layoutDoc?._nativeHeight) || this._panelHeight : 0;
+
+    contentScaling = () => {
+        const nativeH = this.nativeHeight();
+        const nativeW = this.nativeWidth();
+        let scaling = 1;
+        if (!this.layoutDoc?._fitWidth && (!nativeW || !nativeH)) {
+            scaling = 1;
+        } else if (NumCast(this.layoutDoc?._nativeWidth) && ((this.layoutDoc?._fitWidth) ||
+            this._panelHeight / NumCast(this.layoutDoc?._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc?._nativeWidth))) {
+            scaling = this._panelWidth / NumCast(this.layoutDoc?._nativeWidth);
+        } else if (nativeW && nativeH) {
+            const wscale = this.panelWidth() / nativeW;
+            scaling = wscale * nativeH > this._panelHeight ? this._panelHeight / nativeH : wscale;
+        }
+        return scaling;
+    }
+
+    ScreenToLocalTransform = () => {
+        if (this._mainCont && this._mainCont.children) {
+            const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont.children[0].firstChild as HTMLElement);
+            const scale = Utils.GetScreenTransform(this._mainCont).scale;
+            return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale);
+        }
+        return Transform.Identity();
+    }
+    get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
+    get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this._panelWidth * 100}% ` : undefined; }
+
+    // adds a tab to the layout based on the locaiton parameter which can be:
+    //  close[:{left,right,top,bottom}]  - e.g., "close" will close the tab, "close:left" will close the left tab, 
+    //  add[:{left,right,top,bottom}] - e.g., "add" will add a tab to the current stack, "add:right" will add a tab on the right
+    //  replace[:{left,right,top,bottom,<any string>}] - e.g., "replace" will replace the current stack contents, 
+    //                                  "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name, 
+    //                                   "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right
+    //  inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack
+    addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => {
+        SelectionManager.DeselectAll();
+        if (doc._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc);
+        const locationFields = location.split(":");
+        const locationParams = locationFields.length > 1 ? locationFields[1] : "";
+        switch (locationFields[0]) {
+            case "close": return CollectionDockingView.CloseSplit(doc, locationParams);
+            case "fullScreen": return CollectionDockingView.OpenFullScreen(doc);
+            case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack);
+            case "inPlace":
+            case "add":
+            default: return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack);
+        }
+    }
+
+    @computed get renderContentBounds() {
+        const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0];
+        const xbounds = bounds[2] - bounds[0];
+        const ybounds = bounds[3] - bounds[1];
+        const dim = Math.max(xbounds, ybounds);
+        return { l: bounds[0] + xbounds / 2 - dim / 2, t: bounds[1] + ybounds / 2 - dim / 2, cx: bounds[0] + xbounds / 2, cy: bounds[1] + ybounds / 2, dim };
+    }
+    @computed get miniLeft() { return 50 + (NumCast(this._document?._panX) - this.renderContentBounds.cx) / this.renderContentBounds.dim * 100 - this.miniWidth / 2; }
+    @computed get miniTop() { return 50 + (NumCast(this._document?._panY) - this.renderContentBounds.cy) / this.renderContentBounds.dim * 100 - this.miniHeight / 2; }
+    @computed get miniWidth() { return this.panelWidth() / NumCast(this._document?._viewScale, 1) / this.renderContentBounds.dim * 100; }
+    @computed get miniHeight() { return this.panelHeight() / NumCast(this._document?._viewScale, 1) / this.renderContentBounds.dim * 100; }
+    childLayoutTemplate = () => Cast(this._document?.childLayoutTemplate, Doc, null);
+    returnMiniSize = () => NumCast(this._document?._miniMapSize, 150);
+    miniDown = (e: React.PointerEvent) => {
+        this._document && setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
+            this._document!._panX = clamp(NumCast(this._document!._panX) + delta[0] / this.returnMiniSize() * this.renderContentBounds.dim, this.renderContentBounds.l, this.renderContentBounds.l + this.renderContentBounds.dim);
+            this._document!._panY = clamp(NumCast(this._document!._panY) + delta[1] / this.returnMiniSize() * this.renderContentBounds.dim, this.renderContentBounds.t, this.renderContentBounds.t + this.renderContentBounds.dim);
+            return false;
+        }), emptyFunction, emptyFunction);
+    }
+    getCurrentFrame = (): number => {
+        const presTargetDoc = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null);
+        return Cast(presTargetDoc._currentFrame, "number", null);
+    }
+
+    renderMiniMap() {
+        return <div className="miniMap" style={{
+            width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor,
+                StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!, 0))),
+        }}>
+            <CollectionFreeFormView
+                Document={this._document!}
+                LibraryPath={emptyPath}
+                CollectionView={undefined}
+                ContainingCollectionView={undefined}
+                ContainingCollectionDoc={undefined}
+                ChildLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid havin to set stuff like this.
+                noOverlay={true} // don't render overlay Docs since they won't scale
+                active={returnTrue}
+                select={emptyFunction}
+                dropAction={undefined}
+                isSelected={returnFalse}
+                dontRegisterView={true}
+                annotationsKey={""}
+                fieldKey={Doc.LayoutFieldKey(this._document!)}
+                bringToFront={emptyFunction}
+                rootSelected={returnTrue}
+                addDocument={returnFalse}
+                moveDocument={returnFalse}
+                removeDocument={returnFalse}
+                ContentScaling={returnOne}
+                PanelWidth={this.returnMiniSize}
+                PanelHeight={this.returnMiniSize}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
+                ScreenToLocalTransform={this.ScreenToLocalTransform}
+                renderDepth={0}
+                whenActiveChanged={emptyFunction}
+                focus={emptyFunction}
+                backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
+                addDocTab={this.addDocTab}
+                pinToPres={TabDocView.PinDoc}
+                docFilters={CollectionDockingView.Instance.docFilters}
+                searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
+                fitToBox={true}
+            />
+            <div className="miniOverlay" onPointerDown={this.miniDown} >
+                <div className="miniThumb" style={{
+                    width: `${this.miniWidth}% `,
+                    height: `${this.miniHeight}% `,
+                    left: `${this.miniLeft}% `,
+                    top: `${this.miniTop}% `,
+                }}
+                />
+            </div>
+        </div>;
+    }
+    setView = action((view: DocumentView) => this._view = view);
+    @computed get docView() {
+        TraceMobx();
+        return !this._document ? (null) :
+            <><DocumentView key={this._document[Id]}
+                LibraryPath={emptyPath}
+                Document={this._document}
+                getView={this.setView}
+                DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
+                bringToFront={emptyFunction}
+                rootSelected={returnTrue}
+                addDocument={undefined}
+                removeDocument={undefined}
+                ContentScaling={this.contentScaling}
+                PanelWidth={this.panelWidth}
+                PanelHeight={this.panelHeight}
+                NativeHeight={this.nativeHeight}
+                NativeWidth={this.nativeWidth}
+                ScreenToLocalTransform={this.ScreenToLocalTransform}
+                renderDepth={0}
+                parentActive={returnTrue}
+                whenActiveChanged={emptyFunction}
+                focus={emptyFunction}
+                backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
+                addDocTab={this.addDocTab}
+                pinToPres={TabDocView.PinDoc}
+                docFilters={CollectionDockingView.Instance.docFilters}
+                searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
+                ContainingCollectionView={undefined}
+                ContainingCollectionDoc={undefined} />
+                {this._document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)}
+            </>;
+    }
+
+    render() {
+        return !this._isActive ? (null) :
+            (<div className="collectionDockingView-content" ref={ref => {
+                if (this._mainCont = ref) {
+                    (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
+                    DocServer.GetRefField(this.tab.contentItem.config.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.init(this.tab, this._document)));
+                }
+            }}
+                style={{
+                    transform: `translate(${this.previewPanelCenteringOffset}px, 0px)`,
+                    height: this.layoutDoc?._fitWidth ? undefined : "100%",
+                    width: this.widthpercent
+                }}>
+                {this.docView}
+            </div >);
+    }
+}
-- 
cgit v1.2.3-70-g09d2


From d6ed6bc7a368169b15b81b02d4daee67a92b05c4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 30 Aug 2020 00:13:33 -0400
Subject: fixed initialization of non-active tabs.  fixed dragging of tab
 document icon.

---
 .../collections/CollectionDockingViewMenu.tsx      |  3 ---
 src/client/views/collections/TabDocView.tsx        | 27 +++++++++++-----------
 2 files changed, 13 insertions(+), 17 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingViewMenu.tsx b/src/client/views/collections/CollectionDockingViewMenu.tsx
index 4fe97452c..1cab293a8 100644
--- a/src/client/views/collections/CollectionDockingViewMenu.tsx
+++ b/src/client/views/collections/CollectionDockingViewMenu.tsx
@@ -36,9 +36,6 @@ export class CollectionDockingViewMenu extends React.Component<{ views: () => Do
             <span className="dockingViewButtonSelector"
                 onPointerEnter={action(() => !this._ref.current?.getBoundingClientRect().width && (this._tooltipOpen = true))}
                 onPointerDown={action(e => {
-                    if (getComputedStyle(this._ref.current!).width !== "100%") {
-                        e.stopPropagation(); e.preventDefault();
-                    }
                     this.props.views()[0]?.select(false);
                     this._tooltipOpen = false;
                 })} >
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 36959f254..dd383fc32 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -361,19 +361,18 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     }
 
     render() {
-        return !this._isActive ? (null) :
-            (<div className="collectionDockingView-content" ref={ref => {
-                if (this._mainCont = ref) {
-                    (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
-                    DocServer.GetRefField(this.tab.contentItem.config.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.init(this.tab, this._document)));
-                }
-            }}
-                style={{
-                    transform: `translate(${this.previewPanelCenteringOffset}px, 0px)`,
-                    height: this.layoutDoc?._fitWidth ? undefined : "100%",
-                    width: this.widthpercent
-                }}>
-                {this.docView}
-            </div >);
+        return (<div className="collectionDockingView-content" ref={ref => {
+            if (this._mainCont = ref) {
+                (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
+                this.tab && DocServer.GetRefField(this.tab.contentItem.config.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.init(this.tab, this._document)));
+            }
+        }}
+            style={{
+                transform: `translate(${this.previewPanelCenteringOffset}px, 0px)`,
+                height: this.layoutDoc?._fitWidth ? undefined : "100%",
+                width: this.widthpercent
+            }}>
+            {this.docView}
+        </div >);
     }
 }
-- 
cgit v1.2.3-70-g09d2


From dafb4f33ee32ddc323860bf54c560d2def66c152 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 30 Aug 2020 00:58:10 -0400
Subject: fixed undo for following links from a Document view.

---
 src/client/util/DocumentManager.ts          | 1 +
 src/client/views/collections/TabDocView.tsx | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 93c37dbd1..f085f615c 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -160,6 +160,7 @@ export class DocumentManager {
                 docView.props.Document.hidden = !docView.props.Document.hidden;
             }
             else {
+                docView.select(false);
                 docView.props.Document.hidden && (docView.props.Document.hidden = undefined);
                 docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish);
                 highlight();
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index dd383fc32..5bff1cdc3 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -348,7 +348,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 renderDepth={0}
                 parentActive={returnTrue}
                 whenActiveChanged={emptyFunction}
-                focus={emptyFunction}
+                focus={(doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => afterFocus?.()}
                 backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
                 addDocTab={this.addDocTab}
                 pinToPres={TabDocView.PinDoc}
-- 
cgit v1.2.3-70-g09d2


From e8856332c19abe12fe43c940e35b49ab77aae612 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 30 Aug 2020 01:06:23 -0400
Subject: from last

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

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

diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 5bff1cdc3..5acf825f1 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -326,6 +326,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             </div>
         </div>;
     }
+    focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => afterFocus?.();
     setView = action((view: DocumentView) => this._view = view);
     @computed get docView() {
         TraceMobx();
@@ -348,7 +349,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 renderDepth={0}
                 parentActive={returnTrue}
                 whenActiveChanged={emptyFunction}
-                focus={(doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => afterFocus?.()}
+                focus={this.focusFunc}
                 backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
                 addDocTab={this.addDocTab}
                 pinToPres={TabDocView.PinDoc}
-- 
cgit v1.2.3-70-g09d2


From 561a8d0bd130ea5c1fd68a4dd2344f0333d388cc Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sun, 30 Aug 2020 13:10:54 -0400
Subject: fixed importBox upload to give feedback, share code. fixed stacking
 autoHeight to happen immediately.  fixed images to not need to request image
 information.  changed doc decorations to change image native width.  changed
 alert() when dropping on impermissibale doc.  fixed allow dropping over
 images,etc.  changed default image nativeSize to 900

---
 src/client/documents/Documents.ts                  | 23 +++++----
 src/client/util/CurrentUserUtils.ts                |  1 -
 src/client/views/DocumentDecorations.tsx           |  6 +--
 src/client/views/MainView.tsx                      | 56 +++++-----------------
 .../views/collections/CollectionStackingView.tsx   |  9 ++++
 src/client/views/collections/CollectionSubView.tsx |  3 +-
 src/client/views/collections/TabDocView.tsx        |  4 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 src/client/views/globalCssVariables.scss           |  2 +
 src/client/views/globalCssVariables.scss.d.ts      |  1 +
 src/client/views/nodes/DocumentView.tsx            |  7 ++-
 src/client/views/nodes/ImageBox.tsx                | 49 +++++++++++--------
 src/mobile/ImageUpload.tsx                         |  8 ++--
 src/server/ApiManagers/UploadManager.ts            |  2 +-
 14 files changed, 84 insertions(+), 89 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 262086735..9a24a8052 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,5 +1,5 @@
-import { runInAction, action } from "mobx";
-import { extname, basename } from "path";
+import { runInAction } from "mobx";
+import { basename, extname } from "path";
 import { DateField } from "../../fields/DateField";
 import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc";
 import { HtmlField } from "../../fields/HtmlField";
@@ -12,21 +12,22 @@ import { ComputedField, ScriptField } from "../../fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../fields/Types";
 import { AudioField, ImageField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField";
 import { MessageStore } from "../../server/Message";
+import { Upload } from "../../server/SharedMediaTypes";
 import { OmitKeys, Utils } from "../../Utils";
 import { YoutubeBox } from "../apis/youtube/YoutubeBox";
 import { DocServer } from "../DocServer";
+import { Networking } from "../Network";
 import { DocumentManager } from "../util/DocumentManager";
 import { dropActionType } from "../util/DragManager";
 import { DirectoryImportBox } from "../util/Import & Export/DirectoryImportBox";
 import { LinkManager } from "../util/LinkManager";
 import { Scripting } from "../util/Scripting";
-import { UndoManager, undoBatch } from "../util/UndoManager";
-import { DocumentType } from "./DocumentTypes";
-import { SearchBox } from "../views/search/SearchBox";
+import { undoBatch, UndoManager } from "../util/UndoManager";
 import { CollectionDockingView } from "../views/collections/CollectionDockingView";
 import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
 import { ContextMenu } from "../views/ContextMenu";
 import { ContextMenuProps } from "../views/ContextMenuItem";
+import { DFLT_IMAGE_NATIVE_DIM } from "../views/globalCssVariables.scss";
 import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, InkingStroke } from "../views/InkingStroke";
 import { AudioBox } from "../views/nodes/AudioBox";
 import { ColorBox } from "../views/nodes/ColorBox";
@@ -46,11 +47,12 @@ import { SliderBox } from "../views/nodes/SliderBox";
 import { VideoBox } from "../views/nodes/VideoBox";
 import { WebBox } from "../views/nodes/WebBox";
 import { PresElementBox } from "../views/presentationview/PresElementBox";
+import { SearchBox } from "../views/search/SearchBox";
 import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
-import { Networking } from "../Network";
-import { Upload } from "../../server/SharedMediaTypes";
+import { DocumentType } from "./DocumentTypes";
 const path = require('path');
 
+const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", ""));
 export interface DocumentOptions {
     system?: boolean;
     _autoHeight?: boolean;
@@ -146,6 +148,7 @@ export interface DocumentOptions {
     borderRounding?: string;
     boxShadow?: string;
     dontRegisterChildViews?: boolean;
+    dontRegisterView?: boolean;
     lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document.  see PresBox.
     "onDoubleClick-rawScript"?: string; // onDoubleClick script in raw text form
     "onChildDoubleClick-rawScript"?: string; // onChildDoubleClick script in raw text form
@@ -1210,8 +1213,10 @@ export namespace DocUtils {
             proto.text = result.rawText;
             proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, "");
             if (Upload.isImageInformation(result)) {
-                proto["data-nativeWidth"] = (result.nativeWidth > result.nativeHeight) ? 400 * result.nativeWidth / result.nativeHeight : 400;
-                proto["data-nativeHeight"] = (result.nativeWidth > result.nativeHeight) ? 400 : 400 / (result.nativeWidth / result.nativeHeight);
+                const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim);
+                proto["data-nativeOrientation"] = result.exifData?.data?.image?.Orientation;
+                proto["data-nativeWidth"] = (result.nativeWidth < result.nativeHeight) ? maxNativeDim * result.nativeWidth / result.nativeHeight : maxNativeDim;
+                proto["data-nativeHeight"] = (result.nativeWidth < result.nativeHeight) ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight);
                 proto.contentSize = result.contentSize;
             }
             generatedDocuments.push(doc);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 260552879..b9dd18a36 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -864,7 +864,6 @@ export class CurrentUserUtils {
         }
     }
 
-
     static setupClickEditorTemplates(doc: Doc) {
         if (doc["clickFuncs-child"] === undefined) {
             // to use this function, select it from the context menu of a collection.  then edit the onChildClick script.  Add two Doc variables: 'target' and 'thisContainer', then assign 'target' to some target collection.  After that, clicking on any document in the initial collection will open it in the target
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6db5186ba..de87b8aa5 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -475,10 +475,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                     doc[DataSym][fieldKey + "-nativeHeight"] = doc._nativeHeight = nheight = doc._height || 0;
                 }
                 const anno = Cast(doc.annotationOn, Doc, null);
-                if (e.ctrlKey && anno) {
+                if (e.ctrlKey && (anno || doc.type === DocumentType.IMG)) {
                     dW !== 0 && runInAction(() => {
-                        const dataDoc = anno[DataSym];
-                        const annoFieldKey = Doc.LayoutFieldKey(anno);
+                        const dataDoc = (anno ?? doc)[DataSym];
+                        const annoFieldKey = Doc.LayoutFieldKey(anno ?? doc);
                         const nw = NumCast(dataDoc[annoFieldKey + "-nativeWidth"]);
                         const nh = NumCast(dataDoc[annoFieldKey + "-nativeHeight"]);
                         dataDoc[annoFieldKey + "-nativeWidth"] = nw + (dW > 0 ? 10 : -10);
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 07ba7e805..338d9544e 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -9,7 +9,7 @@ import * as React from 'react';
 import * as ReactDOM from 'react-dom';
 import Measure from 'react-measure';
 import * as rp from 'request-promise';
-import { Doc, DocListCast, Field, Opt } from '../../fields/Doc';
+import { Doc, DocListCast, Field, Opt, DocListCastAsync } from '../../fields/Doc';
 import { List } from '../../fields/List';
 import { PrefetchProxy } from '../../fields/Proxy';
 import { listSpec } from '../../fields/Schema';
@@ -18,7 +18,7 @@ import { TraceMobx } from '../../fields/util';
 import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
-import { Docs } from '../documents/Documents';
+import { Docs, DocUtils } from '../documents/Documents';
 import { DocumentType } from '../documents/DocumentTypes';
 import { Networking } from '../Network';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
@@ -63,6 +63,8 @@ import { PDFMenu } from './pdf/PDFMenu';
 import { PreviewCursor } from './PreviewCursor';
 import { PropertiesView } from './PropertiesView';
 import { SearchBox } from './search/SearchBox';
+import { CollectionSubView, CollectionSubViewLoader } from './collections/CollectionSubView';
+import ReactLoading from 'react-loading';
 
 @observer
 export class MainView extends React.Component {
@@ -847,8 +849,6 @@ export class MainView extends React.Component {
     }
 
     importDocument = () => {
-        const sidebar = Cast(Doc.UserDoc().myImportDocs, Doc, null);
-        const sidebarDocView = DocumentManager.Instance.getDocumentView(sidebar);
         const input = document.createElement("input");
         input.type = "file";
         input.multiple = true;
@@ -864,55 +864,21 @@ export class MainView extends React.Component {
                 const json = await response.json();
                 if (json !== "error") {
                     const doc = await DocServer.GetRefField(json);
-                    if (doc instanceof Doc && sidebarDocView) {
-                        sidebarDocView.props.addDocument?.(doc);
+                    if (doc instanceof Doc) {
                         setTimeout(() => {
                             SearchUtil.Search(`{!join from=id to=proto_i}id:link*`, true, {}).then(docs => {
                                 docs.docs.forEach(d => LinkManager.Instance.addLink(d));
                             });
                         }, 2000); // need to give solr some time to update so that this query will find any link docs we've added.
-
                     }
                 }
             } else if (input.files && input.files.length !== 0) {
-                const files = input.files || [];
-                Array.from(files).forEach(async file => {
-                    const res = await Networking.UploadFilesToServer(file);
-                    res.map(async ({ result }) => {
-                        const name = file.name;
-                        if (result instanceof Error) {
-                            return;
-                        }
-                        const path = Utils.prepend(result.accessPaths.agnostic.client);
-                        let doc: Doc;
-                        // Case 1: File is a video
-                        if (file.type.includes("video")) {
-                            doc = Docs.Create.VideoDocument(path, { _height: 100, title: name });
-                            // Case 2: File is a PDF document
-                        } else if (file.type === "application/pdf") {
-                            doc = Docs.Create.PdfDocument(path, { _height: 100, _fitWidth: true, title: name });
-                            // Case 3: File is an image
-                        } else if (file.type.includes("image")) {
-                            doc = Docs.Create.ImageDocument(path, { _height: 100, title: name });
-                            // Case 4: File is an audio document
-                        } else {
-                            doc = Docs.Create.AudioDocument(path, { title: name });
-                        }
-                        const res = await rp.get(Utils.prepend("/getUserDocumentId"));
-                        if (!res) {
-                            throw new Error("No user id returned");
-                        }
-                        const field = await DocServer.GetRefField(res);
-                        let pending: Opt<Doc>;
-                        if (field instanceof Doc) {
-                            pending = sidebar;
-                        }
-                        if (pending) {
-                            const data = await Cast(pending.data, listSpec(Doc));
-                            if (data) data.push(doc);
-                            else pending.data = new List([doc]);
-                        }
-                    });
+                const importDocs = Cast(Doc.UserDoc().myImportDocs, Doc, null);
+                const disposer = OverlayView.Instance.addElement(<ReactLoading type={"spinningBubbles"} color={"green"} height={250} width={250} />, { x: 300, y: 200 });
+
+                DocListCastAsync(importDocs.data).then(async list => {
+                    list?.push(... await DocUtils.uploadFilesToDocs(Array.from(input.files || []), {}));
+                    disposer();
                 });
             } else {
                 console.log("No file selected");
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 5386d617c..04c464b73 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -38,6 +38,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
     _masonryGridRef: HTMLDivElement | null = null;
     _draggerRef = React.createRef<HTMLDivElement>();
     _pivotFieldDisposer?: IReactionDisposer;
+    _autoHeightDisposer?: IReactionDisposer;
     _docXfs: any[] = [];
     _columnStart: number = 0;
     @observable _heightMap = new Map<string, number>();
@@ -148,10 +149,12 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
             () => this.pivotField,
             () => this.layoutDoc._columnHeaders = new List()
         );
+        this._autoHeightDisposer = reaction(() => this.layoutDoc._autoHeight, this.forceAutoHeight);
     }
     componentWillUnmount() {
         super.componentWillUnmount();
         this._pivotFieldDisposer?.();
+        this._autoHeightDisposer?.();
     }
 
     @action
@@ -384,6 +387,11 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
         return this.props.ScreenToLocalTransform().translate(offset[0], offset[1] + offsety);
     }
 
+    forceAutoHeight = () => {
+        const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
+        Doc.Layout(doc)._height = this.refList.reduce((p, r) => p + Number(getComputedStyle(r).height.replace("px", "")), 0);
+    }
+
     sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[], first: boolean) => {
         const key = this.pivotField;
         let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
@@ -450,6 +458,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
             const subItems: ContextMenuProps[] = [];
             subItems.push({ description: `${this.layoutDoc._columnsFill ? "Variable Size" : "Autosize"} Column`, event: () => this.layoutDoc._columnsFill = !this.layoutDoc._columnsFill, icon: "plus" });
             subItems.push({ description: `${this.layoutDoc._autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.layoutDoc._autoHeight = !this.layoutDoc._autoHeight, icon: "plus" });
+            subItems.push({ description: "Clear All", event: () => this.dataDoc.data = new List([]), icon: "times" });
             ContextMenu.Instance.addItem({ description: "Options...", subitems: subItems, icon: "eye" });
         }
     }
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index cb3f486bb..7820e2fa3 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -228,7 +228,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                             Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document);
                         added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse);
                     } else added = res;
-                    e.stopPropagation();
+                    added && e.stopPropagation();
+                    return added;
                 } else {
                     ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
                     added = this.addDocument(docDragData.droppedDocuments);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 5acf825f1..fb3de3b68 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -217,8 +217,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     }
 
     ScreenToLocalTransform = () => {
-        if (this._mainCont && this._mainCont.children) {
-            const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont.children[0].firstChild as HTMLElement);
+        if (this._mainCont?.children) {
+            const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont.children[0]?.firstChild as HTMLElement);
             const scale = Utils.GetScreenTransform(this._mainCont).scale;
             return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(1 / this.contentScaling() / scale);
         }
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 1aa30fc02..f928e3fb8 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -783,7 +783,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
 
     render() {
         return <div className="marqueeView"
-            style={{ overflow: !this.props.ContainingCollectionView ? "visible" : StrCast(this.props.Document._overflow), cursor: MarqueeView.DragMarquee && this ? "crosshair" : "hand" }}
+            style={{ overflow: !this.props.ContainingCollectionView && this.props.annotationsKey ? "visible" : StrCast(this.props.Document._overflow), cursor: MarqueeView.DragMarquee && this ? "crosshair" : "hand" }}
             onDragOver={e => e.preventDefault()}
             onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}>
             {this._visible ? this.marqueeDiv : null}
diff --git a/src/client/views/globalCssVariables.scss b/src/client/views/globalCssVariables.scss
index 7eb07ff55..70a7946ba 100644
--- a/src/client/views/globalCssVariables.scss
+++ b/src/client/views/globalCssVariables.scss
@@ -36,6 +36,7 @@ $remoteCursors-zindex: 997; // ... not sure what level the remote cursors should
 $COLLECTION_BORDER_WIDTH: 1;
 $MINIMIZED_ICON_SIZE:25;
 $MAX_ROW_HEIGHT: 44px;
+$DFLT_IMAGE_NATIVE_DIM: 900px;
 
 :export {
     contextMenuZindex: $contextMenu-zindex;
@@ -45,4 +46,5 @@ $MAX_ROW_HEIGHT: 44px;
     SEARCH_THUMBNAIL_SIZE: $search-thumnail-size;
     ANTIMODEMENU_HEIGHT: $antimodemenu-height;
     SEARCH_PANEL_HEIGHT: $searchpanel-height;
+    DFLT_IMAGE_NATIVE_DIM: $DFLT_IMAGE_NATIVE_DIM;
 }
\ No newline at end of file
diff --git a/src/client/views/globalCssVariables.scss.d.ts b/src/client/views/globalCssVariables.scss.d.ts
index fd1f60f13..531b38d68 100644
--- a/src/client/views/globalCssVariables.scss.d.ts
+++ b/src/client/views/globalCssVariables.scss.d.ts
@@ -7,6 +7,7 @@ interface IGlobalScss {
     SEARCH_THUMBNAIL_SIZE: string;
     ANTIMODEMENU_HEIGHT: string;
     SEARCH_PANEL_HEIGHT: string;
+    DFLT_IMAGE_NATIVE_DIM: string;
 }
 declare const globalCssVariables: IGlobalScss;
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f4eb71145..8c8562267 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -198,7 +198,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this._mainCont.current && (this._multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)));
         // this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)));
 
-        if (!this.props.dontRegisterView) {
+        if (!BoolCast(this.rootDoc.dontRegisterView, this.props.dontRegisterView)) {
             DocumentManager.Instance.DocumentViews.push(this);
         }
     }
@@ -627,7 +627,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @undoBatch @action
     drop = async (e: Event, de: DragManager.DropEvent) => {
         if (this.props.Document === CurrentUserUtils.ActiveDashboard) {
-            alert("linking to document tabs not yet supported.  Drop link on document content.");
+            if ((e.target as any)?.closest?.("*.lm_content")) {
+                alert("You can't perform this move most likely because you don't have permission to modify the destination.");
+            }
+            else alert("linking to document tabs not yet supported.  Drop link on document content.");
             return;
         }
         const makeLink = action((linkDoc: Doc) => {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 6cce5fb87..688bac725 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, observable, runInAction } from 'mobx';
+import { action, computed, observable, runInAction, reaction, IReactionDisposer } from 'mobx';
 import { observer } from "mobx-react";
 import { DataSym, Doc, DocListCast, HeightSym, WidthSym } from '../../../fields/Doc';
 import { documentSchema } from '../../../fields/documentSchemas';
@@ -26,7 +26,6 @@ import { FaceRectangles } from './FaceRectangles';
 import { FieldView, FieldViewProps } from './FieldView';
 import "./ImageBox.scss";
 import React = require("react");
-const requestImageSize = require('../../util/request-image-size');
 const path = require('path');
 const { Howl } = require('howler');
 
@@ -63,6 +62,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(ImageBox, fieldKey); }
     private _imgRef: React.RefObject<HTMLImageElement> = React.createRef();
     private _dropDisposer?: DragManager.DragDropDisposer;
+    private _pathDisposer?: IReactionDisposer;
     @observable private _audioState = 0;
     @observable static _showControls: boolean;
     @observable uploadIcon = uploadIcons.idle;
@@ -72,6 +72,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
         ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document));
     }
 
+    componentDidMount() {
+        this._pathDisposer = reaction(() => this.paths.length && this.resize(this.paths[0]),
+            () => true,
+            { fireImmediately: true });
+    }
+    componentWillUnmount() {
+        this._pathDisposer?.();
+    }
+
     @undoBatch
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
@@ -242,29 +251,29 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
 
     resize = (imgPath: string) => {
         const basePath = imgPath.replace(/_[oms]./, "");
+        const curPath = this.dataDoc[this.fieldKey + "-path"];
         const cachedNativeSize = {
-            width: basePath === this.dataDoc[this.fieldKey + "-path"] ? NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]) : 0,
-            height: basePath === this.dataDoc[this.fieldKey + "-path"] ? NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) : 0,
+            width: basePath === curPath || !curPath ? NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]) : 0,
+            height: basePath === curPath || !curPath ? NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]) : 0,
         };
         const docAspect = this.layoutDoc[HeightSym]() / this.layoutDoc[WidthSym]();
         const cachedAspect = cachedNativeSize.height / cachedNativeSize.width;
         if (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(NumCast(this.layoutDoc._width) / NumCast(this.layoutDoc._height) - cachedNativeSize.width / cachedNativeSize.height) > 0.05) {
             if (!this.layoutDoc.isTemplateDoc || this.dataDoc !== this.layoutDoc) {
-                requestImageSize(imgPath).then(action((inquiredSize: any) => {
-                    const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]) % 180;
-                    const rotatedNativeSize = { width: inquiredSize.width, height: inquiredSize.height };
-                    if (inquiredSize.orientation === 6 || rotation === 90 || rotation === 270) {
-                        rotatedNativeSize.width = inquiredSize.height;
-                        rotatedNativeSize.height = inquiredSize.width;
-                    }
-                    const rotatedAspect = rotatedNativeSize.height / rotatedNativeSize.width;
-                    if (this.layoutDoc[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) {
-                        this.layoutDoc._height = this.layoutDoc[WidthSym]() * rotatedAspect;
-                        this.dataDoc[this.fieldKey + "-nativeWidth"] = this.layoutDoc._nativeWidth = this.layoutDoc._width;
-                        this.dataDoc[this.fieldKey + "-nativeHeight"] = this.layoutDoc._nativeHeight = this.layoutDoc._height;
-                        this.dataDoc[this.fieldKey + "-path"] = basePath;
-                    }
-                })).catch(console.log);
+                const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]) % 180;
+                const orientation = NumCast(this.dataDoc[this.fieldKey + "-nativeOrientation"]);
+                if (orientation === 6 || rotation === 90 || rotation === 270) {
+                    this.layoutDoc._nativeWidth = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]);
+                    this.layoutDoc._nativeHeight = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]);
+                } else {
+                    this.layoutDoc._nativeWidth = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]);
+                    this.layoutDoc._nativeHeight = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]);
+                }
+                const rotatedAspect = NumCast(this.layoutDoc._nativeHeight) / NumCast(this.layoutDoc._nativeWidth);
+                if (this.layoutDoc[WidthSym]() && (!cachedNativeSize.width || !cachedNativeSize.height || Math.abs(1 - docAspect / rotatedAspect) > 0.1)) {
+                    this.layoutDoc._height = this.layoutDoc[WidthSym]() * rotatedAspect;
+                    this.dataDoc[this.fieldKey + "-path"] = basePath;
+                }
             } else if (Math.abs(1 - docAspect / cachedAspect) > 0.1) {
                 this.layoutDoc._width = this.layoutDoc[WidthSym]() || cachedNativeSize.width;
                 this.layoutDoc._height = this.layoutDoc[WidthSym]() * cachedAspect;
@@ -385,8 +394,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
         const { nativeWidth, nativeHeight } = this.nativeSize;
         const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]);
         const aspect = (rotation % 180) ? nativeHeight / nativeWidth : 1;
-        const shift = (rotation % 180) ? (nativeHeight - nativeWidth) * (1 - 1 / aspect) : 0;
-        this.resize(srcpath);
         let transformOrigin = "center center";
         let transform = `translate(0%, 0%) rotate(${rotation}deg) scale(${aspect})`;
         if (rotation === 90 || rotation === -270) {
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index 0ae952304..1ee4c7815 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -5,6 +5,7 @@ import * as rp from 'request-promise';
 import { DocServer } from '../client/DocServer';
 import { Docs } from '../client/documents/Documents';
 import { Networking } from '../client/Network';
+import { DFLT_IMAGE_NATIVE_DIM } from '../client/views/globalCssVariables.scss';
 import { MainViewModal } from '../client/views/MainViewModal';
 import { Doc, Opt } from '../fields/Doc';
 import { List } from '../fields/List';
@@ -20,6 +21,7 @@ export interface ImageUploadProps {
 }
 
 const inputRef = React.createRef<HTMLInputElement>();
+const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", ""));
 
 @observer
 export class Uploader extends React.Component<ImageUploadProps> {
@@ -52,13 +54,13 @@ export class Uploader extends React.Component<ImageUploadProps> {
                             let doc = null;
                             // Case 1: File is a video
                             if (file.type === "video/mp4") {
-                                doc = Docs.Create.VideoDocument(path, { _nativeWidth: 400, _width: 400, title: name });
+                                doc = Docs.Create.VideoDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name });
                                 // Case 2: File is a PDF document
                             } else if (file.type === "application/pdf") {
-                                doc = Docs.Create.PdfDocument(path, { _nativeWidth: 400, _width: 400, _fitWidth: true, title: name });
+                                doc = Docs.Create.PdfDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, _fitWidth: true, title: name });
                                 // Case 3: File is another document type (most likely Image)
                             } else {
-                                doc = Docs.Create.ImageDocument(path, { _nativeWidth: 400, _width: 400, title: name });
+                                doc = Docs.Create.ImageDocument(path, { _nativeWidth: defaultNativeImageDim, _width: 400, title: name });
                             }
                             this.setOpacity(4, "1"); // Slab 4
                             const res = await rp.get(Utils.prepend("/getUserDocumentId"));
diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts
index e088cd2c4..76f5afe16 100644
--- a/src/server/ApiManagers/UploadManager.ts
+++ b/src/server/ApiManagers/UploadManager.ts
@@ -55,7 +55,7 @@ export default class UploadManager extends ApiManager {
                         const results: Upload.FileResponse[] = [];
                         for (const key in files) {
                             const result = await DashUploadUtils.upload(files[key]);
-                            result && results.push(result);
+                            result && !(result.result instanceof Error) && results.push(result);
                         }
                         _success(res, results);
                         resolve();
-- 
cgit v1.2.3-70-g09d2


From fe4a45d0f63683c0f917b6e923e6d48b006e2701 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 31 Aug 2020 23:18:09 -0400
Subject: fixed addDocTab to not re-create the golden layout.  fixed clicking
 tabs to register as an undo event.   fixed color of links made in PDFs to be
 lightBlue.   fixed default link behavior to be 'default'

---
 src/client/views/collections/CollectionDockingView.tsx    |  3 ++-
 src/client/views/collections/TabDocView.tsx               | 15 ++++-----------
 src/client/views/linking/LinkEditor.tsx                   |  4 ++--
 src/client/views/linking/LinkMenuItem.tsx                 |  2 +-
 .../views/nodes/formattedText/FormattedTextBoxComment.tsx |  2 +-
 src/client/views/pdf/Annotation.tsx                       | 14 +++++++-------
 src/client/views/pdf/PDFViewer.tsx                        |  4 ++--
 7 files changed, 19 insertions(+), 25 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 5f05b1193..d39ef5e80 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -197,6 +197,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
                         newContentItem.config.width = 50;
                 }
             }
+            instance._ignoreStateChange = JSON.stringify(instance._goldenLayout.toConfig());
             newContentItem.callDownwards('_$init');
         }
 
@@ -255,7 +256,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
             new _global.ResizeObserver(this.onResize).observe(this._containerRef.current);
             this._reactionDisposer = reaction(() => StrCast(this.props.Document.dockingConfig),
                 config => {
-                    if (!this._goldenLayout || this._ignoreStateChange !== config) {
+                    if (!this._goldenLayout || this._ignoreStateChange !== config) {  //  bcz: TODO! really need to diff config with ignoreStateChange and modify the current goldenLayout instead of building a new one.
                         this.setupGoldenLayout();
                     }
                     this._ignoreStateChange = "";
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index fb3de3b68..31e3fbed6 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -18,7 +18,7 @@ import { DragManager, dropActionType } from "../../util/DragManager";
 import { SelectionManager } from '../../util/SelectionManager';
 import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
-import { undoBatch } from "../../util/UndoManager";
+import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { DocumentView } from "../nodes/DocumentView";
 import { PresBox } from '../nodes/PresBox';
 import { CollectionDockingView } from './CollectionDockingView';
@@ -55,11 +55,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             tab.DashDoc = doc;
 
             CollectionDockingView.Instance.tabMap.add(tab);
-            tab.titleElement[0].onclick = (e: any) => {
-                if (Date.now() - tab.titleElement[0].lastClick < 1000) tab.titleElement[0].select();
-                tab.titleElement[0].lastClick = Date.now();
-                tab.titleElement[0].focus();
-            };
             tab.titleElement[0].onchange = (e: any) => {
                 tab.titleElement[0].size = e.currentTarget.value.length + 1;
                 Doc.GetProto(doc).title = e.currentTarget.value;
@@ -73,9 +68,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             gearSpan.style.paddingLeft = "0px";
             gearSpan.style.paddingRight = "12px";
             const stack = tab.contentItem.parent;
-            tab.element[0].onpointerdown = (e: any) => {
-                e.target.className !== "lm_close_tab" && this.view && SelectionManager.SelectDoc(this.view, false);
-            };
+            tab.element[0].onclick = (e: any) => e.target.className !== "lm_close_tab" && this.view && SelectionManager.SelectDoc(this.view!, false);
             // shifts the focus to this tab when another tab is dragged over it
             tab.element[0].onmouseenter = (e: MouseEvent) => {
                 if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) {
@@ -92,7 +85,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
             tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.props.Document === doc),
                 (selected) => {
-                    selected && tab.contentItem !== tab.header.parent.getActiveContentItem() && tab.header.parent.setActiveContentItem(tab.contentItem);
+                    selected && tab.contentItem !== tab.header.parent.getActiveContentItem() && UndoManager.RunInBatch(() => tab.header.parent.setActiveContentItem(tab.contentItem), "tab switch");
                 }
             );
             tab._disposers.buttonDisposer = reaction(() => this.view,
@@ -245,7 +238,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack);
             case "inPlace":
             case "add":
-            default: return CollectionDockingView.ToggleSplit(doc, locationParams, this.stack);
+            default: return CollectionDockingView.AddSplit(doc, locationParams, this.stack);
         }
     }
 
diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx
index c9c2e657b..d6c3702d1 100644
--- a/src/client/views/linking/LinkEditor.tsx
+++ b/src/client/views/linking/LinkEditor.tsx
@@ -364,7 +364,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
             <div className="linkEditor-followingDropdown-dropdown">
                 <div className="linkEditor-followingDropdown-header"
                     onPointerDown={this.changeDropdown}>
-                    {StrCast(this.props.linkDoc.followLinkLocation, "Default")}
+                    {StrCast(this.props.linkDoc.followLinkLocation, "default")}
                     <FontAwesomeIcon className="linkEditor-followingDropdown-icon"
                         icon={this.openDropdown ? "chevron-up" : "chevron-down"}
                         size={"lg"} />
@@ -372,7 +372,7 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
                 <div className="linkEditor-followingDropdown-optionsList"
                     style={{ display: this.openDropdown ? "" : "none" }}>
                     <div className="linkEditor-followingDropdown-option"
-                        onPointerDown={() => this.changeFollowBehavior("Default")}>
+                        onPointerDown={() => this.changeFollowBehavior("default")}>
                         Default
                         </div>
                     <div className="linkEditor-followingDropdown-option"
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 05b6b584d..17549e3cf 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -157,7 +157,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
             return;
         }
 
-        if (linkDoc.followLinkLocation && linkDoc.followLinkLocation !== "Default") {
+        if (linkDoc.followLinkLocation && linkDoc.followLinkLocation !== "default") {
             const annotationOn = this.props.destinationDoc.annotationOn as Doc;
             this.props.addDocTab(annotationOn instanceof Doc ? annotationOn : this.props.destinationDoc, StrCast(linkDoc.followLinkLocation));
             if (annotationOn) {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index f41f03620..ef0222a4c 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -111,7 +111,7 @@ export class FormattedTextBoxComment {
                                 const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor;
 
                                 if (FormattedTextBoxComment.linkDoc.follow) {
-                                    if (FormattedTextBoxComment.linkDoc.follow === "Default") {
+                                    if (FormattedTextBoxComment.linkDoc.follow === "default") {
                                         DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false);
                                     } else if (FormattedTextBoxComment.linkDoc.follow === "Always open in right tab") {
                                         if (target) { textBox.props.addDocTab(target, "add:right"); }
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index a33068a18..222a6cb0f 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -4,7 +4,7 @@ import { observer } from "mobx-react";
 import { Doc, DocListCast, HeightSym, WidthSym } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
-import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types";
+import { Cast, FieldValue, NumCast, StrCast, PromiseValue } from "../../../fields/Types";
 import { DocumentManager } from "../../util/DocumentManager";
 import { PDFMenu } from "./PDFMenu";
 import "./Annotation.scss";
@@ -86,7 +86,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
     }
 
     @action
-    onPointerDown = async (e: React.PointerEvent) => {
+    onPointerDown = (e: React.PointerEvent) => {
         if (e.button === 2 || e.ctrlKey) {
             PDFMenu.Instance.Status = "annotation";
             PDFMenu.Instance.Delete = this.deleteAnnotation.bind(this);
@@ -97,11 +97,11 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
             e.stopPropagation();
         }
         else if (e.button === 0) {
-            const annoGroup = await Cast(this.props.document.group, Doc);
-            if (annoGroup) {
-                DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation), false, undefined);
-                e.stopPropagation();
-            }
+            e.persist();
+            e.stopPropagation();
+            PromiseValue(this.props.document.group).then(annoGroup => annoGroup instanceof Doc &&
+                DocumentManager.Instance.FollowLink(undefined, annoGroup, (doc, followLinkLocation) => this.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation), false, undefined)
+            );
         }
     }
 
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index d89e66ec5..8edb0e178 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -597,14 +597,14 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         // Doc.GetProto(targetDoc).snipped = this.dataDoc[this.props.fieldKey][Copy]();
         // const snipLayout = Docs.Create.PdfDocument("http://www.msn.com", { title: "snippetView", isTemplateDoc: true, isTemplateForField: "snipped", _fitWidth: true, _width: this.marqueeWidth(), _height: this.marqueeHeight(), _scrollTop: this.marqueeY() });
         // Doc.GetProto(snipLayout).layout = PDFBox.LayoutString("snipped");
-        const annotationDoc = this.highlight("rgba(146, 245, 95, 0.467)"); // yellowish highlight color when dragging out a text selection
+        const annotationDoc = this.highlight("lightBlue");
         if (annotationDoc) {
             DragManager.StartPdfAnnoDrag([ele], new DragManager.PdfAnnoDragData(this.props.Document, annotationDoc, targetDoc), e.pageX, e.pageY, {
                 dragComplete: e => {
                     if (!e.aborted && e.annoDragData && !e.annoDragData.linkedToDoc) {
                         const link = DocUtils.MakeLink({ doc: annotationDoc }, { doc: e.annoDragData.dropDocument }, "Annotation");
                         annotationDoc.isLinkButton = true;
-                        if (link) link.followLinkLocation = "add:right";
+                        if (link) Doc.GetProto(link).followLinkLocation = "default";
                     }
                 }
             });
-- 
cgit v1.2.3-70-g09d2


From a4555fb8d5cd64482dd8431aad03878cb173f688 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 1 Sep 2020 03:58:41 -0400
Subject: fixed following link to a doc that is in a hidden tab to show that
 tab.  fixed linear view to hit content bounds accurately.  fixed editing of
 text in tabs somewhat.  fixed place ment of link anchor boxes for topMost
 views.

---
 src/client/util/DocumentManager.ts                 |  2 ++
 src/client/views/GlobalKeyHandler.ts               |  1 -
 src/client/views/MainView.scss                     |  1 +
 src/client/views/MainView.tsx                      |  4 ++--
 .../views/collections/CollectionLinearView.scss    |  2 ++
 .../views/collections/CollectionLinearView.tsx     | 12 +++---------
 src/client/views/collections/TabDocView.scss       |  4 +++-
 src/client/views/collections/TabDocView.tsx        | 22 +++++++++++++++-------
 src/client/views/linking/LinkMenu.scss             |  2 --
 src/client/views/linking/LinkMenu.tsx              |  4 ++--
 src/client/views/nodes/DocumentLinksButton.tsx     |  7 +++++--
 src/client/views/nodes/DocumentView.tsx            |  5 +++--
 src/client/views/search/SearchBox.tsx              |  6 +++---
 13 files changed, 41 insertions(+), 31 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index f085f615c..9e55c5a44 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -160,6 +160,8 @@ export class DocumentManager {
                 docView.props.Document.hidden = !docView.props.Document.hidden;
             }
             else {
+                const contView = docContext && getFirstDocView(docContext, originatingDoc);
+                contView && contView.topMost && contView.select(false);
                 docView.select(false);
                 docView.props.Document.hidden && (docView.props.Document.hidden = undefined);
                 docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish);
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 076be3ad6..a52eb649d 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -196,7 +196,6 @@ export class KeyManager {
                 break;
             case "f":
                 SearchBox.Instance._searchFullDB = "My Stuff";
-                SearchBox.Instance.newsearchstring = "";
                 SearchBox.Instance.enter(undefined);
                 break;
             case "o":
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index 93cc47215..9ca8f348d 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -31,6 +31,7 @@
     bottom: 10px;
     left: calc(100% + 5px);
     z-index: 1;
+    pointer-events: none;
 }
 
 .mainView-snapLines {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 4eccbaeb1..01df10aa0 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -370,6 +370,7 @@ export class MainView extends React.Component {
     @action
     selectMenu = (button: Doc) => {
         const title = StrCast(Doc.GetProto(button).title);
+        const closed = !this._flyoutWidth;
         this.closeFlyout();
         if (this._panelContent !== title || !this._flyoutWidth) {
             switch (this._panelContent = title) {
@@ -378,12 +379,11 @@ export class MainView extends React.Component {
                     break;
                 case "Catalog":
                     SearchBox.Instance._searchFullDB = "My Stuff";
-                    SearchBox.Instance.newsearchstring = "";
                     SearchBox.Instance.enter(undefined);
                     break;
                 default:
                     this._sidebarContent.proto = button.target as any;
-                    this.expandFlyout();
+                    closed && this.expandFlyout();
                     button._backgroundColor = "lightgrey";
                     button.color = "black";
                     this._lastButton = button;
diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss
index f5c4299a9..ca72b98a5 100644
--- a/src/client/views/collections/CollectionLinearView.scss
+++ b/src/client/views/collections/CollectionLinearView.scss
@@ -4,10 +4,12 @@
 .collectionLinearView-outer {
     overflow: visible;
     height: 100%;
+    pointer-events: none;
 
     .collectionLinearView {
         display: flex;
         height: 100%;
+        align-items: center;
 
         >span {
             background: $dark-color;
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 866d7245a..9eaa02bf8 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -17,6 +17,7 @@ import { DocumentLinksButton } from '../nodes/DocumentLinksButton';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { LinkDescriptionPopup } from '../nodes/LinkDescriptionPopup';
 import { Tooltip } from '@material-ui/core';
+import { all } from 'bluebird';
 
 
 type LinearDocument = makeInterface<[typeof documentSchema,]>;
@@ -113,12 +114,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
         const backgroundColor = StrCast(this.props.Document.backgroundColor, "black");
         const color = StrCast(this.props.Document.color, "white");
 
-        const menuOpener = <label htmlFor={`${guid}`} style={{
-            background: backgroundColor === color ? "black" : backgroundColor,
-            // width: "18px", height: "18px", fontSize: "12.5px",
-            // transition: this.props.Document.linearViewIsExpanded ? "transform 0.2s" : "transform 0.5s",
-            // transform: this.props.Document.linearViewIsExpanded ? "" : "rotate(45deg)"
-        }}
+        const menuOpener = <label htmlFor={`${guid}`} style={{ pointerEvents: "all", cursor: "default", background: backgroundColor === color ? "black" : backgroundColor, }}
             onPointerDown={e => e.stopPropagation()} >
             <p>{BoolCast(this.props.Document.linearViewIsExpanded) ? "–" : "+"}</p>
         </label>;
@@ -140,6 +136,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                         const scalable = pair.layout.onClick || pair.layout.onDragStart;
                         return <div className={`collectionLinearView-docBtn` + (scalable ? "-scalable" : "")} key={pair.layout[Id]} ref={dref}
                             style={{
+                                pointerEvents: "all",
                                 width: scalable ? (nested ? pair.layout[WidthSym]() : this.dimension() - deltaSize) : undefined,
                                 height: nested && pair.layout.linearViewIsExpanded ? pair.layout[HeightSym]() : this.dimension() - deltaSize,
                             }}  >
@@ -194,9 +191,6 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                         </span>
                     </Tooltip>
 
-                    {/* <FontAwesomeIcon icon="times-circle" size="lg" style={{ color: "red" }}
-                        onClick={this.exitLongLinks} /> */}
-
                 </span> : null}
             </div>
         </div>;
diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss
index 9a4b5cbd1..fdb801e03 100644
--- a/src/client/views/collections/TabDocView.scss
+++ b/src/client/views/collections/TabDocView.scss
@@ -1,4 +1,6 @@
-
+input.lm_title:focus {
+    max-width: max-content !important;
+}
 .miniMap {
     position: absolute;
     overflow: hidden;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 31e3fbed6..3cb57f086 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -54,21 +54,29 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             tab.contentItem.config.fixed && (tab.contentItem.parent.config.fixed = true);
             tab.DashDoc = doc;
 
+            const titleEle = tab.titleElement[0];
             CollectionDockingView.Instance.tabMap.add(tab);
-            tab.titleElement[0].onchange = (e: any) => {
-                tab.titleElement[0].size = e.currentTarget.value.length + 1;
+            titleEle.onchange = (e: any) => {
+                titleEle.size = e.currentTarget.value.length + 3;
                 Doc.GetProto(doc).title = e.currentTarget.value;
             };
-            tab.titleElement[0].size = StrCast(doc.title).length + 1;
-            tab.titleElement[0].value = doc.title;
-            tab.titleElement[0].style["max-width"] = "100px";
+            titleEle.size = StrCast(doc.title).length + 3;
+            titleEle.value = doc.title;
+            titleEle.style["max-width"] = "100px";
             const gearSpan = document.createElement("span");
             gearSpan.className = "collectionDockingView-gear";
             gearSpan.style.position = "relative";
             gearSpan.style.paddingLeft = "0px";
             gearSpan.style.paddingRight = "12px";
             const stack = tab.contentItem.parent;
-            tab.element[0].onclick = (e: any) => e.target.className !== "lm_close_tab" && this.view && SelectionManager.SelectDoc(this.view!, false);
+            tab.element[0].onclick = (e: any) => {
+                if (e.target.className !== "lm_close_tab" && this.view) {
+                    SelectionManager.SelectDoc(this.view, false);
+                    if (Date.now() - titleEle.lastClick < 1000) titleEle.select();
+                    titleEle.lastClick = Date.now();
+                    (document.activeElement !== titleEle) && titleEle.focus();
+                }
+            };
             // shifts the focus to this tab when another tab is dragged over it
             tab.element[0].onmouseenter = (e: MouseEvent) => {
                 if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) {
@@ -83,7 +91,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 }, returnFalse, emptyFunction);
             };
 
-            tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.props.Document === doc),
+            tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.topMost && v.props.Document === doc),
                 (selected) => {
                     selected && tab.contentItem !== tab.header.parent.getActiveContentItem() && UndoManager.RunInBatch(() => tab.header.parent.setActiveContentItem(tab.contentItem), "tab switch");
                 }
diff --git a/src/client/views/linking/LinkMenu.scss b/src/client/views/linking/LinkMenu.scss
index 4dc25031d..0e03b46db 100644
--- a/src/client/views/linking/LinkMenu.scss
+++ b/src/client/views/linking/LinkMenu.scss
@@ -4,8 +4,6 @@
     width: auto;
     height: auto;
     position: absolute;
-    top: 0;
-    left: 0;
     z-index: 999;
 
     .linkMenu-list {
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index 31d08edae..f5a1ae8e7 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -91,9 +91,9 @@ export class LinkMenu extends React.Component<Props> {
     render() {
         const sourceDoc = this.props.docView.props.Document;
         const groups: Map<string, Doc[]> = LinkManager.Instance.getRelatedGroupedLinks(sourceDoc);
-        return <div className="linkMenu" ref={this._linkMenuRef} >
+        return <div className="linkMenu" style={{ left: this.position.x, top: this.props.docView.topMost ? undefined : this.position.b + 15, bottom: this.props.docView.topMost ? 20 : undefined }} ref={this._linkMenuRef} >
             {!this._editingLink ?
-                <div className="linkMenu-list" style={{ left: this.position.x, top: this.position.b + 15 }}>
+                <div className="linkMenu-list" >
                     {this.renderAllGroups(groups)}
                 </div> :
                 <div className="linkMenu-listEditor" style={{ left: this.position.x, top: this.position.b + 15 }}>
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index 318f7b7e9..1d346894c 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -25,7 +25,7 @@ export const Flyout = higflyout.default;
 
 interface DocumentLinksButtonProps {
     View: DocumentView;
-    Offset?: number[];
+    Offset?: (number | undefined)[];
     AlwaysOn?: boolean;
     InMenu?: boolean;
     StartLink?: boolean;
@@ -242,7 +242,10 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             id={"link-icon"}
             src={`/assets/${"link.png"}`} />;
 
-        const linkButton = <div ref={this._linkButton} style={{ minWidth: 20, minHeight: 20, position: "absolute", left: this.props.Offset?.[0] }}>
+        const linkButton = <div className="documentLinksButton-cont" ref={this._linkButton} style={{
+            minWidth: 20, minHeight: 20, position: "absolute",
+            left: this.props.Offset?.[0], top: this.props.Offset?.[1], right: this.props.Offset?.[2], bottom: this.props.Offset?.[3]
+        }}>
             <div className={"documentLinksButton"} style={{
                 backgroundColor: this.props.InMenu ? "" : "#add8e6",
                 color: this.props.InMenu ? "white" : "black",
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3651f0d5f..2f2a324c8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -359,7 +359,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 if ((this.layoutDoc.onDragStart || this.props.Document.rootDocument) && !(e.ctrlKey || e.button > 0)) {  // onDragStart implies a button doc that we don't want to select when clicking.   RootDocument & isTemplaetForField implies we're clicking on part of a template instance and we want to select the whole template, not the part
                     stopPropagate = false; // don't stop propagation for field templates -- want the selection to propagate up to the root document of the template
                 } else {
-                    SelectionManager.SelectDoc(this, e.ctrlKey || e.shiftKey);
+                    this.select(e.ctrlKey || e.shiftKey);
+                    //SelectionManager.SelectDoc(this, e.ctrlKey || e.shiftKey);
                 }
                 preventDefault = false;
             }
@@ -855,7 +856,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return this.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false;
     }
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
-    @computed.struct get linkOffset() { return [-15, 0]; }
+    @computed.struct get linkOffset() { return this.topMost ? [0, undefined, undefined, 10] : [-15, undefined, undefined, undefined]; }
     @computed get contents() {
         const pos = this.props.relative ? "relative " : "absolute";
         TraceMobx();
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index d08cc7f5b..c04b1da10 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -102,7 +102,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             this._curRequest = undefined;
             this._maxSearchIndex = 0;
         }
-    })
+    });
 
     enter = action((e: React.KeyboardEvent | undefined) => {
         if (!e || e.key === "Enter") {
@@ -378,7 +378,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             Doc.ClearSearchMatches();
         });
         close && (this.open = this._searchbarOpen = false);
-    })
+    });
 
     @action.bound
     closeResults() {
@@ -483,7 +483,7 @@ export class SearchBox extends ViewBoxBaseComponent<FieldViewProps, SearchBoxDoc
             collectionView.props.Document._searchFilterDocs = docsForFilter?.length ? new List<Doc>(docsForFilter) : undefined;
             collectionView.props.Document._docFilters = docsForFilter?.length && docFilters?.length ? new List<string>(docFilters) : undefined;
         }
-    })
+    });
 
     render() {
         const myDashboards = DocListCast(CurrentUserUtils.MyDashboards.data);
-- 
cgit v1.2.3-70-g09d2


From a55c1ef0211cef68bebdb83b7ee8723c7bcf6edc Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 1 Sep 2020 12:25:34 -0400
Subject: fixed tabs to never select/switch on hover unless dragging. fixed
 display of highlight icons in menu bar.  fixed placement of docDecorations
 level selector.

---
 src/client/util/DocumentManager.ts                 |  2 +-
 src/client/views/DocumentDecorations.scss          |  2 +-
 src/client/views/InkingStroke.tsx                  |  2 +-
 src/client/views/MainView.tsx                      | 18 ++---
 .../views/collections/CollectionDockingView.scss   |  2 +-
 src/client/views/collections/CollectionMenu.scss   |  4 ++
 src/client/views/collections/TabDocView.tsx        | 83 +++++++++++-----------
 src/client/views/nodes/DocumentContentsView.tsx    |  3 +-
 src/client/views/nodes/FontIconBox.scss            | 17 ++++-
 src/client/views/nodes/FontIconBox.tsx             |  7 +-
 src/client/views/nodes/MenuIconBox.scss            | 49 -------------
 src/client/views/nodes/MenuIconBox.tsx             | 33 ---------
 12 files changed, 79 insertions(+), 143 deletions(-)
 delete mode 100644 src/client/views/nodes/MenuIconBox.scss
 delete mode 100644 src/client/views/nodes/MenuIconBox.tsx

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 9e55c5a44..2c7dcf49b 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -161,7 +161,7 @@ export class DocumentManager {
             }
             else {
                 const contView = docContext && getFirstDocView(docContext, originatingDoc);
-                contView && contView.topMost && contView.select(false);
+                contView && contView.topMost && contView.select(false);  // bcz: change this to a function prop: popTab() that will make sure the tab for the document is topmost;
                 docView.select(false);
                 docView.props.Document.hidden && (docView.props.Document.hidden = undefined);
                 docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish);
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 8291d7212..e02408559 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -21,7 +21,7 @@ $linkGap : 3px;
         background: none;
     }
 
-    .documentDecorations-selector {
+    .documentDecorations-levelSelector {
         pointer-events: auto;
         height: 15px;
         width: 15px;
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 1a1a3d75c..da98eca73 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -119,7 +119,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         const hpoints = InteractionUtils.CreatePolyline(data, left, top,
             this.props.isSelected() && strokeWidth > 5 ? strokeColor : "transparent", strokeWidth, (strokeWidth + 15),
             StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
-            "none", "none", undefined, scaleX, scaleY, "", this.props.active() ? "visiblepainted" : "none", false, true);
+            "none", "none", undefined, scaleX, scaleY, "", "visiblepainted", false, true);
 
         //points for adding
         const apoints = InteractionUtils.CreatePoints(data, left, top, strokeColor, strokeWidth, strokeWidth,
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 01df10aa0..7dddd1669 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -285,7 +285,7 @@ export class MainView extends React.Component {
         setupMoveUpEvents(this, e,
             action(e => (this._flyoutWidth = Math.max(e.clientX - 58, 0)) ? false : false),
             () => this._flyoutWidth < 5 && this.closeFlyout(),
-            this.toggleFlyout);
+            this.closeFlyout);
     }
 
     flyoutWidthFunc = () => this._flyoutWidth;
@@ -382,11 +382,7 @@ export class MainView extends React.Component {
                     SearchBox.Instance.enter(undefined);
                     break;
                 default:
-                    this._sidebarContent.proto = button.target as any;
-                    closed && this.expandFlyout();
-                    button._backgroundColor = "lightgrey";
-                    button.color = "black";
-                    this._lastButton = button;
+                    closed && this.expandFlyout(button);
             }
         }
         return true;
@@ -424,8 +420,14 @@ export class MainView extends React.Component {
             </div>;
     }
 
-    expandFlyout = action(() => this._flyoutWidth = (this._flyoutWidth || 250));
-    toggleFlyout = action(() => this._flyoutWidth < 15 ? this.expandFlyout() : this.closeFlyout());
+    expandFlyout = action((button: Doc) => {
+        this._flyoutWidth = (this._flyoutWidth || 250);
+        this._sidebarContent.proto = button.target as any;
+        button._backgroundColor = "lightgrey";
+        button.color = "black";
+        this._lastButton = button;
+    });
+
     closeFlyout = action(() => {
         this._lastButton && (this._lastButton.color = "white");
         this._lastButton && (this._lastButton._backgroundColor = "");
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index d3be1636d..96f5afcd9 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -70,7 +70,7 @@
         margin: auto;
     }
 
-    .collectionDockingView-dragAsDocument {
+    .collectionDockingView-drag {
         touch-action: none;
         position: absolute;
         padding-left: 5px;
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index 21312e5f3..e36e5caa7 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -377,6 +377,7 @@
     .antimodeMenu-button {
         text-align: center;
         display: block;
+        position: relative;
     }
 
     .color-previewI {
@@ -384,12 +385,15 @@
         height: 20%;
         bottom: 0;
         position: absolute;
+        margin-left: 2px;
     }
 
     .color-previewII {
         width: 80%;
         height: 80%;
         margin-left: 10%;
+        position: absolute;
+        bottom: 5;
     }
 
     .btn-group {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 3cb57f086..3c230537c 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -53,67 +53,70 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             tab._disposers = {} as { [name: string]: IReactionDisposer };
             tab.contentItem.config.fixed && (tab.contentItem.parent.config.fixed = true);
             tab.DashDoc = doc;
+            CollectionDockingView.Instance.tabMap.add(tab);
 
+            // setup the title element and set its size according to the # of chars in the title.  Show the full title when clicked.
             const titleEle = tab.titleElement[0];
-            CollectionDockingView.Instance.tabMap.add(tab);
-            titleEle.onchange = (e: any) => {
-                titleEle.size = e.currentTarget.value.length + 3;
-                Doc.GetProto(doc).title = e.currentTarget.value;
-            };
             titleEle.size = StrCast(doc.title).length + 3;
             titleEle.value = doc.title;
             titleEle.style["max-width"] = "100px";
-            const gearSpan = document.createElement("span");
-            gearSpan.className = "collectionDockingView-gear";
-            gearSpan.style.position = "relative";
-            gearSpan.style.paddingLeft = "0px";
-            gearSpan.style.paddingRight = "12px";
-            const stack = tab.contentItem.parent;
-            tab.element[0].onclick = (e: any) => {
-                if (e.target.className !== "lm_close_tab" && this.view) {
-                    SelectionManager.SelectDoc(this.view, false);
-                    if (Date.now() - titleEle.lastClick < 1000) titleEle.select();
-                    titleEle.lastClick = Date.now();
-                    (document.activeElement !== titleEle) && titleEle.focus();
-                }
+            titleEle.onchange = (e: any) => {
+                titleEle.size = e.currentTarget.value.length + 3;
+                Doc.GetProto(doc).title = e.currentTarget.value;
             };
             // shifts the focus to this tab when another tab is dragged over it
             tab.element[0].onmouseenter = (e: MouseEvent) => {
                 if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) {
                     tab.header.parent.setActiveContentItem(tab.contentItem);
+                    console.log("Seetting " + titleEle.value);
+                    tab.setActive(true);
                 }
-                tab.setActive(true);
             };
-            const onDown = (e: React.PointerEvent) => {
+            const onPointerDown = (e: React.PointerEvent) => {
                 setupMoveUpEvents(this, e, (e) => {
-                    !e.defaultPrevented && DragManager.StartDocumentDrag([gearSpan], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY);
+                    !e.defaultPrevented && DragManager.StartDocumentDrag([dragHdl], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY);
                     return !e.defaultPrevented;
                 }, returnFalse, emptyFunction);
             };
 
-            tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.topMost && v.props.Document === doc),
-                (selected) => {
-                    selected && tab.contentItem !== tab.header.parent.getActiveContentItem() && UndoManager.RunInBatch(() => tab.header.parent.setActiveContentItem(tab.contentItem), "tab switch");
+            // select the tab document when the tab is directly clicked and activate the tab whenver the tab document is selected
+            tab.element[0].onclick = (e: any) => {
+                if (e.target.className !== "lm_close_tab" && this.view) {
+                    SelectionManager.SelectDoc(this.view, false);
+                    if (Date.now() - titleEle.lastClick < 1000) titleEle.select();
+                    titleEle.lastClick = Date.now();
+                    (document.activeElement !== titleEle) && titleEle.focus();
                 }
-            );
-            tab._disposers.buttonDisposer = reaction(() => this.view,
-                (view) => {
-                    if (view) {
-                        ReactDOM.render(<span title="Drag as document" className="collectionDockingView-dragAsDocument" onPointerDown={onDown} >
-                            <CollectionDockingViewMenu views={() => [view]} Stack={stack} />
-                        </span>,
-                            gearSpan);
-                        tab._disposers.buttonDisposer?.();
-                    }
-                }, { fireImmediately: true });
+            };
+            tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.topMost && v.props.Document === doc),
+                (selected) => selected && tab.contentItem !== tab.header.parent.getActiveContentItem() &&
+                    UndoManager.RunInBatch(() => tab.header.parent.setActiveContentItem(tab.contentItem), "tab switch"));
 
-            tab.reactComponents = [gearSpan];
-            tab.element.append(gearSpan);
+            //attach the selection doc buttons menu to the drag handle
+            const stack = tab.contentItem.parent;
+            const dragHdl = document.createElement("span");
+            dragHdl.className = "collectionDockingView-gear";
+            dragHdl.style.position = "relative";
+            dragHdl.style.paddingLeft = "0px";
+            dragHdl.style.paddingRight = "12px";
+            tab._disposers.buttonDisposer = reaction(() => this.view, (view) => view &&
+                [ReactDOM.render(
+                    <span title="Drag as document" className="collectionDockingView-drag" onPointerDown={onPointerDown} >
+                        <CollectionDockingViewMenu views={() => [view]} Stack={stack} />
+                    </span>, dragHdl),
+                tab._disposers.buttonDisposer?.()],
+                { fireImmediately: true });
+            tab.reactComponents = [dragHdl];
+            tab.element.append(dragHdl);
+
+            // highlight the tab when the tab document is brushed in any part of the UI
             tab._disposers.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => {
-                tab.titleElement[0].value = title;
-                tab.titleElement[0].style.padding = degree ? 0 : 2;
-                tab.titleElement[0].style.border = `${["gray", "gray", "gray"][degree]} ${["none", "dashed", "solid"][degree]} 2px`;
+                titleEle.value = title;
+                titleEle.style.padding = degree ? 0 : 2;
+                titleEle.style.border = `${["gray", "gray", "gray"][degree]} ${["none", "dashed", "solid"][degree]} 2px`;
             }, { fireImmediately: true });
+
+            // clean up the tab when it is closed
             tab.closeElement.off('click') //unbind the current click handler
                 .click(function () {
                     Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index dc9b7c98f..5d5a1f7f3 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -18,7 +18,6 @@ import { DocHolderBox } from "./DocHolderBox";
 import { DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
 import { FontIconBox } from "./FontIconBox";
-import { MenuIconBox } from "./MenuIconBox";
 import { FieldView, FieldViewProps } from "./FieldView";
 import { FormattedTextBox, FormattedTextBoxProps } from "./formattedText/FormattedTextBox";
 import { ImageBox } from "./ImageBox";
@@ -190,7 +189,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & Fo
                 blacklistedAttrs={[]}
                 renderInWrapper={false}
                 components={{
-                    FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, MenuIconBox, LabelBox, SliderBox, FieldView,
+                    FormattedTextBox, ImageBox, DirectoryImportBox, FontIconBox, LabelBox, SliderBox, FieldView,
                     CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
                     PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, SearchBox,
                     ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
diff --git a/src/client/views/nodes/FontIconBox.scss b/src/client/views/nodes/FontIconBox.scss
index 75bc90d7a..d7c5e9c92 100644
--- a/src/client/views/nodes/FontIconBox.scss
+++ b/src/client/views/nodes/FontIconBox.scss
@@ -37,9 +37,10 @@
 .menuButton-round {
     border-radius: 100%;
     background-color: black;
+    padding: 0;
 
     .fontIconBox-label {
-        margin-left: -10px; // button padding is 10px;
+        //margin-left: -10px; // button padding is 10px;
         bottom: 0;
         position: absolute;
     }
@@ -52,7 +53,6 @@
 .menuButton-square {
     padding-top: 3px;
     padding-bottom: 3px;
-    padding-left: 5px;
 
     .fontIconBox-label {
         border-radius: 0px;
@@ -64,7 +64,8 @@
 .menuButton,
 .menuButton-round,
 .menuButton-square {
-    width: 100%;
+    margin-left: -5%;
+    width: 110%;
     height: 100%;
     pointer-events: all;
     touch-action: none;
@@ -72,6 +73,7 @@
     .menuButton-wrap {
         touch-action: none;
         border-radius: 8px;
+        width: 100%;
 
         // &:hover {
         //     background: rgb(61, 61, 61);
@@ -89,4 +91,13 @@
         width: 95% !important;
         height: 95%;
     }
+}
+.menuButton-round {
+    width: 100%;
+    svg {
+        width: 50% !important;
+        height: 50%;
+        position: relative;
+        bottom: 2px;
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index 87142babd..c55b9d9f2 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -65,10 +65,9 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
         const backgroundColor = StrCast(this.layoutDoc._backgroundColor, StrCast(this.rootDoc.backgroundColor, this.props.backgroundColor?.(this.rootDoc, this.props.renderDepth)));
         const shape = StrCast(this.layoutDoc.iconShape, "round");
         const icon = StrCast(this.dataDoc.icon, "user") as any;
-        const presTrailsIcon = <img
-            style={{ width: shape === 'round' ? 25 : 30, height: shape === 'round' ? 25 : 30, filter: color === 'white' ? 'invert(100%)' : 'invert(0%)', transform: shape === 'round' ? 'translate(-5px, -7px)' : undefined }}
-            id={"pres-icon"}
-            src={`/assets/${"presTrails.png"}`} />;
+        const presSize = shape === 'round' ? 25 : 30;
+        const presTrailsIcon = <img src={`/assets/${"presTrails.png"}`}
+            style={{ width: presSize, height: presSize, filter: `invert(${color === "white" ? "100%" : "0%"})`, marginBottom: "5px" }} />;
         const button = <button className={`menuButton-${shape}`} ref={this._ref} onContextMenu={this.specificContextMenu}
             style={{
                 boxShadow: this.layoutDoc.ischecked ? `4px 4px 12px black` : undefined,
diff --git a/src/client/views/nodes/MenuIconBox.scss b/src/client/views/nodes/MenuIconBox.scss
deleted file mode 100644
index 1b72f5a8f..000000000
--- a/src/client/views/nodes/MenuIconBox.scss
+++ /dev/null
@@ -1,49 +0,0 @@
-.menuButton {
-    //padding: 7px;
-    padding-left: 7px;
-    width: 100%;
-    width: 60px;
-    height: 70px;
-
-    .menuButton-wrap {
-        width: 45px;
-        /* padding: 5px; */
-        touch-action: none;
-        background: black;
-        transform-origin: top left;
-        /* margin-bottom: 5px; */
-        margin-top: 5px;
-        margin-right: 25px;
-        border-radius: 8px;
-
-        &:hover {
-            background: rgb(61, 61, 61);
-            cursor: pointer;
-        }
-    }
-
-    .menuButton-label {
-        color: white;
-        margin-right: 4px;
-        border-radius: 8px;
-        width: 42px;
-        position: relative;
-        text-align: center;
-        font-size: 8px;
-        margin-top: 1px;
-        letter-spacing: normal;
-        padding: 3px;
-        background-color: inherit;
-    }
-
-    .menuButton-icon {
-        width: auto;
-        height: 35px;
-        padding: 5px;
-    }
-
-    svg {
-        width: 95% !important;
-        height: 95%;
-    }
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/MenuIconBox.tsx b/src/client/views/nodes/MenuIconBox.tsx
deleted file mode 100644
index 5ed8a9b78..000000000
--- a/src/client/views/nodes/MenuIconBox.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { observer } from 'mobx-react';
-import * as React from 'react';
-import { createSchema, makeInterface } from '../../../fields/Schema';
-import { StrCast } from '../../../fields/Types';
-import { DocComponent } from '../DocComponent';
-import { FieldView, FieldViewProps } from './FieldView';
-import './MenuIconBox.scss';
-const MenuIconSchema = createSchema({
-    icon: "string"
-});
-
-type MenuIconDocument = makeInterface<[typeof MenuIconSchema]>;
-const MenuIconDocument = makeInterface(MenuIconSchema);
-@observer
-export class MenuIconBox extends DocComponent<FieldViewProps, MenuIconDocument>(MenuIconDocument) {
-    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(MenuIconBox, fieldKey); }
-    _ref: React.RefObject<HTMLButtonElement> = React.createRef();
-
-    render() {
-
-        const color = this.props.backgroundColor?.(this.props.Document, this.props.renderDepth) === "lightgrey" ? "black" : "white";
-        const menuBTN = <div className="menuButton" style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document, this.props.renderDepth) }}>
-            <div className="menuButton-wrap"
-                style={{ backgroundColor: this.props.backgroundColor?.(this.props.Document, this.props.renderDepth) }} >
-                <FontAwesomeIcon className="menuButton-icon" icon={StrCast(this.dataDoc.icon, "user") as any} color={color} size="lg" />
-                <div className="menuButton-label" style={{ color: color }}> {this.dataDoc.title} </div>
-            </div>
-        </div>;
-
-        return menuBTN;
-    }
-}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 7769eab7d388201d2cc2253b5d9911ce7e4cca6f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 2 Sep 2020 19:29:43 +0000
Subject: can't render a dashboard in a tab

---
 src/client/views/collections/TabDocView.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 3c230537c..fb4f5c366 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -191,7 +191,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         if (this.props.glContainer.tab && this._isActive !== this.props.glContainer.tab.isActive) {
             this._isActive = this.props.glContainer.tab.isActive;
             this._isActive && setTimeout(() => this.view && SelectionManager.SelectDoc(this.view, false), 0);
-            (CollectionDockingView.Instance as any)._goldenLayout.isInitialised && CollectionDockingView.Instance.stateChanged();
+            (CollectionDockingView.Instance as any)._goldenLayout?.isInitialised && CollectionDockingView.Instance.stateChanged();
             !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one.
         }
     }
@@ -334,7 +334,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     setView = action((view: DocumentView) => this._view = view);
     @computed get docView() {
         TraceMobx();
-        return !this._document ? (null) :
+        return !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
             <><DocumentView key={this._document[Id]}
                 LibraryPath={emptyPath}
                 Document={this._document}
-- 
cgit v1.2.3-70-g09d2


From 483a4d35ba2c522b889c7bd9b839a0af131ec0bb Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 8 Sep 2020 19:26:24 -0400
Subject: updated the way NativeWidth/Height props work so that, when
 specified, they override locally specified values

---
 src/Utils.ts                                       |  2 ++
 src/client/views/DocumentDecorations.tsx           |  6 +++---
 src/client/views/GestureOverlay.tsx                |  2 --
 src/client/views/MainView.tsx                      | 10 ---------
 src/client/views/OverlayView.tsx                   |  2 --
 src/client/views/Palette.tsx                       |  2 --
 src/client/views/PropertiesView.tsx                |  4 ++--
 src/client/views/TemplateMenu.tsx                  |  2 --
 .../views/collections/CollectionCarouselView.tsx   |  4 ++--
 .../views/collections/CollectionLinearView.tsx     |  2 --
 .../views/collections/CollectionSchemaView.tsx     |  2 --
 .../views/collections/CollectionStackingView.tsx   |  8 +++----
 src/client/views/collections/CollectionSubView.tsx |  4 ++--
 .../views/collections/CollectionTreeView.tsx       |  6 ++----
 src/client/views/collections/SchemaTable.tsx       |  2 --
 src/client/views/collections/TabDocView.tsx        |  2 --
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 14 ++++++------
 .../collectionGrid/CollectionGridView.tsx          |  2 --
 .../CollectionMulticolumnView.tsx                  |  8 ++++---
 .../CollectionMultirowView.tsx                     |  2 --
 src/client/views/nodes/AudioBox.tsx                |  4 ----
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  6 +++---
 .../views/nodes/ContentFittingDocumentView.tsx     | 10 ++++-----
 src/client/views/nodes/DocHolderBox.tsx            |  4 ----
 src/client/views/nodes/DocumentView.tsx            | 10 ++++-----
 src/client/views/nodes/FieldView.tsx               |  4 ++--
 src/client/views/nodes/FilterBox.tsx               |  2 --
 src/client/views/nodes/ImageBox.tsx                | 25 ++++++----------------
 src/client/views/nodes/KeyValuePair.tsx            |  2 --
 src/client/views/nodes/LinkBox.tsx                 |  2 --
 src/client/views/nodes/LinkDocPreview.tsx          |  2 --
 src/client/views/nodes/ScreenshotBox.tsx           |  2 --
 src/client/views/nodes/VideoBox.tsx                |  2 --
 src/client/views/nodes/WebBox.tsx                  |  4 +---
 .../views/nodes/formattedText/DashDocView.tsx      |  2 --
 .../views/nodes/formattedText/FormattedTextBox.tsx |  4 +---
 .../formattedText/FormattedTextBoxComment.tsx      |  4 ++--
 .../views/nodes/formattedText/RichTextSchema.tsx   |  2 --
 src/client/views/pdf/PDFViewer.tsx                 |  2 --
 .../views/presentationview/PresElementBox.tsx      |  2 --
 src/mobile/AudioUpload.tsx                         |  2 --
 src/mobile/MobileInterface.tsx                     |  2 --
 42 files changed, 52 insertions(+), 133 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 6582e43ef..7dff1ac55 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -414,6 +414,8 @@ export function returnTrue() { return true; }
 
 export function returnFalse() { return false; }
 
+export function returnVal(val1?: number, val2?: number) { return val1 !== undefined ? val1 : val2 !== undefined ? val2 : 0; }
+
 export function returnOne() { return 1; }
 
 export function returnZero() { return 0; }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 81c1676b0..e5c6f0aa9 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -10,7 +10,7 @@ import { InkField } from "../../fields/InkField";
 import { ScriptField } from '../../fields/ScriptField';
 import { Cast, NumCast } from "../../fields/Types";
 import { GetEffectiveAcl } from '../../fields/util';
-import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from "../../Utils";
+import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick, returnVal } from "../../Utils";
 import { DocUtils, Docs } from "../documents/Documents";
 import { DocumentType } from '../documents/DocumentTypes';
 import { DragManager } from "../util/DragManager";
@@ -453,8 +453,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             if (e.ctrlKey && !element.props.Document._nativeHeight) element.toggleNativeDimensions();
             if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) {
                 const doc = Document(element.rootDoc);
-                let nwidth = doc._nativeWidth || 0;
-                let nheight = doc._nativeHeight || 0;
+                let nwidth = returnVal(element.NativeWidth?.(), doc._nativeWidth);
+                let nheight = returnVal(element.NativeHeight?.(), doc._nativeHeight);
                 const width = (doc._width || 0);
                 let height = (doc._height || (nheight / nwidth * width));
                 height = !height || isNaN(height) ? 20 : height;
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 63711a3cb..6af3a40cf 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -926,8 +926,6 @@ export class GestureOverlay extends Touchable {
                 ContentScaling={returnOne}
                 PanelWidth={this.return300}
                 PanelHeight={this.return300}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
                 renderDepth={0}
                 backgroundColor={returnEmptyString}
                 focus={emptyFunction}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 318d0368c..d017de457 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -261,8 +261,6 @@ export class MainView extends React.Component {
             removeDocument={undefined}
             ScreenToLocalTransform={Transform.Identity}
             ContentScaling={returnOne}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
             PanelWidth={this.getPWidth}
             PanelHeight={this.getPHeight}
             focus={emptyFunction}
@@ -318,8 +316,6 @@ export class MainView extends React.Component {
                     addDocument={undefined}
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     rootSelected={returnTrue}
                     removeDocument={returnFalse}
                     onClick={undefined}
@@ -354,8 +350,6 @@ export class MainView extends React.Component {
                 addDocument={undefined}
                 addDocTab={this.addDocTabFunc}
                 pinToPres={emptyFunction}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
                 rootSelected={returnTrue}
                 removeDocument={returnFalse}
                 onClick={undefined}
@@ -487,8 +481,6 @@ export class MainView extends React.Component {
                     onClick={undefined}
                     ScreenToLocalTransform={this.buttonBarXf}
                     ContentScaling={returnOne}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     PanelWidth={this.flyoutWidthFunc}
                     PanelHeight={this.getContentsHeight}
                     renderDepth={0}
@@ -553,8 +545,6 @@ export class MainView extends React.Component {
                 removeDocument={undefined}
                 ScreenToLocalTransform={Transform.Identity}
                 ContentScaling={returnOne}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
                 PanelWidth={this.getPWidth}
                 PanelHeight={this.getPHeight}
                 renderDepth={0}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index cc0dd0443..4b8049e14 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -193,8 +193,6 @@ export class OverlayView extends React.Component {
                     addDocument={undefined}
                     removeDocument={undefined}
                     ContentScaling={returnOne}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     PanelWidth={returnOne}
                     PanelHeight={returnOne}
                     ScreenToLocalTransform={Transform.Identity}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 92c3f09b4..9f08a03e1 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -49,8 +49,6 @@ export default class Palette extends React.Component<PaletteProps> {
                             onClick={undefined}
                             ScreenToLocalTransform={Transform.Identity}
                             ContentScaling={returnOne}
-                            NativeHeight={returnZero}
-                            NativeWidth={returnZero}
                             PanelWidth={() => window.screen.width}
                             PanelHeight={() => window.screen.height}
                             renderDepth={0}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 041eec2b4..7da56721a 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -287,9 +287,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     fitToBox={true}
                     FreezeDimensions={true}
                     NativeWidth={layoutDoc.type ===
-                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : returnZero}
+                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : undefined}
                     NativeHeight={layoutDoc.type ===
-                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : returnZero}
+                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : undefined}
                     PanelWidth={panelWidth}
                     PanelHeight={panelHeight}
                     focus={returnFalse}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 870af03aa..c1878115d 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -150,8 +150,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 select={emptyFunction}
                 renderDepth={1}
                 addDocTab={returnFalse}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
                 PanelWidth={this.return100}
                 PanelHeight={this.return100}
                 treeViewHideHeaderFields={true}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 5f63f536d..034d006f2 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -13,7 +13,7 @@ import { Doc } from '../../../fields/Doc';
 import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox';
 import { ContextMenu } from '../ContextMenu';
 import { ObjectField } from '../../../fields/ObjectField';
-import { returnFalse } from '../../../Utils';
+import { returnFalse, returnZero } from '../../../Utils';
 import { ScriptField } from '../../../fields/ScriptField';
 
 type CarouselDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>;
@@ -54,9 +54,9 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
                         onDoubleClick={this.onContentDoubleClick}
                         onClick={this.onContentClick}
                         renderDepth={this.props.renderDepth + 1}
-                        dontRegisterView={layoutTemp} // temporary hack to mark documents as being a template  see imageBox
                         LayoutTemplate={this.props.ChildLayoutTemplate}
                         LayoutTemplateString={this.props.ChildLayoutString}
+                        NativeWidth={layoutTemp ? returnZero : this.props.NativeWidth}
                         Document={curDoc.layout}
                         DataDoc={curDoc.data}
                         PanelHeight={this.panelHeight}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index ea050011a..22c1f51a6 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -153,8 +153,6 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 onClick={undefined}
                                 ScreenToLocalTransform={this.getTransform(dref)}
                                 ContentScaling={returnOne}
-                                NativeHeight={returnZero}
-                                NativeWidth={returnZero}
                                 PanelWidth={nested ? pair.layout[WidthSym] : () => this.dimension()}// ugh - need to get rid of this inline function to avoid recomputing
                                 PanelHeight={nested ? pair.layout[HeightSym] : () => this.dimension()}
                                 renderDepth={this.props.renderDepth + 1}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 1b68c0e1a..332a2001f 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -429,8 +429,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                 <ContentFittingDocumentView
                     Document={this.previewDocument}
                     DataDoc={undefined}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     fitToBox={true}
                     FreezeDimensions={true}
                     focus={emptyFunction}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index b9a94642a..84173d3ba 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -12,7 +12,7 @@ import { listSpec, makeInterface } from "../../../fields/Schema";
 import { SchemaHeaderField } from "../../../fields/SchemaHeaderField";
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types";
 import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, smoothScroll } from "../../../Utils";
+import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, smoothScroll, returnVal } from "../../../Utils";
 import { DragManager, dropActionType } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
@@ -209,8 +209,6 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
             renderDepth={this.props.renderDepth + 1}
             PanelWidth={width}
             PanelHeight={height}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
             fitToBox={false}
             dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.dontRegisterChildViews, this.props.dontRegisterView)}
             rootSelected={this.rootSelected}
@@ -481,8 +479,8 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
     }
 
 
-    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth) || this.props.NativeWidth() || 0; }
-    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight) || this.props.NativeHeight() || 0; }
+    @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), NumCast(this.layoutDoc._nativeWidth)); }
+    @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), NumCast(this.layoutDoc._nativeHeight)); }
 
     @computed get scaling() { return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; }
 
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 4a8d66050..8e4c89922 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -31,8 +31,8 @@ export interface CollectionViewProps extends FieldViewProps {
     setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
     rootSelected: (outsideReaction?: boolean) => boolean;
     fieldKey: string;
-    NativeWidth: () => number;
-    NativeHeight: () => number;
+    NativeWidth?: () => number;
+    NativeHeight?: () => number;
 }
 
 export interface SubCollectionViewProps extends CollectionViewProps {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index f13fee776..7b3e95404 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -357,8 +357,8 @@ class TreeView extends React.Component<TreeViewProps> {
                     backgroundColor={this.props.backgroundColor}
                     fitToBox={this.boundsOfCollectionDocument !== undefined}
                     FreezeDimensions={true}
-                    NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : returnZero}
-                    NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : returnZero}
+                    NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined}
+                    NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined}
                     PanelWidth={panelWidth}
                     PanelHeight={panelHeight}
                     focus={returnFalse}
@@ -464,8 +464,6 @@ class TreeView extends React.Component<TreeViewProps> {
                 ContentScaling={returnOne}
                 PanelWidth={this.truncateTitleWidth}
                 PanelHeight={returnZero}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
                 contextMenuItems={this.contextMenuItems}
                 opacity={returnOne}
                 renderDepth={1}
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 1fb7aa04a..854254195 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -570,8 +570,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                     ref="overlay"><ContentFittingDocumentView
                         Document={this._showDoc}
                         DataDoc={this._showDataDoc}
-                        NativeHeight={returnZero}
-                        NativeWidth={returnZero}
                         fitToBox={true}
                         FreezeDimensions={true}
                         focus={emptyFunction}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index fb4f5c366..93d830b8a 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -306,8 +306,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 ContentScaling={returnOne}
                 PanelWidth={this.returnMiniSize}
                 PanelHeight={this.returnMiniSize}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
                 ScreenToLocalTransform={this.ScreenToLocalTransform}
                 renderDepth={0}
                 whenActiveChanged={emptyFunction}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 86460eee1..aa334df6c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -12,7 +12,7 @@ import { ScriptField } from "../../../../fields/ScriptField";
 import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
 import { TraceMobx } from "../../../../fields/util";
 import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, returnVal } from "../../../../Utils";
 import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
 import { DocServer } from "../../../DocServer";
 import { Docs, DocUtils } from "../../../documents/Documents";
@@ -107,8 +107,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     @computed get fitToContent() { return (this.props.fitToBox || this.Document._fitToBox) && !this.isAnnotationOverlay; }
     @computed get parentScaling() { return this.props.ContentScaling && this.fitToContent && !this.isAnnotationOverlay ? this.props.ContentScaling() : 1; }
     @computed get contentBounds() { return aggregateBounds(this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10)); }
-    @computed get nativeWidth() { return this.fitToContent ? 0 : NumCast(this.Document._nativeWidth, this.props.NativeWidth()); }
-    @computed get nativeHeight() { return this.fitToContent ? 0 : NumCast(this.Document._nativeHeight, this.props.NativeHeight()); }
+    @computed get nativeWidth() { return this.fitToContent ? 0 : returnVal(this.props.NativeWidth?.(), NumCast(this.Document._nativeWidth)); }
+    @computed get nativeHeight() { return this.fitToContent ? 0 : returnVal(this.props.NativeHeight?.(), NumCast(this.Document._nativeHeight)); }
     private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; }
     private get scaleFieldKey() { return this.props.scaleField || "_viewScale"; }
     private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
@@ -942,8 +942,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             moveDocument: this.props.moveDocument,
             pinToPres: this.props.pinToPres,
             whenActiveChanged: this.props.whenActiveChanged,
-            NativeHeight: returnZero,
-            NativeWidth: returnZero,
             fitToBox: false,
             DataDoc: childData,
             Document: childLayout,
@@ -1218,7 +1216,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     @undoBatch
     @action
     toggleNativeDimensions = () => {
-        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth(), this.props.NativeHeight());
+        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth?.() || 0, this.props.NativeHeight?.() || 0);
     }
 
     @undoBatch
@@ -1411,8 +1409,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
 
     @computed get contentScaling() {
         if (this.props.annotationsKey && !this.props.forceScaling) return 0;
-        const nw = NumCast(this.Document._nativeWidth, this.props.NativeWidth());
-        const nh = NumCast(this.Document._nativeHeight, this.props.NativeHeight());
+        const nw = returnVal(this.props.NativeWidth?.(), NumCast(this.Document._nativeWidth));
+        const nh = returnVal(this.props.NativeHeight?.(), NumCast(this.Document._nativeHeight));
         const hscale = nh ? this.props.PanelHeight() / nh : 1;
         const wscale = nw ? this.props.PanelWidth() / nw : 1;
         return wscale < hscale ? wscale : hscale;
diff --git a/src/client/views/collections/collectionGrid/CollectionGridView.tsx b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
index df4d71526..bc04c79f9 100644
--- a/src/client/views/collections/collectionGrid/CollectionGridView.tsx
+++ b/src/client/views/collections/collectionGrid/CollectionGridView.tsx
@@ -165,8 +165,6 @@ export class CollectionGridView extends CollectionSubView(GridSchema) {
             {...this.props}
             Document={layout}
             DataDoc={layout.resolvedDataDoc as Doc}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
             backgroundColor={this.props.backgroundColor}
             ContainingCollectionDoc={this.props.Document}
             PanelWidth={width}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 0afcab5a3..b3f5d1c0f 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -213,19 +213,19 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
         return this.props.addDocTab(doc, where);
     }
     getDisplayDoc(layout: Doc, dxf: () => Transform, width: () => number, height: () => number) {
+        const layoutTemp = this.props.DataDoc ? true : undefined;
         return <ContentFittingDocumentView
             Document={layout}
-            DataDoc={layout.resolvedDataDoc as Doc}
+            DataDoc={layout.resolvedDataDoc as Doc || (layoutTemp ? layout : undefined)}
             backgroundColor={this.props.backgroundColor}
             LayoutTemplate={this.props.ChildLayoutTemplate}
             LayoutTemplateString={this.props.ChildLayoutString}
+            NativeWidth={layoutTemp ? returnZero : this.props.NativeWidth}
             LibraryPath={this.props.LibraryPath}
             FreezeDimensions={this.props.freezeChildDimensions}
             renderDepth={this.props.renderDepth + 1}
             PanelWidth={width}
             PanelHeight={height}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
             fitToBox={false}
             rootSelected={this.rootSelected}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
@@ -248,6 +248,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             ContentScaling={returnOne}
         />;
     }
+    @computed get rootDoc() { return Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document; }
     /**
      * @returns the resolved list of rendered child documents, displayed
      * at their resolved pixel widths, each separated by a resizer. 
@@ -257,6 +258,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
         const { childLayoutPairs } = this;
         const { Document, PanelHeight } = this.props;
         const collector: JSX.Element[] = [];
+        const layoutTemp = this.props.DataDoc ? true : undefined;
         for (let i = 0; i < childLayoutPairs.length; i++) {
             const { layout } = childLayoutPairs[i];
             const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin));
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 53825eece..9a4fb0627 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -224,8 +224,6 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             renderDepth={this.props.renderDepth + 1}
             PanelWidth={width}
             PanelHeight={height}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
             fitToBox={false}
             rootSelected={this.rootSelected}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 0e3c4462c..5e7f8dfda 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -520,8 +520,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 Document={mark}
                 focus={() => this.playLink(mark)}
                 pointerEvents={true}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
                 rootSelected={returnFalse}
                 LayoutTemplate={undefined}
                 ContainingCollectionDoc={this.props.Document}
@@ -607,8 +605,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                     <div className={`audiobox-marker-${this.props.PanelHeight() < 32 ? "mini" : ""}container`} key={l[Id]} style={{ left: `${startTime / this.audioDuration * 100}%` }} onClick={e => e.stopPropagation()}>
                                         <DocumentView {...this.props}
                                             Document={l}
-                                            NativeHeight={returnZero}
-                                            NativeWidth={returnZero}
                                             rootSelected={returnFalse}
                                             ContainingCollectionDoc={this.props.Document}
                                             parentActive={returnTrue}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 16b2f7c2a..bfa66272e 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -11,7 +11,7 @@ import { Document } from "../../../fields/documentSchemas";
 import { TraceMobx } from "../../../fields/util";
 import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
 import { List } from "../../../fields/List";
-import { numberRange, smoothScroll } from "../../../Utils";
+import { numberRange, smoothScroll, returnVal } from "../../../Utils";
 import { ComputedField } from "../../../fields/ScriptField";
 import { listSpec } from "../../../fields/Schema";
 import { DocumentType } from "../../documents/DocumentTypes";
@@ -55,8 +55,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     @computed get freezeDimensions() { return this.props.FreezeDimensions; }
     @computed get dataProvider() { return this.props.dataProvider?.(this.props.Document, this.props.replica); }
     @computed get sizeProvider() { return this.props.sizeProvider?.(this.props.Document, this.props.replica); }
-    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
-    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
+    @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), NumCast(this.layoutDoc._nativeWidth, this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
+    @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), NumCast(this.layoutDoc._nativeHeight, this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
 
     public static getValues(doc: Doc, time: number) {
         const timecode = Math.round(time);
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 6050d03cc..30458b9f8 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -6,7 +6,7 @@ import { Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
 import { ScriptField } from "../../../fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { TraceMobx } from "../../../fields/util";
-import { emptyFunction } from "../../../Utils";
+import { emptyFunction, returnVal } from "../../../Utils";
 import { dropActionType } from "../../util/DragManager";
 import { CollectionView } from "../collections/CollectionView";
 import { DocumentView, DocumentViewProps } from "../nodes/DocumentView";
@@ -26,8 +26,8 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp
     }
     @computed get freezeDimensions() { return this.props.FreezeDimensions; }
 
-    nativeWidth = () => NumCast(this.layoutDoc?.[(this.props.DataDoc ? Doc.LayoutFieldKey(this.layoutDoc) + "-" : "_") + "nativeWidth"], this.props.NativeWidth?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth()));
-    nativeHeight = () => NumCast(this.layoutDoc?.[(this.props.DataDoc ? Doc.LayoutFieldKey(this.layoutDoc) + "-" : "_") + "nativeHeight"], this.props.NativeHeight?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight()));
+    nativeWidth = () => returnVal(this.props.NativeWidth?.(), NumCast(this.layoutDoc?.[(this.props.DataDoc ? Doc.LayoutFieldKey(this.layoutDoc) + "-" : "_") + "nativeWidth"], (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth())));
+    nativeHeight = () => returnVal(this.props.NativeHeight?.(), NumCast(this.layoutDoc?.[(this.props.DataDoc ? Doc.LayoutFieldKey(this.layoutDoc) + "-" : "_") + "nativeHeight"], (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight())));
     @computed get scaling() {
         const wscale = this.props.PanelWidth() / this.nativeWidth();
         if (wscale * this.nativeHeight() > this.props.PanelHeight()) {
@@ -40,8 +40,8 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp
     private PanelWidth = () => this.panelWidth;
     private PanelHeight = () => this.panelHeight;
 
-    @computed get panelWidth() { return this.nativeWidth && !this.props.Document._fitWidth ? this.nativeWidth() * this.contentScaling() : this.props.PanelWidth(); }
-    @computed get panelHeight() { return this.nativeHeight && !this.props.Document._fitWidth ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); }
+    @computed get panelWidth() { return this.nativeWidth() && !this.props.Document._fitWidth ? this.nativeWidth() * this.contentScaling() : this.props.PanelWidth(); }
+    @computed get panelHeight() { return this.nativeHeight() && !this.props.Document._fitWidth ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); }
 
     private getTransform = () => this.props.ScreenToLocalTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling());
     private get centeringOffset() { return this.nativeWidth() && !this.props.Document._fitWidth ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx
index b3b7cc4f3..91f96135f 100644
--- a/src/client/views/nodes/DocHolderBox.tsx
+++ b/src/client/views/nodes/DocHolderBox.tsx
@@ -135,8 +135,6 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
                     pinToPres={this.props.pinToPres}
                     ScreenToLocalTransform={this.getTransform}
                     renderDepth={containedDoc.type !== DocumentType.DOCHOLDER && !this.props.renderDepth ? 0 : this.props.renderDepth + 1}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     PanelWidth={this.pwidth}
                     PanelHeight={this.pheight}
                     focus={this.props.focus}
@@ -166,8 +164,6 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
                     pinToPres={this.props.pinToPres}
                     ScreenToLocalTransform={this.getTransform}
                     renderDepth={containedDoc.type !== DocumentType.DOCHOLDER && !this.props.renderDepth ? 0 : this.props.renderDepth + 1}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     PanelWidth={this.pwidth}
                     PanelHeight={this.pheight}
                     focus={this.props.focus}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a4ac1c4dc..9992874bf 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -11,7 +11,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Ty
 import { GetEffectiveAcl, TraceMobx } from '../../../fields/util';
 import { MobileInterface } from '../../../mobile/MobileInterface';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils } from "../../../Utils";
+import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, returnVal } from "../../../Utils";
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -49,8 +49,8 @@ export interface DocumentViewProps {
     docFilters: () => string[];
     searchFilterDocs: () => Doc[];
     FreezeDimensions?: boolean;
-    NativeWidth: () => number;
-    NativeHeight: () => number;
+    NativeWidth?: () => number;
+    NativeHeight?: () => number;
     Document: Doc;
     DataDoc?: Doc;
     getView?: (view: DocumentView) => any;
@@ -119,8 +119,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     public get ContentDiv() { return this._mainCont.current; }
     @computed get topMost() { return this.props.renderDepth === 0; }
     @computed get freezeDimensions() { return this.props.FreezeDimensions; }
-    @computed get nativeWidth() { return NumCast(this.layoutDoc[(this.props.DataDoc ? Doc.LayoutFieldKey(this.layoutDoc) + "-" : "_") + "nativeWidth"], this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
-    @computed get nativeHeight() { return NumCast(this.layoutDoc[(this.props.DataDoc ? Doc.LayoutFieldKey(this.layoutDoc) + "-" : "_") + "nativeHeight"], this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
+    @computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), NumCast(this.layoutDoc[(this.props.DataDoc ? Doc.LayoutFieldKey(this.layoutDoc) + "-" : "_") + "nativeWidth"], (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0))); }
+    @computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), NumCast(this.layoutDoc[(this.props.DataDoc ? Doc.LayoutFieldKey(this.layoutDoc) + "-" : "_") + "nativeHeight"], (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0))); }
     @computed get onClickHandler() { return this.props.onClick?.() ?? Cast(this.Document.onClick, ScriptField, Cast(this.layoutDoc.onClick, ScriptField, null)); }
     @computed get onDoubleClickHandler() { return this.props.onDoubleClick?.() ?? (Cast(this.layoutDoc.onDoubleClick, ScriptField, null) ?? this.Document.onDoubleClick); }
     @computed get onPointerDownHandler() { return this.props.onPointerDown?.() ?? ScriptCast(this.Document.onPointerDown); }
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 746a906c7..4ec5bc534 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -52,8 +52,8 @@ export interface FieldViewProps {
     PanelHeight: () => number;
     PanelPosition?: string;
     overflow?: boolean;
-    NativeHeight: () => number;
-    NativeWidth: () => number;
+    NativeHeight?: () => number;
+    NativeWidth?: () => number;
     setVideoBox?: (player: VideoBox) => void;
     ContentScaling: () => number;
     ChromeHeight?: () => number;
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index a97f8c541..eab365445 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -164,8 +164,6 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
                     ContainingCollectionView={this.props.ContainingCollectionView}
                     PanelWidth={this.props.PanelWidth}
                     PanelHeight={this.props.PanelHeight}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     LibraryPath={emptyPath}
                     rootSelected={this.props.rootSelected}
                     renderDepth={1}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 952e92ca6..beb6ba6a8 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -75,10 +75,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
     componentDidMount() {
         this._pathDisposer = reaction(() => ({ nativeSize: this.nativeSize, width: this.layoutDoc[WidthSym]() }),
             ({ nativeSize, width }) => {
-                this.layoutDoc._nativeWidth = nativeSize.nativeWidth;
-                this.layoutDoc._nativeHeight = nativeSize.nativeHeight;
-                this.layoutDoc._nativeOrientation = nativeSize.nativeOrientation;
-                this.layoutDoc._height = width * nativeSize.nativeHeight / nativeSize.nativeWidth;
+                if (this.props.NativeWidth?.() !== 0 || !this.layoutDoc._height) {
+                    this.layoutDoc._nativeWidth = nativeSize.nativeWidth;
+                    this.layoutDoc._nativeHeight = nativeSize.nativeHeight;
+                    this.layoutDoc._nativeOrientation = nativeSize.nativeOrientation;
+                    this.layoutDoc._height = width * nativeSize.nativeHeight / nativeSize.nativeWidth;
+                }
             },
             { fireImmediately: true });
     }
@@ -164,19 +166,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
             if (!Doc.UserDoc().noviceMode) {
                 funcs.push({ description: "Export to Google Photos", event: () => GooglePhotos.Transactions.UploadImages([this.props.Document]), icon: "caret-square-right" });
                 funcs.push({ description: "Copy path", event: () => Utils.CopyText(field.url.href), icon: "expand-arrows-alt" });
-                // funcs.push({
-                //     description: "Reset Native Dimensions", event: action(async () => {
-                //         const curNW = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"]);
-                //         const curNH = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"]);
-                //         if (this.props.PanelWidth() / this.props.PanelHeight() > curNW / curNH) {
-                //             this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelHeight() * curNW / curNH;
-                //             this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelHeight();
-                //         } else {
-                //             this.dataDoc[this.fieldKey + "-nativeWidth"] = this.props.PanelWidth();
-                //             this.dataDoc[this.fieldKey + "-nativeHeight"] = this.props.PanelWidth() * curNH / curNW;
-                //         }
-                //     }), icon: "expand-arrows-alt"
-                // });
 
                 const existingAnalyze = ContextMenu.Instance?.findByDescription("Analyzers...");
                 const modes: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
@@ -434,8 +423,6 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
                 forceScaling={true}
                 PanelHeight={this.props.PanelHeight}
                 PanelWidth={this.props.PanelWidth}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
                 annotationsKey={this.annotationKey}
                 isAnnotationOverlay={true}
                 focus={this.props.focus}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 74d10d087..e531083bf 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -71,8 +71,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             whenActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
-            NativeHeight: returnZero,
-            NativeWidth: returnZero,
             PanelWidth: this.props.PanelWidth,
             PanelHeight: this.props.PanelHeight,
             addDocTab: returnFalse,
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index a067f23af..64ae1051b 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -22,8 +22,6 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>(
             <CollectionTreeView {...this.props}
                 ChromeHeight={returnZero}
                 overrideDocuments={[this.dataDoc]}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
                 ignoreFields={Cast(this.props.Document.linkBoxExcludedKeys, listSpec("string"), null)}
                 annotationsKey={""}
                 dontRegisterView={true}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index a70736d90..875026944 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -114,8 +114,6 @@ export class LinkDocPreview extends React.Component<Props> {
                 whenActiveChanged={returnFalse}
                 bringToFront={returnFalse}
                 ContentScaling={returnOne}
-                NativeWidth={returnZero}
-                NativeHeight={returnZero}
                 backgroundColor={this.props.backgroundColor} />;
     }
 
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 5d51c420b..34ad7f3be 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -172,8 +172,6 @@ export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, Screensh
                 <CollectionFreeFormView {...this.props}
                     PanelHeight={this.props.PanelHeight}
                     PanelWidth={this.props.PanelWidth}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     annotationsKey={""}
                     focus={this.props.focus}
                     isSelected={this.props.isSelected}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index d50a10bdd..79123c081 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -368,8 +368,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                 <CollectionFreeFormView {...this.props}
                     PanelHeight={this.props.PanelHeight}
                     PanelWidth={this.props.PanelWidth}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     annotationsKey={this.annotationKey}
                     focus={this.props.focus}
                     isSelected={this.props.isSelected}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index c5d7c3c9f..41c310a96 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -369,7 +369,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
     @undoBatch
     @action
     toggleNativeDimensions = () => {
-        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth(), this.props.NativeHeight());
+        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth?.() || 0, this.props.NativeHeight?.() || 0);
     }
     specificContextMenu = (e: React.MouseEvent): void => {
         const cm = ContextMenu.Instance;
@@ -650,8 +650,6 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                             PanelHeight={this.props.PanelHeight}
                             PanelWidth={this.props.PanelWidth}
                             annotationsKey={this.annotationKey}
-                            NativeHeight={returnZero}
-                            NativeWidth={returnZero}
                             VisibleHeight={this.visibleHeiht}
                             focus={this.props.focus}
                             setPreviewCursor={this.setPreviewCursor}
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 3b77735a7..90655bad6 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -245,8 +245,6 @@ export class DashDocView extends React.Component<IDashDocView> {
                             addDocTab={this._textBox.props.addDocTab}
                             pinToPres={returnFalse}
                             renderDepth={self._textBox.props.renderDepth + 1}
-                            NativeHeight={returnZero}
-                            NativeWidth={returnZero}
                             PanelWidth={finalLayout[WidthSym]}
                             PanelHeight={finalLayout[HeightSym]}
                             focus={this.outerFocus}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index f0dc92b90..335605a00 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -562,7 +562,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @undoBatch
     @action
     toggleNativeDimensions = () => {
-        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth(), this.props.NativeHeight());
+        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth?.()||0, this.props.NativeHeight?.()||0);
     }
 
     public static get DefaultLayout(): Doc | string | undefined {
@@ -1565,8 +1565,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                             <CollectionFreeFormView {...this.props}
                                 PanelHeight={this.props.PanelHeight}
                                 PanelWidth={this.sidebarWidth}
-                                NativeHeight={returnZero}
-                                NativeWidth={returnZero}
                                 scaleField={this.annotationKey + "-scale"}
                                 annotationsKey={this.annotationKey}
                                 isAnnotationOverlay={false}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index b4f648273..8524786c8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -319,8 +319,8 @@ export class FormattedTextBoxComment {
                                             whenActiveChanged={returnFalse}
                                             bringToFront={returnFalse}
                                             ContentScaling={returnOne}
-                                            NativeWidth={() => target._nativeWidth ? NumCast(target._nativeWidth) : 0}
-                                            NativeHeight={() => target._nativeHeight ? NumCast(target._nativeHeight) : 0}
+                                            NativeWidth={target._nativeWidth ? (() => NumCast(target._nativeWidth)) : undefined}
+                                            NativeHeight={target._natvieHeight ? (() => NumCast(target._nativeHeight)) : undefined}
                                         />
                                     </div>
                                 </div>;
diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx
index f0bacb735..a80d2639d 100644
--- a/src/client/views/nodes/formattedText/RichTextSchema.tsx
+++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx
@@ -145,8 +145,6 @@ export class DashDocView {
                     addDocTab={this._textBox.props.addDocTab}
                     pinToPres={returnFalse}
                     renderDepth={self._textBox.props.renderDepth + 1}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     PanelWidth={finalLayout[WidthSym]}
                     PanelHeight={finalLayout[HeightSym]}
                     focus={this.outerFocus}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 18be9b679..65eb23a06 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -679,8 +679,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
                 setPreviewCursor={this.setPreviewCursor}
                 PanelHeight={this.panelWidth}
                 PanelWidth={this.panelHeight}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
                 dropAction={"alias"}
                 VisibleHeight={this.visibleHeight}
                 focus={this.props.focus}
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index c33637d0f..048d3a3d0 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -107,8 +107,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined}
                     ContentScaling={returnOne}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                 />
                 <div className="presElementBox-embeddedMask" />
             </div>;
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 5e86246c5..81b3869ae 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -94,8 +94,6 @@ export class AudioUpload extends React.Component {
                         ContentScaling={returnOne}
                         PanelWidth={() => 600}
                         PanelHeight={() => 400}
-                        NativeHeight={returnZero}
-                        NativeWidth={returnZero}
                         renderDepth={0}
                         focus={emptyFunction}
                         backgroundColor={() => "rgba(0,0,0,0)"}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index ae2c07c8e..cb5191e61 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -213,8 +213,6 @@ export class MobileInterface extends React.Component {
                     ContentScaling={returnOne}
                     PanelWidth={this.returnWidth}
                     PanelHeight={this.returnHeight}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
                     renderDepth={0}
                     focus={emptyFunction}
                     backgroundColor={this.whitebackground}
-- 
cgit v1.2.3-70-g09d2


From f5c00261d8d936abdec22abfae94dd972c0f9e4a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 8 Sep 2020 22:57:51 -0400
Subject: fixed presbox, videobox and some others to set NativeWidth/Height
 properly.

---
 src/client/views/MainView.tsx                       |  4 ----
 src/client/views/PropertiesView.tsx                 | 21 +++++----------------
 .../views/collections/CollectionStackingView.tsx    | 16 ++--------------
 src/client/views/collections/CollectionSubView.tsx  |  1 -
 src/client/views/collections/CollectionView.tsx     |  1 +
 src/client/views/collections/TabDocView.tsx         |  8 ++++----
 .../CollectionMulticolumnView.tsx                   |  1 -
 .../views/nodes/ContentFittingDocumentView.scss     |  1 -
 .../views/nodes/ContentFittingDocumentView.tsx      |  2 +-
 src/client/views/nodes/ScreenshotBox.tsx            |  4 ++--
 src/client/views/nodes/VideoBox.tsx                 |  4 ++--
 src/client/views/nodes/WebBox.tsx                   |  4 ++--
 .../views/nodes/formattedText/FormattedTextBox.tsx  |  6 +++---
 src/client/views/pdf/PDFViewer.tsx                  |  4 ++--
 14 files changed, 24 insertions(+), 53 deletions(-)

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

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index d017de457..bdf8c83e5 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -581,8 +581,6 @@ export class MainView extends React.Component {
                     focus={returnFalse}
                     PanelWidth={() => 500}
                     PanelHeight={() => 800}
-                    NativeHeight={() => 500}
-                    NativeWidth={() => 800}
                     ContentScaling={returnOne}
                     docFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
@@ -648,8 +646,6 @@ export class MainView extends React.Component {
                             focus={returnFalse}
                             PanelWidth={() => 500}
                             PanelHeight={() => 800}
-                            NativeHeight={() => 500}
-                            NativeWidth={() => 800}
                             ContentScaling={returnOne}
                             docFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 7da56721a..d70f4b332 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -80,21 +80,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     @computed get isInk() { return this.selectedDoc?.type === DocumentType.INK; }
 
-    @action
     rtfWidth = () => {
-        if (this.selectedDoc) {
-            return Math.min(this.selectedDoc?.[WidthSym](), this.props.width - 20);
-        } else {
-            return 0;
-        }
+        return !this.selectedDoc ? 0 : Math.min(this.selectedDoc?.[WidthSym](), this.props.width - 20);
     }
-    @action
     rtfHeight = () => {
-        if (this.selectedDoc) {
-            return this.rtfWidth() <= this.selectedDoc?.[WidthSym]() ? Math.min(this.selectedDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
-        } else {
-            return 0;
-        }
+        return !this.selectedDoc ? 0 : this.rtfWidth() <= this.selectedDoc?.[WidthSym]() ? Math.min(this.selectedDoc?.[HeightSym](), this.MAX_EMBED_HEIGHT) : this.MAX_EMBED_HEIGHT;
     }
 
     @action
@@ -286,10 +276,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     backgroundColor={this.previewBackground}
                     fitToBox={true}
                     FreezeDimensions={true}
-                    NativeWidth={layoutDoc.type ===
-                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : undefined}
-                    NativeHeight={layoutDoc.type ===
-                        StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : undefined}
+                    dontCenter={true}
+                    NativeWidth={layoutDoc.type === DocumentType.RTF ? this.rtfWidth : undefined}
+                    NativeHeight={layoutDoc.type === DocumentType.RTF ? this.rtfHeight : undefined}
                     PanelWidth={panelWidth}
                     PanelHeight={panelHeight}
                     focus={returnFalse}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a7276a962..cbc62be91 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -128,19 +128,6 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
         return fields;
     }
 
-    getSimpleDocHeight(d?: Doc) {
-        if (!d) return 0;
-        const layoutDoc = Doc.Layout(d, this.props.ChildLayoutTemplate?.());
-        const nw = NumCast(layoutDoc._nativeWidth);
-        const nh = NumCast(layoutDoc._nativeHeight);
-        let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
-        if (!layoutDoc._fitWidth && nw && nh) {
-            const aspect = nw && nh ? nh / nw : 1;
-            if (!(this.layoutDoc._columnsFill)) wid = Math.min(layoutDoc[WidthSym](), wid);
-            return wid * aspect;
-        }
-        return layoutDoc._fitWidth ? wid * NumCast(layoutDoc.scrollHeight, nh) / (nw || 1) : layoutDoc[HeightSym]();
-    }
     componentDidMount() {
         super.componentDidMount?.();
 
@@ -209,8 +196,9 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
             renderDepth={this.props.renderDepth + 1}
             PanelWidth={width}
             PanelHeight={height}
-            NativeWidth={this.props.childIgnoreNativeSize ? returnZero : undefined}
+            NativeWidth={this.props.childIgnoreNativeSize ? returnZero : undefined}  // explicitly ignore nativeWidth/height if childIgnoreNativeSize is set- used by PresBox
             NativeHeight={this.props.childIgnoreNativeSize ? returnZero : undefined}
+            dontCenter={this.props.childIgnoreNativeSize ? true : false}
             fitToBox={false}
             dontRegisterView={dataDoc ? true : BoolCast(this.layoutDoc.dontRegisterChildViews, this.props.dontRegisterView)}
             rootSelected={this.rootSelected}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 37212a0fa..81f3ddad2 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -28,7 +28,6 @@ export interface CollectionViewProps extends FieldViewProps {
     PanelWidth: () => number;
     PanelHeight: () => number;
     VisibleHeight?: () => number;
-    childIgnoreNativeSize?: boolean;
     setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
     rootSelected: (outsideReaction?: boolean) => boolean;
     fieldKey: string;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ef3128bc0..6939399e6 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -73,6 +73,7 @@ export interface CollectionViewCustomProps {
     filterAddDocument?: (doc: Doc | Doc[]) => boolean;  // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example)
     childOpacity?: () => number;
     hideFilter?: true;
+    childIgnoreNativeSize?: boolean;
 }
 
 export interface CollectionRenderProps {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 93d830b8a..f3d2aaa8f 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -228,8 +228,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         }
         return Transform.Identity();
     }
-    get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
-    get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this._panelWidth * 100}% ` : undefined; }
+    @computed get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
+    @computed get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this._panelWidth * 100}% ` : undefined; }
 
     // adds a tab to the layout based on the locaiton parameter which can be:
     //  close[:{left,right,top,bottom}]  - e.g., "close" will close the tab, "close:left" will close the left tab, 
@@ -345,8 +345,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 ContentScaling={this.contentScaling}
                 PanelWidth={this.panelWidth}
                 PanelHeight={this.panelHeight}
-                NativeHeight={this.nativeHeight}
-                NativeWidth={this.nativeWidth}
+                NativeHeight={this.nativeHeight() ? this.nativeHeight : undefined}
+                NativeWidth={this.nativeWidth() ? this.nativeWidth : undefined}
                 ScreenToLocalTransform={this.ScreenToLocalTransform}
                 renderDepth={0}
                 parentActive={returnTrue}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 556cf79cd..0e4785d36 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -256,7 +256,6 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
         const { childLayoutPairs } = this;
         const { Document, PanelHeight } = this.props;
         const collector: JSX.Element[] = [];
-        const layoutTemp = this.props.DataDoc ? true : undefined;
         for (let i = 0; i < childLayoutPairs.length; i++) {
             const { layout } = childLayoutPairs[i];
             const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin));
diff --git a/src/client/views/nodes/ContentFittingDocumentView.scss b/src/client/views/nodes/ContentFittingDocumentView.scss
index eb2d93b9a..50562951a 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.scss
+++ b/src/client/views/nodes/ContentFittingDocumentView.scss
@@ -3,7 +3,6 @@
 .contentFittingDocumentView {
     position: relative;
     display: flex;
-    align-items: center;
 
     .contentFittingDocumentView-previewDoc {
         position: relative;
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 1fe7e6207..55149a44b 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -62,7 +62,7 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp
             {!this.props.Document || !this.props.PanelWidth ? (null) : (
                 <div className="contentFittingDocumentView-previewDoc"
                     style={{
-                        transform: !this.props.dontCenter ? `translate(${this.centeringOffset}px, 0px)` : undefined,
+                        transform: !this.props.dontCenter ? `translate(${this.centeringOffset}px, ${this.centeringYOffset}px)` : undefined,
                         borderRadius: this.borderRounding,
                         height: Math.abs(this.centeringYOffset) > 0.001 ? `${100 * this.nativeHeight() / this.nativeWidth() * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(),
                         width: Math.abs(this.centeringOffset) > 0.001 ? `${100 * (this.props.PanelWidth() - this.centeringOffset * 2) / this.props.PanelWidth()}%` : this.props.PanelWidth()
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 34ad7f3be..f13f373d0 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -9,7 +9,7 @@ import { InkTool } from "../../../fields/InkField";
 import { listSpec, makeInterface } from "../../../fields/Schema";
 import { Cast, NumCast } from "../../../fields/Types";
 import { VideoField } from "../../../fields/URLField";
-import { emptyFunction, returnFalse, returnOne, returnZero, Utils } from "../../../Utils";
+import { emptyFunction, returnFalse, returnOne, returnZero, Utils, OmitKeys, OmitKeys } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { ContextMenu } from "../ContextMenu";
@@ -169,7 +169,7 @@ export class ScreenshotBox extends ViewBoxBaseComponent<FieldViewProps, Screensh
         return (<div className="videoBox" onContextMenu={this.specificContextMenu}
             style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
             <div className="videoBox-viewer" >
-                <CollectionFreeFormView {...this.props}
+                <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
                     PanelHeight={this.props.PanelHeight}
                     PanelWidth={this.props.PanelWidth}
                     annotationsKey={""}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 79123c081..925bc9dd6 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -8,7 +8,7 @@ import { InkTool } from "../../../fields/InkField";
 import { createSchema, makeInterface } from "../../../fields/Schema";
 import { Cast, StrCast } from "../../../fields/Types";
 import { VideoField } from "../../../fields/URLField";
-import { Utils, emptyFunction, returnOne, returnZero } from "../../../Utils";
+import { Utils, emptyFunction, returnOne, returnZero, OmitKeys, OmitKeys } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { ContextMenu } from "../ContextMenu";
@@ -365,7 +365,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         return (<div className="videoBox" onContextMenu={this.specificContextMenu}
             style={{ transform: `scale(${this.props.ContentScaling()})`, width: `${100 / this.props.ContentScaling()}%`, height: `${100 / this.props.ContentScaling()}%` }} >
             <div className="videoBox-viewer" >
-                <CollectionFreeFormView {...this.props}
+                <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
                     PanelHeight={this.props.PanelHeight}
                     PanelWidth={this.props.PanelWidth}
                     annotationsKey={this.annotationKey}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 41c310a96..f841fa6e1 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -14,7 +14,7 @@ import { listSpec, makeInterface } from "../../../fields/Schema";
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { WebField } from "../../../fields/URLField";
 import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
-import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils, returnTrue } from "../../../Utils";
+import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils, returnTrue, OmitKeys } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import { ImageUtils } from "../../util/Import & Export/ImageUtils";
@@ -646,7 +646,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                         height: NumCast(this.layoutDoc.scrollHeight),
                         pointerEvents: this.layoutDoc._isBackground ? "none" : undefined
                     }}>
-                        <CollectionFreeFormView {...this.props}
+                        <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
                             PanelHeight={this.props.PanelHeight}
                             PanelWidth={this.props.PanelWidth}
                             annotationsKey={this.annotationKey}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 335605a00..f7777f83c 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -23,7 +23,7 @@ import { RichTextUtils } from '../../../../fields/RichTextUtils';
 import { makeInterface } from "../../../../fields/Schema";
 import { Cast, DateCast, NumCast, StrCast, ScriptCast, BoolCast } from "../../../../fields/Types";
 import { TraceMobx, OVERRIDE_ACL, GetEffectiveAcl } from '../../../../fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents } from '../../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents, OmitKeys } from '../../../../Utils';
 import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils';
 import { DocServer } from "../../../DocServer";
 import { Docs, DocUtils } from '../../../documents/Documents';
@@ -562,7 +562,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     @undoBatch
     @action
     toggleNativeDimensions = () => {
-        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth?.()||0, this.props.NativeHeight?.()||0);
+        Doc.toggleNativeDimensions(this.layoutDoc, this.props.ContentScaling(), this.props.NativeWidth?.() || 0, this.props.NativeHeight?.() || 0);
     }
 
     public static get DefaultLayout(): Doc | string | undefined {
@@ -1562,7 +1562,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                         <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} /> :
                         <div className={"formattedTextBox-sidebar" + (Doc.GetSelectedTool() !== InkTool.None ? "-inking" : "")}
                             style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}>
-                            <CollectionFreeFormView {...this.props}
+                            <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
                                 PanelHeight={this.props.PanelHeight}
                                 PanelWidth={this.sidebarWidth}
                                 scaleField={this.annotationKey + "-scale"}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 65eb23a06..e0195a100 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -13,7 +13,7 @@ import { ScriptField } from "../../../fields/ScriptField";
 import { Cast, NumCast } from "../../../fields/Types";
 import { PdfField } from "../../../fields/URLField";
 import { GetEffectiveAcl, TraceMobx } from "../../../fields/util";
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, emptyPath, intersectRect, returnZero, smoothScroll, Utils } from "../../../Utils";
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, emptyPath, intersectRect, returnZero, smoothScroll, Utils, OmitKeys } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { Networking } from "../../Network";
@@ -673,7 +673,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     @computed get overlayLayer() {
         return <div className={`pdfViewerDash-overlay${Doc.GetSelectedTool() !== InkTool.None || SnappingManager.GetIsDragging() ? "-inking" : ""}`} id="overlay"
             style={{ transform: `scale(${this._zoomed})` }}>
-            <CollectionFreeFormView {...this.props}
+            <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
                 LibraryPath={this.props.ContainingCollectionView?.props.LibraryPath ?? emptyPath}
                 annotationsKey={this.annotationKey}
                 setPreviewCursor={this.setPreviewCursor}
-- 
cgit v1.2.3-70-g09d2


From 15615e6789ae4eb121a6d0ac6ba607e74369bd6e Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 9 Sep 2020 16:57:25 -0400
Subject: several pdf fixes - clipping link anchors to bounds of container. 
 pdf box titles don't change based on zoom anymore.   can't zoom a pdf if not
 selected.  fixed scrolling of previews without scrolling targets.

---
 src/client/views/collections/CollectionSubView.tsx |  3 +-
 src/client/views/collections/TabDocView.tsx        |  8 ++---
 .../CollectionFreeFormLinkView.tsx                 | 30 ++++++++++++----
 src/client/views/nodes/LinkDocPreview.tsx          |  2 +-
 src/client/views/nodes/PDFBox.scss                 |  7 ++++
 src/client/views/nodes/PDFBox.tsx                  |  7 ++--
 .../formattedText/FormattedTextBoxComment.tsx      | 42 +++++++++++-----------
 src/client/views/pdf/PDFViewer.scss                |  2 ++
 src/client/views/pdf/PDFViewer.tsx                 | 31 ++++++++++------
 9 files changed, 86 insertions(+), 46 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index aa6b74f2d..c79547bb4 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -270,7 +270,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 return;
             }
 
-            console.log("Html = ", html);
             if (html) {
                 if (FormattedTextBox.IsFragment(html)) {
                     const href = FormattedTextBox.GetHref(html);
@@ -333,7 +332,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                             Doc.GetProto(htmlDoc)["data-text"] = Doc.GetProto(htmlDoc).text = text;
                             this.props.addDocument(htmlDoc);
                             if (srcWeb) {
-                                const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")?.[0].contentDocument?.getSelection()?.focusNode as any);
+                                const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")?.[0]?.contentDocument?.getSelection()?.focusNode as any);
                                 if (focusNode) {
                                     const rect = "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect();
                                     const x = (rect?.x || 0);
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f3d2aaa8f..589649ad9 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -68,7 +68,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             tab.element[0].onmouseenter = (e: MouseEvent) => {
                 if (SnappingManager.GetIsDragging() && tab.contentItem !== tab.header.parent.getActiveContentItem()) {
                     tab.header.parent.setActiveContentItem(tab.contentItem);
-                    console.log("Seetting " + titleEle.value);
                     tab.setActive(true);
                 }
             };
@@ -88,7 +87,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     (document.activeElement !== titleEle) && titleEle.focus();
                 }
             };
-            tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => v.topMost && v.props.Document === doc),
+            tab._disposers.selectionDisposer = reaction(() => SelectionManager.SelectedDocuments().some(v => (v.topMost || v.props.treeViewDoc) && v.props.Document === doc),
                 (selected) => selected && tab.contentItem !== tab.header.parent.getActiveContentItem() &&
                     UndoManager.RunInBatch(() => tab.header.parent.setActiveContentItem(tab.contentItem), "tab switch"));
 
@@ -190,9 +189,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     private onActiveContentItemChanged() {
         if (this.props.glContainer.tab && this._isActive !== this.props.glContainer.tab.isActive) {
             this._isActive = this.props.glContainer.tab.isActive;
-            this._isActive && setTimeout(() => this.view && SelectionManager.SelectDoc(this.view, false), 0);
             (CollectionDockingView.Instance as any)._goldenLayout?.isInitialised && CollectionDockingView.Instance.stateChanged();
             !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one.
+            this._isActive && this.view && SelectionManager.SelectDoc(this.view, false);
         }
     }
 
@@ -330,6 +329,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     }
     focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => afterFocus?.();
     setView = action((view: DocumentView) => this._view = view);
+    active = () => this._isActive;
     @computed get docView() {
         TraceMobx();
         return !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
@@ -349,7 +349,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 NativeWidth={this.nativeWidth() ? this.nativeWidth : undefined}
                 ScreenToLocalTransform={this.ScreenToLocalTransform}
                 renderDepth={0}
-                parentActive={returnTrue}
+                parentActive={this.active}
                 whenActiveChanged={emptyFunction}
                 focus={this.focusFunc}
                 backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 3a2979696..417b4c1ff 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -103,8 +103,24 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
             //         showLinks={action(() => { })}
             //     />, { x: 300, y: 300 });
         });
+
+
     }
 
+    visibleY = (el: any) => {
+        var rect = el.getBoundingClientRect(), top = rect.top, height = rect.height,
+            el = el.parentNode;
+        do {
+            rect = el.getBoundingClientRect();
+            if (top <= rect.bottom === false && getComputedStyle(el).overflow === "hidden") return rect.bottom;
+            // Check if the element is out of view due to a container scrolling
+            if ((top + height) <= rect.top && getComputedStyle(el).overflow === "hidden") return rect.top;
+            el = el.parentNode;
+        } while (el != document.body);
+        // Check its within the document viewport
+        return top;//top <= document.documentElement.clientHeight && getComputedStyle(document.documentElement).overflow === "hidden";
+    };
+
     @computed get renderData() {
         this._start;
         if (SnappingManager.GetIsDragging() || !this.props.A.ContentDiv || !this.props.B.ContentDiv || !this.props.LinkDocs.length) {
@@ -115,16 +131,18 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         const bcont = this.props.B.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
         const a = (acont.length ? acont[0] : this.props.A.ContentDiv).getBoundingClientRect();
         const b = (bcont.length ? bcont[0] : this.props.B.ContentDiv).getBoundingClientRect();
-        const apt = Utils.closestPtBetweenRectangles(a.left, a.top, a.width, a.height,
-            b.left, b.top, b.width, b.height,
+        const atop = this.visibleY(this.props.A.ContentDiv);
+        const btop = this.visibleY(this.props.B.ContentDiv);
+        const apt = Utils.closestPtBetweenRectangles(a.left, atop, a.width, a.height,
+            b.left, btop, b.width, b.height,
             a.left + a.width / 2, a.top + a.height / 2);
-        const bpt = Utils.closestPtBetweenRectangles(b.left, b.top, b.width, b.height,
-            a.left, a.top, a.width, a.height,
+        const bpt = Utils.closestPtBetweenRectangles(b.left, btop, b.width, b.height,
+            a.left, atop, a.width, a.height,
             apt.point.x, apt.point.y);
         const pt1 = [apt.point.x, apt.point.y];
         const pt2 = [bpt.point.x, bpt.point.y];
-        const pt1vec = [pt1[0] - (a.left + a.width / 2), pt1[1] - (a.top + a.height / 2)];
-        const pt2vec = [pt2[0] - (b.left + b.width / 2), pt2[1] - (b.top + b.height / 2)];
+        const pt1vec = [pt1[0] - (a.left + a.width / 2), pt1[1] - (atop + a.height / 2)];
+        const pt2vec = [pt2[0] - (b.left + b.width / 2), pt2[1] - (btop + b.height / 2)];
         const pt1len = Math.sqrt((pt1vec[0] * pt1vec[0]) + (pt1vec[1] * pt1vec[1]));
         const pt2len = Math.sqrt((pt2vec[0] * pt2vec[0]) + (pt2vec[1] * pt2vec[1]));
         const ptlen = Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) / 2;
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 875026944..42b68e8f4 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -107,7 +107,7 @@ export class LinkDocPreview extends React.Component<Props> {
                 searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionDoc={undefined}
                 ContainingCollectionView={undefined}
-                renderDepth={0}
+                renderDepth={-1}
                 PanelWidth={this.width} //Math.min(350, NumCast(target._width, 350))}
                 PanelHeight={this.height} //Math.min(250, NumCast(target._height, 250))}
                 focus={emptyFunction}
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 1c73ec8cb..a7dc55c52 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -204,6 +204,7 @@
 .pdfBox {
     width: 100%;
     height: 100%;
+    pointer-events: none;
     .pdfViewerDash-text {
         .textLayer {
             span {
@@ -213,6 +214,12 @@
     }
 }
 
+.pdfBox-background {
+    width: 100%;
+    height: 100%;
+    background: lightGray;
+}
+
 .pdfBox-interactive {
     width: 100%;
     height: 100%;
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 7bdbe3cae..266017b5b 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -247,6 +247,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
     @computed get renderPdfView() {
         const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField);
         return <div className={"pdfBox"} onContextMenu={this.specificContextMenu} style={{ height: this.props.Document._scrollTop && !this.Document._fitWidth && (window.screen.width > 600) ? NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined }}>
+            <div className="pdfBox-background"></div>
             <PDFViewer {...this.props} pdf={this._pdf!} url={pdfUrl!.url.pathname} active={this.props.active} loaded={this.loaded}
                 setPdfViewer={this.setPdfViewer} ContainingCollectionView={this.props.ContainingCollectionView}
                 renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth}
@@ -256,7 +257,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
                 ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select}
                 isSelected={this.props.isSelected} whenActiveChanged={this.whenActiveChanged}
                 isChildActive={this.isChildActive}
-                fieldKey={this.props.fieldKey} startupLive={this._initialScale < 2.5 || this.props.Document._scrollTop ? true : false} />
+                fieldKey={this.props.fieldKey} startupLive={true} />
             {this.settingsPanel()}
         </div>;
     }
@@ -264,8 +265,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
     _pdfjsRequested = false;
     render() {
         const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField, null);
-        if (this.props.isSelected() || this.props.renderDepth === 0 || this.props.Document._scrollY !== undefined) this._everActive = true;
-        if (pdfUrl && (this._everActive || this.props.Document._scrollTop)) {
+        if (this.props.isSelected() || (this.props.active() && this.props.renderDepth === 0) || this.props.Document._scrollY !== undefined) this._everActive = true;
+        if (pdfUrl && this._everActive) {
             if (pdfUrl instanceof PdfField && this._pdf) {
                 return this.renderPdfView;
             }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 8524786c8..6c71f08e7 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -96,37 +96,38 @@ export class FormattedTextBoxComment {
             FormattedTextBoxComment.tooltip.onpointerdown = async (e: PointerEvent) => {
                 const keep = e.target && (e.target as any).type === "checkbox" ? true : false;
                 const textBox = FormattedTextBoxComment.textBox;
-                if (FormattedTextBoxComment.linkDoc && !keep && textBox) {
-                    if (FormattedTextBoxComment.linkDoc.author) {
-
-                        if (FormattedTextBoxComment._deleteRef && FormattedTextBoxComment._deleteRef.contains(e.target as any)) {
+                const linkDoc = FormattedTextBoxComment.linkDoc;
+                if (linkDoc && !keep && textBox) {
+                    FormattedTextBoxComment.linkDoc = undefined;
+                    if (linkDoc.author) {
+                        if (FormattedTextBoxComment._deleteRef?.contains(e.target as any)) {
                             this.deleteLink();
                         } else if (FormattedTextBoxComment._followRef && FormattedTextBoxComment._followRef.contains(e.target as any)) {
-                            if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) {
-                                textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "add" : "add:right");
+                            if (linkDoc.type !== DocumentType.LINK) {
+                                textBox.props.addDocTab(linkDoc, e.ctrlKey ? "add" : "add:right");
                             } else {
-                                const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(FormattedTextBoxComment.linkDoc.anchor1, Doc)), textBox.dataDoc) ?
-                                    Cast(FormattedTextBoxComment.linkDoc.anchor2, Doc) : (Cast(FormattedTextBoxComment.linkDoc.anchor1, Doc))
-                                    || FormattedTextBoxComment.linkDoc);
+                                const anchor = FieldValue(Doc.AreProtosEqual(FieldValue(Cast(linkDoc.anchor1, Doc)), textBox.dataDoc) ?
+                                    Cast(linkDoc.anchor2, Doc) : (Cast(linkDoc.anchor1, Doc))
+                                    || linkDoc);
                                 const target = anchor?.annotationOn ? await DocCastAsync(anchor.annotationOn) : anchor;
 
-                                if (FormattedTextBoxComment.linkDoc.follow) {
-                                    if (FormattedTextBoxComment.linkDoc.follow === "default") {
-                                        DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false);
-                                    } else if (FormattedTextBoxComment.linkDoc.follow === "Always open in right tab") {
+                                if (linkDoc.follow) {
+                                    if (linkDoc.follow === "default") {
+                                        DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false);
+                                    } else if (linkDoc.follow === "Always open in right tab") {
                                         if (target) { textBox.props.addDocTab(target, "add:right"); }
-                                    } else if (FormattedTextBoxComment.linkDoc.follow === "Always open in new tab") {
+                                    } else if (linkDoc.follow === "Always open in new tab") {
                                         if (target) { textBox.props.addDocTab(target, "add"); }
                                     }
                                 } else {
-                                    DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false);
+                                    DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document, doc => textBox.props.addDocTab(doc, "add:right"), false);
                                 }
                             }
                         } else {
-                            if (FormattedTextBoxComment.linkDoc.type !== DocumentType.LINK) {
-                                textBox.props.addDocTab(FormattedTextBoxComment.linkDoc, e.ctrlKey ? "add" : "add:right");
+                            if (linkDoc.type !== DocumentType.LINK) {
+                                textBox.props.addDocTab(linkDoc, e.ctrlKey ? "add" : "add:right");
                             } else {
-                                DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document,
+                                DocumentManager.Instance.FollowLink(linkDoc, textBox.props.Document,
                                     (doc: Doc, followLinkLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "add" : followLinkLocation));
                             }
                         }
@@ -140,7 +141,7 @@ export class FormattedTextBoxComment {
                 e.stopPropagation();
                 e.preventDefault();
             };
-            root && root.appendChild(FormattedTextBoxComment.tooltip);
+            root?.appendChild(FormattedTextBoxComment.tooltip);
         }
     }
 
@@ -158,6 +159,7 @@ export class FormattedTextBoxComment {
         FormattedTextBoxComment.textBox = undefined;
         FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none");
         ReactDOM.unmountComponentAtNode(FormattedTextBoxComment.tooltipText);
+        FormattedTextBoxComment.linkDoc = undefined;
     }
     public static SetState(textBox: any, start: number, end: number, mark: Mark) {
         FormattedTextBoxComment.textBox = textBox;
@@ -312,7 +314,7 @@ export class FormattedTextBoxComment {
                                             searchFilterDocs={returnEmptyDoclist}
                                             ContainingCollectionDoc={undefined}
                                             ContainingCollectionView={undefined}
-                                            renderDepth={0}
+                                            renderDepth={-1}
                                             PanelWidth={() => 175} //Math.min(350, NumCast(target._width, 350))}
                                             PanelHeight={() => 175} //Math.min(250, NumCast(target._height, 250))}
                                             focus={emptyFunction}
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index 86c73bfee..70b4c417c 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -2,6 +2,8 @@
 .pdfViewerDash, .pdfViewerDash-interactive {
     width: 100%;
     height: 100%;
+    top: 0;
+    left:0;
     position: absolute;
     overflow-y: auto;
     overflow-x: hidden;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 03ccca019..e7702fb5e 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -33,8 +33,10 @@ import "./PDFViewer.scss";
 const pdfjs = require('pdfjs-dist/es5/build/pdf.js');
 import React = require("react");
 import { LinkDocPreview } from "../nodes/LinkDocPreview";
+import { FormattedTextBoxComment } from "../nodes/formattedText/FormattedTextBoxComment";
 const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
 const pdfjsLib = require("pdfjs-dist");
+const _global = (window /* browser */ || global /* node */) as any;
 
 export const pageSchema = createSchema({
     _curPage: "number",
@@ -144,9 +146,14 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
             };
             this._coverPath = "http://cs.brown.edu/~bcz/face.gif";//href.startsWith(window.location.origin) ? await Networking.PostToServer("/thumbnail", params) : { width: 100, height: 100, path: "" };
         }
-        runInAction(() => this._showWaiting = this._showCover = true);
+        runInAction(() => this._showWaiting = true);
         this.props.startupLive && this.setupPdfJsViewer();
-        this._mainCont.current && (this._mainCont.current.scrollTop = this.layoutDoc._scrollTop || 0);
+        if (this._mainCont.current) {
+            this._mainCont.current.scrollTop = this.layoutDoc._scrollTop || 0;
+            const observer = new _global.ResizeObserver(action((entries: any) => this._mainCont.current && (this._mainCont.current.scrollTop = this.layoutDoc._scrollTop || 0)));
+            observer.observe(this._mainCont.current);
+        }
+
         this._disposers.searchMatch = reaction(() => Doc.IsSearchMatch(this.rootDoc),
             m => {
                 if (m) (this._lastSearch = true) && this.search(Doc.SearchQuery(), m.searchMatch > 0);
@@ -168,7 +175,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
             (scrollY) => {
                 if (scrollY !== undefined) {
                     (this._showCover || this._showWaiting) && this.setupPdfJsViewer();
-                    (!LinkDocPreview.TargetDoc) && this._mainCont.current && smoothScroll(1000, this._mainCont.current, (this.Document._scrollY || 0));
+                    (this.props.renderDepth === -1 || (!LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc)) && this._mainCont.current && smoothScroll(1000, this._mainCont.current, (this.Document._scrollY || 0));
                     setTimeout(() => this.Document._scrollY = undefined, 1000);
                 }
             },
@@ -265,7 +272,9 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         document.addEventListener("copy", this.copy);
         const eventBus = new PDFJSViewer.EventBus(true);
         eventBus._on("pagesinit", this.pagesinit);
-        eventBus._on("pagerendered", action(() => this._showCover = this._showWaiting = false));
+        eventBus._on("pagerendered", action(() => {
+            this._showWaiting = false;
+        }));
         const pdfLinkService = new PDFJSViewer.PDFLinkService({ eventBus });
         const pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService, eventBus });
         this._pdfViewer = new PDFJSViewer.PDFViewer({
@@ -369,12 +378,14 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
     pageDelay: any;
     @action
     onScroll = (e: React.UIEvent<HTMLElement>) => {
-        this.Document._scrollY === undefined && (this.layoutDoc._scrollTop = this._mainCont.current!.scrollTop);
-        this.pageDelay && clearTimeout(this.pageDelay);
-        this.pageDelay = setTimeout(() => {
-            this.pageDelay = undefined;
-            this._pdfViewer && (this.Document._curPage = this._pdfViewer.currentPageNumber);
-        }, 250);
+        if (!LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
+            this.Document._scrollY === undefined && (this.layoutDoc._scrollTop = this._mainCont.current!.scrollTop);
+            this.pageDelay && clearTimeout(this.pageDelay);
+            this.pageDelay = setTimeout(() => {
+                this.pageDelay = undefined;
+                this._pdfViewer && (this.Document._curPage = this._pdfViewer.currentPageNumber);
+            }, 250);
+        }
     }
 
     // get the page index that the vertical offset passed in is on
-- 
cgit v1.2.3-70-g09d2


From 075b626e1eab5d2852d5157c4105e3110e4fe7e4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 10 Sep 2020 10:16:59 -0400
Subject: fixed shift-dragging of tabs

---
 src/client/views/collections/CollectionDockingView.tsx | 2 +-
 src/client/views/collections/TabDocView.tsx            | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index c891d2035..bed7e9735 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -353,7 +353,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
 
     tabDestroyed = (tab: any) => {
         this.tabMap.delete(tab);
-        Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
+        tab._disposers && Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
         tab.reactComponents?.forEach((ele: any) => ReactDOM.unmountComponentAtNode(ele));
     }
     tabCreated = (tab: any) => {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 589649ad9..5ace82b3c 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -367,7 +367,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         return (<div className="collectionDockingView-content" ref={ref => {
             if (this._mainCont = ref) {
                 (this._mainCont as any).InitTab = (tab: any) => this.init(tab, this._document);
-                this.tab && DocServer.GetRefField(this.tab.contentItem.config.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.init(this.tab, this._document)));
+                DocServer.GetRefField(this.props.documentId).then(action(doc => doc instanceof Doc && (this._document = doc) && this.tab && this.init(this.tab, this._document)));
             }
         }}
             style={{
-- 
cgit v1.2.3-70-g09d2


From 51eea45ec6ee39cb83ee3b0780ad262b8b8b5dd8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 10 Sep 2020 20:10:58 -0400
Subject: made basic progressivized slides using TreeView

---
 src/client/documents/Documents.ts                  |  2 +
 src/client/util/CurrentUserUtils.ts                |  4 ++
 src/client/views/EditableView.tsx                  | 23 ++++++----
 src/client/views/PropertiesView.tsx                |  2 +-
 .../views/collections/CollectionTreeView.scss      | 13 +++++-
 .../views/collections/CollectionTreeView.tsx       | 49 ++++++++++++++++++----
 src/client/views/collections/CollectionView.tsx    |  2 +-
 src/client/views/collections/TabDocView.tsx        |  4 ++
 .../collections/collectionFreeForm/MarqueeView.tsx | 24 +++++++----
 src/client/views/nodes/DocumentView.tsx            |  3 --
 src/client/views/nodes/PresBox.tsx                 | 16 ++++---
 11 files changed, 105 insertions(+), 37 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 2f7b5a449..f67887c09 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -130,6 +130,7 @@ export interface DocumentOptions {
     opacity?: number;
     defaultBackgroundColor?: string;
     _isBackground?: boolean;
+    "_isBackground-canClick"?: boolean; // a background document that you can still click on to edit its contents
     isLinkButton?: boolean;
     _columnWidth?: number;
     _fontSize?: string;
@@ -195,6 +196,7 @@ export interface DocumentOptions {
     treeViewExpandedView?: string; // which field/thing is displayed when this item is opened in tree view
     treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked
     treeViewTruncateTitleWidth?: number;
+    treeViewOutlineMode?: boolean; // whether slide should function as a text outline
     treeViewLockExpandedView?: boolean; // whether the expanded view can be changed
     treeViewDefaultExpandedView?: string; // default expanded view
     limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 2f08aa928..b3567a4e8 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -418,6 +418,9 @@ export class CurrentUserUtils {
             doc.emptyPane = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _width: 500, _height: 800, title: "Untitled Tab", system: true, cloneFieldFilter: new List<string>(["system"]) });
             ((doc.emptyPane as Doc).proto as Doc)["dragFactory-count"] = 0;
         }
+        if (doc.emptySlide === undefined) {
+            doc.emptySlide = Docs.Create.TreeDocument([], { title: "slide", treeViewOutlineMode: true, "_isBackground-canClick": true, _backgroundColor: "transparent", _width: 300, _height: 300, system: true, cloneFieldFilter: new List<string>(["system"]) });
+        }
         if (doc.emptyComparison === undefined) {
             doc.emptyComparison = Docs.Create.ComparisonDocument({ title: "compare", _width: 300, _height: 300, system: true, cloneFieldFilter: new List<string>(["system"]) });
         }
@@ -453,6 +456,7 @@ export class CurrentUserUtils {
         return [
             { toolTip: "Tap to create a collection in a new pane, drag for a collection", title: "Col", icon: "folder", click: 'openOnRight(copyDragFactory(this.clickFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyCollection as Doc, noviceMode: true, clickFactory: doc.emptyPane as Doc, },
             { toolTip: "Tap to create a webpage in a new pane, drag for a webpage", title: "Web", icon: "globe-asia", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyWebpage as Doc, noviceMode: true },
+            { toolTip: "Tap to create a progressive slide", title: "Slide", icon: "file", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptySlide as Doc, noviceMode: true },
             { toolTip: "Tap to create a cat image in a new pane, drag for a cat image", title: "Image", icon: "cat", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyImage as Doc },
             { toolTip: "Tap to create a comparison box in a new pane, drag for a comparison box", title: "Compare", icon: "columns", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyComparison as Doc, noviceMode: true },
             { toolTip: "Tap to create a screen grabber in a new pane, drag for a screen grabber", title: "Grab", icon: "photo-video", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScreenshot as Doc },
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 1b4b9a2be..cbbd78a20 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -18,11 +18,12 @@ export interface EditableProps {
      * @param value - The string entered by the user to set the value to
      * @returns `true` if setting the value was successful, `false` otherwise
      *  */
-    SetValue(value: string, shiftDown?: boolean): boolean;
+    SetValue(value: string, shiftDown?: boolean, enterKey?: boolean): boolean;
 
     OnFillDown?(value: string): void;
 
     OnTab?(shift?: boolean): void;
+    OnEmpty?(): void;
 
     /**
      * The contents to render when not editing
@@ -93,13 +94,17 @@ export class EditableView extends React.Component<EditableProps> {
         switch (e.key) {
             case "Tab":
                 e.stopPropagation();
-                this.finalizeEdit(e.currentTarget.value, e.shiftKey, false);
-                this.props.OnTab && this.props.OnTab(e.shiftKey);
+                this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, false);
+                this.props.OnTab?.(e.shiftKey);
+                break;
+            case "Backspace":
+                e.stopPropagation();
+                if (!e.currentTarget.value) this.props.OnEmpty?.();
                 break;
             case "Enter":
                 e.stopPropagation();
                 if (!e.ctrlKey) {
-                    this.finalizeEdit(e.currentTarget.value, e.shiftKey, false);
+                    this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true);
                 } else if (this.props.OnFillDown) {
                     this.props.OnFillDown(e.currentTarget.value);
                     this._editing = false;
@@ -130,10 +135,10 @@ export class EditableView extends React.Component<EditableProps> {
     }
 
     @action
-    private finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean) {
-        if (this.props.SetValue(value, shiftDown)) {
+    private finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) {
+        if (this.props.SetValue(value, shiftDown, enterKey)) {
             this._editing = false;
-            this.props.isEditingCallback?.(false);
+            this.props.isEditingCallback?.(false,);
         } else {
             this._editing = false;
             this.props.isEditingCallback?.(false);
@@ -164,7 +169,7 @@ export class EditableView extends React.Component<EditableProps> {
                     className: "editableView-input",
                     onKeyDown: this.onKeyDown,
                     autoFocus: true,
-                    onBlur: e => this.finalizeEdit(e.currentTarget.value, false, true),
+                    onBlur: e => this.finalizeEdit(e.currentTarget.value, false, true, false),
                     onPointerDown: this.stopPropagation,
                     onClick: this.stopPropagation,
                     onPointerUp: this.stopPropagation,
@@ -178,7 +183,7 @@ export class EditableView extends React.Component<EditableProps> {
                 onKeyDown={this.onKeyDown}
                 autoFocus={true}
                 onKeyPress={e => e.stopPropagation()}
-                onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true)}
+                onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)}
                 onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation}
                 style={{ display: this.props.display, fontSize: this.props.fontSize, minWidth: 20 }}
                 placeholder={this.props.placeholder}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index d70f4b332..5a9402d70 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1040,7 +1040,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     </div>}
                     {!selectedItem ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
-                            onPointerDown={action(() => { this.openPresProgressivize = !this.openPresProgressivize; })}
+                            onPointerDown={action(() => this.openPresProgressivize = !this.openPresProgressivize)}
                             style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
                             &nbsp; <FontAwesomeIcon icon={"tasks"} /> &nbsp; Progressivize
                         <div className="propertiesView-presTrails-title-icon">
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index e192f1760..3f437b799 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -30,6 +30,14 @@
         padding-left: 0;
     }
 
+    .outline-bullet {
+        position: relative;
+        width: 15px;
+        color: $intermediate-color;
+        margin-top: 3px;
+        transform: scale(0.5);
+    }
+
     .bullet {
         position: relative;
         width: 15px;
@@ -106,11 +114,14 @@
     cursor: pointer;
 }
 
+.treeViewItem-border-outline,
 .treeViewItem-border {
     display: flex;
-    border-left: dashed 1px #00000042;
     overflow: hidden;
 }
+.treeViewItem-border{
+    border-left: dashed 1px #00000042;
+}
 
 .treeViewItem-header-editing,
 .treeViewItem-header {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index d2b86d3c6..a6975f517 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -181,22 +181,38 @@ class TreeView extends React.Component<TreeViewProps> {
         fontStyle={style}
         fontSize={12}
         GetValue={() => StrCast(this.doc[key])}
-        SetValue={undoBatch((value: string) => {
-            Doc.SetInPlace(this.doc, key, value, false) || true;
-            Doc.SetInPlace(this.doc, "editTitle", undefined, false);
+        SetValue={undoBatch((value: string, shiftKey: boolean, enterKey: boolean) => {
+            if (this.props.treeView.doc.treeViewOutlineMode && enterKey) {
+                Doc.SetInPlace(this.doc, key, value, false);
+                const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
+                Doc.SetInPlace(this.doc, "editTitle", undefined, false);
+                Doc.SetInPlace(doc, "editTitle", "*", false);
+                this.props.addDocument(doc);
+                doc.context = this.props.treeView.Document;
+            } else {
+                Doc.SetInPlace(this.doc, key, value, false) || true;
+                Doc.SetInPlace(this.doc, "editTitle", undefined, false);
+            }
         })}
         OnFillDown={undoBatch((value: string) => {
             Doc.SetInPlace(this.doc, key, value, false);
-            const doc = Docs.Create.FreeformDocument([], { title: "-", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
+            const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
             Doc.SetInPlace(this.doc, "editTitle", undefined, false);
             Doc.SetInPlace(doc, "editTitle", "*", false);
-            return this.props.addDocument(doc);
+            const added = this.props.addDocument(doc);
+            doc.context = this.props.treeView.Document;
+            return added;
         })}
         onClick={() => {
             SelectionManager.DeselectAll();
             Doc.UserDoc().activeSelection = new List([this.doc]);
             return false;
         }}
+        OnEmpty={undoBatch(() => {
+            if (this.props.treeView.doc.treeViewOutlineMode) {
+                this.props.removeDoc?.(this.doc);
+            }
+        })}
         OnTab={undoBatch((shift?: boolean) => {
             shift ? this.props.outdentDocument?.() : this.props.indentDocument?.();
             setTimeout(() => Doc.SetInPlace(this.doc, "editTitle", `${this.props.treeView._uniqueId}`, false), 0);
@@ -398,13 +414,25 @@ class TreeView extends React.Component<TreeViewProps> {
         e.stopPropagation();
     }
 
+    @computed get renderOutlineBullet() {
+        TraceMobx();
+        return <div className="outline-bullet"
+            title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
+            onClick={this.bulletClick}
+            style={{ opacity: NumCast(this.doc.opacity, 1) }}>
+            {<FontAwesomeIcon icon={"circle"} />}
+        </div>;
+    }
     @computed get renderBullet() {
         TraceMobx();
         const checked = this.doc.type === DocumentType.COL ? undefined : this.onCheckedClick ? (this.doc.treeViewChecked ?? "unchecked") : undefined;
         return <div className="bullet"
             title={this.childDocs?.length ? `click to see ${this.childDocs?.length} items` : "view fields"}
             onClick={this.bulletClick}
-            style={{ color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"), opacity: checked === "unchecked" ? undefined : 0.4 }}>
+            style={{
+                color: StrCast(this.doc.color, checked === "unchecked" ? "white" : "inherit"),
+                opacity: checked === "unchecked" ? undefined : 0.4
+            }}>
             {<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs?.length ? "caret-square-right" : "caret-right") : (this.childDocs?.length ? "caret-square-down" : "caret-down"))} />}
         </div>;
     }
@@ -521,10 +549,10 @@ class TreeView extends React.Component<TreeViewProps> {
                             }
                         }}
                         onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
-                        {this.renderBullet}
+                        {this.props.treeView.props.Document.treeViewOutlineMode ? this.renderOutlineBullet : this.renderBullet}
                         {this.renderTitle}
                     </div>
-                    <div className="treeViewItem-border" style={{ borderColor: sorting === undefined ? undefined : sorting ? "crimson" : "blue" }}>
+                    <div className={`treeViewItem-border${this.props.treeView.props.Document.treeViewOutlineMode ? "outline" : ""}`} style={{ borderColor: sorting === undefined ? undefined : sorting ? "crimson" : "blue" }}>
                         {!this.treeViewOpen || this.props.renderedIds.indexOf(this.doc[Id]) !== -1 ? (null) : this.renderContent}
                     </div>
                 </li>
@@ -617,6 +645,7 @@ class TreeView extends React.Component<TreeViewProps> {
                         Doc.AddDocToList(docs[i - 1], fieldKey, child);
                         docs[i - 1].treeViewOpen = true;
                         remove(child);
+                        child.context = treeView.Document;
                     }
                 }
             };
@@ -627,6 +656,7 @@ class TreeView extends React.Component<TreeViewProps> {
                     Doc.AddDocToList(parentCollectionDoc, fieldKey, child, parentPrevSibling, false);
                     parentCollectionDoc.treeViewOpen = true;
                     remove(child);
+                    child.context = treeView.Document;
                 }
             };
             const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => {
@@ -729,8 +759,11 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                 flg && Doc.AddDocToList(this.doc[DataSym], this.props.fieldKey, doc, relativeTo, before, false, false, false), true);
         if (this.doc.resolvedDataDoc instanceof Promise) {
             this.doc.resolvedDataDoc.then((resolved: any) => doAddDoc(doc));
+        } else if (relativeTo === undefined) {
+            this.props.addDocument(doc);
         } else {
             doAddDoc(doc);
+            (doc instanceof Doc ? [doc] : doc).forEach(d => d.context = this.props.Document);
         }
         return true;
     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 6939399e6..7084aba40 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -391,7 +391,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
             ChildLayoutTemplate: this.childLayoutTemplate,
             ChildLayoutString: this.childLayoutString,
         };
-        const boxShadow = Doc.UserDoc().renderStyle === "comic" || this.props.Document._isBackground || this.collectionViewType === CollectionViewType.Linear ? undefined :
+        const boxShadow = Doc.UserDoc().renderStyle === "comic" || this.props.Document.treeViewOutlineMode || this.props.Document._isBackground || this.collectionViewType === CollectionViewType.Linear ? undefined :
             `${CurrentUserUtils.ActiveDashboard?.darkScheme ? "rgb(30, 32, 31) " : "#9c9396 "} ${StrCast(this.props.Document.boxShadow, "0.2vw 0.2vw 0.8vw")}`;
         return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
             style={{ pointerEvents: this.props.Document._isBackground ? "none" : undefined, boxShadow }}>
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 5ace82b3c..aa1852250 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -146,6 +146,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     CollectionDockingView.AddSplit(curPres, "right");
                 }
                 DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null));
+                setTimeout(() => {
+                    curPres._itemIndex = DocListCast(curPres.data).length - 1;
+                    doc.treeViewOutlineMode && PresBox.Instance.progressivizeChild(null as any);
+                }, 100);
             }
         }
     }
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index deb7e68e8..ebad3bf45 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -116,15 +116,23 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                 })();
                 e.stopPropagation();
             } else if (e.key === "b" && e.ctrlKey) {
+                // e.preventDefault();
+                // navigator.clipboard.readText().then(text => {
+                //     const ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== "");
+                //     if (ns.length === 1 && text.startsWith("http")) {
+                //         this.props.addDocument(Docs.Create.ImageDocument(text, { _nativeWidth: 300, _width: 300, x: x, y: y }));// paste an image from its URL in the paste buffer
+                //     } else {
+                //         this.pasteTable(ns, x, y);
+                //     }
+                // });
+                // e.stopPropagation();
+
                 e.preventDefault();
-                navigator.clipboard.readText().then(text => {
-                    const ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== "");
-                    if (ns.length === 1 && text.startsWith("http")) {
-                        this.props.addDocument(Docs.Create.ImageDocument(text, { _nativeWidth: 300, _width: 300, x: x, y: y }));// paste an image from its URL in the paste buffer
-                    } else {
-                        this.pasteTable(ns, x, y);
-                    }
-                });
+                const slide = Doc.copyDragFactory(Doc.UserDoc().emptySlide as Doc)!;
+                slide.x = x;
+                slide.y = y;
+                this.props.addDocument(slide);
+                setTimeout(() => SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(slide)!, false));
                 e.stopPropagation();
             } else if (!e.ctrlKey && !e.metaKey) {
                 FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout ? e.key : "";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7ef5eaf54..7b7c3578b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -593,9 +593,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         if (CurrentUserUtils.ActiveDashboard === this.props.Document) {
             alert("Can't delete the active dashboard");
         } else {
-            const selected = SelectionManager.SelectedDocuments().slice();
-            SelectionManager.DeselectAll();
-            selected.map(dv => dv.props.removeDocument?.(dv.props.Document));
             this.props.removeDocument?.(this.props.Document);
         }
     }
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 99fb5d2ce..79f1b7ddc 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -1258,7 +1258,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                     <div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                         <div className="ribbon-box">
                             {this.stringType} selected
-                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform' ? "inline-flex" : "none" }}>
+                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc.type === DocumentType.COL ? "inline-flex" : "none" }}>
                                 <div className="ribbon-button" style={{ backgroundColor: activeItem.presProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeChild}>Contents</div>
                                 <div className="ribbon-button" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} onClick={this.editProgressivize}>Edit</div>
                             </div>
@@ -1435,18 +1435,22 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     }
 
     @action
-    progressivizeChild = (e: React.MouseEvent) => {
-        e.stopPropagation();
+    progressivizeChild = (e?: React.MouseEvent) => {
+        e?.stopPropagation();
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
-        const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
         if (!activeItem.presProgressivize) {
             targetDoc.editing = false;
             activeItem.presProgressivize = true;
             targetDoc.presProgressivize = true;
             targetDoc._currentFrame = 0;
-            docs.forEach((doc, i) => CollectionFreeFormDocumentView.setupKeyframes([doc], i, true));
-            targetDoc.lastFrame = docs.length - 1;
+            let count = 0;
+            const setupProgressivize = (doc: Doc) => {
+                CollectionFreeFormDocumentView.setupKeyframes([doc], count++, true);
+                targetDoc.treeViewOutlineMode && DocListCast(doc[Doc.LayoutFieldKey(doc)]).forEach(d => setupProgressivize(d));
+            }
+            setupProgressivize(targetDoc);
+            targetDoc.lastFrame = count;
         } else {
             targetDoc.editProgressivize = false;
             activeItem.presProgressivize = false;
-- 
cgit v1.2.3-70-g09d2


From 5b4a692b0c87a58e17c0ae799f935e22a326b856 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 11 Sep 2020 23:42:55 -0400
Subject: moved minimap button to bottom-right of tab panes

---
 src/client/views/collections/CollectionMenu.tsx |  12 ---
 src/client/views/collections/TabDocView.scss    |  18 +++++
 src/client/views/collections/TabDocView.tsx     | 100 ++++++++++++------------
 3 files changed, 70 insertions(+), 60 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5c0a3777f..a58edc604 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -561,11 +561,6 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
         CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice());
         this.document._currentFrame = Math.max(0, (currentFrame || 0) - 1);
     }
-    @undoBatch
-    @action
-    miniMap = (): void => {
-        this.document.hideMinimap = !this.document.hideMinimap;
-    }
 
     private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""];
     private _width = ["1", "5", "10", "100"];
@@ -849,13 +844,6 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
     render() {
         return !this.props.docView.layoutDoc ? (null) :
             <div className="collectionFreeFormMenu-cont">
-                {this.props.docView.props.renderDepth !== 0 || this.isText || this.props.isDoc ? (null) :
-                    <Tooltip key="map" title={<div className="dash-tooltip">Toggle Mini Map</div>} placement="bottom">
-                        <div className="backKeyframe" onClick={this.miniMap} style={{ marginRight: "5px" }}>
-                            <FontAwesomeIcon icon={"map"} size={"lg"} />
-                        </div>
-                    </Tooltip>
-                }
                 {!this.isText && !this.props.isDoc ? <Tooltip key="back" title={<div className="dash-tooltip">Back Frame</div>} placement="bottom">
                     <div className="backKeyframe" onClick={this.prevKeyframe}>
                         <FontAwesomeIcon icon={"caret-left"} size={"lg"} />
diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss
index fdb801e03..b808f3ae4 100644
--- a/src/client/views/collections/TabDocView.scss
+++ b/src/client/views/collections/TabDocView.scss
@@ -1,6 +1,7 @@
 input.lm_title:focus {
     max-width: max-content !important;
 }
+.miniMap-hidden,
 .miniMap {
     position: absolute;
     overflow: hidden;
@@ -8,6 +9,9 @@ input.lm_title:focus {
     bottom: 10;
     border: solid 1px;
     box-shadow: black 0.4vw 0.4vw 0.8vw;
+    width: 100%;
+    height: 100%;
+    transition: all 0.5s;
 
     .miniOverlay {
         width: 100%;
@@ -19,4 +23,18 @@ input.lm_title:focus {
             position: absolute;
         }
     }
+}
+.miniMap-hidden {
+    position: absolute;
+    bottom: 0;
+    right: 0;
+    width: 40px;
+    height: 40px;
+    background: transparent;
+    transform: translate(20px, 20px) rotate(45deg);
+    border-radius: 30px;
+    > svg {
+        margin-top: 3px;
+        transform: translate(0px, 7px);
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index aa1852250..f4fda67cd 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -27,6 +27,7 @@ import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
 import { CollectionViewType } from './CollectionView';
 import React = require("react");
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
@@ -282,54 +283,57 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     }
 
     renderMiniMap() {
-        return <div className="miniMap" style={{
-            width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor,
-                StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!, 0))),
-        }}>
-            <CollectionFreeFormView
-                Document={this._document!}
-                LibraryPath={emptyPath}
-                CollectionView={undefined}
-                ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
-                ChildLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid havin to set stuff like this.
-                noOverlay={true} // don't render overlay Docs since they won't scale
-                active={returnTrue}
-                select={emptyFunction}
-                dropAction={undefined}
-                isSelected={returnFalse}
-                dontRegisterView={true}
-                annotationsKey={""}
-                fieldKey={Doc.LayoutFieldKey(this._document!)}
-                bringToFront={emptyFunction}
-                rootSelected={returnTrue}
-                addDocument={returnFalse}
-                moveDocument={returnFalse}
-                removeDocument={returnFalse}
-                ContentScaling={returnOne}
-                PanelWidth={this.returnMiniSize}
-                PanelHeight={this.returnMiniSize}
-                ScreenToLocalTransform={this.ScreenToLocalTransform}
-                renderDepth={0}
-                whenActiveChanged={emptyFunction}
-                focus={emptyFunction}
-                backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
-                addDocTab={this.addDocTab}
-                pinToPres={TabDocView.PinDoc}
-                docFilters={CollectionDockingView.Instance.docFilters}
-                searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
-                fitToBox={true}
-            />
-            <div className="miniOverlay" onPointerDown={this.miniDown} >
-                <div className="miniThumb" style={{
-                    width: `${this.miniWidth}% `,
-                    height: `${this.miniHeight}% `,
-                    left: `${this.miniLeft}% `,
-                    top: `${this.miniTop}% `,
-                }}
-                />
+        return <>
+            {this._document?.hideMinimap ? (null) :
+                <div className="miniMap" style={{ width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor, StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!, 0))), }}>
+                    <CollectionFreeFormView
+                        Document={this._document!}
+                        LibraryPath={emptyPath}
+                        CollectionView={undefined}
+                        ContainingCollectionView={undefined}
+                        ContainingCollectionDoc={undefined}
+                        ChildLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid havin to set stuff like this.
+                        noOverlay={true} // don't render overlay Docs since they won't scale
+                        active={returnTrue}
+                        select={emptyFunction}
+                        dropAction={undefined}
+                        isSelected={returnFalse}
+                        dontRegisterView={true}
+                        annotationsKey={""}
+                        fieldKey={Doc.LayoutFieldKey(this._document!)}
+                        bringToFront={emptyFunction}
+                        rootSelected={returnTrue}
+                        addDocument={returnFalse}
+                        moveDocument={returnFalse}
+                        removeDocument={returnFalse}
+                        ContentScaling={returnOne}
+                        PanelWidth={this.returnMiniSize}
+                        PanelHeight={this.returnMiniSize}
+                        ScreenToLocalTransform={this.ScreenToLocalTransform}
+                        renderDepth={0}
+                        whenActiveChanged={emptyFunction}
+                        focus={emptyFunction}
+                        backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
+                        addDocTab={this.addDocTab}
+                        pinToPres={TabDocView.PinDoc}
+                        docFilters={CollectionDockingView.Instance.docFilters}
+                        searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
+                        fitToBox={true}
+                    />
+                    <div className="miniOverlay" onPointerDown={this.miniDown} >
+                        <div className="miniThumb" style={{
+                            width: `${this.miniWidth}% `,
+                            height: `${this.miniHeight}% `,
+                            left: `${this.miniLeft}% `,
+                            top: `${this.miniTop}% `,
+                        }}
+                        />
+                    </div>
+                </div>}
+            <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
+                <FontAwesomeIcon icon={"globe-asia"} size="lg" />
             </div>
-        </div>;
+        </>;
     }
     focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => afterFocus?.();
     setView = action((view: DocumentView) => this._view = view);
@@ -363,7 +367,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined} />
-                {this._document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)}
+                {this._document!._viewType !== CollectionViewType.Freeform ? (null) : this.renderMiniMap()}
             </>;
     }
 
-- 
cgit v1.2.3-70-g09d2


From 6c03a4ad74ca93311139e8fecda8a4793c103488 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 14 Sep 2020 22:17:54 -0400
Subject: updated header text view.  fixed dragging tree view items to
 unregister listeners. fixed contextMenu icon selection to ignore
 dashFieldViews.   fixed selectOnLoadChar to not apply when a
 childlayoutstring is specified.  fixed dropping text box on item view to only
 use json parseable text.

---
 src/client/documents/Documents.ts                  |  1 +
 src/client/util/CurrentUserUtils.ts                | 13 ++++++++--
 src/client/views/DocumentButtonBar.tsx             |  1 +
 src/client/views/PreviewCursor.tsx                 |  4 +--
 src/client/views/collections/CollectionMenu.tsx    |  6 +++--
 .../views/collections/CollectionTreeView.tsx       | 12 +++++++++
 src/client/views/collections/TabDocView.tsx        | 12 ++++++---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  4 +--
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 src/client/views/nodes/AudioBox.tsx                |  4 +--
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  2 +-
 src/client/views/nodes/ComparisonBox.tsx           |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  6 ++---
 .../nodes/formattedText/FormattedTextBox.scss      |  5 +++-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 29 +++++++++++++++-------
 15 files changed, 73 insertions(+), 30 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index d22e20101..0911f3e04 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -98,6 +98,7 @@ export interface DocumentOptions {
     layoutKey?: string;
     type?: string;
     title?: string;
+    version?: string; // version identifier for a document
     label?: string;
     hidden?: boolean;
     userDoc?: Doc; // the userDocument
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index b38cdabbc..6d4035b75 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -408,7 +408,7 @@ export class CurrentUserUtils {
             FormattedTextBox.SelectOnLoad = textDoc[Id];
             doc.emptySlide = textDoc;
         }
-        if (doc.emptyHeader === undefined) {
+        if (doc.emptyHeader === undefined || (doc.emptyHeader as Doc).version !== "0") {
             const json = {
                 doc: {
                     type: "doc",
@@ -428,7 +428,7 @@ export class CurrentUserUtils {
                 selection: { type: "text", anchor: 1, head: 1 },
                 storedMarks: []
             };
-            const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { title: "header", target: doc, _headerHeight: 24, _headerFontSize: 9, _autoHeight: true, system: true, cloneFieldFilter: new List<string>(["system"]) }, "header"); // text needs to be a space to allow templateText to be created
+            const headerTemplate = Docs.Create.RTFDocument(new RichTextField(JSON.stringify(json), ""), { title: "header", version: "0", target: doc, _height: 70, _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, system: true, cloneFieldFilter: new List<string>(["system"]) }, "header"); // text needs to be a space to allow templateText to be created
             headerTemplate[DataSym].layout =
                 "<div>" +
                 "    <FormattedTextBox {...props} fieldKey={'header'} dontSelectOnLoad={'true'} ignoreAutoHeight={'true'} pointerEvents='{this._headerPointerEvents||`none`}' fontSize='{this._headerFontSize}px' height='{this._headerHeight}px' background='{this._headerColor||this.target.userColor}' />" +
@@ -1001,6 +1001,15 @@ export class CurrentUserUtils {
         doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true });
         doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true });
 
+        // uncomment this to setup a default note style that uses the custom header layout
+        PromiseValue(doc.emptyHeader).then(factory => {
+            if (Cast(doc.defaultTextLayout, Doc, null)?.version !== "0") {
+                const deleg = Doc.delegateDragFactory(factory as Doc);
+                deleg.title = "header";
+                doc.defaultTextLayout = new PrefetchProxy(deleg);
+                Doc.AddDocToList(Cast(doc["template-notes"], Doc, null), "data", deleg);
+            }
+        });
         return doc;
     }
 
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index e8b18fca4..7629ed173 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -298,6 +298,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
         while (child.children.length) {
             const next = Array.from(child.children).find(c => typeof (c.className) === "string");
             if (next?.className.includes("documentView-node")) break;
+            if (next?.className.includes("dashFieldView")) break;
             if (next) child = next;
             else break;
         }
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index 7575aa430..ee5a390a7 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -22,7 +22,7 @@ export class PreviewCursor extends React.Component<{}> {
     static _getTransform: () => Transform;
     static _addDocument: (doc: Doc | Doc[]) => void;
     static _addLiveTextDoc: (doc: Doc) => void;
-    static _nudge?: (x: number, y: number) => boolean;
+    static _nudge?: undefined | ((x: number, y: number) => boolean);
     @observable static _clickPoint = [0, 0];
     @observable public static Visible = false;
     constructor(props: any) {
@@ -158,7 +158,7 @@ export class PreviewCursor extends React.Component<{}> {
         addLiveText: (doc: Doc) => void,
         getTransform: () => Transform,
         addDocument: (doc: Doc | Doc[]) => boolean,
-        nudge: (nudgeX: number, nudgeY: number) => boolean) {
+        nudge: undefined | ((nudgeX: number, nudgeY: number) => boolean)) {
         this._clickPoint = [x, y];
         this._onKeyPress = onKeyPress;
         this._addLiveTextDoc = addLiveText;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 8342c5b12..9e67faed5 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -123,8 +123,10 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         params: ["target", "source"], title: "item view",
         script: "self.target.childLayoutTemplate = getDocTemplate(self.source?.[0])",
         immediate: undoBatch((source: Doc[]) => {
-            if (source.length === 1 && source[0].type === DocumentType.RTF && Cast(source[0].text, RichTextField, null)?.Text) {
-                Doc.SetInPlace(this.target, "childLayoutString", Cast(source[0].text, RichTextField, null)?.Text, false);
+            let formatStr = source.length && Cast(source[0].text, RichTextField, null)?.Text;
+            try { formatStr && JSON.parse(formatStr); } catch (e) { formatStr = ""; }
+            if (source.length === 1 && formatStr) {
+                Doc.SetInPlace(this.target, "childLayoutString", formatStr, false);
             } else if (source.length) {
                 this.target.childLayoutTemplate = Doc.getDocTemplate(source?.[0]);
             } else {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 60ce7e001..463439762 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -145,15 +145,25 @@ class TreeView extends React.Component<TreeViewProps> {
     }
 
     componentWillUnmount() {
+        console.log("DISMOUT" + this.doc.title);
         document.removeEventListener("pointermove", this.onDragMove, true);
+        document.removeEventListener("pointermove", this.onDragUp, true);
     }
 
+    onDragUp = (e: PointerEvent) => {
+        console.log("DUP" + this.doc.title);
+        document.removeEventListener("pointerup", this.onDragUp, true);
+        document.removeEventListener("pointermove", this.onDragMove, true);
+    }
     onPointerEnter = (e: React.PointerEvent): void => {
         this.props.active(true) && Doc.BrushDoc(this.dataDoc);
         if (e.buttons === 1 && SnappingManager.GetIsDragging()) {
             this._header!.current!.className = "treeViewItem-header";
             document.removeEventListener("pointermove", this.onDragMove, true);
             document.addEventListener("pointermove", this.onDragMove, true);
+            document.removeEventListener("pointerup", this.onDragUp, true);
+            document.addEventListener("pointerup", this.onDragUp, true);
+            console.log("DSTART" + this.doc.title);
         }
     }
     onPointerLeave = (e: React.PointerEvent): void => {
@@ -161,6 +171,8 @@ class TreeView extends React.Component<TreeViewProps> {
         if (this._header?.current?.className !== "treeViewItem-header-editing") {
             this._header!.current!.className = "treeViewItem-header";
         }
+        console.log("DLEAVE" + this.doc.title);
+        document.removeEventListener("pointerup", this.onDragUp, true);
         document.removeEventListener("pointermove", this.onDragMove, true);
     }
     onDragMove = (e: PointerEvent): void => {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f4fda67cd..62f6d50fc 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -28,6 +28,7 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV
 import { CollectionViewType } from './CollectionView';
 import React = require("react");
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
@@ -330,9 +331,12 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                         />
                     </div>
                 </div>}
-            <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
-                <FontAwesomeIcon icon={"globe-asia"} size="lg" />
-            </div>
+
+            <Tooltip title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
+                <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
+                    <FontAwesomeIcon icon={"globe-asia"} size="lg" />
+                </div>
+            </Tooltip>
         </>;
     }
     focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => afterFocus?.();
@@ -367,7 +371,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined} />
-                {this._document!._viewType !== CollectionViewType.Freeform ? (null) : this.renderMiniMap()}
+                {this._document._viewType !== CollectionViewType.Freeform ? (null) : this.renderMiniMap()}
             </>;
     }
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 60e347786..ef58afeb5 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1116,8 +1116,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                     dataProvider={this.childDataProvider}
                     sizeProvider={this.childSizeProvider}
                     pointerEvents={this.backgroundActive || this.props.childPointerEvents ?
-                        true :
-                        (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? false : undefined}
+                        "all" :
+                        (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : undefined}
                     jitterRotation={NumCast(this.props.Document._jitterRotation) || ((Doc.UserDoc().renderStyle === "comic" ? 10 : 0))}
                     //fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this
                     fitToBox={BoolCast(this.props.freezeChildDimensions)} // bcz: check this
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index ec1ddd0a5..6436e74e9 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -137,7 +137,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                 //setTimeout(() => SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(slide)!, false));
                 e.stopPropagation();
             } else if (!e.ctrlKey && !e.metaKey) {
-                FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout ? e.key : "";
+                FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout && !this.props.ChildLayoutString ? e.key : "";
                 const tbox = Docs.Create.TextDocument("", {
                     _width: 200, _height: 100, x: x, y: y, _autoHeight: true, _fontSize: StrCast(Doc.UserDoc().fontSize),
                     _fontFamily: StrCast(Doc.UserDoc().fontFamily),
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 7658ee5cb..88f6a65be 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -535,7 +535,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
             return <DocumentView {...this.props}
                 Document={mark}
                 focus={() => this.playLink(mark)}
-                pointerEvents={true}
+                pointerEvents={"all"}
                 rootSelected={returnFalse}
                 LayoutTemplate={undefined}
                 ContainingCollectionDoc={this.props.Document}
@@ -628,7 +628,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                                             backgroundColor={returnTransparent}
                                             ContentScaling={returnOne}
                                             forcedBackgroundColor={returnTransparent}
-                                            pointerEvents={false}
+                                            pointerEvents={"none"}
                                             LayoutTemplate={undefined}
                                             LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(l, la2)}`)}
                                         />
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 3be32dce5..5df36435c 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -265,7 +265,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 zIndex: this.ZInd,
                 mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any,
                 display: this.ZInd === -99 ? "none" : undefined,
-                pointerEvents: this.props.Document._isBackground || this.Opacity === 0 || this.props.Document.type === DocumentType.INK || this.props.Document.isInkMask ? "none" : this.props.pointerEvents ? "all" : undefined
+                pointerEvents: this.props.Document._isBackground || this.Opacity === 0 || this.props.Document.type === DocumentType.INK || this.props.Document.isInkMask ? "none" : this.props.pointerEvents
             }} >
 
             {Doc.UserDoc().renderStyle !== "comic" ? (null) :
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index 616cddfcf..2af5b3182 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -74,7 +74,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps, C
 
     render() {
         const clipWidth = NumCast(this.layoutDoc._clipWidth) + "%";
-        const childProps: DocumentViewProps = { ...this.props, pointerEvents: false, parentActive: this.props.active };
+        const childProps: DocumentViewProps = { ...this.props, pointerEvents: "none", parentActive: this.props.active };
         const clearButton = (which: string) => {
             return <div className={`clear-button ${which}`}
                 onPointerDown={e => e.stopPropagation()} // prevent triggering slider movement in registerSliding 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 771a8f526..15e571839 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -79,7 +79,7 @@ export interface DocumentViewProps {
     ContentScaling: () => number;
     PanelWidth: () => number;
     PanelHeight: () => number;
-    pointerEvents?: boolean;
+    pointerEvents?: string;
     focus: (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: DocFocusFunc) => void;
     parentActive: (outsideReaction: boolean) => boolean;
     whenActiveChanged: (isActive: boolean) => void;
@@ -960,7 +960,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     dontRegisterView={false}
                     forcedBackgroundColor={returnTransparent}
                     removeDocument={this.hideLinkAnchor}
-                    pointerEvents={false}
+                    pointerEvents={"none"}
                     LayoutTemplate={undefined}
                     LayoutTemplateString={LinkAnchorBox.LayoutString(`anchor${Doc.LinkEndpoint(d, this.props.Document)}`)} />
             </div >);
@@ -1017,7 +1017,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             </div>;
     }
     @computed get ignorePointerEvents() {
-        return this.props.pointerEvents === false ||
+        return this.props.pointerEvents === "none" ||
             (SnappingManager.GetIsDragging() && this.Document["_isBackground-canClick"]) ||
             (this.Document._isBackground && !this.isSelected() && !SnappingManager.GetIsDragging()) ||
             (this.Document.type === DocumentType.INK && Doc.GetSelectedTool() !== InkTool.None);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.scss b/src/client/views/nodes/formattedText/FormattedTextBox.scss
index 43e64d2d2..d1109b388 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.scss
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.scss
@@ -86,7 +86,9 @@
 }
 
 .formattedTextBox-inner-rounded, .formattedTextBox-inner-rounded-selected,
-.formattedTextBox-inner, .formattedTextBox-inner-selected {
+.formattedTextBox-inner, 
+.formattedTextBox-inner-minimal,
+.formattedTextBox-inner-selected {
     height: 100%;
     white-space: pre-wrap;
     .ProseMirror:hover {
@@ -426,6 +428,7 @@ footnote::after {
         left: 10%;
     }
 
+    .formattedTextBox-inner-minimal,
     .formattedTextBox-inner-rounded,
     .formattedTextBox-inner {
         height: 100%;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index c6b4775c9..dc7d355b7 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -238,7 +238,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const tsel = this._editorView.state.selection.$from;
             tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 1000)));
             const curText = state.doc.textBetween(0, state.doc.content.size, " \n");
-            const curTemp = Cast(this.layoutDoc[this.props.fieldKey], RichTextField);               // the actual text in the text box
+            const curTemp = this.layoutDoc.resolvedDataDoc ? Cast(this.layoutDoc[this.props.fieldKey], RichTextField) : undefined;               // the actual text in the text box
             const curProto = Cast(Cast(this.dataDoc.proto, Doc, null)?.[this.fieldKey], RichTextField, null);              // the default text inherited from a prototype
             const curLayout = this.rootDoc !== this.layoutDoc ? Cast(this.layoutDoc[this.fieldKey], RichTextField, null) : undefined; // the default text stored in a layout template
             const json = JSON.stringify(state.toJSON());
@@ -247,7 +247,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
 
             const removeSelection = (json: string | undefined) => {
                 return json?.indexOf("\"storedMarks\"") === -1 ? json?.replace(/"selection":.*/, "") : json?.replace(/"selection":"\"storedMarks\""/, "\"storedMarks\"");
-            }
+            };
 
             if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) {
                 if (!this._applyingChange && removeSelection(json) !== removeSelection(curProto?.Data)) {
@@ -617,7 +617,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : [];
         appearanceItems.push({ description: "Change Perspective...", noexpand: true, subitems: changeItems, icon: "external-link-alt" });
         // this.rootDoc.isTemplateDoc && appearanceItems.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.rootDoc), icon: "eye" });
-        Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" });
+        appearanceItems.push({ description: "Reset default note style", event: () => this.rootDoc.layoutKey = "layout", icon: "eye" });
         appearanceItems.push({
             description: "Make Default Layout", event: () => {
                 if (!this.layoutDoc.isTemplateDoc) {
@@ -1155,9 +1155,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             if (FormattedTextBox.SelectOnLoadChar && this._editorView) {
                 const $from = this._editorView.state.selection.anchor ? this._editorView.state.doc.resolve(this._editorView.state.selection.anchor - 1) : undefined;
                 const mark = schema.marks.user_mark.create({ userid: Doc.CurrentUserEmail, modified: Math.floor(Date.now() / 1000) });
-                const curMarks = this._editorView!.state.storedMarks ?? $from?.marksAcross(this._editorView.state.selection.$head) ?? [];
+                const curMarks = this._editorView.state.storedMarks ?? $from?.marksAcross(this._editorView.state.selection.$head) ?? [];
                 const storedMarks = [...curMarks.filter(m => m.type !== mark.type), mark];
-                this._editorView.dispatch(this._editorView!.state.tr.setStoredMarks(storedMarks).insertText(FormattedTextBox.SelectOnLoadChar).setStoredMarks(storedMarks));
+                this._editorView.dispatch(this._editorView.state.tr.setStoredMarks(storedMarks).insertText(FormattedTextBox.SelectOnLoadChar).setStoredMarks(storedMarks));
                 FormattedTextBox.SelectOnLoadChar = "";
             } else if (curText?.Text) {
                 selectAll(this._editorView!.state, this._editorView?.dispatch);
@@ -1496,7 +1496,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
             const nh = this.layoutDoc.isTemplateForField ? 0 : NumCast(this.layoutDoc._nativeHeight, 0);
             const dh = NumCast(this.rootDoc._height, 0);
             const newHeight = Math.max(10, (nh ? dh / nh * scrollHeight : scrollHeight) + (this.props.ChromeHeight ? this.props.ChromeHeight() : 0));
-            if (this.rootDoc !== this.layoutDoc.doc && !this.layoutDoc.resolvedDataDoc) {
+            if (!this.props.LayoutTemplateString && this.rootDoc !== this.layoutDoc.doc && !this.layoutDoc.resolvedDataDoc) {
                 // if we have a template that hasn't been resolved yet, we can't set the height or we'd be setting it on the unresolved template.  So set a timeout and hope its arrived...
                 console.log("Delayed height adjustment...");
                 setTimeout(() => {
@@ -1505,6 +1505,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                 }, 10);
             } else {
                 try {
+                    // let ele = this._boxRef.current;
+                    // while (ele && ele.className !== "documentView-contentsView") ele = ele.parentElement as any;
+                    // if (ele) {
+                    //     const docHeight = Number(getComputedStyle(ele).height.replace("px", ""));
+                    //     const boxHeight = Number(getComputedStyle(this._boxRef.current!).height.replace("px", ""));
+                    //     const outer = docHeight - boxHeight - (this.props.ChromeHeight ? this.props.ChromeHeight() : 0);
+                    //     this.rootDoc._height = newHeight + outer;
+                    //     this.layoutDoc._nativeHeight = nh ? scrollHeight : undefined;
+                    // }
                     const boxHeight = Number(getComputedStyle(this._boxRef.current!).height.replace("px", ""));
                     const outer = this.rootDoc[HeightSym]() - boxHeight - (this.props.ChromeHeight ? this.props.ChromeHeight() : 0);
                     this.rootDoc._height = newHeight + outer;
@@ -1527,7 +1536,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         if (!this.props.isSelected() && FormattedTextBoxComment.textBox === this) {
             setTimeout(() => FormattedTextBoxComment.Hide(), 0);
         }
-        const selPad = this.props.isSelected() && !this.layoutDoc._singleLine ? -10 : 0;
+        const minimal = this.props.ignoreAutoHeight;
+        const selPad = (this.props.isSelected() && !this.layoutDoc._singleLine) || minimal ? -10 : 0;
         const selclass = this.props.isSelected() && !this.layoutDoc._singleLine ? "-selected" : "";
         return (
             <div className={"formattedTextBox-cont"} ref={this._boxRef}
@@ -1575,10 +1585,11 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
                     <div className={`formattedTextBox-outer`} ref={this._scrollRef}
                         style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, pointerEvents: !this.props.active() ? "none" : undefined }}
                         onScroll={this.onscrolled} onDrop={this.ondrop} >
-                        <div className={`formattedTextBox-inner${rounded}${selclass}`} ref={this.createDropTarget}
+                        <div className={minimal ? "formattedTextBox-minimal" : `formattedTextBox-inner${rounded}${selclass}`} ref={this.createDropTarget}
                             style={{
                                 overflow: this.layoutDoc._singleLine ? "hidden" : undefined,
-                                padding: this.layoutDoc._textBoxPadding ? StrCast(this.layoutDoc._textBoxPadding) : `${Math.max(0, NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0) + selPad)}px  ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0) + selPad}px`,
+                                padding: this.layoutDoc._textBoxPadding ? StrCast(this.layoutDoc._textBoxPadding) :
+                                    `${Math.max(0, NumCast(this.layoutDoc._yMargin, this.props.yMargin || 0) + selPad)}px  ${NumCast(this.layoutDoc._xMargin, this.props.xMargin || 0) + selPad}px`,
                                 pointerEvents: !this.props.active() ? ((this.layoutDoc.isLinkButton || this.props.onClick) ? "none" : undefined) : undefined
                             }}
                         />
-- 
cgit v1.2.3-70-g09d2


From 6a988e009eb1a43145c14f0d55af405318fd144f Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 15 Sep 2020 14:39:41 -0400
Subject: fixed tabs to activate when following.a link to a contained item. 
 fixed  deactivating tabs to not shrink immediately so you can click the close
 button.

---
 src/client/util/DocumentManager.ts           |  2 --
 src/client/views/collections/TabDocView.scss | 12 +++++++++--
 src/client/views/collections/TabDocView.tsx  | 10 ++++++----
 src/fields/Doc.ts                            | 30 +++++++++++++++-------------
 4 files changed, 32 insertions(+), 22 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 903760c58..c3d78a028 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -162,8 +162,6 @@ export class DocumentManager {
                 docView.props.Document.hidden = !docView.props.Document.hidden;
             }
             else {
-                const contView = docContext && getFirstDocView(docContext, originatingDoc);
-                contView && contView.topMost && contView.select(false);  // bcz: change this to a function prop: popTab() that will make sure the tab for the document is topmost;
                 docView.select(false);
                 docView.props.Document.hidden && (docView.props.Document.hidden = undefined);
                 docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish);
diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss
index c0a46543d..5dfb9366a 100644
--- a/src/client/views/collections/TabDocView.scss
+++ b/src/client/views/collections/TabDocView.scss
@@ -1,5 +1,13 @@
-input.lm_title:focus {
-    max-width: max-content !important;
+input.lm_title:focus,
+input.lm_title
+{
+    max-width: unset !important;
+    transition-delay: unset;
+    width: 100%;
+}
+input.lm_title {
+    transition-delay: 0.35s;
+    width: 100px;
 }
 .miniMap-hidden,
 .miniMap {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 62f6d50fc..76ca82c63 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -61,7 +61,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             const titleEle = tab.titleElement[0];
             titleEle.size = StrCast(doc.title).length + 3;
             titleEle.value = doc.title;
-            titleEle.style["max-width"] = "100px";
             titleEle.onchange = (e: any) => {
                 titleEle.size = e.currentTarget.value.length + 3;
                 Doc.GetProto(doc).title = e.currentTarget.value;
@@ -81,7 +80,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             };
 
             // select the tab document when the tab is directly clicked and activate the tab whenver the tab document is selected
-            tab.element[0].onclick = (e: any) => {
+            titleEle.onpointerdown = (e: any) => {
                 if (e.target.className !== "lm_close_tab" && this.view) {
                     SelectionManager.SelectDoc(this.view, false);
                     if (Date.now() - titleEle.lastClick < 1000) titleEle.select();
@@ -197,7 +196,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             this._isActive = this.props.glContainer.tab.isActive;
             (CollectionDockingView.Instance as any)._goldenLayout?.isInitialised && CollectionDockingView.Instance.stateChanged();
             !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one.
-            this._isActive && this.view && SelectionManager.SelectDoc(this.view, false);
+            // this._isActive && this.view && SelectionManager.SelectDoc(this.view, false);
         }
     }
 
@@ -339,7 +338,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             </Tooltip>
         </>;
     }
-    focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => afterFocus?.();
+    focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => {
+        this.tab.header.parent.setActiveContentItem(this.tab.contentItem)
+        afterFocus?.();
+    }
     setView = action((view: DocumentView) => this._view = view);
     active = () => this._isActive;
     @computed get docView() {
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index ff45dda80..a8950f1ee 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -688,24 +688,26 @@ export namespace Doc {
             if (templateLayoutDoc.resolvedDataDoc === (targetDoc.rootDocument || Doc.GetProto(targetDoc)) && templateLayoutDoc.PARAMS === StrCast(targetDoc.PARAMS)) {
                 expandedTemplateLayout = templateLayoutDoc; // reuse an existing template layout if its for the same document with the same params
             } else {
-                _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey + args, true);
                 templateLayoutDoc.resolvedDataDoc && (templateLayoutDoc = Cast(templateLayoutDoc.proto, Doc, null) || templateLayoutDoc); // if the template has already been applied (ie, a nested template), then use the template's prototype
-                setTimeout(action(() => {
-                    if (!targetDoc[expandedLayoutFieldKey]) {
-                        const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]");
-                        // the template's arguments are stored in params which is derefenced to find
-                        // the actual field key where the parameterized template data is stored.
-                        newLayoutDoc[params] = args !== "..." ? args : ""; // ... signifies the layout has sub template(s) -- so we have to expand the layout for them so that they can get the correct 'rootDocument' field, but we don't need to reassign their params.  it would be better if the 'rootDocument' field could be passed dynamically to avoid have to create instances
-                        newLayoutDoc.rootDocument = targetDoc;
-                        targetDoc[expandedLayoutFieldKey] = newLayoutDoc;
-                        const dataDoc = Doc.GetProto(targetDoc);
-                        newLayoutDoc.resolvedDataDoc = dataDoc;
-                        if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List) {
+                if (!targetDoc[expandedLayoutFieldKey]) {
+                    const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]");
+                    // the template's arguments are stored in params which is derefenced to find
+                    // the actual field key where the parameterized template data is stored.
+                    newLayoutDoc[params] = args !== "..." ? args : ""; // ... signifies the layout has sub template(s) -- so we have to expand the layout for them so that they can get the correct 'rootDocument' field, but we don't need to reassign their params.  it would be better if the 'rootDocument' field could be passed dynamically to avoid have to create instances
+                    newLayoutDoc.rootDocument = targetDoc;
+                    const dataDoc = Doc.GetProto(targetDoc);
+                    newLayoutDoc.resolvedDataDoc = dataDoc;
+
+                    _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey + args, true);
+                    setTimeout(() => {
+                        if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List && (templateLayoutDoc[templateField] as any).length) {
                             dataDoc[templateField] = ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"] as List)`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc });
                         }
+                        targetDoc[expandedLayoutFieldKey] = newLayoutDoc;
+
                         _pendingMap.delete(targetDoc[Id] + expandedLayoutFieldKey + args);
-                    }
-                }), 0);
+                    });
+                }
             }
         }
         return expandedTemplateLayout instanceof Doc ? expandedTemplateLayout : undefined; // layout is undefined if the expandedTemplateLayout is pending.
-- 
cgit v1.2.3-70-g09d2


From 7d2d10747fec2d3377004bf6df7e95d7661e27f6 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 15 Sep 2020 22:46:19 -0400
Subject: fixed some warnings

---
 src/client/views/collections/TabDocView.tsx               | 2 +-
 src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 1 +
 src/client/views/nodes/FontIconBox.tsx                    | 4 ++--
 src/client/views/pdf/Annotation.tsx                       | 6 +++---
 src/client/views/pdf/PDFMenu.tsx                          | 4 ++--
 5 files changed, 9 insertions(+), 8 deletions(-)

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

diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 76ca82c63..84dc6c9fb 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -339,7 +339,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         </>;
     }
     focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => {
-        this.tab.header.parent.setActiveContentItem(this.tab.contentItem)
+        this.tab.header.parent.setActiveContentItem(this.tab.contentItem);
         afterFocus?.();
     }
     setView = action((view: DocumentView) => this._view = view);
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 5df36435c..57d461bf8 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -265,6 +265,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 zIndex: this.ZInd,
                 mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any,
                 display: this.ZInd === -99 ? "none" : undefined,
+                // @ts-ignore
                 pointerEvents: this.props.Document._isBackground || this.Opacity === 0 || this.props.Document.type === DocumentType.INK || this.props.Document.isInkMask ? "none" : this.props.pointerEvents
             }} >
 
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index 463f1654e..f9b62ceb5 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -41,8 +41,8 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
         const dragFactory = Cast(this.layoutDoc.dragFactory, Doc, null);
         dragFactory && this.props.addDocTab(dragFactory, "add:right");
     }
-    dragAsTemplate = (): void => { this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); }
-    useAsPrototype = (): void => { this.layoutDoc.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'); }
+    dragAsTemplate = (): void => { this.layoutDoc.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)'); };
+    useAsPrototype = (): void => { this.layoutDoc.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'); };
 
     specificContextMenu = (): void => {
         const cm = ContextMenu.Instance;
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 78438e7e3..f680a00df 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -4,7 +4,7 @@ import { observer } from "mobx-react";
 import { Doc, DocListCast, HeightSym, WidthSym } from "../../../fields/Doc";
 import { Id } from "../../../fields/FieldSymbols";
 import { List } from "../../../fields/List";
-import { Cast, FieldValue, NumCast, StrCast, PromiseValue } from "../../../fields/Types";
+import { Cast, FieldValue, BoolCast, NumCast, StrCast, PromiseValue } from "../../../fields/Types";
 import { DocumentManager } from "../../util/DocumentManager";
 import { PDFMenu } from "./PDFMenu";
 import "./Annotation.scss";
@@ -91,9 +91,9 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
     makePushpin = action(() => {
         const group = Cast(this.props.document.group, Doc, null);
         group.isPushpin = !group.isPushpin;
-    })
+    });
 
-    isPushpin = () => Cast(this.props.document.group, Doc, null).isPushpin;
+    isPushpin = () => BoolCast(Cast(this.props.document.group, Doc, null).isPushpin);
 
     @action
     onPointerDown = (e: React.PointerEvent) => {
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 1a5b14e07..1f8872e3d 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -109,8 +109,8 @@ export class PDFMenu extends AntimodeMenu<AntimodeMenuProps> {
         this.highlightColor = Utils.colorString(col);
     }
 
-    @action keyChanged = (e: React.ChangeEvent<HTMLInputElement>) => { this._keyValue = e.currentTarget.value; }
-    @action valueChanged = (e: React.ChangeEvent<HTMLInputElement>) => { this._valueValue = e.currentTarget.value; }
+    @action keyChanged = (e: React.ChangeEvent<HTMLInputElement>) => { this._keyValue = e.currentTarget.value; };
+    @action valueChanged = (e: React.ChangeEvent<HTMLInputElement>) => { this._valueValue = e.currentTarget.value; };
     @action addTag = (e: React.PointerEvent) => {
         if (this._keyValue.length > 0 && this._valueValue.length > 0) {
             this._added = this.AddTag(this._keyValue, this._valueValue);
-- 
cgit v1.2.3-70-g09d2


From 4fc10a64e35234da2dafd03c3f53f5e080e754d2 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 16 Sep 2020 11:40:25 -0400
Subject: cleaned up TabDocView a bit

---
 src/client/util/DragManager.ts                     |  1 +
 .../views/collections/CollectionTreeView.tsx       |  4 +-
 src/client/views/collections/TabDocView.tsx        | 96 +++++++++-------------
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  6 +-
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/nodes/LinkDocPreview.tsx          |  2 +-
 7 files changed, 48 insertions(+), 65 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 367155c90..7b64d1ccc 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -223,6 +223,7 @@ export namespace DragManager {
         };
         dragData.draggedDocuments.map(d => d.dragFactory); // does this help?  trying to make sure the dragFactory Doc is loaded
         StartDrag(eles, dragData, downX, downY, options, finishDrag);
+        return true;
     }
 
     // drag a button template and drop a new button 
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 1aa3a9364..61c8f580d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -52,7 +52,7 @@ export interface TreeViewProps {
     indentDocument?: () => void;
     outdentDocument?: () => void;
     ScreenToLocalTransform: () => Transform;
-    backgroundColor?: (doc: Doc, renderDepth: number) => string | undefined;
+    backgroundColor?: (doc: Opt<Doc>, renderDepth: number) => string | undefined;
     outerXf: () => { translateX: number, translateY: number };
     treeView: CollectionTreeView;
     parentKey: string;
@@ -655,7 +655,7 @@ class TreeView extends React.Component<TreeViewProps> {
         dropAction: dropActionType,
         addDocTab: (doc: Doc, where: string) => boolean,
         pinToPres: (document: Doc) => void,
-        backgroundColor: undefined | ((document: Doc, renderDepth: number) => string | undefined),
+        backgroundColor: undefined | ((document: Opt<Doc>, renderDepth: number) => string | undefined),
         screenToLocalXf: () => Transform,
         outerXf: () => { translateX: number, translateY: number },
         active: (outsideReaction?: boolean) => boolean,
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 84dc6c9fb..06d182f34 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -1,3 +1,5 @@
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
 import 'golden-layout/src/css/goldenlayout-base.css';
 import 'golden-layout/src/css/goldenlayout-dark-theme.css';
 import { clamp } from 'lodash';
@@ -10,7 +12,7 @@ import { FieldId } from "../../../fields/RefField";
 import { listSpec } from '../../../fields/Schema';
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { TraceMobx } from '../../../fields/util';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { CurrentUserUtils } from '../../util/CurrentUserUtils';
 import { DocumentManager } from '../../util/DocumentManager';
@@ -22,13 +24,11 @@ import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { DocumentView } from "../nodes/DocumentView";
 import { PresBox } from '../nodes/PresBox';
 import { CollectionDockingView } from './CollectionDockingView';
-import "./TabDocView.scss";
 import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
 import { CollectionViewType } from './CollectionView';
+import "./TabDocView.scss";
 import React = require("react");
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Tooltip } from '@material-ui/core';
 const _global = (window /* browser */ || global /* node */) as any;
 
 interface TabDocViewProps {
@@ -72,11 +72,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     tab.setActive(true);
                 }
             };
-            const onPointerDown = (e: React.PointerEvent) => {
-                setupMoveUpEvents(this, e, (e) => {
-                    !e.defaultPrevented && DragManager.StartDocumentDrag([dragHdl], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY);
-                    return !e.defaultPrevented;
-                }, returnFalse, emptyFunction);
+            const dragBtnDown = (e: React.PointerEvent) => {
+                setupMoveUpEvents(this, e, e => !e.defaultPrevented && DragManager.StartDocumentDrag([dragHdl], new DragManager.DocumentDragData([doc], doc.dropAction as dropActionType), e.clientX, e.clientY), returnFalse, emptyFunction);
             };
 
             // select the tab document when the tab is directly clicked and activate the tab whenver the tab document is selected
@@ -99,12 +96,8 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             dragHdl.style.position = "relative";
             dragHdl.style.paddingLeft = "0px";
             dragHdl.style.paddingRight = "12px";
-            tab._disposers.buttonDisposer = reaction(() => this.view, (view) => view &&
-                [ReactDOM.render(
-                    <span title="Drag as document" className="collectionDockingView-drag" onPointerDown={onPointerDown} >
-                        <CollectionDockingViewMenu views={() => [view]} Stack={stack} />
-                    </span>, dragHdl),
-                tab._disposers.buttonDisposer?.()],
+            tab._disposers.buttonDisposer = reaction(() => this.view, view =>
+                view && [ReactDOM.render(<span className="tabDocView-drag" onPointerDown={dragBtnDown}><CollectionDockingViewMenu views={() => [view]} Stack={stack} /></span>, dragHdl), tab._disposers.buttonDisposer?.()],
                 { fireImmediately: true });
             tab.reactComponents = [dragHdl];
             tab.element.append(dragHdl);
@@ -126,6 +119,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 });
         }
     }
+
     /**
      * Adds a document to the presentation view
      **/
@@ -154,13 +148,13 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             }
         }
     }
+
     /**
      * Adds a document to the presentation view
      **/
     @undoBatch
     @action
     public static UnpinDoc(doc: Doc) {
-        //add this new doc to props.Document
         const curPres = CurrentUserUtils.ActivePresentation;
         if (curPres) {
             const ind = DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc));
@@ -169,20 +163,18 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     }
 
     componentDidMount() {
-        const color = () => StrCast(this._document?._backgroundColor, this._document && CollectionDockingView.Instance?.props.backgroundColor?.(this._document, 0) || "white");
         const selected = () => SelectionManager.SelectedDocuments().some(v => v.props.Document === this._document);
-        const updateTabColor = () => this.tab?.titleElement[0] && (this.tab.titleElement[0].style.backgroundColor = selected() ? color() : "");
-        const observer = new _global.ResizeObserver(action((entries: any) => {
+        new _global.ResizeObserver(action((entries: any) => {
             for (const entry of entries) {
                 this._panelWidth = entry.contentRect.width;
                 this._panelHeight = entry.contentRect.height;
             }
-            updateTabColor();
-        }));
-        observer.observe(this.props.glContainer._element[0]);
+        })).observe(this.props.glContainer._element[0]);
         this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged);
         this.props.glContainer.tab?.isActive && this.onActiveContentItemChanged();
-        this._tabReaction = reaction(() => ({ views: SelectionManager.SelectedDocuments(), color: color() }), updateTabColor, { fireImmediately: true });
+        this._tabReaction = reaction(() => ({ selected: selected(), color: this.tabColor, title: this.tab.titleElement[0] }),
+            ({ selected, color, title }) => title && (title.style.backgroundColor = selected ? color : ""),
+            { fireImmediately: true });
     }
 
     componentWillUnmount() {
@@ -196,30 +188,23 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             this._isActive = this.props.glContainer.tab.isActive;
             (CollectionDockingView.Instance as any)._goldenLayout?.isInitialised && CollectionDockingView.Instance.stateChanged();
             !this._isActive && this._document && Doc.UnBrushDoc(this._document); // bcz: bad -- trying to simulate a pointer leave event when a new tab is opened up on top of an existing one.
-            // this._isActive && this.view && SelectionManager.SelectDoc(this.view, false);
         }
     }
 
-    get layoutDoc() { return this._document && Doc.Layout(this._document); }
     nativeAspect = () => this.nativeWidth() ? this.nativeWidth() / this.nativeHeight() : 0;
     panelWidth = () => this.layoutDoc?.maxWidth ? Math.min(Math.max(NumCast(this.layoutDoc._width), NumCast(this.layoutDoc._nativeWidth)), this._panelWidth) :
         (this.nativeAspect() && this.nativeAspect() < this._panelWidth / this._panelHeight ? this._panelHeight * this.nativeAspect() : this._panelWidth)
     panelHeight = () => this.nativeAspect() && this.nativeAspect() > this._panelWidth / this._panelHeight ? this._panelWidth / this.nativeAspect() : this._panelHeight;
     nativeWidth = () => !this.layoutDoc?._fitWidth ? NumCast(this.layoutDoc?._nativeWidth) || this._panelWidth : 0;
     nativeHeight = () => !this.layoutDoc?._fitWidth ? NumCast(this.layoutDoc?._nativeHeight) || this._panelHeight : 0;
-
     contentScaling = () => {
-        const nativeH = this.nativeHeight();
-        const nativeW = this.nativeWidth();
+        const nativeH = NumCast(this.layoutDoc?._nativeHeight);
+        const nativeW = NumCast(this.layoutDoc?._nativeWidth);
         let scaling = 1;
-        if (!this.layoutDoc?._fitWidth && (!nativeW || !nativeH)) {
-            scaling = 1;
-        } else if (NumCast(this.layoutDoc?._nativeWidth) && ((this.layoutDoc?._fitWidth) ||
-            this._panelHeight / NumCast(this.layoutDoc?._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc?._nativeWidth))) {
-            scaling = this._panelWidth / NumCast(this.layoutDoc?._nativeWidth);
+        if (nativeW && (this.layoutDoc?._fitWidth || this._panelHeight / nativeH > this._panelWidth / nativeW)) {
+            scaling = this._panelWidth / nativeW;  // width-limited or fitWidth
         } else if (nativeW && nativeH) {
-            const wscale = this.panelWidth() / nativeW;
-            scaling = wscale * nativeH > this._panelHeight ? this._panelHeight / nativeH : wscale;
+            scaling = this._panelHeight / nativeH; // height-limited
         }
         return scaling;
     }
@@ -234,6 +219,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     }
     @computed get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
     @computed get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this._panelWidth * 100}% ` : undefined; }
+    @computed get layoutDoc() { return this._document && Doc.Layout(this._document); }
 
     // adds a tab to the layout based on the locaiton parameter which can be:
     //  close[:{left,right,top,bottom}]  - e.g., "close" will close the tab, "close:left" will close the left tab, 
@@ -244,10 +230,10 @@ export class TabDocView extends React.Component<TabDocViewProps> {
     //  inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack
     addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => {
         SelectionManager.DeselectAll();
-        if (doc._viewType === CollectionViewType.Docking) return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc);
-        const locationFields = location.split(":");
+        const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":");
         const locationParams = locationFields.length > 1 ? locationFields[1] : "";
         switch (locationFields[0]) {
+            case "dashboard": return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc);
             case "close": return CollectionDockingView.CloseSplit(doc, locationParams);
             case "fullScreen": return CollectionDockingView.OpenFullScreen(doc);
             case "replace": return CollectionDockingView.ReplaceTab(doc, locationParams, this.stack);
@@ -257,35 +243,37 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         }
     }
 
-    @computed get renderContentBounds() {
+    @computed get tabColor() { return StrCast(this._document!._backgroundColor, StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!, 0))); }
+    @computed get renderBounds() {
         const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0];
         const xbounds = bounds[2] - bounds[0];
         const ybounds = bounds[3] - bounds[1];
         const dim = Math.max(xbounds, ybounds);
         return { l: bounds[0] + xbounds / 2 - dim / 2, t: bounds[1] + ybounds / 2 - dim / 2, cx: bounds[0] + xbounds / 2, cy: bounds[1] + ybounds / 2, dim };
     }
-    @computed get miniLeft() { return 50 + (NumCast(this._document?._panX) - this.renderContentBounds.cx) / this.renderContentBounds.dim * 100 - this.miniWidth / 2; }
-    @computed get miniTop() { return 50 + (NumCast(this._document?._panY) - this.renderContentBounds.cy) / this.renderContentBounds.dim * 100 - this.miniHeight / 2; }
-    @computed get miniWidth() { return this.panelWidth() / NumCast(this._document?._viewScale, 1) / this.renderContentBounds.dim * 100; }
-    @computed get miniHeight() { return this.panelHeight() / NumCast(this._document?._viewScale, 1) / this.renderContentBounds.dim * 100; }
     childLayoutTemplate = () => Cast(this._document?.childLayoutTemplate, Doc, null);
     returnMiniSize = () => NumCast(this._document?._miniMapSize, 150);
     miniDown = (e: React.PointerEvent) => {
-        this._document && setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
-            this._document!._panX = clamp(NumCast(this._document!._panX) + delta[0] / this.returnMiniSize() * this.renderContentBounds.dim, this.renderContentBounds.l, this.renderContentBounds.l + this.renderContentBounds.dim);
-            this._document!._panY = clamp(NumCast(this._document!._panY) + delta[1] / this.returnMiniSize() * this.renderContentBounds.dim, this.renderContentBounds.t, this.renderContentBounds.t + this.renderContentBounds.dim);
+        const doc = this._document;
+        const miniSize = this.returnMiniSize();
+        doc && setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => {
+            doc._panX = clamp(NumCast(doc._panX) + delta[0] / miniSize * this.renderBounds.dim, this.renderBounds.l, this.renderBounds.l + this.renderBounds.dim);
+            doc._panY = clamp(NumCast(doc._panY) + delta[1] / miniSize * this.renderBounds.dim, this.renderBounds.t, this.renderBounds.t + this.renderBounds.dim);
             return false;
         }), emptyFunction, emptyFunction);
     }
-    getCurrentFrame = (): number => {
-        const presTargetDoc = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null);
-        return Cast(presTargetDoc._currentFrame, "number", null);
+    getCurrentFrame = () => {
+        return NumCast(Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null)._currentFrame);
     }
-
     renderMiniMap() {
+        const miniWidth = this.panelWidth() / NumCast(this._document?._viewScale, 1) / this.renderBounds.dim * 100;
+        const miniHeight = this.panelHeight() / NumCast(this._document?._viewScale, 1) / this.renderBounds.dim * 100;
+        const miniLeft = 50 + (NumCast(this._document?._panX) - this.renderBounds.cx) / this.renderBounds.dim * 100 - miniWidth / 2;
+        const miniTop = 50 + (NumCast(this._document?._panY) - this.renderBounds.cy) / this.renderBounds.dim * 100 - miniHeight / 2;
+        const miniSize = this.returnMiniSize();
         return <>
             {this._document?.hideMinimap ? (null) :
-                <div className="miniMap" style={{ width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor, StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!, 0))), }}>
+                <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.tabColor }}>
                     <CollectionFreeFormView
                         Document={this._document!}
                         LibraryPath={emptyPath}
@@ -321,13 +309,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                         fitToBox={true}
                     />
                     <div className="miniOverlay" onPointerDown={this.miniDown} >
-                        <div className="miniThumb" style={{
-                            width: `${this.miniWidth}% `,
-                            height: `${this.miniHeight}% `,
-                            left: `${this.miniLeft}% `,
-                            top: `${this.miniTop}% `,
-                        }}
-                        />
+                        <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% `, }} />
                     </div>
                 </div>}
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 1cae12a9d..de48821af 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -372,12 +372,12 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         }
     }
 
-    getClusterColor = (doc: Doc) => {
+    getClusterColor = (doc: Opt<Doc>) => {
         let clusterColor = this.props.backgroundColor?.(doc, this.props.renderDepth + 1);
-        const cluster = NumCast(doc.cluster);
+        const cluster = NumCast(doc?.cluster);
         if (this.Document._useClusters) {
             if (this._clusterSets.length <= cluster) {
-                setTimeout(() => this.updateCluster(doc), 0);
+                setTimeout(() => doc && this.updateCluster(doc), 0);
             } else {
                 // choose a cluster color from a palette
                 const colors = ["#da42429e", "#31ea318c", "rgba(197, 87, 20, 0.55)", "#4a7ae2c4", "rgba(216, 9, 255, 0.5)", "#ff7601", "#1dffff", "yellow", "rgba(27, 130, 49, 0.55)", "rgba(0, 0, 0, 0.268)"];
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 966355e8f..3915ea4f6 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -87,7 +87,7 @@ export interface DocumentViewProps {
     addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
     pinToPres: (document: Doc) => void;
     backgroundHalo?: () => boolean;
-    backgroundColor?: (doc: Doc, renderDepth: number) => string | undefined;
+    backgroundColor?: (doc: Opt<Doc>, renderDepth: number) => string | undefined;
     forcedBackgroundColor?: (doc: Doc) => string | undefined;
     opacity?: () => number | undefined;
     ChromeHeight?: () => number;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index c7a1dfcb0..0d29e43b8 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -39,7 +39,7 @@ export interface FieldViewProps {
     pinToPres: (document: Doc) => void;
     removeDocument?: (document: Doc | Doc[]) => boolean;
     moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
-    backgroundColor?: (document: Doc, renderDepth: number) => string | undefined;
+    backgroundColor?: (document: Opt<Doc>, renderDepth: number) => string | undefined;
     ScreenToLocalTransform: () => Transform;
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
     active: (outsideReaction?: boolean) => boolean;
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 2d26c5c6d..89ea57f65 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -16,7 +16,7 @@ interface Props {
     linkDoc?: Doc;
     linkSrc?: Doc;
     href?: string;
-    backgroundColor: (doc: Doc, renderDepth: number) => string;
+    backgroundColor: (doc: Opt<Doc>, renderDepth: number) => string;
     addDocTab: (document: Doc, where: string) => boolean;
     location: number[];
 }
-- 
cgit v1.2.3-70-g09d2


From 7c628f44e72a7d0b4c40c561dca4101712540e87 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 16 Sep 2020 13:37:22 -0400
Subject: added a global option to determine whether documents are brought to
 front when dragged.  fixed document override of this option to use the same
 variable _raiseWhenDragged.

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/CurrentUserUtils.ts                |  1 +
 src/client/util/SettingsManager.tsx                |  6 +++---
 src/client/views/collections/TabDocView.tsx        |  4 ++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  4 ++--
 src/client/views/nodes/DocumentView.tsx            | 23 +++++++++++-----------
 6 files changed, 20 insertions(+), 20 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 0911f3e04..04c7a0f59 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -133,7 +133,7 @@ export interface DocumentOptions {
     opacity?: number;
     defaultBackgroundColor?: string;
     _isBackground?: boolean;
-    "_isBackground-canClick"?: boolean; // a background document that you can still click on to edit its contents
+    _raiseWhenDragged?: boolean; // whether a document is brought to front when dragged.
     isLinkButton?: boolean;
     _columnWidth?: number;
     _fontSize?: string;
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 4bfa479a1..3258e1877 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -964,6 +964,7 @@ export class CurrentUserUtils {
         doc.noviceMode = doc.noviceMode === undefined ? "true" : doc.noviceMode;
         doc.title = Doc.CurrentUserEmail;
         doc.userColor = "orange";
+        doc._raiseWhenDragged = true;
         doc.activeInkPen = doc;
         doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)");
         doc.activeInkWidth = StrCast(doc.activeInkWidth, "1");
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index d4c92b20f..5b8fe3576 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -118,9 +118,9 @@ export class SettingsManager extends React.Component<{}> {
                         checked={BoolCast(Doc.UserDoc()["documentLinksButton-hideEnd"])} />
                 </div>
                 <div>
-                    Autoscroll
-                    <input type="checkbox" onChange={e => Doc.UserDoc()._noAutoscroll = !Doc.UserDoc()._noAutoscroll}
-                        checked={!BoolCast(Doc.UserDoc()._noAutoscroll)} />
+                    <div className="preferences-check">Raise on drag</div>
+                    <input type="checkbox" onChange={e => Doc.UserDoc()._raiseWhenDragged = !Doc.UserDoc()._raiseWhenDragged}
+                        checked={BoolCast(Doc.UserDoc()._raiseWhenDragged)} />
                 </div>
             </div>
         </div>;
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 06d182f34..bd5032536 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -243,7 +243,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         }
     }
 
-    @computed get tabColor() { return StrCast(this._document!._backgroundColor, StrCast(this._document!.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document!, 0))); }
+    @computed get tabColor() { return StrCast(this._document?._backgroundColor, StrCast(this._document?.backgroundColor, CollectionDockingView.Instance.props.backgroundColor?.(this._document, 0))); }
     @computed get renderBounds() {
         const bounds = this._document ? Cast(this._document._renderContentBounds, listSpec("number"), [0, 0, this.returnMiniSize(), this.returnMiniSize()]) : [0, 0, 0, 0];
         const xbounds = bounds[2] - bounds[0];
@@ -280,7 +280,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                         CollectionView={undefined}
                         ContainingCollectionView={undefined}
                         ContainingCollectionDoc={undefined}
-                        ChildLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid havin to set stuff like this.
+                        ChildLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
                         noOverlay={true} // don't render overlay Docs since they won't scale
                         active={returnTrue}
                         select={emptyFunction}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index de48821af..85641531d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -217,7 +217,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             const nd = [NumCast(layoutDoc._nativeWidth), NumCast(layoutDoc._nativeHeight)];
             layoutDoc._width = NumCast(layoutDoc._width, 300);
             layoutDoc._height = NumCast(layoutDoc._height, nd[0] && nd[1] ? nd[1] / nd[0] * NumCast(layoutDoc._width) : 300);
-            d._isBackground === undefined && !d["_isBackground-canClick"] && (d.zIndex = zsorted.length + 1 + i); // bringToFront
+            !d._isBackground && (d._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : d._raiseWhenDragged) && (d.zIndex = zsorted.length + 1 + i); // bringToFront
         }
 
         (docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(docDragData.droppedDocuments);
@@ -839,7 +839,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     }
 
     bringToFront = action((doc: Doc, sendToBack?: boolean) => {
-        if (sendToBack || doc._isBackground || doc["_isBackground-canClick"]) {
+        if (sendToBack || doc._isBackground) {
             doc.zIndex = 0;
         } else if (doc.isInkMask) {
             doc.zIndex = 5000;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3915ea4f6..def9d8554 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -303,7 +303,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             let stopPropagate = true;
             let preventDefault = true;
-            !this.props.Document._isBackground && !this.props.Document["_isBackground-canClick"] && this.props.bringToFront(this.props.Document);
+            !this.props.Document._isBackground && (this.rootDoc._raiseWhenDragged === undefined ? Doc.UserDoc()._raiseWhenDragged : this.rootDoc._raiseWhenDragged) && this.props.bringToFront(this.rootDoc);
             if (this._doubleTap && ((this.props.renderDepth && this.props.Document.type !== DocumentType.FONTICON) || this.onDoubleClickHandler)) {// && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
                 if (this._timeout) {
                     clearTimeout(this._timeout);
@@ -602,9 +602,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     @undoBatch @action
-    toggleLockInBack = () => {
-        this.rootDoc["_isBackground-canClick"] = !this.rootDoc["_isBackground-canClick"];
-        if (this.rootDoc["_isBackground-canClick"]) this.rootDoc.zIndex = 0;
+    toggleRaiseWhenDragged = () => {
+        this.rootDoc._raiseWhenDragged = this.rootDoc._raiseWhenDragged === undefined ? false : undefined;
     }
 
     @undoBatch @action
@@ -790,19 +789,20 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         if (!Doc.IsSystem(this.rootDoc) && this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Tree) {
             const existingOnClick = cm.findByDescription("OnClick...");
             const onClicks: ContextMenuProps[] = existingOnClick && "subitems" in existingOnClick ? existingOnClick.subitems : [];
+
+            const zorders = cm.findByDescription("ZOrder...");
+            const zorderItems: ContextMenuProps[] = zorders && "subitems" in zorders ? zorders.subitems : [];
+            zorderItems.push({ description: "Bring to Front", event: () => this.props.bringToFront(this.rootDoc, false), icon: "expand-arrows-alt" });
+            zorderItems.push({ description: "Send to Back", event: () => this.props.bringToFront(this.rootDoc, true), icon: "expand-arrows-alt" });
+            zorderItems.push({ description: this.rootDoc._raiseWhenDragged !== false ? "Keep ZIndex when dragged" : "Allow ZIndex to change when dragged", event: this.toggleRaiseWhenDragged, icon: "expand-arrows-alt" });
+            !zorders && cm.addItem({ description: "ZOrder...", subitems: zorderItems, icon: "compass" });
+
             if (!this.Document.annotationOn) {
                 const options = cm.findByDescription("Options...");
                 const optionItems: ContextMenuProps[] = options && "subitems" in options ? options.subitems : [];
                 !this.props.treeViewDoc && this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && optionItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" });
                 !options && cm.addItem({ description: "Options...", subitems: optionItems, icon: "compass" });
 
-                const zorders = cm.findByDescription("ZOrder...");
-                const zorderItems: ContextMenuProps[] = zorders && "subitems" in zorders ? zorders.subitems : [];
-                zorderItems.push({ description: "Bring to Front", event: () => this.props.bringToFront(this.rootDoc, false), icon: "expand-arrows-alt" });
-                zorderItems.push({ description: "Send to Back", event: () => this.props.bringToFront(this.rootDoc, true), icon: "expand-arrows-alt" });
-                zorderItems.push({ description: this.rootDoc["_isBackground-canClick"] ? "Unlock from Back" : "Lock in Back", event: this.toggleLockInBack, icon: "expand-arrows-alt" });
-                !zorders && cm.addItem({ description: "ZOrder...", subitems: zorderItems, icon: "compass" });
-
                 onClicks.push({ description: "Enter Portal", event: this.makeIntoPortal, icon: "window-restore" });
                 onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(self, "${this.Document.layoutKey}")`), icon: "concierge-bell" });
                 onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
@@ -1049,7 +1049,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
     @computed get ignorePointerEvents() {
         return this.props.pointerEvents === "none" ||
-            (SnappingManager.GetIsDragging() && this.Document["_isBackground-canClick"]) ||
             (this.Document._isBackground && !this.isSelected() && !SnappingManager.GetIsDragging()) ||
             (this.Document.type === DocumentType.INK && Doc.GetSelectedTool() !== InkTool.None);
     }
-- 
cgit v1.2.3-70-g09d2


From 77c23b7513a5c7609d8833a750988c32b35a43e4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 16 Sep 2020 22:39:51 -0400
Subject: a bunch of changes to dragging/selection of ui buttons to turn off
 context menus, remove close buttons on doc decoartions, fix the title region
 fo tabs,

---
 src/client/documents/Documents.ts                  |  1 +
 src/client/util/CurrentUserUtils.ts                | 78 ++++++++--------------
 src/client/util/DragManager.ts                     | 10 +--
 src/client/util/DropConverter.ts                   | 11 ++-
 src/client/views/DocumentDecorations.tsx           | 32 +++++----
 src/client/views/GlobalKeyHandler.ts               |  2 +-
 src/client/views/MainView.scss                     | 26 ++++++++
 src/client/views/MainView.tsx                      |  6 +-
 .../views/collections/CollectionDockingView.tsx    |  6 +-
 src/client/views/collections/CollectionMenu.tsx    |  2 +-
 src/client/views/collections/CollectionSubView.tsx | 12 ++--
 src/client/views/collections/TabDocView.scss       |  5 ++
 src/client/views/collections/TabDocView.tsx        |  9 +--
 src/client/views/nodes/DocumentView.tsx            |  5 ++
 src/client/views/nodes/FilterBox.tsx               |  6 +-
 src/client/views/nodes/FontIconBox.tsx             | 10 +--
 16 files changed, 127 insertions(+), 94 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 04c7a0f59..36834d2df 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -92,6 +92,7 @@ export interface DocumentOptions {
     y?: number;
     z?: number;
     author?: string;
+    _hideContextMenu?: boolean; // whether the context menu can be shown
     dropAction?: dropActionType;
     childDropAction?: dropActionType;
     targetDropAction?: dropActionType;
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 3258e1877..2e7fd1b21 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -65,8 +65,7 @@ export class CurrentUserUtils {
                     [this.mobileButtonText({}, "NEW MOBILE BUTTON"), this.mobileButtonInfo({}, "You can customize this button and make it your own.")])]);
             doc["template-mobile-button"] = CurrentUserUtils.ficon({
                 onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(queryTemplate) as any as Doc,
-                removeDropProperties: new List<string>(["dropAction"]), title: "mobile button", icon: "mobile"
+                dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, title: "mobile button", icon: "mobile"
             });
         }
 
@@ -81,8 +80,7 @@ export class CurrentUserUtils {
             slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
             doc["template-button-slides"] = CurrentUserUtils.ficon({
                 onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(slideTemplate) as any as Doc,
-                removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "address-card"
+                dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, title: "presentation slide", icon: "address-card"
             });
         }
 
@@ -128,8 +126,7 @@ export class CurrentUserUtils {
 
             doc["template-button-link"] = CurrentUserUtils.ficon({
                 onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(linkTemplate) as any as Doc,
-                removeDropProperties: new List<string>(["dropAction"]), title: "link view", icon: "window-maximize", system: true
+                dragFactory: new PrefetchProxy(linkTemplate) as any as Doc, title: "link view", icon: "window-maximize", system: true
             });
         }
 
@@ -160,8 +157,7 @@ export class CurrentUserUtils {
 
             doc["template-button-switch"] = CurrentUserUtils.ficon({
                 onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(box) as any as Doc,
-                removeDropProperties: new List<string>(["dropAction"]), title: "data switch", icon: "toggle-on", system: true
+                dragFactory: new PrefetchProxy(box) as any as Doc, title: "data switch", icon: "toggle-on", system: true
             });
         }
 
@@ -210,28 +206,7 @@ export class CurrentUserUtils {
 
             doc["template-button-detail"] = CurrentUserUtils.ficon({
                 onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(detailView) as any as Doc,
-                removeDropProperties: new List<string>(["dropAction"]), title: "detail view", icon: "window-maximize", system: true
-            });
-        }
-        if (doc["template-button-simple"] === undefined) {
-            const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create;
-
-            const openInTarget = ScriptField.MakeScript("openOnRight(self.doubleClickView)");
-            const carousel = CarouselDocument([], {
-                title: "data", _height: 350, _itemIndex: 0, "_carousel-caption-xMargin": 10, "_carousel-caption-yMargin": 10,
-                onChildDoubleClick: openInTarget, backgroundColor: "#9b9b9b3F", system: true
-            });
-
-            const shared = { _chromeStatus: "disabled", _autoHeight: true, _xMargin: 0 };
-            const detailViewOpts = { title: "detailView", _width: 300, _fontFamily: "Arial", _fontSize: "12px" };
-            const detailView = Docs.Create.StackingDocument([carousel], { ...shared, ...detailViewOpts, system: true });
-            detailView.isTemplateDoc = makeTemplate(detailView);
-
-            doc["template-button-simple"] = CurrentUserUtils.ficon({
-                onDragStart: ScriptField.MakeFunction('copyDragFactory(this.dragFactory)'),
-                dragFactory: new PrefetchProxy(detailView) as any as Doc,
-                removeDropProperties: new List<string>(["dropAction"]), title: "simple view", icon: "window-maximize", system: true
+                dragFactory: new PrefetchProxy(detailView) as any as Doc, title: "detail view", icon: "window-maximize", system: true
             });
         }
 
@@ -239,7 +214,6 @@ export class CurrentUserUtils {
             doc["template-button-slides"] as Doc,
             doc["template-mobile-button"] as Doc,
             doc["template-button-detail"] as Doc,
-            doc["template-button-simple"] as Doc,
             doc["template-button-link"] as Doc,
             //doc["template-button-switch"] as Doc]
         ];
@@ -247,7 +221,7 @@ export class CurrentUserUtils {
             doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument(requiredTypes, {
                 title: "Advanced Item Prototypes", _xMargin: 0, _showTitle: "title",
                 hidden: ComputedField.MakeFunction("self.userDoc.noviceMode") as any,
-                userDoc: doc,
+                userDoc: doc, _stayInCollection: true, _hideContextMenu: true,
                 _autoHeight: true, _width: 500, _columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
                 dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true
             }));
@@ -302,8 +276,7 @@ export class CurrentUserUtils {
                 { title: "Note Layouts", _height: 75, system: true }));
         } else {
             const curNoteTypes = Cast(doc["template-notes"], Doc, null);
-            const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc,
-            doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc];
+            const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc];//, doc["template-note-Todo"] as any as Doc];
             DocListCastAsync(curNoteTypes.data).then(async curNotes => {
                 await Promise.all(curNotes!);
                 requiredTypes.map(ntype => Doc.AddDocToList(curNoteTypes, "data", ntype));
@@ -484,7 +457,7 @@ export class CurrentUserUtils {
             { toolTip: "Tap to create a scripting box in a new pane, drag for a scripting box", title: "Script", icon: "terminal", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyScript as Doc },
             { toolTip: "Tap to create a mobile view in a new pane, drag for a mobile view", title: "Phone", icon: "mobile", click: 'openOnRight(Doc.UserDoc().activeMobileMenu)', drag: 'this.dragFactory', dragFactory: doc.activeMobileMenu as Doc },
             { toolTip: "Tap to create a document previewer in a new pane, drag for a document previewer", title: "Prev", icon: "expand", click: 'openOnRight(copyDragFactory(this.dragFactory))', drag: 'copyDragFactory(this.dragFactory)', dragFactory: doc.emptyDocHolder as Doc },
-            { toolTip: "Tap to create a custom header note document, drag for a custom header note", title: "Custom", icon: "window-maximize", click: 'openOnRight(delegateDragFactory(this.dragFactory))', drag: 'delegateDragFactory(this.dragFactory)', dragFactory: doc.emptyHeader as Doc, noviceMode: true },
+            { toolTip: "Tap to create a custom header note document, drag for a custom header note", title: "Custom", icon: "window-maximize", click: 'openOnRight(delegateDragFactory(this.dragFactory))', drag: 'delegateDragFactory(this.dragFactory)', dragFactory: doc.emptyHeader as Doc },
             { toolTip: "Toggle a Calculator REPL", title: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' },
         ];
 
@@ -503,7 +476,7 @@ export class CurrentUserUtils {
         }
         const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title));
         const creatorBtns = buttons.map(({ title, toolTip, icon, ignoreClick, drag, click, ischecked, activeInkPen, backgroundColor, dragFactory, noviceMode, clickFactory }) => Docs.Create.FontIconDocument({
-            _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35, _stayInCollection: true,
+            _nativeWidth: 50, _nativeHeight: 50, _width: 35, _height: 35,
             icon,
             title,
             toolTip,
@@ -514,7 +487,9 @@ export class CurrentUserUtils {
             ischecked: ischecked ? ComputedField.MakeFunction(ischecked) : undefined,
             activeInkPen,
             backgroundColor,
-            removeDropProperties: new List<string>(["dropAction"]),
+            _hideContextMenu: true,
+            removeDropProperties: new List<string>(["dropAction", "_stayInCollection"]),
+            _stayInCollection: true,
             dragFactory,
             clickFactory,
             userDoc: noviceMode ? undefined as any : doc,
@@ -524,7 +499,7 @@ export class CurrentUserUtils {
 
         if (dragCreatorSet === undefined) {
             doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, {
-                title: "Basic Item Creators", _showTitle: "title", _xMargin: 0,
+                title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, _stayInCollection: true, _hideContextMenu: true,
                 _autoHeight: true, _width: 500, _columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled",
                 dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), system: true
             }));
@@ -567,12 +542,13 @@ export class CurrentUserUtils {
                 Docs.Create.FontIconDocument({
                     icon,
                     iconShape: "square",
+                    _stayInCollection: true,
+                    _hideContextMenu: true,
                     title,
                     target,
                     _backgroundColor: "black",
                     dropAction: "alias",
-                    removeDropProperties: new List<string>(["dropAction"]),
-                    childDropAction: "same",
+                    removeDropProperties: new List<string>(["dropAction", "_stayInCollection"]),
                     _width: 60,
                     _height: 60,
                     watchedDocuments,
@@ -584,6 +560,7 @@ export class CurrentUserUtils {
 
             doc.menuStack = new PrefetchProxy(Docs.Create.StackingDocument(menuBtns, {
                 title: "menuItemPanel",
+                childDropAction: "alias",
                 dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
                 _backgroundColor: "black",
                 _gridGap: 0,
@@ -741,14 +718,14 @@ export class CurrentUserUtils {
         // setup a color picker
         if (doc.myColorPicker === undefined) {
             const color = Docs.Create.ColorDocument({
-                title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List<string>(["dropAction", "forceActive"]), system: true
+                title: "color picker", _width: 300, dropAction: "alias", _hideContextMenu: true, _stayInCollection: true, forceActive: true, removeDropProperties: new List<string>(["dropAction", "_stayInCollection", "_hideContextMenu", "forceActive"]), system: true
             });
             doc.myColorPicker = new PrefetchProxy(color);
         }
 
         if (doc.myTools === undefined) {
             const toolsStack = new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], {
-                title: "My Tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", forceActive: true, system: true
+                title: "My Tools", _width: 500, _yMargin: 20, lockedPosition: true, _chromeStatus: "disabled", forceActive: true, system: true, _stayInCollection: true, _hideContextMenu: true,
             })) as any as Doc;
 
             doc.myTools = toolsStack;
@@ -810,7 +787,7 @@ export class CurrentUserUtils {
         if (doc.myFilter === undefined) {
             doc.myFilter = new PrefetchProxy(Docs.Create.FilterDocument({
                 title: "FilterDoc", _height: 500,
-                treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias",
+                treeViewHideTitle: true, _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "none",
                 treeViewTruncateTitleWidth: 150, treeViewPreventOpen: false,
                 lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true, targetDropAction: "same", system: true
             }));
@@ -861,16 +838,16 @@ export class CurrentUserUtils {
     })) as any as Doc
 
     static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({
-        ...opts, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true
+        ...opts, dropAction: "alias", removeDropProperties: new List<string>(["dropAction", "stayInCollection"]), _nativeWidth: 40, _nativeHeight: 40, _width: 40, _height: 40, system: true
     })) as any as Doc
 
     /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window
     static setupDockedButtons(doc: Doc) {
         if (doc["dockedBtn-undo"] === undefined) {
-            doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), toolTip: "click to undo", title: "undo", icon: "undo-alt", system: true });
+            doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), _stayInCollection: true, dropAction: "alias", _hideContextMenu: true, removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "click to undo", title: "undo", icon: "undo-alt", system: true });
         }
         if (doc["dockedBtn-redo"] === undefined) {
-            doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), toolTip: "click to redo", title: "redo", icon: "redo-alt", system: true });
+            doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), _stayInCollection: true, dropAction: "alias", _hideContextMenu: true, removeDropProperties: new List<string>(["dropAction", "_hideContextMenu", "stayInCollection"]), toolTip: "click to redo", title: "redo", icon: "redo-alt", system: true });
         }
         if (doc.dockedBtns === undefined) {
             doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc]);
@@ -902,12 +879,15 @@ export class CurrentUserUtils {
     // Import sidebar is where shared documents are contained
     static setupImportSidebar(doc: Doc) {
         if (doc.myImportDocs === undefined) {
-            doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "My ImportDocuments", forceActive: true, ignoreClick: true, _showTitle: "title", childDropAction: "alias", _autoHeight: true, _yMargin: 50, _gridGap: 15, lockedPosition: true, _chromeStatus: "disabled", system: true }));
+            doc.myImportDocs = new PrefetchProxy(Docs.Create.StackingDocument([], {
+                title: "My ImportDocuments", forceActive: true, ignoreClick: true, _showTitle: "title", _stayInCollection: true, _hideContextMenu: true,
+                childDropAction: "alias", _autoHeight: true, _yMargin: 50, _gridGap: 15, lockedPosition: true, _chromeStatus: "disabled", system: true
+            }));
         }
         if (doc.myImportPanel === undefined) {
             const uploads = Cast(doc.myImportDocs, Doc, null);
-            const newUpload = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("importDocument()"), toolTip: "Import External document", _backgroundColor: "black", title: "Import", icon: "upload", system: true });
-            doc.myImportPanel = new PrefetchProxy(Docs.Create.StackingDocument([newUpload, uploads], { title: "My ImportPanel", _yMargin: 20, ignoreClick: true, lockedPosition: true, system: true }));
+            const newUpload = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("importDocument()"), toolTip: "Import External document", _backgroundColor: "black", _stayInCollection: true, _hideContextMenu: true, title: "Import", icon: "upload", system: true });
+            doc.myImportPanel = new PrefetchProxy(Docs.Create.StackingDocument([newUpload, uploads], { title: "My ImportPanel", _yMargin: 20, ignoreClick: true, _stayInCollection: true, _hideContextMenu: true, lockedPosition: true, system: true }));
         }
     }
 
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 7b64d1ccc..91ffab41d 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -13,7 +13,7 @@ import * as globalCssVariables from "../views/globalCssVariables.scss";
 import { UndoManager } from "./UndoManager";
 import { SnappingManager } from "./SnappingManager";
 
-export type dropActionType = "alias" | "copy" | "move" | "same" | undefined; // undefined = move
+export type dropActionType = "alias" | "copy" | "move" | "same" | "none" | undefined; // undefined = move
 export function SetupDrag(
     _reference: React.RefObject<HTMLElement>,
     docFunc: () => Doc | Promise<Doc> | undefined,
@@ -129,9 +129,10 @@ export namespace DragManager {
         treeViewDoc?: Doc;
         dontHideOnDrop?: boolean;
         offset: number[];
-        dropAction: dropActionType;
+        userDropAction: dropActionType;     // the user requested drop action -- this will be honored as specified by modifier keys
+        defaultDropAction?: dropActionType;  // an optionally specified default drop action when there is no user drop actionl - this will be honored if there is no user drop action
+        dropAction: dropActionType;         // a drop action request by the initiating code.  the actual drop action may be different -- eg, if the request is 'alias', but the document is dropped within the same collection, the drop action will be switched to 'move'
         removeDropProperties?: string[];
-        userDropAction: dropActionType;
         moveDocument?: MoveFunction;
         removeDocument?: RemoveFunction;
         isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged.  this will suppress onDragStart scripts
@@ -320,6 +321,7 @@ export namespace DragManager {
     export let docsBeingDragged: Doc[] = [];
     export let CanEmbed = false;
     export function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: DragCompleteEvent) => void) {
+        if (dragData.dropAction === "none") return;
         const batch = UndoManager.StartBatch("dragging");
         eles = eles.filter(e => e);
         CanEmbed = false;
@@ -418,7 +420,7 @@ export namespace DragManager {
         const moveHandler = (e: PointerEvent) => {
             e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop
             if (dragData instanceof DocumentDragData) {
-                dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : undefined;
+                dragData.userDropAction = e.ctrlKey && e.altKey ? "copy" : e.ctrlKey ? "alias" : dragData.defaultDropAction;
             }
             if (e?.shiftKey && dragData.draggedDocuments.length === 1) {
                 dragData.dropAction = dragData.userDropAction || "same";
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index 1bbd46938..32817eefd 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -2,12 +2,13 @@ import { DragManager } from "./DragManager";
 import { Doc, DocListCast, Opt } from "../../fields/Doc";
 import { DocumentType } from "../documents/DocumentTypes";
 import { ObjectField } from "../../fields/ObjectField";
-import { StrCast } from "../../fields/Types";
+import { StrCast, Cast } from "../../fields/Types";
 import { Docs } from "../documents/Documents";
 import { ScriptField, ComputedField } from "../../fields/ScriptField";
 import { RichTextField } from "../../fields/RichTextField";
 import { ImageField } from "../../fields/URLField";
 import { Scripting } from "./Scripting";
+import { listSpec } from "../../fields/Schema";
 
 // 
 // converts 'doc' into a template that can be used to render other documents.
@@ -54,7 +55,13 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
         let dbox = doc;
         // bcz: isButtonBar is intended to allow a collection of linear buttons to be dropped and nested into another collection of buttons... it's not being used yet, and isn't very elegant
         if (doc.type === DocumentType.FONTICON || StrCast(Doc.Layout(doc).layout).includes("FontIconBox")) {
-            //dbox = Doc.MakeAlias(doc);  // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon
+            if (data.removeDropProperties || dbox.removeDropProperties) {
+                //dbox = Doc.MakeAlias(doc);  // don't need to do anything if dropping an icon doc onto an icon bar since there should be no layout data for an icon
+                dbox = Doc.MakeAlias(dbox);
+                const dragProps = Cast(dbox.removeDropProperties, listSpec("string"), []);
+                const remProps = (data.removeDropProperties || []).concat(Array.from(dragProps));
+                remProps.map(prop => dbox[prop] = undefined);
+            }
         } else if (!doc.onDragStart && !doc.isButtonBar) {
             const layoutDoc = doc;// doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc;
             if (layoutDoc.type !== DocumentType.FONTICON) {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 41be364fd..e4e27bec7 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -13,7 +13,7 @@ import { GetEffectiveAcl } from '../../fields/util';
 import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick, returnVal } from "../../Utils";
 import { DocUtils, Docs } from "../documents/Documents";
 import { DocumentType } from '../documents/DocumentTypes';
-import { DragManager } from "../util/DragManager";
+import { DragManager, dropActionType } from "../util/DragManager";
 import { SelectionManager } from "../util/SelectionManager";
 import { SnappingManager } from '../util/SnappingManager';
 import { undoBatch, UndoManager } from "../util/UndoManager";
@@ -137,8 +137,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         const dragData = new DragManager.DocumentDragData(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
         const [left, top] = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).inverse().transformPoint(0, 0);
         dragData.offset = dragDocView.props.ScreenToLocalTransform().scale(dragDocView.props.ContentScaling()).transformDirection(e.x - left, e.y - top);
-        dragData.moveDocument = SelectionManager.SelectedDocuments()[0].props.moveDocument;
+        dragData.moveDocument = dragDocView.props.moveDocument;
         dragData.isSelectionMove = true;
+        dragData.dropAction = dragDocView.props.Document.dropAction as dropActionType;
         this.Interacting = true;
         this._hidden = true;
         DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(dv => dv.ContentDiv!), dragData, e.x, e.y, {
@@ -578,20 +579,25 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             return (null);
         }
         const canDelete = SelectionManager.SelectedDocuments().some(docView => {
-            const collectionAcl = GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]);
-            return collectionAcl === AclAdmin || collectionAcl === AclEdit;
+            const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit;
+            return !docView.props.Document._stayInCollection && (collectionAcl === AclAdmin || collectionAcl === AclEdit);
         });
-        const minimal = bounds.r - bounds.x < 100 ? true : false;
-        const closeIcon = canDelete ? (
+        const canOpen = SelectionManager.SelectedDocuments().some(docView => !docView.props.Document._stayInCollection);
+        const closeIcon = !canDelete ? (null) : (
             <Tooltip title={<div className="dash-tooltip">Close</div>} placement="top">
                 <div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
                     <FontAwesomeIcon className="documentdecorations-times" icon={"times"} size="lg" />
-                </div></Tooltip>) : (null);
+                </div></Tooltip>);
+
+        const openIcon = !canOpen ? (null) : <Tooltip title={<div className="dash-tooltip">Open In a New Pane</div>} placement="top"><div className="documentDecorations-openInTab" onContextMenu={e => { e.preventDefault(); e.stopPropagation(); }} onPointerDown={this.onMaximizeDown}>
+            {SelectionManager.SelectedDocuments().length === 1 ? <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}
                 onBlur={e => this.titleBlur(true)} onChange={action(e => this._accumulatedTitle = e.target.value)} onKeyPress={this.titleEntered} /> :
-            <div className="documentDecorations-title" style={{ gridColumnEnd: minimal ? 4 : 5 }} key="title" onPointerDown={this.onTitleDown} >
+            <div className="documentDecorations-title" style={{ gridColumnEnd: 5 }} key="title" onPointerDown={this.onTitleDown} >
                 <span style={{ width: "100%", display: "inline-block", cursor: "move" }}>{`${this.selectionTitle}`}</span>
             </div>;
 
@@ -627,14 +633,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 }}>
                     {closeIcon}
                     {Object.keys(SelectionManager.SelectedDocuments()[0].props).includes("treeViewDoc") ? (null) : titleArea}
-                    {SelectionManager.SelectedDocuments().length !== 1 || seldoc.Document.type === DocumentType.INK || minimal || Object.keys(SelectionManager.SelectedDocuments()[0].props).includes("treeViewDoc") ? (null) :
+                    {SelectionManager.SelectedDocuments().length !== 1 || seldoc.Document.type === DocumentType.INK || Object.keys(SelectionManager.SelectedDocuments()[0].props).includes("treeViewDoc") ? (null) :
                         <Tooltip title={<div className="dash-tooltip">{`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}</div>} placement="top">
                             <div className="documentDecorations-iconifyButton" onPointerDown={this.onIconifyDown}>
                                 <FontAwesomeIcon icon={seldoc.finalLayoutKey.includes("icon") ? "window-restore" : "window-minimize"} className="documentView-minimizedIcon" />
                             </div></Tooltip>}
-                    <Tooltip title={<div className="dash-tooltip">Open In a New Pane</div>} placement="top"><div className="documentDecorations-openInTab" onContextMenu={e => { e.preventDefault(); e.stopPropagation(); }} onPointerDown={this.onMaximizeDown}>
-                        {SelectionManager.SelectedDocuments().length === 1 ? <FontAwesomeIcon icon="external-link-alt" className="documentView-minimizedIcon" /> : "..."}
-                    </div></Tooltip>
+                    {openIcon}
                     <div className="documentDecorations-topLeftResizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} />
                     <div className="documentDecorations-topResizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} />
                     <div className="documentDecorations-topRightResizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} />
@@ -654,9 +658,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                         onPointerDown={useRotation ? this.onRotateDown : this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}>{useRotation && "⟲"}</div>
 
                 </div >
-                <div className="link-button-container" key="links" style={{ left: bounds.x - this._resizeBorderWidth / 2 + 10, top: bounds.b + this._resizeBorderWidth / 2 }}>
+                {seldoc?.Document.type === DocumentType.FONTICON ? (null) : <div className="link-button-container" key="links" style={{ left: bounds.x - this._resizeBorderWidth / 2 + 10, top: bounds.b + this._resizeBorderWidth / 2 }}>
                     <DocumentButtonBar views={SelectionManager.SelectedDocuments} />
-                </div>
+                </div>}
             </>}
         </div >
         );
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 83c02b09b..b231b2171 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -113,7 +113,7 @@ export class KeyManager {
                 }
 
                 const selected = SelectionManager.SelectedDocuments().slice();
-                UndoManager.RunInBatch(() => selected.map(dv => dv.props.removeDocument?.(dv.props.Document)), "delete");
+                UndoManager.RunInBatch(() => selected.map(dv => !dv.props.Document._stayInCollection && dv.props.removeDocument?.(dv.props.Document)), "delete");
                 SelectionManager.DeselectAll();
                 break;
             case "arrowleft": UndoManager.RunInBatch(() => SelectionManager.SelectedDocuments().map(dv => dv.props.nudge?.(-1, 0)), "nudge left"); break;
diff --git a/src/client/views/MainView.scss b/src/client/views/MainView.scss
index aebb28859..5bab43a3b 100644
--- a/src/client/views/MainView.scss
+++ b/src/client/views/MainView.scss
@@ -382,4 +382,30 @@
     display: block;
     width: 500px;
     height: 1000px;
+}
+
+.lm_drag_tab {
+    padding: 0;
+    width: 15px !important;
+    height: 15px !important;
+    position: relative !important;
+    display: inline-flex !important;
+    align-items: center;
+    top: 0 !important;
+    right: unset !important;
+    left: 0 !important;
+}
+.lm_close_tab {
+    padding: 0;
+    width: 15px !important;
+    height: 15px !important;
+    position: relative !important;
+    display: inline-flex !important;
+    align-items: center;
+    top: 0 !important;
+    right: unset !important;
+    left: 0 !important;
+}
+.lm_tab, .lm_tab_active {
+    display: flex !important;
 }
\ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 82261fcf0..c2290dd09 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -445,11 +445,7 @@ export class MainView extends React.Component {
 
     remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true);
     moveButtonDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => this.remButtonDoc(doc) && addDocument(doc);
-    addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => {
-        const ret = flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc);
-        ret && (doc._stayInCollection = undefined);
-        return ret;
-    }, true)
+    addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true);
 
     buttonBarXf = () => {
         if (!this._docBtnRef.current) return Transform.Identity();
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 306b9187e..4685d2ffc 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -152,7 +152,11 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
             const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
             if (instance._goldenLayout.root.contentItems.length === 0) { // if no rows / columns
                 instance._goldenLayout.root.addChild(newContentItem);
-            } else if (instance._goldenLayout.root.contentItems[0].isRow) { // if row
+            } else if (instance._goldenLayout.root.contentItems.length === 1 && instance._goldenLayout.root.contentItems[0].contentItems.length === 1 &&
+                instance._goldenLayout.root.contentItems[0].contentItems[0].contentItems.length === 0) {
+                instance._goldenLayout.root.contentItems[0].contentItems[0].addChild(docContentConfig);
+            }
+            else if (instance._goldenLayout.root.contentItems[0].isRow) { // if row
                 switch (pullSide) {
                     default:
                     case "right": instance._goldenLayout.root.contentItems[0].addChild(newContentItem); break;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 9e67faed5..0f8a5df0d 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -417,7 +417,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         if (this._dragRef.current && this.selectedDoc) {
             const dragData = new DragManager.DocumentDragData([this.selectedDoc]);
             const [left, top] = [e.clientX, e.clientY];
-            dragData.dropAction = "alias";
+            dragData.defaultDropAction = "alias";
             DragManager.StartDocumentDrag([this._dragRef.current], dragData, left, top, {
                 offsetX: dragData.offset[0],
                 offsetY: dragData.offset[1],
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index ed5414954..dc1d5a8dd 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,5 +1,4 @@
 import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx";
-import { basename } from 'path';
 import CursorField from "../../../fields/CursorField";
 import { Doc, Opt, Field, DocListCast } from "../../../fields/Doc";
 import { Id, ToString } from "../../../fields/FieldSymbols";
@@ -220,15 +219,20 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             if (docDragData) {
                 let added = false;
                 const dropAction = docDragData.dropAction || docDragData.userDropAction;
-                if ((!dropAction || dropAction === "move") && docDragData.moveDocument) {
+                const targetDocments = DocListCast(this.dataDoc[this.props.fieldKey]);
+                const someMoved = !docDragData.userDropAction && docDragData.draggedDocuments.some(drag => targetDocments.includes(drag));
+                if (someMoved) docDragData.droppedDocuments = docDragData.droppedDocuments.map((drop, i) => targetDocments.includes(docDragData.draggedDocuments[i]) ? docDragData.draggedDocuments[i] : drop);
+                if ((!dropAction || dropAction === "move" || someMoved) && docDragData.moveDocument) {
                     const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d);
                     const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d);
-                    const res = addedDocs.length ? this.addDocument(addedDocs) : true;
                     if (movedDocs.length) {
                         const canAdd = this.props.Document._viewType === CollectionViewType.Pile || de.embedKey || !this.props.isAnnotationOverlay ||
                             Doc.AreProtosEqual(Cast(movedDocs[0].annotationOn, Doc, null), this.props.Document);
                         added = docDragData.moveDocument(movedDocs, this.props.Document, canAdd ? this.addDocument : returnFalse);
-                    } else added = res;
+                    } else {
+                        ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData });
+                        added = addedDocs.length ? this.addDocument(addedDocs) : true;
+                    }
                     added && e.stopPropagation();
                     return added;
                 } else {
diff --git a/src/client/views/collections/TabDocView.scss b/src/client/views/collections/TabDocView.scss
index 5dfb9366a..edf556c9f 100644
--- a/src/client/views/collections/TabDocView.scss
+++ b/src/client/views/collections/TabDocView.scss
@@ -4,10 +4,15 @@ input.lm_title
     max-width: unset !important;
     transition-delay: unset;
     width: 100%;
+    cursor: text;
 }
 input.lm_title {
     transition-delay: 0.35s;
     width: 100px;
+    cursor: pointer;
+}
+.tabDocView-drag {
+    margin: auto;
 }
 .miniMap-hidden,
 .miniMap {
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index bd5032536..f89285923 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -91,16 +91,13 @@ export class TabDocView extends React.Component<TabDocViewProps> {
 
             //attach the selection doc buttons menu to the drag handle
             const stack = tab.contentItem.parent;
-            const dragHdl = document.createElement("span");
-            dragHdl.className = "collectionDockingView-gear";
-            dragHdl.style.position = "relative";
-            dragHdl.style.paddingLeft = "0px";
-            dragHdl.style.paddingRight = "12px";
+            const dragHdl = document.createElement("div");
+            dragHdl.className = "lm_drag_tab";
             tab._disposers.buttonDisposer = reaction(() => this.view, view =>
                 view && [ReactDOM.render(<span className="tabDocView-drag" onPointerDown={dragBtnDown}><CollectionDockingViewMenu views={() => [view]} Stack={stack} /></span>, dragHdl), tab._disposers.buttonDisposer?.()],
                 { fireImmediately: true });
             tab.reactComponents = [dragHdl];
-            tab.element.append(dragHdl);
+            tab.closeElement.before(dragHdl);
 
             // highlight the tab when the tab document is brushed in any part of the UI
             tab._disposers.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index def9d8554..5ca57a193 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -752,6 +752,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     @action
     onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => {
+        if (e && this.rootDoc._hideContextMenu && Doc.UserDoc().noviceMode) {
+            e.preventDefault();
+            e.stopPropagation();
+            !this.isSelected(true) && SelectionManager.SelectDoc(this, false);
+        }
         // the touch onContextMenu is button 0, the pointer onContextMenu is button 2
         if (e) {
             if (e.button === 0 && !e.ctrlKey || e.isDefaultPrevented()) {
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index eab365445..7a010532f 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -94,13 +94,13 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
             });
             let newFacet: Opt<Doc>;
             if (facetHeader === "text" || rtfields / allCollectionDocs.length > 0.1) {
-                newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true });
+                newFacet = Docs.Create.TextDocument("", { _width: 100, _height: 25, _stayInCollection: true, _hideContextMenu: true, treeViewExpandedView: "layout", title: facetHeader, treeViewOpen: true, forceActive: true, ignoreClick: true });
                 Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
                 newFacet._textBoxPadding = 4;
                 const scriptText = `setDocFilter(this?.target, "${facetHeader}", text, "match")`;
                 newFacet.onTextChanged = ScriptField.MakeScript(scriptText, { this: Doc.name, text: "string" });
             } else if (facetHeader !== "tags" && nonNumbers / facetValues.length < .1) {
-                newFacet = Docs.Create.SliderDocument({ title: facetHeader, treeViewExpandedView: "layout", treeViewOpen: true });
+                newFacet = Docs.Create.SliderDocument({ title: facetHeader, _stayInCollection: true, _hideContextMenu: true, treeViewExpandedView: "layout", treeViewOpen: true });
                 const newFacetField = Doc.LayoutFieldKey(newFacet);
                 const ranged = Doc.readDocRangeFilter(targetDoc, facetHeader);
                 Doc.GetProto(newFacet).type = DocumentType.COL; // forces item to show an open/close button instead ofa checkbox
@@ -118,7 +118,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
                 newFacet.title = facetHeader;
                 newFacet.treeViewOpen = true;
                 newFacet.type = DocumentType.COL;
-                const capturedVariables = { layoutDoc: targetDoc, dataDoc: (targetDoc.data as any)[0][DataSym] };
+                const capturedVariables = { layoutDoc: targetDoc, _stayInCollection: true, _hideContextMenu: true, dataDoc: (targetDoc.data as any)[0][DataSym] };
                 newFacet.data = ComputedField.MakeFunction(`readFacetData(layoutDoc, "${facetHeader}")`, {}, capturedVariables);
             }
             newFacet && Doc.AddDocToList(this.dataDoc, this.props.fieldKey, newFacet);
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index f9b62ceb5..6e96513c7 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -45,10 +45,12 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
     useAsPrototype = (): void => { this.layoutDoc.onDragStart = ScriptField.MakeFunction('makeDelegate(this.dragFactory, true)'); };
 
     specificContextMenu = (): void => {
-        const cm = ContextMenu.Instance;
-        cm.addItem({ description: "Show Template", event: this.showTemplate, icon: "tag" });
-        !Doc.UserDoc().noviceMode && cm.addItem({ description: "Use as Render Template", event: this.dragAsTemplate, icon: "tag" });
-        !Doc.UserDoc().noviceMode && cm.addItem({ description: "Use as Prototype", event: this.useAsPrototype, icon: "tag" });
+        if (!Doc.UserDoc().noviceMode) {
+            const cm = ContextMenu.Instance;
+            cm.addItem({ description: "Show Template", event: this.showTemplate, icon: "tag" });
+            cm.addItem({ description: "Use as Render Template", event: this.dragAsTemplate, icon: "tag" });
+            cm.addItem({ description: "Use as Prototype", event: this.useAsPrototype, icon: "tag" });
+        }
     }
 
     componentWillUnmount() {
-- 
cgit v1.2.3-70-g09d2


From 5e0f26eaf42f23327f31bab10d15965d2ab744e7 Mon Sep 17 00:00:00 2001
From: Geireann Lindfield Roberts <60007097+geireann@users.noreply.github.com>
Date: Fri, 18 Sep 2020 17:42:47 +0800
Subject: Fixed merge from presentation_updates

---
 src/client/views/DocumentButtonBar.tsx             |  52 ++-
 src/client/views/MainView.tsx                      |   2 +-
 src/client/views/PropertiesView.tsx                |   9 +-
 src/client/views/collections/CollectionMenu.tsx    |  65 ++-
 src/client/views/collections/TabDocView.tsx        |  46 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  14 +-
 .../collectionFreeForm/MarqueeOptionsMenu.tsx      |   7 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |   3 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |   8 +-
 src/client/views/nodes/PresBox.scss                | 336 ++++++++-------
 src/client/views/nodes/PresBox.tsx                 | 461 ++++++++++++---------
 .../views/presentationview/PresElementBox.scss     |   1 +
 .../views/presentationview/PresElementBox.tsx      |  42 +-
 13 files changed, 603 insertions(+), 443 deletions(-)

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

diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index b18b2302d..b4b46d8d9 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -24,6 +24,7 @@ import { DocumentView } from './nodes/DocumentView';
 import { GoogleRef } from "./nodes/formattedText/FormattedTextBox";
 import { TemplateMenu } from "./TemplateMenu";
 import React = require("react");
+import { PresBox } from './nodes/PresBox';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -184,22 +185,39 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
     get pinButton() {
         const targetDoc = this.view0?.props.Document;
         let isPinned = targetDoc && Doc.isDocPinned(targetDoc);
-        // More than 1 document selected then all must be in presentation for isPinned to be true (then it will unpin all)
-        if (SelectionManager.SelectedDocuments().length > 1) {
-            SelectionManager.SelectedDocuments().forEach((docView: DocumentView) => {
-                if (Doc.isDocPinned(docView.props.Document)) isPinned = true;
-                else isPinned = false;
-            });
-        }
-        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div></>}>
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation"}</div></>}>
             <div className="documentButtonBar-linker"
-                style={{ backgroundColor: isPinned ? "white" : "", color: isPinned ? "black" : "white", border: isPinned ? "black 1px solid " : "" }}
-                onClick={e => this.props.views().map(view => view && TabDocView.PinDoc(view.props.Document, isPinned))}>
-                <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin"
-                />
+                style={{ color: "white" }}
+                onClick={e => this.props.views().map(view => view && TabDocView.PinDoc(view.props.Document, false))}>
+                <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin" />
             </div></Tooltip>;
     }
 
+    @computed
+    get pinWithViewButton() {
+        const presPinWithViewIcon = <img src={`/assets/${"pinWithView.png"}`}
+            style={{ width: 17, transform: 'translate(0, 1px)' }} />;
+        const targetDoc = this.view0?.props.Document;
+        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin with current view"}</div></>}>
+            <div className="documentButtonBar-linker"
+                onClick={e => {
+                    if (targetDoc) {
+                        TabDocView.PinDoc(targetDoc, false);
+                        const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
+                        const x = targetDoc._panX;
+                        const y = targetDoc._panY;
+                        const scale = targetDoc._viewScale;
+                        activeDoc.presPinView = true;
+                        activeDoc.presPinViewX = x;
+                        activeDoc.presPinViewY = y;
+                        activeDoc.presPinViewScale = scale;
+                    }
+                }}>
+                {presPinWithViewIcon}
+            </div>
+        </Tooltip>;
+    }
+
     @computed
     get shareButton() {
         const targetDoc = this.view0?.props.Document;
@@ -236,7 +254,8 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
         return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{`${CurrentUserUtils.propertiesWidth > 0 ? "Close" : "Open"} Properties Panel`}</div></>}>
             <div className="documentButtonBar-linker" style={{ color: "white", cursor: "e-resize" }} onClick={action(e =>
                 CurrentUserUtils.propertiesWidth = CurrentUserUtils.propertiesWidth > 0 ? 0 : 250)}>
-                <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="ellipsis-h" />
+                <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="ellipsis-h"
+                />
             </div></Tooltip >;
     }
 
@@ -258,7 +277,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
         this.props.views()[0]?.select(false);
         this._tooltipOpen = false;
         setupMoveUpEvents(this, e, this.onAliasButtonMoved, emptyFunction, emptyFunction);
-    });
+    })
     onAliasButtonMoved = () => {
         if (this._dragRef.current) {
             const dragDocView = this.view0!;
@@ -336,6 +355,9 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
             <div className="documentButtonBar-button">
                 {this.pinButton}
             </div>
+            {/* <div className="documentButtonBar-button">
+                {this.pinWithViewButton}
+            </div> */}
             {!Doc.UserDoc()["documentLinksButton-fullMenu"] ? (null) : <div className="documentButtonBar-button">
                 {this.shareButton}
             </div>}
@@ -356,4 +378,4 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
             </div>} */}
         </div>;
     }
-}
+}
\ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index c2290dd09..595e07326 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -213,7 +213,7 @@ export class MainView extends React.Component {
             }));
         }
         const pres = Docs.Create.PresDocument(new List<Doc>(),
-            { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias", _chromeStatus: "replaced", boxShadow: "0 0", system: true });
+            { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias", _chromeStatus: "replaced", boxShadow: "0 0" });
         CollectionDockingView.AddSplit(pres, "right");
         this.userDoc.activePresentation = pres;
         Doc.AddDocToList(this.userDoc.myPresentations as Doc, "data", pres);
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 53261d8de..b12d539e4 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -43,10 +43,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
 
     @computed get MAX_EMBED_HEIGHT() { return 200; }
 
-    @computed get selectedDoc() { return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc; }
+    @computed get selectedDoc() { console.log(this.selectedDocumentView?.rootDoc.title); return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc; }
     @computed get selectedDocumentView() {
-        if (PresBox.Instance?._selectedArray.length) return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
         if (SelectionManager.SelectedDocuments().length) return SelectionManager.SelectedDocuments()[0];
+        if (PresBox.Instance && PresBox.Instance._selectedArray) return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
         return undefined;
     }
     @computed get isPres(): boolean {
@@ -1012,6 +1012,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
             }
             if (this.isPres) {
                 const selectedItem: boolean = PresBox.Instance?._selectedArray.length > 0;
+                const type = PresBox.Instance.activeItem?.type;
                 return <div className="propertiesView" style={{ width: this.props.width }}>
                     <div className="propertiesView-title" style={{ width: this.props.width }}>
                         Presentation
@@ -1038,7 +1039,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             {PresBox.Instance.transitionDropdown}
                         </div> : null}
                     </div>}
-                    {!selectedItem ? (null) : <div className="propertiesView-presTrails">
+                    {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => this.openPresProgressivize = !this.openPresProgressivize)}
                             style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
@@ -1051,7 +1052,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                             {PresBox.Instance.progressivizeDropdown}
                         </div> : null}
                     </div>}
-                    {!selectedItem ? (null) : <div className="propertiesView-presTrails">
+                    {!selectedItem || (type !== DocumentType.COL && type !== DocumentType.VID && type !== DocumentType.AUDIO) ? (null) : <div className="propertiesView-presTrails">
                         <div className="propertiesView-presTrails-title"
                             onPointerDown={action(() => { this.openSlideOptions = !this.openSlideOptions; })}
                             style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 5ac0a8ff0..390aa8485 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -369,9 +369,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
     }
 
     @computed get selectedDocumentView() {
-        if (SelectionManager.SelectedDocuments().length) {
-            return SelectionManager.SelectedDocuments()[0];
-        } else { return undefined; }
+        return SelectionManager.SelectedDocuments().length ? SelectionManager.SelectedDocuments()[0] : undefined;
     }
     @computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
     @computed get notACollection() {
@@ -387,13 +385,39 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         const targetDoc = this.selectedDoc;
         const isPinned = targetDoc && Doc.isDocPinned(targetDoc);
         return !targetDoc ? (null) : <Tooltip key="pin" title={<div className="dash-tooltip">{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}</div>} placement="top">
-            <button className="antimodeMenu-button" style={{ backgroundColor: isPinned ? "121212" : undefined, borderRight: "1px solid gray" }}
+            <button className="antimodeMenu-button" style={{ backgroundColor: isPinned ? "121212" : undefined, borderLeft: "1px solid gray" }}
                 onClick={e => TabDocView.PinDoc(targetDoc, isPinned)}>
                 <FontAwesomeIcon className="documentdecorations-icon" size="lg" icon="map-pin" />
             </button>
         </Tooltip>;
     }
 
+    @computed
+    get pinWithViewButton() {
+        const presPinWithViewIcon = <img src={`/assets/${"pinWithView.png"}`}
+            style={{ width: 19 }} />;
+        const targetDoc = this.selectedDoc;
+        return (!targetDoc || (targetDoc._viewType !== CollectionViewType.Freeform && targetDoc.type !== DocumentType.IMG)) ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation trail with current view"}</div></>} placement="top">
+            <button className="antimodeMenu-button" style={{ borderRight: "1px solid gray", borderLeft: "1px solid gray", justifyContent: 'center' }}
+                onClick={e => {
+                    if (targetDoc) {
+                        TabDocView.PinDoc(targetDoc, false);
+                        const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
+                        const x = targetDoc._panX;
+                        const y = targetDoc._panY;
+                        const scale = targetDoc._viewScale;
+                        activeDoc.presPinView = true;
+                        activeDoc.presPinViewX = x;
+                        activeDoc.presPinViewY = y;
+                        activeDoc.presPinViewScale = scale;
+                    }
+                }}>
+                {presPinWithViewIcon}
+            </button>
+        </Tooltip>;
+    }
+
+
     @undoBatch
     onAlias = () => {
         if (this.selectedDoc && this.selectedDocumentView) {
@@ -449,33 +473,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
         </Tooltip>;
     }
 
-    @computed
-    get pinWithViewButton() {
-        const targetDoc = this.selectedDoc;
-        if (targetDoc) {
-            const x = targetDoc._panX;
-            const y = targetDoc._panY;
-            const scale = targetDoc._viewScale;
-        }
-        return !targetDoc ? (null) : <Tooltip title={<><div className="dash-tooltip">{"Pin to presentation with current view"}</div></>} placement="top">
-            <button className="antidmodeMenu-button" style={{ borderRight: "1px solid gray" }}
-                onClick={e => {
-                    if (targetDoc) {
-                        TabDocView.PinDoc(targetDoc, false);
-                        const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1];
-                        const x = targetDoc._panX;
-                        const y = targetDoc._panY;
-                        const scale = targetDoc._viewScale;
-                        activeDoc.presPinView = true;
-                        activeDoc.presPinViewX = x;
-                        activeDoc.presPinViewY = y;
-                        activeDoc.presPinViewScale = scale;
-                    }
-                }}>
-                <FontAwesomeIcon className="documentdecorations-icon" size="lg" icon="map-marker" />
-            </button>
-        </Tooltip>;
-    }
 
 
     render() {
@@ -485,8 +482,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                     <div className="collectionViewBaseChrome">
                         {this.notACollection || this.props.type === CollectionViewType.Invalid ? (null) : this.viewModes}
                         {!this._buttonizableCommands ? (null) : this.templateChrome}
-
-
                         {this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? (null) :
                             <Tooltip title={<div className="dash-tooltip">Toggle Overlay Layer</div>} placement="bottom">
                                 <button className={"antimodeMenu-button"} key="float"
@@ -497,7 +492,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
                             </Tooltip>}
                         {this.notACollection ? (null) : this.lightboxButton}
                         {this.aliasButton}
-                        {this.pinButton}
+                        {/* {this.pinButton} */}
                         {this.pinWithViewButton}
                     </div>
                     {this.subChrome}
@@ -1308,4 +1303,4 @@ Scripting.addGlobal(function gotoFrame(doc: any, newFrame: any) {
     }
     CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0);
     doc._currentFrame = Math.max(0, newFrame);
-});
\ No newline at end of file
+});
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f89285923..2096d782f 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -22,7 +22,7 @@ import { SnappingManager } from '../../util/SnappingManager';
 import { Transform } from '../../util/Transform';
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { DocumentView } from "../nodes/DocumentView";
-import { PresBox } from '../nodes/PresBox';
+import { PresBox, PresMovement } from '../nodes/PresBox';
 import { CollectionDockingView } from './CollectionDockingView';
 import { CollectionDockingViewMenu } from './CollectionDockingViewMenu';
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
@@ -122,27 +122,27 @@ export class TabDocView extends React.Component<TabDocViewProps> {
      **/
     @undoBatch
     @action
-    public static PinDoc(doc: Doc, unpin = false) {
-        if (unpin) TabDocView.UnpinDoc(doc);
-        else {
-            //add this new doc to props.Document
-            const curPres = CurrentUserUtils.ActivePresentation;
-            if (curPres) {
-                const pinDoc = Doc.MakeAlias(doc);
-                pinDoc.presentationTargetDoc = doc;
-                pinDoc.presZoomButton = true;
-                pinDoc.context = curPres;
-                Doc.AddDocToList(curPres, "data", pinDoc);
-                if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
-                if (!DocumentManager.Instance.getDocumentView(curPres)) {
-                    CollectionDockingView.AddSplit(curPres, "right");
-                }
-                DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null));
-                setTimeout(() => {
-                    curPres._itemIndex = DocListCast(curPres.data).length - 1;
-                    doc.treeViewOutlineMode && PresBox.Instance.progressivizeChild(null as any);
-                }, 100);
+    public static PinDoc(doc: Doc, unpin = false, audioRange?: boolean) {
+        if (unpin) console.log('remove unpin');
+        //add this new doc to props.Document
+        const curPres = CurrentUserUtils.ActivePresentation;
+        if (curPres) {
+            const pinDoc = Doc.MakeAlias(doc);
+            pinDoc.presentationTargetDoc = doc;
+            pinDoc.title = doc.title;
+            pinDoc.presMovement = PresMovement.Zoom;
+            pinDoc.context = curPres;
+            Doc.AddDocToList(curPres, "data", pinDoc);
+            if (pinDoc.type === "audio" && !audioRange) {
+                pinDoc.presStartTime = 0;
+                pinDoc.presEndTime = doc.duration;
             }
+            if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
+            const curPresDocView = DocumentManager.Instance.getDocumentView(curPres);
+            if (!curPresDocView) {
+                CollectionDockingView.AddSplit(curPres, "right");
+            }
+            DocumentManager.Instance.jumpToDocument(doc, false, undefined, Cast(doc.context, Doc, null));
         }
     }
 
@@ -318,7 +318,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         </>;
     }
     focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => {
-        this.tab.header.parent.setActiveContentItem(this.tab.contentItem);
+        // this.tab.header.parent.setActiveContentItem(this.tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
         afterFocus?.();
     }
     setView = action((view: DocumentView) => this._view = view);
@@ -371,4 +371,4 @@ export class TabDocView extends React.Component<TabDocViewProps> {
             {this.docView}
         </div >);
     }
-}
+}
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 7b0aaef3c..3d7927bc6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -209,7 +209,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             const layoutDoc = Doc.Layout(d);
             if (this.Document._currentFrame !== undefined) {
                 const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000));
-                CollectionFreeFormDocumentView.setValues(this.Document._currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.h, vals.w, vals.scroll, vals.opacity);
+                CollectionFreeFormDocumentView.setValues(this.Document._currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.h, vals.w, this.Document.editScrollProgressivize ? vals.scroll : undefined, vals.opacity);
             } else {
                 d.x = x + NumCast(d.x) - dropPos[0];
                 d.y = y + NumCast(d.y) - dropPos[1];
@@ -906,7 +906,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
 
             if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) {
                 // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
-                if (!doc.z) this.setPan(newPanX, newPanY, doc.presTransition || doc.presTransition === 0 ? `transform ${doc.presTransition}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
+                if (!doc.z) this.setPan(newPanX, newPanY, doc.focusSpeed || doc.focusSpeed === 0 ? `transform ${doc.focusSpeed}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
             }
             Doc.BrushDoc(this.props.Document);
             this.props.focus(this.props.Document);
@@ -1595,18 +1595,10 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
             <div key="presorder">{PresBox.Instance.order}</div>
             <svg key="svg" className={presPaths}>
                 <defs>
-                    <marker id="arrow" markerWidth="3" overflow="visible" markerHeight="3" refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
-                        <path d="M0,0 L0,6 L9,3 z" fill="#69a6db" />
-                    </marker>
-                    <marker id="square" markerWidth="3" markerHeight="3" overflow="visible"
-                        refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
-                        <path d="M 5,1 L 9,5 5,9 1,5 z" fill="#69a6db" />
-                    </marker>
                     <marker id="markerSquare" markerWidth="7" markerHeight="7" refX="4" refY="4"
                         orient="auto" overflow="visible">
                         <rect x="1" y="1" width="5" height="5" fill="#69a6db" />
                     </marker>
-
                     <marker id="markerArrow" markerWidth="5" markerHeight="5" refX="2" refY="7"
                         orient="auto" overflow="visible">
                         <path d="M2,2 L2,13 L8,7 L2,2" fill="#69a6db" />
@@ -1637,4 +1629,4 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
             {this.zoomProgressivize}
         </div>;
     }
-}
+}
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
index 46298ec6f..63d61b927 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx
@@ -24,6 +24,8 @@ export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
     }
 
     render() {
+        const presPinWithViewIcon = <img src={`/assets/${"pinWithView.png"}`}
+            style={{ width: 19, transform: 'translate(-2px, -2px)' }} />;
         const buttons = [
             <Tooltip key="group" title={<><div className="dash-tooltip">Create a Collection</div></>} placement="bottom">
                 <button
@@ -53,12 +55,11 @@ export class MarqueeOptionsMenu extends AntimodeMenu<AntimodeMenuProps> {
                     <FontAwesomeIcon icon="font" size="lg" />
                 </button>
             </Tooltip>,
-            <Tooltip key="pinWithView" title={<><div className="dash-tooltip">Pin to presentation with selected view</div></>} placement="bottom">
+            <Tooltip key="pinWithView" title={<><div className="dash-tooltip">Pin with selected view</div></>} placement="bottom">
                 <button
                     className="antimodeMenu-button"
                     onPointerDown={this.pinWithView}>
-                    <FontAwesomeIcon icon="map-pin" size="lg" />
-                    <div style={{ position: 'relative', fontSize: 25, fontWeight: 700, transform: 'translate(-4px, -22px)', color: 'rgba(250,250,250,0.55)' }}>V</div>
+                    <>{presPinWithViewIcon}</>
                 </button>
             </Tooltip>,
         ];
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 4f2399962..d04ef4ff9 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -25,6 +25,7 @@ import "./MarqueeView.scss";
 import React = require("react");
 import { Id } from "../../../../fields/FieldSymbols";
 import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
+import { PresMovement } from "../../nodes/PresBox";
 
 interface MarqueeViewProps {
     getContainerTransform: () => Transform;
@@ -394,7 +395,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         if (curPres) {
             const pinDoc = Doc.MakeAlias(doc);
             pinDoc.presentationTargetDoc = doc;
-            pinDoc.presZoomButton = true;
+            pinDoc.presMovement = PresMovement.Zoom;
             pinDoc.context = curPres;
             Doc.AddDocToList(curPres, "data", pinDoc);
             if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 57d461bf8..d6f8ce19c 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -65,7 +65,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
             w: Cast(doc["w-indexed"], listSpec("number"), [NumCast(doc._width)]).reduce((p, w, i) => (i <= timecode && w !== undefined) || p === undefined ? w : p, undefined as any as number),
             x: Cast(doc["x-indexed"], listSpec("number"), [NumCast(doc.x)]).reduce((p, x, i) => (i <= timecode && x !== undefined) || p === undefined ? x : p, undefined as any as number),
             y: Cast(doc["y-indexed"], listSpec("number"), [NumCast(doc.y)]).reduce((p, y, i) => (i <= timecode && y !== undefined) || p === undefined ? y : p, undefined as any as number),
-            scroll: Cast(doc["scroll-indexed"], listSpec("number"), [NumCast(doc._scrollTop, 0)]).reduce((p, s, i) => (i <= timecode && s !== undefined) || p === undefined ? s : p, undefined as any as number),
+            scroll: Cast(doc["scroll-indexed"], listSpec("number"), [NumCast(doc._scrollY, 0)]).reduce((p, s, i) => (i <= timecode && s !== undefined) || p === undefined ? s : p, undefined as any as number),
             opacity: Cast(doc["opacity-indexed"], listSpec("number"), [NumCast(doc.opacity, 1)]).reduce((p, o, i) => i <= timecode || p === undefined ? o : p, undefined as any as number),
         });
     }
@@ -83,7 +83,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         hindexed[timecode] = h as any as number;
         windexed[timecode] = w as any as number;
         oindexed[timecode] = opacity as any as number;
-        scrollIndexed[timecode] = scroll as any as number;
+        if (scroll) scrollIndexed[timecode] = scroll as any as number;
         d["x-indexed"] = new List<number>(xindexed);
         d["y-indexed"] = new List<number>(yindexed);
         d["h-indexed"] = new List<number>(hindexed);
@@ -110,10 +110,10 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
 
     public static setupScroll(doc: Doc, timecode: number) {
         const scrollList = new List<number>();
-        scrollList[timecode] = NumCast(doc._scrollTop);
+        scrollList[timecode] = NumCast(doc._scrollY);
         doc["scroll-indexed"] = scrollList;
         doc.activeFrame = ComputedField.MakeFunction("self._currentFrame");
-        doc._scrollTop = ComputedField.MakeInterpolated("scroll", "activeFrame");
+        doc._scrollY = ComputedField.MakeInterpolated("scroll", "activeFrame");
     }
 
 
diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss
index 08160a2f4..7bc6c1dfd 100644
--- a/src/client/views/nodes/PresBox.scss
+++ b/src/client/views/nodes/PresBox.scss
@@ -144,6 +144,21 @@ $light-background: #ececec;
         grid-template-columns: repeat(auto-fit, 70px);
     }
 
+    .ribbon-colorBox {
+        cursor: pointer;
+        border: solid 1px black;
+        display: flex;
+        margin-left: 5px;
+        margin-top: 5px;
+        margin-bottom: 5px;
+        justify-content: center;
+        align-items: center;
+        height: 15px;
+        width: 15px;
+        padding: 0px;
+        transform: translate(2px, 3px);
+    }
+
     .ribbon-property {
         font-size: 11;
         font-weight: 200;
@@ -413,12 +428,40 @@ $light-background: #ececec;
     }
 
     .ribbon-button {
+        cursor: pointer;
+        font-size: 10.5;
+        font-weight: 300;
+        height: 20;
+        background-color: #979797;
+        color: white;
+        display: flex;
+        margin-top: 5px;
+        margin-bottom: 5px;
+        border-radius: 5px;
+        margin-right: 5px;
+        width: max-content;
+        justify-content: center;
+        align-items: center;
+        padding-right: 10px;
+        padding-left: 10px;
+    }
+
+    .ribbon-button:hover {
+        transform: scale(1.03);
+        transition: all 0.4s;
+        font-weight: 400;
+        opacity: 1;
+        color: white;
+        background-color: black;
+    }
+
+    .ribbon-toggle {
         cursor: pointer;
         font-size: 10.5;
         font-weight: 200;
         height: 20;
         background-color: $light-background;
-        border: solid 1px black;
+        border: solid 1px rgba(0, 0, 0, 0.5);
         display: flex;
         margin-top: 5px;
         margin-bottom: 5px;
@@ -431,12 +474,14 @@ $light-background: #ececec;
         padding-left: 10px;
     }
 
-    .ribbon-button.active {
+    .ribbon-toggle.active {
         background-color: #aedef8;
     }
 
-    .ribbon-button:hover {
-        background-color: lightgrey;
+    .ribbon-toggle:hover {
+        transform: scale(1.03);
+        transition: all 0.4s;
+        border: solid 1px rgba(0, 0, 0, 0.75);
     }
 
     svg.svg-inline--fa.fa-thumbtack.fa-w-12.toolbar-thumbtack {
@@ -801,82 +846,6 @@ $light-background: #ececec;
     }
 
 
-    .presPanelOverlay {
-        background-color: #323232;
-        color: white;
-        border-radius: 5px;
-        grid-template-rows: 100%;
-        height: 25;
-        width: max-content;
-        min-width: max-content;
-        justify-content: space-evenly;
-        align-items: center;
-        display: flex;
-        position: absolute;
-        right: 10px;
-        transition: all 0.2s;
-
-        .presPanel-button-text {
-            display: flex;
-            height: 20;
-            width: max-content;
-            font-family: Roboto;
-            font-weight: 400;
-            margin-left: 3px;
-            margin-right: 3px;
-            padding-right: 3px;
-            padding-left: 3px;
-            letter-spacing: normal;
-            border-radius: 5px;
-            align-items: center;
-            justify-content: center;
-            transition: all 0.3s;
-        }
-
-        .presPanel-divider {
-            width: 0.5px;
-            height: 80%;
-            border-right: solid 1px #5a5a5a;
-        }
-
-        .presPanel-button-frame {
-            justify-self: center;
-            align-self: center;
-            align-items: center;
-            display: grid;
-            grid-template-columns: auto auto auto;
-            justify-content: space-around;
-            font-size: 11;
-            margin-left: 7;
-            width: 30;
-            height: 85%;
-            background-color: rgba(91, 157, 221, 0.4);
-            border-radius: 5px;
-        }
-
-        .presPanel-button {
-            cursor: pointer;
-            display: flex;
-            height: 20;
-            min-width: 20;
-            margin-left: 3px;
-            margin-right: 3px;
-            border-radius: 100%;
-            align-items: center;
-            justify-content: center;
-            transition: all 0.3s;
-        }
-
-        .presPanel-button:hover {
-            background-color: #5a5a5a;
-        }
-
-        .presPanel-button-text:hover {
-            background-color: #5a5a5a;
-        }
-    }
-
-
 
     .collectionViewBaseChrome-viewPicker {
         min-width: 50;
@@ -952,80 +921,165 @@ $light-background: #ececec;
     }
 }
 
-.miniPres:hover {
-    opacity: 1;
-}
-
 .miniPres {
     cursor: grab;
     position: absolute;
-    overflow: hidden;
     right: 10;
     top: 10;
     opacity: 0.1;
     transition: all 0.4s;
-    /* border: solid 1px; */
     color: white;
-    /* box-shadow: black 0.4vw 0.4vw 0.8vw; */
+}
 
-    .miniPresOverlay {
-        display: grid;
-        grid-template-columns: auto auto auto auto auto auto auto auto auto auto;
-        grid-template-rows: 100%;
-        height: 100%;
-        justify-items: center;
-        align-items: center;
+.miniPres:hover {
+    opacity: 1;
+}
 
-        .miniPres-button-text {
-            cursor: pointer;
-            display: flex;
-            height: 20;
-            font-weight: 400;
-            min-width: 100%;
-            border-radius: 5px;
-            align-items: center;
-            justify-content: center;
-            transition: all 0.3s;
-        }
+.presPanelOverlay {
+    background-color: #323232;
+    color: white;
+    border-radius: 5px;
+    grid-template-rows: 100%;
+    height: 25;
+    width: max-content;
+    min-width: max-content;
+    justify-content: space-evenly;
+    align-items: center;
+    display: flex;
+    position: absolute;
+    right: 10px;
+    transition: all 0.2s;
 
-        .miniPres-button-frame {
-            justify-self: center;
-            align-self: center;
-            align-items: center;
-            display: grid;
-            grid-template-columns: auto auto auto;
-            justify-content: space-around;
-            font-size: 11;
-            margin-left: 7;
-            width: 30;
-            height: 85%;
-            background-color: rgba(91, 157, 221, 0.4);
-            border-radius: 5px;
-        }
+    .presPanel-button-text {
+        display: flex;
+        height: 20;
+        width: max-content;
+        font-family: Roboto;
+        font-weight: 400;
+        margin-left: 3px;
+        margin-right: 3px;
+        padding-right: 3px;
+        padding-left: 3px;
+        letter-spacing: normal;
+        border-radius: 5px;
+        align-items: center;
+        justify-content: center;
+        transition: all 0.3s;
+    }
 
-        .miniPres-divider {
-            width: 0.5px;
-            height: 80%;
-            border-right: solid 2px #5a5a5a;
-        }
+    .presPanel-divider {
+        width: 0.5px;
+        height: 80%;
+        border-right: solid 1px #5a5a5a;
+    }
 
-        .miniPres-button {
-            cursor: pointer;
-            display: flex;
-            height: 20;
-            min-width: 20;
-            border-radius: 100%;
-            align-items: center;
-            justify-content: center;
-            transition: all 0.3s;
-        }
+    .presPanel-button-frame {
+        justify-self: center;
+        align-self: center;
+        align-items: center;
+        display: grid;
+        grid-template-columns: auto auto auto;
+        justify-content: space-around;
+        font-size: 11;
+        margin-left: 7;
+        width: 30;
+        height: 85%;
+        background-color: rgba(91, 157, 221, 0.4);
+        border-radius: 5px;
+    }
 
-        .miniPres-button:hover {
-            background-color: #5a5a5a;
-        }
+    .presPanel-button {
+        cursor: pointer;
+        display: flex;
+        height: 20;
+        min-width: 20;
+        margin-left: 3px;
+        margin-right: 3px;
+        border-radius: 100%;
+        align-items: center;
+        justify-content: center;
+        transition: all 0.3s;
+    }
 
-        .miniPres-button-text:hover {
-            background-color: #5a5a5a;
-        }
+    .presPanel-button:hover {
+        background-color: #5a5a5a;
     }
-}
\ No newline at end of file
+
+    .presPanel-button-text:hover {
+        background-color: #5a5a5a;
+    }
+}
+
+// .miniPres {
+//     cursor: grab;
+//     position: absolute;
+//     overflow: hidden;
+//     right: 10;
+//     top: 10;
+//     opacity: 0.1;
+//     transition: all 0.4s;
+//     /* border: solid 1px; */
+//     color: white;
+//     /* box-shadow: black 0.4vw 0.4vw 0.8vw; */
+
+//     .miniPresOverlay {
+//         display: grid;
+//         grid-template-columns: auto auto auto auto auto auto auto auto auto auto;
+//         grid-template-rows: 100%;
+//         height: 100%;
+//         justify-items: center;
+//         align-items: center;
+
+//         .miniPres-button-text {
+//             cursor: pointer;
+//             display: flex;
+//             height: 20;
+//             font-weight: 400;
+//             min-width: 100%;
+//             border-radius: 5px;
+//             align-items: center;
+//             justify-content: center;
+//             transition: all 0.3s;
+//         }
+
+//         .miniPres-button-frame {
+//             justify-self: center;
+//             align-self: center;
+//             align-items: center;
+//             display: grid;
+//             grid-template-columns: auto auto auto;
+//             justify-content: space-around;
+//             font-size: 11;
+//             margin-left: 7;
+//             width: 30;
+//             height: 85%;
+//             background-color: rgba(91, 157, 221, 0.4);
+//             border-radius: 5px;
+//         }
+
+//         .miniPres-divider {
+//             width: 0.5px;
+//             height: 80%;
+//             border-right: solid 2px #5a5a5a;
+//         }
+
+//         .miniPres-button {
+//             cursor: pointer;
+//             display: flex;
+//             height: 20;
+//             min-width: 20;
+//             border-radius: 100%;
+//             align-items: center;
+//             justify-content: center;
+//             transition: all 0.3s;
+//         }
+
+//         .miniPres-button:hover {
+//             background-color: #5a5a5a;
+//         }
+
+//         .miniPres-button-text:hover {
+//             background-color: #5a5a5a;
+//         }
+//     }
+// }
\ No newline at end of file
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index b0563c373..72c1669e7 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -4,7 +4,7 @@ import { Tooltip } from "@material-ui/core";
 import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { ColorState, SketchPicker } from "react-color";
-import { Doc, DocCastAsync, DocListCast } from "../../../fields/Doc";
+import { Doc, DocCastAsync, DocListCast, DocListCastAsync } from "../../../fields/Doc";
 import { documentSchema } from "../../../fields/documentSchemas";
 import { InkTool } from "../../../fields/InkField";
 import { List } from "../../../fields/List";
@@ -28,6 +28,23 @@ import { AudioBox } from "./AudioBox";
 import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./PresBox.scss";
+import { VideoBox } from "./VideoBox";
+
+export enum PresMovement {
+    Zoom = "zoom",
+    Pan = "pan",
+    Jump = "jump",
+    None = "none",
+}
+
+export enum PresEffect {
+    Fade = "fade",
+    Flip = "flip",
+    Rotate = "rotate",
+    Bounce = "bounce",
+    Roll = "roll",
+    None = "none",
+}
 
 type PresBoxSchema = makeInterface<[typeof documentSchema]>;
 const PresBoxDocument = makeInterface(documentSchema);
@@ -50,7 +67,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @observable private transitionTools: boolean = false;
     @observable private newDocumentTools: boolean = false;
     @observable private progressivizeTools: boolean = false;
-    @observable private moreInfoTools: boolean = false;
     @observable private playTools: boolean = false;
     @observable private presentTools: boolean = false;
     @observable private pathBoolean: boolean = false;
@@ -79,11 +95,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         this.props.Document.presentationFieldKey = this.fieldKey; // provide info to the presElement script so that it can look up rendering information about the presBox
     }
     @computed get selectedDocumentView() {
-        if (SelectionManager.SelectedDocuments().length) {
-            return SelectionManager.SelectedDocuments()[0];
-        } else if (PresBox.Instance._selectedArray.length) {
-            return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
-        } else { return undefined; }
+        if (SelectionManager.SelectedDocuments().length) return SelectionManager.SelectedDocuments()[0];
+        if (PresBox.Instance && PresBox.Instance._selectedArray) return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
+        return undefined;
     }
     @computed get isPres(): boolean {
         document.removeEventListener("keydown", this.keyEvents, true);
@@ -97,18 +111,21 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
 
     componentWillUnmount() {
         document.removeEventListener("keydown", this.keyEvents, true);
-        this.turnOffEdit();
+        // Turn of progressivize editors
+        this.turnOffEdit(true);
     }
 
-    componentDidMount() {
+    componentDidMount = async () => {
         this.rootDoc.presBox = this.rootDoc;
         this.rootDoc._forceRenderEngine = "timeline";
         this.rootDoc._replacedChrome = "replaced";
         this.layoutDoc.presStatus = "edit";
         this.layoutDoc._gridGap = 5;
-        if (!DocListCast((Doc.UserDoc().myPresentations as Doc).data).includes(this.rootDoc)) {
-            Doc.AddDocToList(Doc.UserDoc().myPresentations as Doc, "data", this.rootDoc);
-        }
+        this.turnOffEdit(true);
+        DocListCastAsync((Doc.UserDoc().myPresentations as Doc).data).then(async pres => {
+            await Promise.all(pres!);
+            if (!DocListCast((Doc.UserDoc().myPresentations as Doc).data).includes(this.rootDoc)) Doc.AddDocToList(Doc.UserDoc().myPresentations as Doc, "data", this.rootDoc);
+        });
     }
 
     updateCurrentPresentation = () => {
@@ -131,32 +148,38 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const lastFrame = Cast(targetDoc.lastFrame, "number", null);
         const curFrame = NumCast(targetDoc._currentFrame);
         let internalFrames: boolean = false;
-        if (targetDoc.presProgressivize || activeItem.zoomProgressivize || targetDoc.scrollProgressivize) internalFrames = true;
+        if (activeItem.presProgressivize || activeItem.zoomProgressivize || targetDoc.scrollProgressivize) internalFrames = true;
         // Case 1: There are still other frames and should go through all frames before going to next slide
         if (internalFrames && lastFrame !== undefined && curFrame < lastFrame) {
             targetDoc._viewTransition = "all 1s";
             setTimeout(() => targetDoc._viewTransition = undefined, 1010);
-            targetDoc._currentFrame = curFrame + 1;
-            if (targetDoc.scrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(targetDoc, currentFrame);
-            if (targetDoc.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, targetDoc);
+            // targetDoc._currentFrame = curFrame + 1;
+            this.nextKeyframe(targetDoc, activeItem);
+            // if (targetDoc.scrollProgressivize) CollectionFreeFormDocumentView.updateScrollframe(targetDoc, currentFrame);
+            if (activeItem.presProgressivize) CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, targetDoc);
             else targetDoc.editing = true;
-            if (activeItem.zoomProgressivize) this.zoomProgressivizeNext(targetDoc);
-            // Case 2: Audio or video therefore wait to play the audio or video before moving on
-        } else if ((targetDoc.type === DocumentType.AUDIO) && !this._moveOnFromAudio && this.layoutDoc.presStatus !== 'auto') {
-            AudioBox.Instance.playFrom(0);
-            this._moveOnFromAudio = true;
-            // Case 3: No more frames in current doc and next slide is defined, therefore move to next slide
+            // if (activeItem.zoomProgressivize) this.zoomProgressivizeNext(targetDoc);
+            // Case 2: 'Play on next' for audio or video therefore first navigate to the audio/video before it should be played
+        } else if ((targetDoc.type === DocumentType.AUDIO || targetDoc.type === DocumentType.VID) && !activeItem.playAuto && activeItem.playNow && this.layoutDoc.presStatus !== 'auto') {
+            if (targetDoc.type === DocumentType.AUDIO) AudioBox.Instance.playFrom(NumCast(activeItem.presStartTime));
+            // if (targetDoc.type === DocumentType.VID) { VideoBox.Instance.Play() };
+            activeItem.playNow = false;
+            // Case 3: No more frames in current doc and next slide is defined, therefore move to next slide 
         } else if (this.childDocs[this.itemIndex + 1] !== undefined) {
+            if (activeNext.presPinView) setTimeout(() => this.selectPres(), 0);
+            else this.selectPres();
             const nextSelected = this.itemIndex + 1;
-            if (targetDoc.type === DocumentType.AUDIO) AudioBox.Instance.pause();
-            this.gotoDocument(nextSelected, this.itemIndex);
+            if (targetDoc.type === DocumentType.AUDIO) { if (AudioBox.Instance._ele) AudioBox.Instance.pause(); }
+            // if (targetDoc.type === DocumentType.VID) { if (AudioBox.Instance._ele) VideoBox.Instance.Pause(); }
             const targetNext = Cast(activeNext.presentationTargetDoc, Doc, null);
-            if (activeNext && targetNext.type === DocumentType.AUDIO && activeNext.playAuto) {
-                AudioBox.Instance.playFrom(0);
-                this._moveOnFromAudio = true;
-            } else this._moveOnFromAudio = false;
+            // If next slide is audio / video 'Play automatically' then the next slide should be played
+            if (activeNext && (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) && activeNext.playAuto) {
+                console.log('play next automatically');
+                if (targetNext.type === DocumentType.AUDIO) AudioBox.Instance.playFrom(NumCast(activeNext.presStartTime));
+                // if (targetNext.type === DocumentType.VID) { VideoBox.Instance.Play() };
+            } else if (targetNext.type === DocumentType.AUDIO || targetNext.type === DocumentType.VID) { activeNext.playNow = true; console.log('play next after it is navigated to'); }
+            this.gotoDocument(nextSelected, this.itemIndex);
         } else if (this.childDocs[this.itemIndex + 1] === undefined && this.layoutDoc.presLoop) {
-            const nextSelected = 0;
             this.gotoDocument(0, this.itemIndex);
         }
     }
@@ -176,6 +199,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const prevTargetDoc = Cast(prevItem.presentationTargetDoc, Doc, null);
         const lastFrame = Cast(targetDoc.lastFrame, "number", null);
         const curFrame = NumCast(targetDoc._currentFrame);
+        if (prevItem.presPinView) setTimeout(() => this.selectPres(), 0);
+        else this.selectPres();
         if (lastFrame !== undefined && curFrame >= 1) {
             this.prevKeyframe(targetDoc, activeItem);
         } else if (activeItem) {
@@ -193,9 +218,27 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         Doc.UnBrushAllDocs();
         if (index >= 0 && index < this.childDocs.length) {
             this.rootDoc._itemIndex = index;
+            const activeItem: Doc = this.activeItem;
             const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null);
+            if (activeItem.presPinView) {
+                const bestTarget = DocumentManager.Instance.getFirstDocumentView(presTargetDoc)?.props.Document;
+                bestTarget && runInAction(() => {
+                    if (activeItem.presMovement === PresMovement.Jump) {
+                        bestTarget!._viewTransition = '0s';
+                    } else {
+                        bestTarget!._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 1s';
+                        setTimeout(() => bestTarget!._viewTransition = undefined, activeItem.presTransition ? NumCast(activeItem.presTransition) + 10 : 1010);
+                    }
+                });
+            } else {
+                presTargetDoc && runInAction(() => {
+                    if (activeItem.presMovement === PresMovement.Jump) presTargetDoc.focusSpeed = 0;
+                    else presTargetDoc.focusSpeed = activeItem.presTransition ? activeItem.presTransition : 500;
+                });
+                setTimeout(() => presTargetDoc.focusSpeed = 500, this.activeItem.presTransition ? NumCast(this.activeItem.presTransition) + 10 : 510);
+            }
             if (presTargetDoc?.lastFrame !== undefined) {
-                presTargetDoc.currentFrame = 0;
+                presTargetDoc._currentFrame = 0;
             }
             this._selectedArray = [this.childDocs[index]]; //Update selected array
             //Handles movement to element
@@ -219,7 +262,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const presCollection = Cast(this.layoutDoc.presCollection, Doc, null);
         const collectionDocView = presCollection ? await DocumentManager.Instance.getDocumentView(presCollection) : undefined;
         this.turnOffEdit();
-
         if (this.itemIndex >= 0) {
             if (srcContext && targetDoc) {
                 this.layoutDoc.presCollection = srcContext;
@@ -244,9 +286,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 this.zoomProgressivizeNext(targetDoc);
             } else if (docToJump === curDoc) {
                 //checking if curDoc has navigation open
-                if (curDoc.presNavButton && targetDoc) {
+                if (curDoc.presMovement === PresMovement.Pan && targetDoc) {
                     await DocumentManager.Instance.jumpToDocument(targetDoc, false, undefined, srcContext);
-                } else if (curDoc.presZoomButton && targetDoc) {
+                } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) {
                     //awaiting jump so that new scale can be found, since jumping is async
                     await DocumentManager.Instance.jumpToDocument(targetDoc, true, undefined, srcContext);
                 }
@@ -261,10 +303,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             // if targetDoc is not displayed but one of its aliases is, then we need to modify that alias, not the original target
             const bestTarget = DocumentManager.Instance.getFirstDocumentView(targetDoc)?.props.Document;
             bestTarget && runInAction(() => {
-                bestTarget._viewTransition = "all 1s";
-                bestTarget._panX = activeItem.presPinViewX;
-                bestTarget._panY = activeItem.presPinViewY;
-                bestTarget._viewScale = activeItem.presPinViewScale;
+                bestTarget!._viewTransition = activeItem.presTransition ? `transform ${activeItem.presTransition}ms` : 'all 0.5s';
+                bestTarget!._panX = activeItem.presPinViewX;
+                bestTarget!._panY = activeItem.presPinViewY;
+                bestTarget!._viewScale = activeItem.presPinViewScale;
             });
             //setTimeout(() => targetDoc._viewTransition = undefined, 1010);
         }
@@ -358,13 +400,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         this.updateCurrentPresentation();
         let activeItem: Doc = this.activeItem;
         let targetDoc: Doc = this.targetDoc;
-        let duration = NumCast(targetDoc.presDuration) + NumCast(targetDoc.presTransition);
+        let duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition);
         const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms));
         const load = async () => { // Wrap the loop into an async function for this to work
             for (var i = startSlide; i < this.childDocs.length; i++) {
                 activeItem = Cast(this.childDocs[this.itemIndex], Doc, null);
                 targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null);
-                duration = NumCast(targetDoc.presDuration) + NumCast(targetDoc.presTransition);
+                duration = NumCast(activeItem.presDuration) + NumCast(activeItem.presTransition);
                 if (duration <= 100) { duration = 2500; }
                 if (NumCast(targetDoc.lastFrame) > 0) {
                     for (var f = 0; f < NumCast(targetDoc.lastFrame); f++) {
@@ -404,7 +446,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         this.rootDoc._itemIndex = 0;
     }
 
-    @action togglePath = () => this.pathBoolean = !this.pathBoolean;
+    @action togglePath = (srcContext: Doc, off?: boolean) => {
+        if (off) {
+            this.pathBoolean = false;
+            srcContext.presPathView = false;
+        } else {
+            this.pathBoolean = !this.pathBoolean;
+            srcContext.presPathView = this.pathBoolean;
+        }
+    }
     @action toggleExpandMode = () => {
         this.rootDoc.expandBoolean = !this.rootDoc.expandBoolean;
         this.childDocs.forEach((doc) => {
@@ -445,7 +495,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             CollectionDockingView.AddSplit(this.rootDoc, "right");
             this.layoutDoc.inOverlay = false;
         } else if (this.layoutDoc.context && docView) {
-            this.layoutDoc.presStatus = 'manual';
+            this.layoutDoc.presStatus = 'edit';
+            clearTimeout(this._presTimer);
             const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
             this.rootDoc.x = pt[0] + (this.props.PanelWidth() - 250);
             this.rootDoc.y = pt[1] + 10;
@@ -454,7 +505,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             docView.props.removeDocument?.(this.layoutDoc);
             Doc.AddDocToList((Doc.UserDoc().myOverlayDocs as Doc), undefined, this.rootDoc);
         } else {
-            this.layoutDoc.presStatus = 'manual';
+            this.layoutDoc.presStatus = 'edit';
+            clearTimeout(this._presTimer);
             const pt = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
             this.rootDoc.x = pt[0] + (this.props.PanelWidth() - 250);
             this.rootDoc.y = pt[1] + 10;
@@ -485,33 +537,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @undoBatch
     updateMovement = action((movement: any, activeItem: Doc, targetDoc: Doc) => {
         switch (movement) {
-            case 'zoom': //Pan and zoom
-                activeItem.presNavButton = false;
-                activeItem.presZoomButton = !activeItem.presZoomButton;
-                targetDoc.presTransition = activeItem.presTransition;
-                if (activeItem.presZoomButton) activeItem.presMovement = 'zoom';
-                else activeItem.presMovement = 'none';
+            case PresMovement.Zoom: //Pan and zoom
+                activeItem.presMovement = PresMovement.Zoom;
                 break;
-            case 'pan': //Pan
-                activeItem.presZoomButton = false;
-                activeItem.presNavButton = !activeItem.presNavButton;
-                targetDoc.presTransition = activeItem.presTransition;
-                if (activeItem.presNavButton) activeItem.presMovement = 'pan';
-                else activeItem.presMovement = 'none';
+            case PresMovement.Pan: //Pan
+                activeItem.presMovement = PresMovement.Pan;
                 break;
-            case 'jump': //Jump Cut
-                activeItem.presTransition = targetDoc.presTransition;
-                targetDoc.presTransition = 0;
-                activeItem.presZoomButton = true;
-                activeItem.presSwitchButton = !activeItem.presSwitchButton;
-                if (activeItem.presSwitchButton) activeItem.presMovement = 'jump';
-                else activeItem.presMovement = 'none';
+            case PresMovement.Jump: //Jump Cut
+                activeItem.presJump = true;
+                activeItem.presMovement = PresMovement.Jump;
                 break;
-            case 'none': default:
-                activeItem.presMovement = 'none';
-                activeItem.presZoomButton = false;
-                activeItem.presNavButton = false;
-                activeItem.presSwitchButton = false;
+            case PresMovement.None: default:
+                activeItem.presMovement = PresMovement.None;
                 break;
         }
     });
@@ -519,10 +556,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     setMovementName = action((movement: any, activeItem: Doc): string => {
         let output: string = 'none';
         switch (movement) {
-            case 'zoom': output = 'Zoom'; break; //Pan and zoom
-            case 'pan': output = 'Pan'; break; //Pan
-            case 'jump': output = 'Jump cut'; break; //Jump Cut
-            case 'none': output = 'None'; break; //None
+            case PresMovement.Zoom: output = 'Zoom'; break; //Pan and zoom
+            case PresMovement.Pan: output = 'Pan'; break; //Pan
+            case PresMovement.Jump: output = 'Jump cut'; break; //Jump Cut
+            case PresMovement.None: output = 'None'; break; //None
             default: output = 'Zoom'; activeItem.presMovement = 'zoom'; break; //default set as zoom
         }
         return output;
@@ -535,9 +572,20 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         docs.forEach((doc, i) => {
             if (this.childDocs.includes(doc)) {
                 if (docs.length === i + 1) return false;
+            } else if (doc.type === DocumentType.LABEL) {
+                const audio = Cast(doc.annotationOn, Doc, null) as Doc;
+                if (audio) {
+                    audio.aliasOf instanceof Doc;
+                    audio.presStartTime = NumCast(doc.audioStart);
+                    audio.presEndTime = NumCast(doc.audioEnd);
+                    audio.presDuration = NumCast(doc.audioEnd) - NumCast(doc.audioStart);
+                    TabDocView.PinDoc(audio, false, true);
+                    setTimeout(() => this.removeDocument(doc), 1);
+                    return false;
+                }
             } else {
                 doc.aliasOf instanceof Doc && (doc.presentationTargetDoc = doc.aliasOf);
-                !this.childDocs.includes(doc) && (doc.presZoomButton = true);
+                !this.childDocs.includes(doc) && (doc.presMovement = PresMovement.Zoom);
                 if (this.rootDoc.expandBoolean) doc.presExpandInlineButton = true;
             }
         });
@@ -571,16 +619,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const list = this._selectedArray.map((doc: Doc, index: any) => {
             const curDoc = Cast(doc, Doc, null);
             const tagDoc = Cast(curDoc.presentationTargetDoc!, Doc, null);
-            return (
-                <div className="selectedList-items">{index + 1}.  {tagDoc.title}</div>
-            );
+            if (tagDoc) return (
+                <div className="selectedList-items">{index + 1}.  {curDoc.title}</div>
+            ); else if (curDoc) return <div className="selectedList-items">{index + 1}.  {curDoc.title}</div>
         });
         return list;
     }
 
     @action
     selectPres = () => {
-        const presDocView = DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc)!;
+        const presDocView = DocumentManager.Instance.getDocumentView(this.rootDoc)!;
         SelectionManager.SelectDoc(presDocView, false);
     }
 
@@ -588,7 +636,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @action
     selectElement = (doc: Doc) => {
         this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.itemIndex));
-        this.selectPres();
+        if (doc.presPinView) setTimeout(() => this.selectPres(), 0);
+        else this.selectPres();
     }
 
     //Command click
@@ -645,7 +694,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             handled = true;
         } if (e.keyCode === 32) { // spacebar to 'present' or autoplay
             if (this.layoutDoc.presStatus !== "edit") this.startAutoPres(0);
-            else this.layoutDoc.presStatus = "manual"; if (this._presTimer) clearTimeout(this._presTimer);
+            else this.next();
             handled = true;
         } if (e.keyCode === 8) { // delete selected items
             if (this.layoutDoc.presStatus === "edit") {
@@ -680,14 +729,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
      */
     @undoBatch
     @action
-    viewPaths = async () => {
+    viewPaths = () => {
         const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
-        if (this.pathBoolean && srcContext) {
-            this.togglePath();
-            srcContext.presPathView = false;
-        } else if (srcContext) {
-            this.togglePath();
-            srcContext.presPathView = true;
+        if (srcContext) {
+            this.togglePath(srcContext);
         }
     }
 
@@ -697,10 +742,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         this.childDocs.forEach((doc, index) => {
             const tagDoc = Cast(doc.presentationTargetDoc, Doc, null);
             const srcContext = Cast(tagDoc?.context, Doc, null);
+            const width = NumCast(tagDoc._width) / 10;
+            const height = Math.max(NumCast(tagDoc._height) / 10, 15);
+            const edge = Math.max(width, height);
+            const fontSize = edge * 0.8;
             // Case A: Document is contained within the colleciton
             if (this.rootDoc.presCollection === srcContext) {
                 order.push(
-                    <div className="pathOrder" style={{ top: NumCast(tagDoc.y), left: NumCast(tagDoc.x) }}>
+                    <div className="pathOrder" style={{ top: NumCast(tagDoc.y) - (edge / 2), left: NumCast(tagDoc.x) - (edge / 2), width: edge, height: edge, fontSize: fontSize }}>
                         <div className="pathOrder-frame">{index + 1}</div>
                     </div>);
                 // Case B: Document is not inside of the collection
@@ -744,6 +793,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 stroke: "#69a6db",
                 strokeWidth: 5,
                 strokeDasharray: '10 5',
+                boxShadow: '0px 4px 4px rgba(0, 0, 0, 0.25)',
             }}
             fill="none"
             markerStart="url(#markerSquare)"
@@ -781,7 +831,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         if (change) timeInMS += change;
         if (timeInMS < 100) timeInMS = 100;
         if (timeInMS > 10000) timeInMS = 10000;
-        if (this.targetDoc) this.targetDoc.presTransition = timeInMS;
+        if (this.activeItem) this.activeItem.presTransition = timeInMS;
     }
 
     // Converts seconds to ms and updates presDuration
@@ -790,7 +840,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         if (change) timeInMS += change;
         if (timeInMS < 100) timeInMS = 100;
         if (timeInMS > 20000) timeInMS = 20000;
-        if (this.targetDoc) this.targetDoc.presDuration = timeInMS;
+        if (this.activeItem) this.activeItem.presDuration = timeInMS;
     }
 
 
@@ -798,9 +848,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
         if (activeItem && targetDoc) {
-            const transitionSpeed = targetDoc.presTransition ? NumCast(targetDoc.presTransition) / 1000 : 0.5;
-            let duration = targetDoc.presDuration ? NumCast(targetDoc.presDuration) / 1000 : 2;
-            if (targetDoc.type === DocumentType.AUDIO) duration = NumCast(targetDoc.duration);
+            const transitionSpeed = activeItem.presTransition ? NumCast(activeItem.presTransition) / 1000 : 0.5;
+            let duration = activeItem.presDuration ? NumCast(activeItem.presDuration) / 1000 : 2;
+            if (activeItem.type === DocumentType.AUDIO) duration = NumCast(activeItem.duration);
             const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None';
             activeItem.presMovement = activeItem.presMovement ? activeItem.presMovement : 'Zoom';
             return (
@@ -811,18 +861,17 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                             {this.setMovementName(activeItem.presMovement, activeItem)}
                             <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2, color: this.openMovementDropdown ? '#5B9FDD' : 'black' }} icon={"angle-down"} />
                             <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onPointerDown={e => e.stopPropagation()} style={{ display: this.openMovementDropdown ? "grid" : "none" }}>
-                                <div className={`presBox-dropdownOption ${activeItem.presMovement === 'none' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement('none', activeItem, targetDoc)}>None</div>
-                                <div className={`presBox-dropdownOption ${activeItem.presMovement === 'zoom' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement('zoom', activeItem, targetDoc)}>Pan and Zoom</div>
-                                <div className={`presBox-dropdownOption ${activeItem.presMovement === 'pan' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement('pan', activeItem, targetDoc)}>Pan</div>
-                                <div className={`presBox-dropdownOption ${activeItem.presMovement === 'jump' ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement('jump', activeItem, targetDoc)}>Jump cut</div>
+                                <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.None ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.None, activeItem, targetDoc)}>None</div>
+                                <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Zoom ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Zoom, activeItem, targetDoc)}>Pan and Zoom</div>
+                                <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Pan ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Pan, activeItem, targetDoc)}>Pan</div>
+                                <div className={`presBox-dropdownOption ${activeItem.presMovement === PresMovement.Jump ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.updateMovement(PresMovement.Jump, activeItem, targetDoc)}>Jump cut</div>
                             </div>
                         </div>
-                        <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === 'pan' || activeItem.presMovement === 'zoom' ? "inline-flex" : "none" }}>
+                        <div className="ribbon-doubleButton" style={{ display: activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "inline-flex" : "none" }}>
                             <div className="presBox-subheading">Transition Speed</div>
                             <div className="ribbon-property">
                                 <input className="presBox-input"
                                     type="number" value={transitionSpeed}
-                                    onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                                     onChange={action((e) => this.setTransitionTime(e.target.value))} /> s
                             </div>
                             <div className="ribbon-propertyUpDown">
@@ -834,8 +883,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                 </div>
                             </div>
                         </div>
-                        <input type="range" step="0.1" min="0.1" max="10" value={transitionSpeed} className={`toolbar-slider ${activeItem.presMovement === 'pan' || activeItem.presMovement === 'zoom' ? "" : "none"}`} id="toolbar-slider" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setTransitionTime(e.target.value); }} />
-                        <div className={`slider-headers ${activeItem.presMovement === 'pan' || activeItem.presMovement === 'zoom' ? "" : "none"}`}>
+                        <input type="range" step="0.1" min="0.1" max="10" value={transitionSpeed} className={`toolbar-slider ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`} id="toolbar-slider" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setTransitionTime(e.target.value); }} />
+                        <div className={`slider-headers ${activeItem.presMovement === PresMovement.Pan || activeItem.presMovement === PresMovement.Zoom ? "" : "none"}`}>
                             <div className="slider-text">Fast</div>
                             <div className="slider-text">Medium</div>
                             <div className="slider-text">Slow</div>
@@ -844,15 +893,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                     <div className="ribbon-box">
                         Visibility {"&"} Duration
                         <div className="ribbon-doubleButton">
-                            <Tooltip title={<><div className="dash-tooltip">{"Hide before presented"}</div></>}><div className={`ribbon-button ${activeItem.presHideTillShownButton ? "active" : ""}`} onClick={() => activeItem.presHideTillShownButton = !activeItem.presHideTillShownButton}>Hide before</div></Tooltip>
-                            <Tooltip title={<><div className="dash-tooltip">{"Hide after presented"}</div></>}><div className={`ribbon-button ${activeItem.presHideAfterButton ? "active" : ""}`} onClick={() => activeItem.presHideAfterButton = !activeItem.presHideAfterButton}>Hide after</div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Hide before presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideTillShownButton ? "active" : ""}`} onClick={() => activeItem.presHideTillShownButton = !activeItem.presHideTillShownButton}>Hide before</div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Hide after presented"}</div></>}><div className={`ribbon-toggle ${activeItem.presHideAfterButton ? "active" : ""}`} onClick={() => activeItem.presHideAfterButton = !activeItem.presHideAfterButton}>Hide after</div></Tooltip>
+                            <Tooltip title={<><div className="dash-tooltip">{"Open document in a new tab"}</div></>}><div className="ribbon-toggle" style={{ backgroundColor: activeItem.openDocument ? "#aedef8" : "" }} onClick={() => activeItem.openDocument = !activeItem.openDocument}>Open</div></Tooltip>
                         </div>
                         <div className="ribbon-doubleButton" >
                             <div className="presBox-subheading">Slide Duration</div>
                             <div className="ribbon-property">
                                 <input className="presBox-input"
                                     type="number" value={duration}
-                                    onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
+                                    // onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                                     onChange={action((e) => this.setDurationTime(e.target.value))} /> s
                             </div>
                             <div className="ribbon-propertyUpDown">
@@ -929,14 +979,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     applyTo = (array: Doc[]) => {
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
-        array.forEach((doc, index) => {
+        array.forEach((doc) => {
             const curDoc = Cast(doc, Doc, null);
             const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null);
             if (tagDoc && targetDoc) {
-                tagDoc.presTransition = targetDoc.presTransition;
-                tagDoc.presDuration = targetDoc.presDuration;
+                curDoc.presTransition = activeItem.presTransition;
+                curDoc.presDuration = activeItem.presDuration;
                 tagDoc.presEffect = targetDoc.presEffect;
                 tagDoc.presEffectDirection = targetDoc.presEffectDirection;
+                tagDoc.presMovement = targetDoc.presMovement;
                 curDoc.presMovement = activeItem.presMovement;
                 this.updateMovement(activeItem.presMovement, curDoc, tagDoc);
                 curDoc.presHideTillShownButton = activeItem.presHideTillShownButton;
@@ -947,20 +998,39 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @computed get optionsDropdown() {
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
+        const presPinWithViewIcon = <img src={`/assets/${"pinWithView.png"}`}
+            style={{ width: 16, filter: 'invert(1)' }} />;
         if (activeItem && targetDoc) {
             return (
                 <div>
                     <div className={'presBox-ribbon'} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                         <div className="ribbon-box">
                             <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.AUDIO ? "inline-flex" : "none" }}>
-                                <div className="ribbon-button" style={{ backgroundColor: activeItem.playAuto ? "#aedef8" : "" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play automatically</div>
-                                <div className="ribbon-button" style={{ display: "flex", backgroundColor: activeItem.playAuto ? "" : "#aedef8" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play on next</div>
-                            </div>
-                            <div className="ribbon-doubleButton" style={{ display: "flex" }}>
-                                <div className="ribbon-button" style={{ backgroundColor: activeItem.openDocument ? "#aedef8" : "" }} onClick={() => activeItem.openDocument = !activeItem.openDocument}>Open document</div>
+                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.playAuto ? "#aedef8" : "" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play automatically</div>
+                                <div className="ribbon-toggle" style={{ display: "flex", backgroundColor: activeItem.playAuto ? "" : "#aedef8" }} onClick={() => activeItem.playAuto = !activeItem.playAuto}>Play on next</div>
                             </div>
+                            {targetDoc.type === DocumentType.VID ? <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presVidFullScreen ? "#aedef8" : "" }} onClick={() => activeItem.presVidFullScreen = !activeItem.presVidFullScreen}>Full screen</div> : (null)}
+                            {targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                                <div className="presBox-subheading">Start time</div>
+                                <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                                    <input className="presBox-input"
+                                        style={{ textAlign: 'left', width: 50 }}
+                                        type="number" value={NumCast(activeItem.presStartTime)}
+                                        onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { activeItem.presStartTime = Number(e.target.value); })} />
+                                </div>
+                            </div> : (null)}
+                            {targetDoc.type === DocumentType.VID || targetDoc.type === DocumentType.AUDIO ? <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
+                                <div className="presBox-subheading">End time</div>
+                                <div className="ribbon-property" style={{ paddingRight: 0, paddingLeft: 0 }}>
+                                    <input className="presBox-input"
+                                        style={{ textAlign: 'left', width: 50 }}
+                                        type="number" value={NumCast(activeItem.presEndTime)}
+                                        onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presEndTime = Number(val); })} />
+                                </div>
+                            </div> : (null)}
+                            {targetDoc.type === DocumentType.COL ? 'Presentation Pin View' : (null)}
                             <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.COL ? "inline-flex" : "none" }}>
-                                <div className="ribbon-button" style={{ backgroundColor: activeItem.presPinView ? "#aedef8" : "" }}
+                                <div className="ribbon-toggle" style={{ width: 20, padding: 0, backgroundColor: activeItem.presPinView ? "#aedef8" : "" }}
                                     onClick={() => {
                                         activeItem.presPinView = !activeItem.presPinView;
                                         targetDoc.presPinView = activeItem.presPinView;
@@ -972,7 +1042,16 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                             activeItem.presPinViewY = y;
                                             activeItem.presPinViewScale = scale;
                                         }
-                                    }}>Presentation pin view</div>
+                                    }}>{presPinWithViewIcon}</div>
+                                {activeItem.presPinView ? <div className="ribbon-button"
+                                    onClick={() => {
+                                        const x = targetDoc._panX;
+                                        const y = targetDoc._panY;
+                                        const scale = targetDoc._viewScale;
+                                        activeItem.presPinViewX = x;
+                                        activeItem.presPinViewY = y;
+                                        activeItem.presPinViewScale = scale
+                                    }}>Update</div> : (null)}
                             </div>
                             <div style={{ display: activeItem.presPinView ? "block" : "none" }}>
                                 <div className="ribbon-doubleButton" style={{ marginRight: 10 }}>
@@ -981,7 +1060,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         <input className="presBox-input"
                                             style={{ textAlign: 'left', width: 50 }}
                                             type="number" value={NumCast(activeItem.presPinViewX)}
-                                            onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                                             onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewX = Number(val); })} />
                                     </div>
                                 </div>
@@ -991,7 +1069,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         <input className="presBox-input"
                                             style={{ textAlign: 'left', width: 50 }}
                                             type="number" value={NumCast(activeItem.presPinViewY)}
-                                            onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                                             onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewY = Number(val); })} />
                                     </div>
                                 </div>
@@ -1001,13 +1078,12 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                         <input className="presBox-input"
                                             style={{ textAlign: 'left', width: 50 }}
                                             type="number" value={NumCast(activeItem.presPinViewScale)}
-                                            onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                                             onChange={action((e: React.ChangeEvent<HTMLInputElement>) => { const val = e.target.value; activeItem.presPinViewScale = Number(val); })} />
                                     </div>
                                 </div>
                             </div>
                             {/* <div className="ribbon-doubleButton" style={{ display: targetDoc.type === DocumentType.WEB ? "inline-flex" : "none" }}>
-                                <div className="ribbon-button" onClick={this.progressivizeText}>Store original website</div>
+                                <div className="ribbon-toggle" onClick={this.progressivizeText}>Store original website</div>
                             </div> */}
                         </div>
                     </div>
@@ -1051,18 +1127,18 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                     <div className="ribbon-box">
                         Slide Title: <br></br>
                         <input className="ribbon-textInput" placeholder="..." type="text" name="fname"
-                            onFocus={() => document.removeEventListener("keydown", this.keyEvents, true)}
                             onChange={(e) => {
                                 e.stopPropagation();
                                 e.preventDefault();
                                 runInAction(() => this.title = e.target.value);
-                            }}></input>
+                            }}>
+                        </input>
                     </div>
                     <div className="ribbon-box">
                         Choose type:
                         <div className="ribbon-doubleButton">
-                            <div title="Text" className={'ribbon-button'} style={{ background: this.addFreeform ? "" : "#aedef8" }} onClick={action(() => this.addFreeform = !this.addFreeform)}>Text</div>
-                            <div title="Freeform" className={'ribbon-button'} style={{ background: this.addFreeform ? "#aedef8" : "" }} onClick={action(() => this.addFreeform = !this.addFreeform)}>Freeform</div>
+                            <div title="Text" className={'ribbon-toggle'} style={{ background: this.addFreeform ? "" : "#aedef8" }} onClick={action(() => this.addFreeform = !this.addFreeform)}>Text</div>
+                            <div title="Freeform" className={'ribbon-toggle'} style={{ background: this.addFreeform ? "#aedef8" : "" }} onClick={action(() => this.addFreeform = !this.addFreeform)}>Freeform</div>
                         </div>
                     </div>
                     <div className="ribbon-box" style={{ display: this.addFreeform ? "grid" : "none" }}>
@@ -1129,13 +1205,13 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             y = NumCast(targetDoc.y) + NumCast(targetDoc._height) + 20;
         }
         let doc = undefined;
-        const title = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 58, _fontSize: "24px", });
-        const subtitle = Docs.Create.TextDocument("Click to change subtitle", { title: "Slide subtitle", _width: 380, _height: 50, x: 10, y: 118, _fontSize: "16px" });
-        const header = Docs.Create.TextDocument("Click to change header", { title: "Slide header", _width: 380, _height: 65, x: 10, y: 80, _fontSize: "20px" });
-        const contentTitle = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 10, _fontSize: "24px" });
-        const content = Docs.Create.TextDocument("Click to change text", { title: "Slide text", _width: 380, _height: 145, x: 10, y: 70, _fontSize: "14px" });
-        const content1 = Docs.Create.TextDocument("Click to change text", { title: "Column 1", _width: 185, _height: 140, x: 10, y: 80, _fontSize: "14px" });
-        const content2 = Docs.Create.TextDocument("Click to change text", { title: "Column 2", _width: 185, _height: 140, x: 205, y: 80, _fontSize: "14px" });
+        const title = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 58, _fontSize: "24pt", });
+        const subtitle = Docs.Create.TextDocument("Click to change subtitle", { title: "Slide subtitle", _width: 380, _height: 50, x: 10, y: 118, _fontSize: "16pt" });
+        const header = Docs.Create.TextDocument("Click to change header", { title: "Slide header", _width: 380, _height: 65, x: 10, y: 80, _fontSize: "20pt" });
+        const contentTitle = Docs.Create.TextDocument("Click to change title", { title: "Slide title", _width: 380, _height: 60, x: 10, y: 10, _fontSize: "24pt" });
+        const content = Docs.Create.TextDocument("Click to change text", { title: "Slide text", _width: 380, _height: 145, x: 10, y: 70, _fontSize: "14pt" });
+        const content1 = Docs.Create.TextDocument("Click to change text", { title: "Column 1", _width: 185, _height: 140, x: 10, y: 80, _fontSize: "14pt" });
+        const content2 = Docs.Create.TextDocument("Click to change text", { title: "Column 2", _width: 185, _height: 140, x: 205, y: 80, _fontSize: "14pt" });
         switch (layout) {
             case 'blank':
                 doc = Docs.Create.FreeformDocument([], { title: input ? input : "Blank slide", _width: 400, _height: 225, x: x, y: y });
@@ -1162,10 +1238,10 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     @computed get presentDropdown() {
         return (
             <div className={`dropdown-play ${this.presentTools ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
-                <div className="dropdown-play-button" onClick={this.updateMinimize}>
+                <div className="dropdown-play-button" onClick={(action(() => { this.updateMinimize(); this.turnOffEdit(true); }))}>
                     Minimize
                 </div>
-                <div className="dropdown-play-button" onClick={(action(() => { this.layoutDoc.presStatus = "manual"; this.turnOffEdit(); }))}>
+                <div className="dropdown-play-button" onClick={(action(() => { this.layoutDoc.presStatus = "manual"; this.turnOffEdit(true); }))}>
                     Sidebar view
                 </div>
             </div>
@@ -1179,7 +1255,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const childDocs = DocListCast(tagDoc[Doc.LayoutFieldKey(tagDoc)]);
         const currentFrame = Cast(tagDoc._currentFrame, "number", null);
         if (currentFrame === undefined) {
-            tagDoc.currentFrame = 0;
+            tagDoc._currentFrame = 0;
             CollectionFreeFormDocumentView.setupScroll(tagDoc, 0);
             CollectionFreeFormDocumentView.setupKeyframes(childDocs, 0);
         }
@@ -1187,15 +1263,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         CollectionFreeFormDocumentView.updateKeyframe(childDocs, currentFrame || 0, tagDoc);
         tagDoc._currentFrame = Math.max(0, (currentFrame || 0) + 1);
         tagDoc.lastFrame = Math.max(NumCast(tagDoc._currentFrame), NumCast(tagDoc.lastFrame));
-        if (curDoc.zoomProgressivize) {
-            const resize = document.getElementById('resizable');
-            if (resize) {
-                resize.style.width = this.checkList(tagDoc, curDoc["viewfinder-width-indexed"]) + 'px';
-                resize.style.height = this.checkList(tagDoc, curDoc["viewfinder-height-indexed"]) + 'px';
-                resize.style.top = this.checkList(tagDoc, curDoc["viewfinder-top-indexed"]) + 'px';
-                resize.style.left = this.checkList(tagDoc, curDoc["viewfinder-left-indexed"]) + 'px';
-            }
-        }
+        // if (curDoc.zoomProgressivize) {
+        //     const resize = document.getElementById('resizable');
+        //     if (resize) {
+        //         resize.style.width = this.checkList(tagDoc, curDoc["viewfinder-width-indexed"]) + 'px';
+        //         resize.style.height = this.checkList(tagDoc, curDoc["viewfinder-height-indexed"]) + 'px';
+        //         resize.style.top = this.checkList(tagDoc, curDoc["viewfinder-top-indexed"]) + 'px';
+        //         resize.style.left = this.checkList(tagDoc, curDoc["viewfinder-left-indexed"]) + 'px';
+        //     }
+        // }
     }
 
     @undoBatch
@@ -1209,15 +1285,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         }
         CollectionFreeFormDocumentView.gotoKeyframe(childDocs.slice());
         tagDoc._currentFrame = Math.max(0, (currentFrame || 0) - 1);
-        if (actItem.zoomProgressivize) {
-            const resize = document.getElementById('resizable');
-            if (resize) {
-                resize.style.width = this.checkList(tagDoc, actItem["viewfinder-width-indexed"]) + 'px';
-                resize.style.height = this.checkList(tagDoc, actItem["viewfinder-height-indexed"]) + 'px';
-                resize.style.top = this.checkList(tagDoc, actItem["viewfinder-top-indexed"]) + 'px';
-                resize.style.left = this.checkList(tagDoc, actItem["viewfinder-left-indexed"]) + 'px';
-            }
-        }
+        // if (actItem.zoomProgressivize) {
+        //     const resize = document.getElementById('resizable');
+        //     if (resize) {
+        //         resize.style.width = this.checkList(tagDoc, actItem["viewfinder-width-indexed"]) + 'px';
+        //         resize.style.height = this.checkList(tagDoc, actItem["viewfinder-height-indexed"]) + 'px';
+        //         resize.style.top = this.checkList(tagDoc, actItem["viewfinder-top-indexed"]) + 'px';
+        //         resize.style.left = this.checkList(tagDoc, actItem["viewfinder-left-indexed"]) + 'px';
+        //     }
+        // }
     }
 
     /**
@@ -1227,9 +1303,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
         let type: string = '';
-        const effectiveType = targetDoc.treeViewOutlineMode ? DocumentType.COL : targetDoc.type;// bcz: Argh .. .need a better way to identify a slide doc
         if (activeItem) {
-            switch (effectiveType) {
+            switch (targetDoc.type) {
                 case DocumentType.PDF: type = "PDF"; break;
                 case DocumentType.RTF: type = "Text node"; break;
                 case DocumentType.COL: type = "Collection"; break;
@@ -1249,9 +1324,8 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
 
 
     @computed get progressivizeDropdown() {
-        const activeItem = this.activeItem;
-        const targetDoc = this.targetDoc;
-        const effectiveType = targetDoc.treeViewOutlineMode ? DocumentType.COL : targetDoc.type;
+        const activeItem: Doc = this.activeItem;
+        const targetDoc: Doc = this.targetDoc;
         if (activeItem && targetDoc) {
             const activeFontColor = targetDoc["pres-text-color"] ? StrCast(targetDoc["pres-text-color"]) : "Black";
             const viewedFontColor = targetDoc["pres-text-viewed-color"] ? StrCast(targetDoc["pres-text-viewed-color"]) : "Black";
@@ -1260,29 +1334,29 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                     <div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}>
                         <div className="ribbon-box">
                             {this.stringType} selected
-                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: effectiveType === DocumentType.COL ? "inline-flex" : "none" }}>
-                                <div className="ribbon-button" style={{ backgroundColor: activeItem.presProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeChild}>Contents</div>
-                                <div className="ribbon-button" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} onClick={this.editProgressivize}>Edit</div>
+                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}>
+                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.presProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeChild}>Contents</div>
+                                <div className="ribbon-toggle" style={{ opacity: activeItem.presProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} onClick={this.editProgressivize}>Edit</div>
                             </div>
                             <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? "inline-flex" : "none" }}>
                                 <div className="presBox-subheading">Active text color</div>
-                                <div className="ribbon-property" style={{ backgroundColor: activeFontColor }} onClick={action(() => { this.openActiveColorPicker = !this.openActiveColorPicker; })}>
+                                <div className="ribbon-colorBox" style={{ backgroundColor: activeFontColor, height: 15, width: 15 }} onClick={action(() => { this.openActiveColorPicker = !this.openActiveColorPicker; })}>
                                 </div>
                             </div>
                             {this.activeColorPicker}
                             <div className="ribbon-doubleButton" style={{ display: activeItem.presProgressivize ? "inline-flex" : "none" }}>
                                 <div className="presBox-subheading">Viewed font color</div>
-                                <div className="ribbon-property" style={{ backgroundColor: viewedFontColor }} onClick={action(() => this.openViewedColorPicker = !this.openViewedColorPicker)}>
+                                <div className="ribbon-colorBox" style={{ backgroundColor: viewedFontColor, height: 15, width: 15 }} onClick={action(() => this.openViewedColorPicker = !this.openViewedColorPicker)}>
                                 </div>
                             </div>
                             {this.viewedColorPicker}
-                            {/* <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (effectiveType === DocumentType.COL && targetDoc._viewType === 'freeform') || effectiveType === DocumentType.IMG ? "inline-flex" : "none" }}>
-                                <div className="ribbon-button" style={{ backgroundColor: activeItem.zoomProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeZoom}>Zoom</div>
-                                <div className="ribbon-button" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? "#aedef8" : "" }} onClick={this.editZoomProgressivize}>Edit</div>
+                            {/* <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: (targetDoc.type === DocumentType.COL && targetDoc._viewType === 'freeform') || targetDoc.type === DocumentType.IMG ? "inline-flex" : "none" }}>
+                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.zoomProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeZoom}>Zoom</div>
+                                <div className="ribbon-toggle" style={{ opacity: activeItem.zoomProgressivize ? 1 : 0.4, backgroundColor: activeItem.editZoomProgressivize ? "#aedef8" : "" }} onClick={this.editZoomProgressivize}>Edit</div>
                             </div> */}
-                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc._viewType === "stacking" || effectiveType === DocumentType.PDF || effectiveType === DocumentType.WEB || effectiveType === DocumentType.RTF ? "inline-flex" : "none" }}>
-                                <div className="ribbon-button" style={{ backgroundColor: activeItem.scrollProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeScroll}>Scroll</div>
-                                <div className="ribbon-button" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? "#aedef8" : "" }} onClick={this.editScrollProgressivize}>Edit</div>
+                            <div className="ribbon-doubleButton" style={{ borderTop: 'solid 1px darkgrey', display: targetDoc._viewType === "stacking" || targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.WEB || targetDoc.type === DocumentType.RTF ? "inline-flex" : "none" }}>
+                                <div className="ribbon-toggle" style={{ backgroundColor: activeItem.scrollProgressivize ? "#aedef8" : "" }} onClick={this.progressivizeScroll}>Scroll</div>
+                                <div className="ribbon-toggle" style={{ opacity: activeItem.scrollProgressivize ? 1 : 0.4, backgroundColor: targetDoc.editScrollProgressivize ? "#aedef8" : "" }} onClick={this.editScrollProgressivize}>Edit</div>
                             </div>
                         </div>
                         <div className="ribbon-final-box" style={{ display: activeItem.zoomProgressivize || activeItem.scrollProgressivize || activeItem.presProgressivize || activeItem.textProgressivize ? "grid" : "none" }}>
@@ -1302,7 +1376,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                                 </div>
                                 <Tooltip title={<><div className="dash-tooltip">{"Last frame"}</div></>}><div className="ribbon-property">{NumCast(targetDoc.lastFrame)}</div></Tooltip>
                             </div>
-                            <div className="ribbon-button" style={{ height: 20, backgroundColor: "#AEDDF8" }} onClick={() => console.log(" TODO: play frames")}>Play</div>
+                            <div className="ribbon-toggle" style={{ height: 20, backgroundColor: "#AEDDF8" }} onClick={() => console.log(" TODO: play frames")}>Play</div>
                         </div>
                     </div>
                 </div>
@@ -1349,15 +1423,21 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
             color={StrCast(targetDoc["pres-text-viewed-color"])} />;
     }
 
-    turnOffEdit = () => {
+    @action
+    turnOffEdit = (paths?: boolean) => {
+        if (paths) {
+            // Turn off paths
+            const srcContext = Cast(this.rootDoc.presCollection, Doc, null);
+            if (srcContext) this.togglePath(srcContext, true);
+        }
+        // Turn off the progressivize editors for each
         this.childDocs.forEach((doc) => {
             doc.editSnapZoomProgressivize = false;
             doc.editZoomProgressivize = false;
-            doc.editScrollProgressivize = false;
             const targetDoc = Cast(doc.presentationTargetDoc, Doc, null);
             if (targetDoc) {
                 targetDoc.editZoomProgressivize = false;
-                targetDoc.editScrollProgressivize = false;
+                // targetDoc.editScrollProgressivize = false;
             }
         });
     }
@@ -1437,28 +1517,23 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
     }
 
     @action
-    progressivizeChild = (e?: React.MouseEvent) => {
-        e?.stopPropagation();
+    progressivizeChild = (e: React.MouseEvent) => {
+        e.stopPropagation();
         const activeItem: Doc = this.activeItem;
         const targetDoc: Doc = this.targetDoc;
+        const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]);
         if (!activeItem.presProgressivize) {
             targetDoc.editing = false;
             activeItem.presProgressivize = true;
             targetDoc.presProgressivize = true;
             targetDoc._currentFrame = 0;
-            let count = 0;
-            const setupProgressivize = (doc: Doc) => {
-                CollectionFreeFormDocumentView.setupKeyframes([doc], count++, true);
-                targetDoc.treeViewOutlineMode && DocListCast(doc[Doc.LayoutFieldKey(doc)]).forEach(setupProgressivize);
-            };
-            setupProgressivize(targetDoc);
-            targetDoc.lastFrame = count;
+            docs.forEach((doc, i) => CollectionFreeFormDocumentView.setupKeyframes([doc], i, true));
+            targetDoc.lastFrame = targetDoc.lastFrame ? NumCast(targetDoc.lastFrame) : docs.length - 1;
         } else {
             targetDoc.editProgressivize = false;
             activeItem.presProgressivize = false;
             targetDoc.presProgressivize = false;
             targetDoc._currentFrame = 0;
-            targetDoc.lastFrame = 0;
             targetDoc.editing = true;
         }
     }
@@ -1667,9 +1742,9 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         const targetDoc: Doc = this.targetDoc;
         return (
             <>
-                {this.targetDoc ? <div className="miniPres-button-frame" style={{ display: targetDoc.lastFrame !== undefined && targetDoc.lastFrame >= 0 ? "inline-flex" : "none" }}>
+                {this.targetDoc ? <div className="presPanel-button-frame" style={{ display: targetDoc.lastFrame !== undefined && targetDoc.lastFrame >= 0 ? "inline-flex" : "none" }}>
                     <div>{targetDoc._currentFrame}</div>
-                    <div className="miniPres-divider" style={{ border: 'solid 0.5px white', height: '60%' }}></div>
+                    <div className="presPanel-divider" style={{ border: 'solid 0.5px white', height: '60%' }}></div>
                     <div>{targetDoc.lastFrame}</div>
                 </div> : null}
             </>
@@ -1690,7 +1765,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
                 {this.playButtonFrames}
             </div>
             <div className="presPanel-divider"></div>
-            {this.props.PanelWidth() > 250 ? <div className="presPanel-button-text" onClick={() => this.layoutDoc.presStatus = "edit"}>EXIT</div>
+            {this.props.PanelWidth() > 250 ? <div className="presPanel-button-text" onClick={() => { this.layoutDoc.presStatus = "edit"; clearTimeout(this._presTimer); }}>EXIT</div>
                 : <div className="presPanel-button" onClick={() => this.layoutDoc.presStatus = "edit"}>
                     <FontAwesomeIcon icon={"times"} />
                 </div>}
@@ -1699,7 +1774,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
 
     @action
     startOrPause = () => {
-        if (this.layoutDoc.presStatus === "manual") this.startAutoPres(this.itemIndex);
+        if (this.layoutDoc.presStatus === "manual" || this.layoutDoc.presStatus === "edit") this.startAutoPres(this.itemIndex);
         else this.pauseAutoPres();
     }
 
@@ -1710,21 +1785,21 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>
         this.childDocs.slice();
         const mode = StrCast(this.rootDoc._viewType) as CollectionViewType;
         return this.layoutDoc.inOverlay ?
-            <div className="miniPres" style={{ width: 250, height: 35, background: '#323232', top: 0, zIndex: 3000000 }}>
-                {<div className="miniPresOverlay">
-                    <Tooltip title={<><div className="dash-tooltip">{"Loop"}</div></>}><div className="miniPres-button" style={{ color: this.layoutDoc.presLoop ? '#AEDDF8' : undefined }} onClick={() => this.layoutDoc.presLoop = !this.layoutDoc.presLoop}><FontAwesomeIcon icon={"redo-alt"} /></div></Tooltip>
-                    <div className="miniPres-divider"></div>
-                    <div className="miniPres-button" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
-                    <Tooltip title={<><div className="dash-tooltip">{this.layoutDoc.presStatus === "auto" ? "Pause" : "Autoplay"}</div></>}><div className="miniPres-button" onClick={this.startOrPause}><FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div></Tooltip>
-                    <div className="miniPres-button" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
-                    <div className="miniPres-divider"></div>
-                    <div className="miniPres-button-text">
+            <div className="miniPres">
+                <div className="presPanelOverlay" style={{ display: "inline-flex", height: 35, background: '#323232', top: 0, zIndex: 3000000 }}>
+                    <Tooltip title={<><div className="dash-tooltip">{"Loop"}</div></>}><div className="presPanel-button" style={{ color: this.layoutDoc.presLoop ? '#AEDDF8' : undefined }} onClick={() => this.layoutDoc.presLoop = !this.layoutDoc.presLoop}><FontAwesomeIcon icon={"redo-alt"} /></div></Tooltip>
+                    <div className="presPanel-divider"></div>
+                    <div className="presPanel-button" onClick={this.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
+                    <Tooltip title={<><div className="dash-tooltip">{this.layoutDoc.presStatus === "auto" ? "Pause" : "Autoplay"}</div></>}><div className="presPanel-button" onClick={this.startOrPause}><FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div></Tooltip>
+                    <div className="presPanel-button" onClick={this.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
+                    <div className="presPanel-divider"></div>
+                    <div className="presPanel-button-text">
                         Slide {this.itemIndex + 1} / {this.childDocs.length}
                         {this.playButtonFrames}
                     </div>
-                    <div className="miniPres-divider"></div>
-                    <div className="miniPres-button-text" onClick={this.updateMinimize}>EXIT</div>
-                </div>}
+                    <div className="presPanel-divider"></div>
+                    <div className="presPanel-button-text" onClick={this.updateMinimize}>EXIT</div>
+                </div>
             </div>
             :
             <div className="presBox-cont" style={{ minWidth: this.layoutDoc.inOverlay ? 240 : undefined }} >
diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss
index 6ee190b82..4642caeb2 100644
--- a/src/client/views/presentationview/PresElementBox.scss
+++ b/src/client/views/presentationview/PresElementBox.scss
@@ -114,6 +114,7 @@ $light-background: #ececec;
 }
 
 .presElementBox-name {
+    z-index: 300;
     align-self: center;
     font-size: 13px;
     font-family: Roboto;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 048d3a3d0..0c8b20ae3 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, IReactionDisposer, reaction } from "mobx";
+import { action, computed, IReactionDisposer, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, DataSym, DocListCast } from "../../../fields/Doc";
 import { documentSchema } from '../../../fields/documentSchemas';
@@ -15,12 +15,13 @@ import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import "./PresElementBox.scss";
 import React = require("react");
 import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
-import { PresBox } from "../nodes/PresBox";
+import { PresBox, PresMovement } from "../nodes/PresBox";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { Tooltip } from "@material-ui/core";
 import { DragManager } from "../../util/DragManager";
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 import { undoBatch } from "../../util/UndoManager";
+import { EditableView } from "../EditableView";
 
 export const presSchema = createSchema({
     presentationTargetDoc: Doc,
@@ -114,20 +115,23 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
 
     @computed get duration() {
         let durationInS: number;
-        if (this.targetDoc.presDuration) durationInS = NumCast(this.targetDoc.presDuration) / 1000;
+        if (this.rootDoc.type === DocumentType.AUDIO) { durationInS = NumCast(this.rootDoc.presEndTime) - NumCast(this.rootDoc.presStartTime); durationInS = Math.round(durationInS * 10) / 10 }
+        else if (this.rootDoc.presDuration) durationInS = NumCast(this.rootDoc.presDuration) / 1000;
         else durationInS = 2;
-        return "D: " + durationInS + "s";
+        return this.rootDoc.presMovement === PresMovement.Jump ? (null) : "D: " + durationInS + "s";
     }
 
     @computed get transition() {
         let transitionInS: number;
-        if (this.targetDoc.presTransition) transitionInS = NumCast(this.targetDoc.presTransition) / 1000;
+        if (this.rootDoc.presTransition) transitionInS = NumCast(this.rootDoc.presTransition) / 1000;
         else transitionInS = 0.5;
         return "M: " + transitionInS + "s";
     }
 
     private _itemRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _dragRef: React.RefObject<HTMLDivElement> = React.createRef();
+    private _titleRef: React.RefObject<EditableView> = React.createRef();
+
 
     @action
     headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
@@ -180,19 +184,19 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
 
 
     onPointerTop = (e: React.PointerEvent<HTMLDivElement>) => {
-        if (DragManager.docsBeingDragged.length > 0) {
+        if (DragManager.docsBeingDragged.length > 1) {
             this._highlightTopRef.current!.style.borderTop = "solid 2px #5B9FDD";
         }
     }
 
     onPointerBottom = (e: React.PointerEvent<HTMLDivElement>) => {
-        if (DragManager.docsBeingDragged.length > 0) {
+        if (DragManager.docsBeingDragged.length > 1) {
             this._highlightBottomRef.current!.style.borderBottom = "solid 2px #5B9FDD";
         }
     }
 
     onPointerLeave = (e: React.PointerEvent<HTMLDivElement>) => {
-        if (DragManager.docsBeingDragged.length > 0) {
+        if (DragManager.docsBeingDragged.length > 1) {
             this._highlightBottomRef.current!.style.borderBottom = "0px";
             this._highlightTopRef.current!.style.borderTop = "0px";
         }
@@ -200,8 +204,8 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
 
     @action
     toggleProperties = () => {
-        if (CurrentUserUtils.propertiesWidth === 0) {
-            CurrentUserUtils.propertiesWidth = 250;
+        if (CurrentUserUtils.propertiesWidth < 5) {
+            action(() => (CurrentUserUtils.propertiesWidth = 250));
         }
     }
 
@@ -214,9 +218,14 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
         e.stopPropagation();
     });
 
+    @action
+    onSetValue = (value: string) => {
+        this.rootDoc.title = value;
+        return true;
+    }
+
     render() {
         const className = "presElementBox-item" + (PresBox.Instance._selectedArray.includes(this.rootDoc) ? " presElementBox-active" : "");
-        const pbi = "presElementBox-interaction";
         return !(this.rootDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : (
             <div className={className} key={this.props.Document[Id] + this.indexInPres}
                 ref={this._itemRef}
@@ -240,6 +249,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     }
                 }}
                 onDoubleClick={e => {
+                    console.log('double click to open');
                     this.toggleProperties();
                     this.props.focus(this.rootDoc);
                     PresBox.Instance._eleArray = [];
@@ -255,7 +265,15 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                         {`${this.indexInPres + 1}.`}
                     </div>
                     <div ref={this._dragRef} className="presElementBox-name" style={{ maxWidth: (PresBox.Instance.toolbarWidth - 70) }}>
-                        {`${this.targetDoc?.title}`}
+                        <EditableView
+                            ref={this._titleRef}
+                            contents={this.rootDoc.title}
+                            GetValue={() => StrCast(this.rootDoc.title)}
+                            SetValue={action((value: string) => {
+                                this.onSetValue(value);
+                                return true;
+                            })}
+                        />
                     </div>
                     <Tooltip title={<><div className="dash-tooltip">{"Movement speed"}</div></>}><div className="presElementBox-time" style={{ display: PresBox.Instance.toolbarWidth > 300 ? "block" : "none" }}>{this.transition}</div></Tooltip>
                     <Tooltip title={<><div className="dash-tooltip">{"Duration"}</div></>}><div className="presElementBox-time" style={{ display: PresBox.Instance.toolbarWidth > 300 ? "block" : "none" }}>{this.duration}</div></Tooltip>
-- 
cgit v1.2.3-70-g09d2


From 8e672ed0e062b9483d3c0e19fa5e2e0a505a0472 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 18 Sep 2020 09:24:00 -0400
Subject: fixed following link to doc in hidden tab

---
 src/client/views/collections/TabDocView.tsx | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 2096d782f..1be85cfc1 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -169,7 +169,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         })).observe(this.props.glContainer._element[0]);
         this.props.glContainer.layoutManager.on("activeContentItemChanged", this.onActiveContentItemChanged);
         this.props.glContainer.tab?.isActive && this.onActiveContentItemChanged();
-        this._tabReaction = reaction(() => ({ selected: selected(), color: this.tabColor, title: this.tab.titleElement[0] }),
+        this._tabReaction = reaction(() => ({ selected: selected(), color: this.tabColor, title: this.tab?.titleElement[0] }),
             ({ selected, color, title }) => title && (title.style.backgroundColor = selected ? color : ""),
             { fireImmediately: true });
     }
@@ -318,7 +318,9 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         </>;
     }
     focusFunc = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => void) => {
-        // this.tab.header.parent.setActiveContentItem(this.tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
+        if (!this.tab.header.parent._activeContentItem || this.tab.header.parent._activeContentItem !== this.tab.contentItem) {
+            this.tab.header.parent.setActiveContentItem(this.tab.contentItem); // glr: Panning does not work when this is set - (this line is for trying to make a tab that is not topmost become topmost)
+        }
         afterFocus?.();
     }
     setView = action((view: DocumentView) => this._view = view);
-- 
cgit v1.2.3-70-g09d2


From 7a12eccf31f0a04800b0ddd47cd18fcbcfcadb93 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 18 Sep 2020 23:07:08 -0400
Subject: change imageBox to choose img size based on PanelWidth, not document
 width.  fixed textboxcommetn date display

---
 src/client/views/DocumentDecorations.tsx           |  2 +-
 src/client/views/collections/TabDocView.tsx        | 86 +++++++++++-----------
 src/client/views/nodes/ImageBox.tsx                | 16 ++--
 src/client/views/nodes/PDFBox.tsx                  |  2 +
 src/client/views/nodes/WebBox.tsx                  |  5 +-
 .../formattedText/FormattedTextBoxComment.tsx      |  4 +-
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 7 files changed, 59 insertions(+), 58 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 257ddc302..9a49093b4 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -334,7 +334,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             const bounds = e.currentTarget.getBoundingClientRect();
             this._offX = this._resizeHdlId.toLowerCase().includes("left") ? bounds.right - e.clientX : bounds.left - e.clientX;
             this._offY = this._resizeHdlId.toLowerCase().includes("top") ? bounds.bottom - e.clientY : bounds.top - e.clientY;
-            this.Interacting = true;
+            this.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
             this._resizeUndo = UndoManager.StartBatch("DocDecs resize");
             SelectionManager.SelectedDocuments()[0].props.setupDragLines?.(e.ctrlKey || e.shiftKey);
         }
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 1be85cfc1..1effed643 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -269,46 +269,45 @@ export class TabDocView extends React.Component<TabDocViewProps> {
         const miniTop = 50 + (NumCast(this._document?._panY) - this.renderBounds.cy) / this.renderBounds.dim * 100 - miniHeight / 2;
         const miniSize = this.returnMiniSize();
         return <>
-            {this._document?.hideMinimap ? (null) :
-                <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.tabColor }}>
-                    <CollectionFreeFormView
-                        Document={this._document!}
-                        LibraryPath={emptyPath}
-                        CollectionView={undefined}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
-                        ChildLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
-                        noOverlay={true} // don't render overlay Docs since they won't scale
-                        active={returnTrue}
-                        select={emptyFunction}
-                        dropAction={undefined}
-                        isSelected={returnFalse}
-                        dontRegisterView={true}
-                        annotationsKey={""}
-                        fieldKey={Doc.LayoutFieldKey(this._document!)}
-                        bringToFront={emptyFunction}
-                        rootSelected={returnTrue}
-                        addDocument={returnFalse}
-                        moveDocument={returnFalse}
-                        removeDocument={returnFalse}
-                        ContentScaling={returnOne}
-                        PanelWidth={this.returnMiniSize}
-                        PanelHeight={this.returnMiniSize}
-                        ScreenToLocalTransform={this.ScreenToLocalTransform}
-                        renderDepth={0}
-                        whenActiveChanged={emptyFunction}
-                        focus={emptyFunction}
-                        backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
-                        addDocTab={this.addDocTab}
-                        pinToPres={TabDocView.PinDoc}
-                        docFilters={CollectionDockingView.Instance.docFilters}
-                        searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
-                        fitToBox={true}
-                    />
-                    <div className="miniOverlay" onPointerDown={this.miniDown} >
-                        <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% `, }} />
-                    </div>
-                </div>}
+            <div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.tabColor }}>
+                <CollectionFreeFormView
+                    Document={this._document!}
+                    LibraryPath={emptyPath}
+                    CollectionView={undefined}
+                    ContainingCollectionView={undefined}
+                    ContainingCollectionDoc={undefined}
+                    ChildLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
+                    noOverlay={true} // don't render overlay Docs since they won't scale
+                    active={returnTrue}
+                    select={emptyFunction}
+                    dropAction={undefined}
+                    isSelected={returnFalse}
+                    dontRegisterView={true}
+                    annotationsKey={""}
+                    fieldKey={Doc.LayoutFieldKey(this._document!)}
+                    bringToFront={emptyFunction}
+                    rootSelected={returnTrue}
+                    addDocument={returnFalse}
+                    moveDocument={returnFalse}
+                    removeDocument={returnFalse}
+                    ContentScaling={returnOne}
+                    PanelWidth={this.returnMiniSize}
+                    PanelHeight={this.returnMiniSize}
+                    ScreenToLocalTransform={this.ScreenToLocalTransform}
+                    renderDepth={0}
+                    whenActiveChanged={emptyFunction}
+                    focus={emptyFunction}
+                    backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
+                    addDocTab={this.addDocTab}
+                    pinToPres={TabDocView.PinDoc}
+                    docFilters={CollectionDockingView.Instance.docFilters}
+                    searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
+                    fitToBox={true}
+                />
+                <div className="miniOverlay" onPointerDown={this.miniDown} >
+                    <div className="miniThumb" style={{ width: `${miniWidth}% `, height: `${miniHeight}% `, left: `${miniLeft}% `, top: `${miniTop}% `, }} />
+                </div>
+            </div>
 
             <Tooltip title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
                 <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
@@ -354,7 +353,12 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined} />
-                {this._document._viewType !== CollectionViewType.Freeform ? (null) : this.renderMiniMap()}
+                {this._document._viewType !== CollectionViewType.Freeform || this._document.hideMinimap ? (null) : this.renderMiniMap()}
+                <Tooltip title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
+                    <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
+                        <FontAwesomeIcon icon={"globe-asia"} size="lg" />
+                    </div>
+                </Tooltip>
             </>;
     }
 
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index ce056b80c..c2662b35b 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -210,15 +210,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
 
     choosePath(url: URL) {
         const lower = url.href.toLowerCase();
-        if (url.protocol === "data") {
-            return url.href;
-        } else if (url.href.indexOf(window.location.origin) === -1) {
-            return Utils.CorsProxy(url.href);
-        } else if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) {
-            return url.href;//Why is this here
-        }
+        if (url.protocol === "data") return url.href;
+        if (url.href.indexOf(window.location.origin) === -1) return Utils.CorsProxy(url.href);
+        if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) return url.href;  //Why is this here
+
         const ext = path.extname(url.href);
-        this._curSuffix = this.props.renderDepth < 1 ? "_o" : this.layoutDoc[WidthSym]() < 100 ? "_s" : "_m";
+        this._curSuffix = this.props.renderDepth < 1 ? "_o" : this.props.PanelWidth() < 100 ? "_s" : "_m";
         return url.href.replace(ext, this._curSuffix + ext);
     }
 
@@ -323,8 +320,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
 
     @computed get nativeSize() {
         TraceMobx();
-        const pw = this.props.PanelWidth?.() || 50;
-        const nativeWidth = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"], pw);
+        const nativeWidth = NumCast(this.dataDoc[this.fieldKey + "-nativeWidth"], 500);
         const nativeHeight = NumCast(this.dataDoc[this.fieldKey + "-nativeHeight"], 1);
         const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + "-nativeOrientation"], 1);
         return { nativeWidth, nativeHeight, nativeOrientation };
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 266017b5b..b199111f9 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -22,6 +22,7 @@ import "./PDFBox.scss";
 import React = require("react");
 import { documentSchema } from '../../../fields/documentSchemas';
 import { CollectionViewType } from '../collections/CollectionView';
+import { TraceMobx } from '../../../fields/util';
 
 type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>;
 const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema);
@@ -264,6 +265,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
 
     _pdfjsRequested = false;
     render() {
+        TraceMobx();
         const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField, null);
         if (this.props.isSelected() || (this.props.active() && this.props.renderDepth === 0) || this.props.Document._scrollY !== undefined) this._everActive = true;
         if (pdfUrl && this._everActive) {
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index dac6d3bf8..3b9c3359e 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -414,12 +414,11 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
     @computed
     get content() {
         const view = this.urlContent;
-        const decInteracting = DocumentDecorations.Instance?.Interacting;
 
-        const frozen = !this.props.isSelected() || decInteracting;
+        const frozen = !this.props.isSelected() || DocumentDecorations.Instance?.Interacting;
 
         return (<>
-            <div className={"webBox-cont" + (this.props.isSelected() && Doc.GetSelectedTool() === InkTool.None && !decInteracting ? "-interactive" : "")}
+            <div className={"webBox-cont" + (this.props.isSelected() && Doc.GetSelectedTool() === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
                 style={{ width: NumCast(this.layoutDoc[this.fieldKey + "-contentWidth"]) || (Number.isFinite(this.props.ContentScaling()) ? `${Math.max(100, 100 / this.props.ContentScaling())}% ` : "100%") }}
                 onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
                 {view}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index f015d329c..a37210de6 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -100,7 +100,7 @@ export class FormattedTextBoxComment {
             FormattedTextBoxComment.tooltip.style.height = "100%";
             FormattedTextBoxComment.tooltip.style.overflow = "hidden";
             FormattedTextBoxComment.tooltip.style.display = "none";
-            FormattedTextBoxComment.tooltip.appendChild(FormattedTextBoxComment.tooltipInput);
+            // FormattedTextBoxComment.tooltip.appendChild(FormattedTextBoxComment.tooltipInput);
             FormattedTextBoxComment.tooltip.onpointerdown = async (e: PointerEvent) => {
                 const keep = e.target && (e.target as any).type === "checkbox" ? true : false;
                 const textBox = FormattedTextBoxComment.textBox;
@@ -211,7 +211,7 @@ export class FormattedTextBoxComment {
                 FormattedTextBoxComment.SetState(FormattedTextBoxComment.textBox, state.selection.$from.pos - nbef, state.selection.$from.pos + naft, mark);
             }
             if (mark && child && ((nbef && naft) || !noselection)) {
-                FormattedTextBoxComment.tooltipText.textContent = mark.attrs.userid + " date=" + (new Date(mark.attrs.modified * 5000)).toDateString();
+                FormattedTextBoxComment.tooltipText.textContent = mark.attrs.userid + " on " + (new Date(mark.attrs.modified * 1000)).toLocaleString();
                 set = "";
                 FormattedTextBoxComment.tooltipInput.style.display = "";
             }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 6973b073c..6431ef707 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -727,7 +727,7 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
         </div>;
     }
     @computed get pdfViewerDiv() {
-        return <div className={"pdfViewerDash-text" + ((!DocumentDecorations.Instance?.Interacting && (this.props.isSelected() || this.props.isChildActive())) ? "-selected" : "")} ref={this._viewer} />;
+        return <div className={"pdfViewerDash-text" + ((this.props.isSelected() || this.props.isChildActive())) ? "-selected" : ""} ref={this._viewer} />;
     }
     @computed get contentScaling() { return this.props.ContentScaling(); }
     @computed get standinViews() {
-- 
cgit v1.2.3-70-g09d2


From 3c6e77b7d2bcf4782d981b19bc32e402e07863ad Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 28 Sep 2020 10:11:12 -0400
Subject: fixed docRangeFilters to be propagated everywhere and evaluated like
 docFilters (if the field isn't there, it fails)

---
 src/client/documents/Documents.ts                            |  2 +-
 src/client/views/GestureOverlay.tsx                          |  1 +
 src/client/views/MainView.tsx                                |  7 +++++++
 src/client/views/OverlayView.tsx                             |  1 +
 src/client/views/Palette.tsx                                 |  1 +
 src/client/views/PropertiesView.tsx                          |  1 +
 src/client/views/TemplateMenu.tsx                            |  1 +
 src/client/views/collections/CollectionLinearView.tsx        |  1 +
 src/client/views/collections/CollectionSchemaView.tsx        |  1 +
 src/client/views/collections/CollectionStackingView.tsx      |  1 +
 src/client/views/collections/CollectionSubView.tsx           | 12 ++++++++----
 src/client/views/collections/CollectionTreeView.tsx          |  1 +
 src/client/views/collections/SchemaTable.tsx                 |  1 +
 src/client/views/collections/TabDocView.tsx                  |  2 ++
 src/client/views/collections/TreeView.tsx                    |  3 +++
 .../collectionFreeForm/CollectionFreeFormView.tsx            |  1 +
 .../collectionMulticolumn/CollectionMulticolumnView.tsx      |  1 +
 .../collectionMulticolumn/CollectionMultirowView.tsx         |  1 +
 src/client/views/nodes/DocHolderBox.tsx                      |  2 ++
 src/client/views/nodes/DocumentView.tsx                      |  2 ++
 src/client/views/nodes/FieldView.tsx                         |  1 +
 src/client/views/nodes/FilterBox.tsx                         |  1 +
 src/client/views/nodes/ImageBox.tsx                          |  1 +
 src/client/views/nodes/KeyValuePair.tsx                      |  1 +
 src/client/views/nodes/LinkDocPreview.tsx                    |  1 +
 src/client/views/nodes/PDFBox.tsx                            |  2 +-
 src/client/views/nodes/VideoBox.tsx                          |  1 +
 src/client/views/nodes/WebBox.tsx                            |  1 +
 src/client/views/nodes/formattedText/DashDocView.tsx         |  1 +
 .../views/nodes/formattedText/FormattedTextBoxComment.tsx    |  1 +
 src/client/views/nodes/formattedText/RichTextSchema.tsx      |  1 +
 src/client/views/pdf/PDFViewer.tsx                           |  1 -
 src/client/views/presentationview/PresElementBox.tsx         |  1 +
 src/mobile/AudioUpload.tsx                                   |  1 +
 src/mobile/MobileInterface.tsx                               |  1 +
 35 files changed, 52 insertions(+), 7 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 9bd428610..1d7e4f386 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -931,7 +931,7 @@ export namespace DocUtils {
                 const min = Number(docRangeFilters[i + 1]);
                 const max = Number(docRangeFilters[i + 2]);
                 const val = Cast(d[key], "number", null);
-                if (val !== undefined && (val < min || val > max)) {
+                if (val === undefined || (val < min || val > max)) {
                     return false;
                 }
             }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 97dfb7c50..18743e850 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -905,6 +905,7 @@ export class GestureOverlay extends Touchable {
                 parentActive={returnTrue}
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
+                docRangeFilters={returnEmptyFilter}
                 docFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionView={undefined}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index ad98f7ea2..4299dba86 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -269,6 +269,7 @@ export class MainView extends React.Component {
             whenActiveChanged={emptyFunction}
             bringToFront={emptyFunction}
             docFilters={returnEmptyFilter}
+            docRangeFilters={returnEmptyFilter}
             searchFilterDocs={returnEmptyDoclist}
             ContainingCollectionView={undefined}
             ContainingCollectionDoc={undefined}
@@ -331,6 +332,7 @@ export class MainView extends React.Component {
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
+                    docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined}
@@ -365,6 +367,7 @@ export class MainView extends React.Component {
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
                 docFilters={returnEmptyFilter}
+                docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined}
@@ -484,6 +487,7 @@ export class MainView extends React.Component {
                     focus={emptyFunction}
                     whenActiveChanged={emptyFunction}
                     docFilters={returnEmptyFilter}
+                    docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined} />
@@ -549,6 +553,7 @@ export class MainView extends React.Component {
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
                 docFilters={returnEmptyFilter}
+                docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined} />
@@ -580,6 +585,7 @@ export class MainView extends React.Component {
                     PanelHeight={() => 800}
                     ContentScaling={returnOne}
                     docFilters={returnEmptyFilter}
+                    docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                 />
             </div>;
@@ -645,6 +651,7 @@ export class MainView extends React.Component {
                             PanelHeight={() => 800}
                             ContentScaling={returnOne}
                             docFilters={returnEmptyFilter}
+                            docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                         />
                     </div>;
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 4b8049e14..b40c9edfb 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -204,6 +204,7 @@ export class OverlayView extends React.Component {
                     addDocTab={returnFalse}
                     pinToPres={emptyFunction}
                     docFilters={returnEmptyFilter}
+                    docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined} />
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 9f08a03e1..62e0fb379 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -58,6 +58,7 @@ export default class Palette extends React.Component<PaletteProps> {
                             whenActiveChanged={emptyFunction}
                             bringToFront={emptyFunction}
                             docFilters={returnEmptyFilter}
+                            docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
                             ContainingCollectionView={undefined}
                             ContainingCollectionDoc={undefined} />
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 59358ce40..5877c1d6d 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -284,6 +284,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                     focus={returnFalse}
                     ScreenToLocalTransform={this.getTransform}
                     docFilters={returnEmptyFilter}
+                    docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionDoc={undefined}
                     ContainingCollectionView={undefined}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index cf2118cb2..94efff4ee 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -131,6 +131,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 ContainingCollectionDoc={undefined}
                 ContainingCollectionView={undefined}
                 docFilters={returnEmptyFilter}
+                docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
                 rootSelected={returnFalse}
                 onCheckedClick={this.scriptField}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index ae9915331..859ee9362 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -160,6 +160,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 whenActiveChanged={emptyFunction}
                                 bringToFront={emptyFunction}
                                 docFilters={this.props.docFilters}
+                                docRangeFilters={this.props.docRangeFilters}
                                 searchFilterDocs={this.props.searchFilterDocs}
                                 ContainingCollectionView={undefined}
                                 ContainingCollectionDoc={undefined} />
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 520d4c8c5..27575374a 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -439,6 +439,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                     PanelHeight={this.previewHeight}
                     ScreenToLocalTransform={this.getPreviewTransform}
                     docFilters={this.docFilters}
+                    docRangeFilters={this.docRangeFilters}
                     searchFilterDocs={this.searchFilterDocs}
                     ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                     ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 7912cfc8e..4ee00e0f4 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -207,6 +207,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
             opacity={opacity}
             focus={this.focusDocument}
             docFilters={this.docFilters}
+            docRangeFilters={this.docRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a78923312..c6737780f 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -111,6 +111,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             return this.props.ignoreFields?.includes("_docFilters") ? [] :
                 [...this.props.docFilters(), ...Cast(this.props.Document._docFilters, listSpec("string"), [])];
         }
+        docRangeFilters = () => {
+            return this.props.ignoreFields?.includes("_docRangeFilters") ? [] :
+                [...this.props.docRangeFilters(), ...Cast(this.props.Document._docRangeFilters, listSpec("string"), [])];
+        }
         searchFilterDocs = () => {
             return [...this.props.searchFilterDocs(), ...DocListCast(this.props.Document._searchFilterDocs)];
         }
@@ -132,13 +136,13 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
 
             const docFilters = this.docFilters();
+            const docRangeFilters = this.docRangeFilters();
             const searchDocs = this.searchFilterDocs();
             if (this.props.Document.dontRegisterView || (!docFilters.length && !searchDocs.length)) return childDocs;
 
             const docsforFilter: Doc[] = [];
-            const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
             childDocs.forEach((d) => {
-                let notFiltered = d.z || ((!searchDocs.length || searchDocs.includes(d)) && (!docFilters.length || DocUtils.FilterDocs([d], docFilters, docRangeFilters, viewSpecScript).length > 0));
+                let notFiltered = d.z || ((!searchDocs.length || searchDocs.includes(d)) && ((!docFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([d], docFilters, docRangeFilters, viewSpecScript).length > 0));
                 const fieldKey = Doc.LayoutFieldKey(d);
                 const annos = !Field.toString(Doc.LayoutField(d) as Field).includes("CollectionView");
                 const data = d[annos ? fieldKey + "-annotations" : fieldKey];
@@ -146,13 +150,13 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                     let subDocs = DocListCast(data);
                     if (subDocs.length > 0) {
                         let newarray: Doc[] = [];
-                        notFiltered = notFiltered || (!searchDocs.length && docFilters.length && DocUtils.FilterDocs(subDocs, docFilters, docRangeFilters, viewSpecScript).length);
+                        notFiltered = notFiltered || (!searchDocs.length && (!docFilters.length && !docRangeFilters.length) && DocUtils.FilterDocs(subDocs, docFilters, docRangeFilters, viewSpecScript).length);
                         while (subDocs.length > 0 && !notFiltered) {
                             newarray = [];
                             subDocs.forEach((t) => {
                                 const fieldKey = Doc.LayoutFieldKey(t);
                                 const annos = !Field.toString(Doc.LayoutField(t) as Field).includes("CollectionView");
-                                notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && (!docFilters.length || DocUtils.FilterDocs([t], docFilters, docRangeFilters, viewSpecScript).length));
+                                notFiltered = notFiltered || ((!searchDocs.length || searchDocs.includes(t)) && ((!docFilters.length && !docRangeFilters.length) || DocUtils.FilterDocs([t], docFilters, docRangeFilters, viewSpecScript).length));
                                 DocListCast(t[annos ? fieldKey + "-annotations" : fieldKey]).forEach((newdoc) => newarray.push(newdoc));
                             });
                             subDocs = newarray;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 549d841e4..a7c8a7cdc 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -173,6 +173,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
                 focus={this.props.focus}
                 ScreenToLocalTransform={this.titleTransform}
                 docFilters={returnEmptyFilter}
+                docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionDoc={this.doc}
                 ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 13aa60e7c..eda62bf0b 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -580,6 +580,7 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
                         PanelHeight={() => 150}
                         ScreenToLocalTransform={this.getPreviewTransform}
                         docFilters={returnEmptyFilter}
+                        docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                         ContainingCollectionDoc={this.props.CollectionView?.props.Document}
                         ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 1effed643..23e261ef6 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -301,6 +301,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     addDocTab={this.addDocTab}
                     pinToPres={TabDocView.PinDoc}
                     docFilters={CollectionDockingView.Instance.docFilters}
+                    docRangeFilters={CollectionDockingView.Instance.docRangeFilters}
                     searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                     fitToBox={true}
                 />
@@ -350,6 +351,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 addDocTab={this.addDocTab}
                 pinToPres={TabDocView.PinDoc}
                 docFilters={CollectionDockingView.Instance.docFilters}
+                docRangeFilters={CollectionDockingView.Instance.docRangeFilters}
                 searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined} />
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 744e8fed6..072cd23db 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -402,6 +402,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     focus={returnFalse}
                     ScreenToLocalTransform={this.docTransform}
                     docFilters={returnEmptyFilter}
+                    docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionDoc={this.props.containingCollection}
                     ContainingCollectionView={undefined}
@@ -515,6 +516,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 bringToFront={emptyFunction}
                 dontRegisterView={BoolCast(this.props.treeView.props.Document.dontRegisterChildViews)}
                 docFilters={returnEmptyFilter}
+                docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={this.props.containingCollection}
@@ -585,6 +587,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                                 focus={this.refocus}
                                 ScreenToLocalTransform={this.docTransform}
                                 docFilters={returnEmptyFilter}
+                                docRangeFilters={returnEmptyFilter}
                                 searchFilterDocs={returnEmptyDoclist}
                                 ContainingCollectionDoc={this.props.containingCollection}
                                 ContainingCollectionView={undefined}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8af048d67..75ad8e5b0 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -964,6 +964,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             ContainingCollectionView: this.props.CollectionView,
             ContainingCollectionDoc: this.props.Document,
             docFilters: this.docFilters,
+            docRangeFilters: this.docRangeFilters,
             searchFilterDocs: this.searchFilterDocs,
             focus: this.focusDocument,
             backgroundColor: this.getClusterColor,
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 0e4785d36..b99bef15e 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -233,6 +233,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             ScreenToLocalTransform={dxf}
             focus={this.props.focus}
             docFilters={this.docFilters}
+            docRangeFilters={this.docRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 9a4fb0627..c5e1816d9 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -232,6 +232,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             ScreenToLocalTransform={dxf}
             focus={this.props.focus}
             docFilters={this.docFilters}
+            docRangeFilters={this.docRangeFilters}
             searchFilterDocs={this.searchFilterDocs}
             ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx
index 91f96135f..dd254ae93 100644
--- a/src/client/views/nodes/DocHolderBox.tsx
+++ b/src/client/views/nodes/DocHolderBox.tsx
@@ -120,6 +120,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     docFilters={this.props.docFilters}
+                    docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
                     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}
@@ -148,6 +149,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     docFilters={this.props.docFilters}
+                    docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
                     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}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e0955f9fe..aec5ba79a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -48,6 +48,7 @@ export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView>;
     ContainingCollectionDoc: Opt<Doc>;
     docFilters: () => string[];
+    docRangeFilters: () => string[];
     searchFilterDocs: () => Doc[];
     FreezeDimensions?: boolean;
     NativeWidth?: () => number;
@@ -915,6 +916,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return (<div className="documentView-contentsView" style={{ pointerEvents: this.props.contentsPointerEvents as any, borderRadius: "inherit", width: "100%", height: "100%" }}>
             <DocumentContentsView key={1}
                 docFilters={this.props.docFilters}
+                docRangeFilters={this.props.docRangeFilters}
                 searchFilterDocs={this.props.searchFilterDocs}
                 ContainingCollectionView={this.props.ContainingCollectionView}
                 ContainingCollectionDoc={this.props.ContainingCollectionDoc}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 0d29e43b8..d65b43704 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -29,6 +29,7 @@ export interface FieldViewProps {
     dropAction: dropActionType;
     backgroundHalo?: () => boolean;
     docFilters: () => string[];
+    docRangeFilters: () => string[];
     searchFilterDocs: () => Doc[];
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (isCtrlPressed: boolean) => void;
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 067477dcf..c1978e331 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -187,6 +187,7 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
                     fieldKey={`${this.props.fieldKey}`}
                     CollectionView={undefined}
                     docFilters={returnEmptyFilter}
+                    docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionDoc={this.props.ContainingCollectionDoc}
                     ContainingCollectionView={this.props.ContainingCollectionView}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index c2662b35b..164456cfb 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -434,6 +434,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
                 ScreenToLocalTransform={this.screenToLocalTransform}
                 renderDepth={this.props.renderDepth + 1}
                 docFilters={this.props.docFilters}
+                docRangeFilters={this.props.docRangeFilters}
                 searchFilterDocs={this.props.searchFilterDocs}
                 ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
                 {this.contentFunc}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index e531083bf..2e2319447 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -57,6 +57,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             DataDoc: this.props.doc,
             LibraryPath: [],
             docFilters: returnEmptyFilter,
+            docRangeFilters: returnEmptyFilter,
             searchFilterDocs: returnEmptyDoclist,
             ContainingCollectionView: undefined,
             ContainingCollectionDoc: undefined,
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 89ea57f65..234dce374 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -104,6 +104,7 @@ export class LinkDocPreview extends React.Component<Props> {
                 pinToPres={returnFalse}
                 dontRegisterView={true}
                 docFilters={returnEmptyFilter}
+                docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
                 ContainingCollectionDoc={undefined}
                 ContainingCollectionView={undefined}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 64e0eeb2c..6db95e842 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -253,7 +253,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
             <PDFViewer {...this.props} pdf={this._pdf!} url={pdfUrl!.url.pathname} active={this.props.active} loaded={this.loaded}
                 setPdfViewer={this.setPdfViewer} ContainingCollectionView={this.props.ContainingCollectionView}
                 renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth}
-                addDocTab={this.props.addDocTab} focus={this.props.focus} docFilters={this.props.docFilters} searchFilterDocs={this.props.searchFilterDocs}
+                addDocTab={this.props.addDocTab} focus={this.props.focus} searchFilterDocs={this.props.searchFilterDocs}
                 pinToPres={this.props.pinToPres} addDocument={this.addDocument}
                 Document={this.props.Document} DataDoc={this.dataDoc} ContentScaling={this.props.ContentScaling}
                 ScreenToLocalTransform={this.props.ScreenToLocalTransform} select={this.props.select}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 51506970d..998ddde9a 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -383,6 +383,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                     ScreenToLocalTransform={this.props.ScreenToLocalTransform}
                     renderDepth={this.props.renderDepth + 1}
                     docFilters={this.props.docFilters}
+                    docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
                     ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
                     {this.contentFunc}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 3b9c3359e..2517943d7 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -670,6 +670,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
                             ScreenToLocalTransform={this.scrollXf}
                             renderDepth={this.props.renderDepth + 1}
                             docFilters={this.props.docFilters}
+                            docRangeFilters={this.props.docRangeFilters}
                             searchFilterDocs={this.props.searchFilterDocs}
                             ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
                         </CollectionFreeFormView>
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index ffa6e904a..123946dea 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -246,6 +246,7 @@ export class DashDocView extends React.Component<IDashDocView> {
                             bringToFront={emptyFunction}
                             dontRegisterView={false}
                             docFilters={this.props.tbox?.props.docFilters || returnEmptyFilter}
+                            docRangeFilters={this.props.tbox?.props.docRangeFilters || returnEmptyFilter}
                             searchFilterDocs={this.props.tbox?.props.searchFilterDocs || returnEmptyDoclist}
                             ContainingCollectionView={this._textBox.props.ContainingCollectionView}
                             ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 14bbee1ac..a986cdcb9 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -308,6 +308,7 @@ export class FormattedTextBoxComment {
                                             pinToPres={returnFalse}
                                             dontRegisterView={true}
                                             docFilters={returnEmptyFilter}
+                                            docRangeFilters={returnEmptyFilter}
                                             searchFilterDocs={returnEmptyDoclist}
                                             ContainingCollectionDoc={undefined}
                                             ContainingCollectionView={undefined}
diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx
index 962085f0d..1767a04de 100644
--- a/src/client/views/nodes/formattedText/RichTextSchema.tsx
+++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx
@@ -154,6 +154,7 @@ export class DashDocView {
                     bringToFront={emptyFunction}
                     dontRegisterView={false}
                     docFilters={this._textBox.props.docFilters}
+                    docRangeFilters={this._textBox.props.docRangeFilters}
                     searchFilterDocs={this._textBox.props.searchFilterDocs}
                     ContainingCollectionView={this._textBox.props.ContainingCollectionView}
                     ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 6179f81fd..caa22b58a 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -59,7 +59,6 @@ interface IViewerProps {
     fieldKey: string;
     Document: Doc;
     DataDoc?: Doc;
-    docFilters: () => string[];
     searchFilterDocs: () => Doc[];
     ContainingCollectionView: Opt<CollectionView>;
     PanelWidth: () => number;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index e9ab5911d..aa44c13d1 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -104,6 +104,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
                     bringToFront={returnFalse}
                     opacity={returnOne}
                     docFilters={this.props.docFilters}
+                    docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined}
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 81b3869ae..36663c85f 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -88,6 +88,7 @@ export class AudioUpload extends React.Component {
                         rootSelected={returnTrue}
                         removeDocument={undefined}
                         docFilters={returnEmptyFilter}
+                        docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
                         onClick={undefined}
                         ScreenToLocalTransform={Transform.Identity}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index cb5191e61..72914e62b 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -220,6 +220,7 @@ export class MobileInterface extends React.Component {
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
+                    docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
                     ContainingCollectionView={undefined}
                     ContainingCollectionDoc={undefined}
-- 
cgit v1.2.3-70-g09d2


From f24477e19320ce5055fa5c5e3dd5007d590397a9 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 30 Sep 2020 15:45:25 -0400
Subject: removed minimap for non-collection views.

---
 src/client/views/collections/TabDocView.tsx | 14 ++++++++------
 src/client/views/linking/LinkMenuItem.tsx   |  2 +-
 2 files changed, 9 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 23e261ef6..8c1a003b9 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -355,12 +355,14 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                 searchFilterDocs={CollectionDockingView.Instance.searchFilterDocs}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined} />
-                {this._document._viewType !== CollectionViewType.Freeform || this._document.hideMinimap ? (null) : this.renderMiniMap()}
-                <Tooltip title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
-                    <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
-                        <FontAwesomeIcon icon={"globe-asia"} size="lg" />
-                    </div>
-                </Tooltip>
+                {this._document._viewType !== CollectionViewType.Freeform ? (null) :
+                    <>{this._document.hideMinimap ? (null) : this.renderMiniMap()}
+                        <Tooltip key="ttip" title={<div className="dash-tooltip">{"toggle minimap"}</div>}>
+                            <div className="miniMap-hidden" onPointerDown={e => e.stopPropagation()} onClick={action(e => { e.stopPropagation(); this._document!.hideMinimap = !this._document!.hideMinimap; })} >
+                                <FontAwesomeIcon icon={"globe-asia"} size="lg" />
+                            </div>
+                        </Tooltip>
+                    </>}
             </>;
     }
 
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 5e880a7ee..3a8d41fef 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -166,7 +166,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
                 });
             }
         } else {
-            DocumentManager.Instance.FollowLink(linkDoc, sourceDoc, (doc, where) => addDocTab(doc, where), false);
+            DocumentManager.Instance.FollowLink(linkDoc, sourceDoc, addDocTab, false);
         }
 
         linkDoc.linksToAnnotation && Hypothesis.scrollToAnnotation(StrCast(linkDoc.annotationId), destinationDoc);
-- 
cgit v1.2.3-70-g09d2

