From b25f333713706a7456ab418960082bcabe830f11 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 20 Mar 2023 20:48:38 -0400
Subject: fixed copying of docs with template layout docs.  fixed clone to
 search through RTFs for referenced documents to clone.  renamed nested
 documents docId instead of docid for consistency with other nested field ids.

---
 src/client/views/nodes/formattedText/DashDocView.tsx | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

(limited to 'src/client/views/nodes/formattedText/DashDocView.tsx')

diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 19ee1fc7b..61345f891 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -42,7 +42,7 @@ export class DashDocView {
 
         this.root = ReactDOM.createRoot(this.dom);
         this.root.render(
-            <DashDocViewInternal docid={node.attrs.docid} alias={node.attrs.alias} width={node.attrs.width} height={node.attrs.height} hidden={node.attrs.hidden} fieldKey={node.attrs.fieldKey} tbox={tbox} view={view} node={node} getPos={getPos} />
+            <DashDocViewInternal docId={node.attrs.docId} alias={node.attrs.alias} width={node.attrs.width} height={node.attrs.height} hidden={node.attrs.hidden} fieldKey={node.attrs.fieldKey} tbox={tbox} view={view} node={node} getPos={getPos} />
         );
     }
     destroy() {
@@ -53,7 +53,7 @@ export class DashDocView {
 }
 
 interface IDashDocViewInternal {
-    docid: string;
+    docId: string;
     alias: string;
     tbox: FormattedTextBox;
     width: string;
@@ -77,7 +77,7 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
 
     updateDoc = action((dashDoc: Doc) => {
         this._dashDoc = dashDoc;
-        this._finalLayout = this.props.docid ? dashDoc : Doc.expandTemplateLayout(Doc.Layout(dashDoc), dashDoc, this.props.fieldKey);
+        this._finalLayout = this.props.docId ? dashDoc : Doc.expandTemplateLayout(Doc.Layout(dashDoc), dashDoc, this.props.fieldKey);
 
         if (this._finalLayout) {
             if (!Doc.AreProtosEqual(this._finalLayout, dashDoc)) {
@@ -107,12 +107,12 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
         super(props);
         this._textBox = this.props.tbox;
 
-        DocServer.GetRefField(this.props.docid + this.props.alias).then(async dashDoc => {
+        DocServer.GetRefField(this.props.docId + this.props.alias).then(async dashDoc => {
             if (!(dashDoc instanceof Doc)) {
                 this.props.alias &&
-                    DocServer.GetRefField(this.props.docid).then(async dashDocBase => {
+                    DocServer.GetRefField(this.props.docId).then(async dashDocBase => {
                         if (dashDocBase instanceof Doc) {
-                            const aliasedDoc = Doc.MakeAlias(dashDocBase, this.props.docid + this.props.alias);
+                            const aliasedDoc = Doc.MakeAlias(dashDocBase, this.props.docId + this.props.alias);
                             aliasedDoc.layoutKey = 'layout';
                             this.props.fieldKey && DocUtils.makeCustomViewClicked(aliasedDoc, Docs.Create.StackingDocument, this.props.fieldKey, undefined);
                             this.updateDoc(aliasedDoc);
@@ -161,12 +161,12 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
     };
 
     onPointerLeave = () => {
-        const ele = document.getElementById('DashDocCommentView-' + this.props.docid) as HTMLDivElement;
+        const ele = document.getElementById('DashDocCommentView-' + this.props.docId) as HTMLDivElement;
         ele && (ele.style.backgroundColor = '');
     };
 
     onPointerEnter = () => {
-        const ele = document.getElementById('DashDocCommentView-' + this.props.docid) as HTMLDivElement;
+        const ele = document.getElementById('DashDocCommentView-' + this.props.docId) as HTMLDivElement;
         ele && (ele.style.backgroundColor = 'orange');
     };
 
-- 
cgit v1.2.3-70-g09d2


From 5d1e3710a015d8915bd367ece753817d84d9d916 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 11 Apr 2023 14:43:54 -0400
Subject: exracted FollowLinkScript() function.  got rid of template parameters
 to simplify templating.

---
 src/client/documents/Documents.ts                  |  5 +--
 src/client/util/CurrentUserUtils.ts                |  3 +-
 src/client/util/LinkFollower.ts                    | 22 ++++++++----
 src/client/views/DocumentButtonBar.tsx             | 13 ++++---
 src/client/views/DocumentDecorations.tsx           |  6 ++--
 src/client/views/MarqueeAnnotator.tsx              |  3 +-
 src/client/views/PropertiesButtons.tsx             |  5 +--
 src/client/views/StyleProvider.tsx                 | 12 +++----
 .../collections/CollectionStackedTimeline.tsx      |  6 ++--
 src/client/views/nodes/DocumentContentsView.tsx    |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  8 ++---
 src/client/views/nodes/VideoBox.tsx                |  5 +--
 .../views/nodes/formattedText/DashDocView.tsx      |  2 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  3 +-
 src/fields/Doc.ts                                  | 41 +++++++---------------
 15 files changed, 65 insertions(+), 71 deletions(-)

(limited to 'src/client/views/nodes/formattedText/DashDocView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 7600fcac9..8d97ce5af 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -21,6 +21,7 @@ import { Networking } from '../Network';
 import { DocumentManager } from '../util/DocumentManager';
 import { DragManager, dropActionType } from '../util/DragManager';
 import { DirectoryImportBox } from '../util/Import & Export/DirectoryImportBox';
+import { FollowLinkScript } from '../util/LinkFollower';
 import { LinkManager } from '../util/LinkManager';
 import { ScriptingGlobals } from '../util/ScriptingGlobals';
 import { undoBatch, UndoManager } from '../util/UndoManager';
@@ -507,7 +508,7 @@ export namespace Docs {
                     layout: { view: LinkBox, dataField: defaultDataKey },
                     options: {
                         childDontRegisterViews: true,
-                        onClick: ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' }),
+                        onClick: FollowLinkScript(),
                         hideLinkAnchors: true,
                         _height: 150,
                         description: '',
@@ -1694,7 +1695,7 @@ export namespace DocUtils {
                 _width: 15,
                 _height: 15,
                 _xPadding: 0,
-                onClick: ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' }),
+                onClick: FollowLinkScript(),
                 _timecodeToShow: Cast(doc._timecodeToShow, 'number', null),
             });
             Doc.AddDocToList(context, annotationField, pushpin);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 3d0db04b4..76ea3e3ea 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -25,6 +25,7 @@ import { OpenWhere } from "../views/nodes/DocumentView";
 import { OverlayView } from "../views/OverlayView";
 import { DragManager } from "./DragManager";
 import { MakeTemplate } from "./DropConverter";
+import { FollowLinkScript } from "./LinkFollower";
 import { LinkManager } from "./LinkManager";
 import { ScriptingGlobals } from "./ScriptingGlobals";
 import { ColorScheme } from "./SettingsManager";
@@ -271,7 +272,7 @@ export class CurrentUserUtils {
             {key: "Map",        creator: opts => Docs.Create.MapDocument([], opts),         opts: { _width: 800, _height: 600, _fitWidth: true, _showSidebar: true,  }},
             {key: "Screengrab", creator: Docs.Create.ScreenshotDocument,                    opts: { _width: 400, _height: 200 }},
             {key: "WebCam",     creator: opts => Docs.Create.WebCamDocument("", opts),      opts: { _width: 400, _height: 200, recording:true, system: true, cloneFieldFilter: new List<string>(["system"]) }},
-            {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, onClick: ScriptField.MakeScript("followLink(this,altKey)", {altKey:"boolean"}) }},
+            {key: "Button",     creator: Docs.Create.ButtonDocument,                        opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, onClick: FollowLinkScript()}},
             {key: "Script",     creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }},
             {key: "DataViz",    creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts),   opts: { _width: 300, _height: 300 }},
             {key: "Header",     creator: headerTemplate,                                    opts: { _width: 300, _height: 70, _headerPointerEvents: "all", _headerHeight: 12, _headerFontSize: 9, _autoHeight: true, treeViewHideUnrendered: true}},
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts
index f5aae6632..d4d7c66f5 100644
--- a/src/client/util/LinkFollower.ts
+++ b/src/client/util/LinkFollower.ts
@@ -1,9 +1,9 @@
-import { action, runInAction } from 'mobx';
-import { Doc, DocListCast, Opt } from '../../fields/Doc';
-import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types';
+import { action, observable, runInAction } from 'mobx';
+import { Doc, DocListCast, Field, FieldResult, Opt } from '../../fields/Doc';
+import { ScriptField } from '../../fields/ScriptField';
+import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../fields/Types';
 import { DocumentType } from '../documents/DocumentTypes';
-import { DocumentDecorations } from '../views/DocumentDecorations';
-import { DocFocusOptions, DocumentViewSharedProps, OpenWhere } from '../views/nodes/DocumentView';
+import { DocFocusOptions, OpenWhere } from '../views/nodes/DocumentView';
 import { PresBox } from '../views/nodes/trails';
 import { DocumentManager } from './DocumentManager';
 import { LinkManager } from './LinkManager';
@@ -23,18 +23,19 @@ import { UndoManager } from './UndoManager';
  * - user defined kvps
  */
 export class LinkFollower {
+    @observable public static IsFollowing = false;
     // follows a link - if the target is on screen, it highlights/pans to it.
     // if the target isn't onscreen, then it will open up the target in the lightbox, or in place
     // depending on the followLinkLocation property of the source (or the link itself as a fallback);
     public static FollowLink = (linkDoc: Opt<Doc>, sourceDoc: Doc, altKey: boolean) => {
         const batch = UndoManager.StartBatch('follow link click');
-        runInAction(() => (DocumentDecorations.Instance.overrideBounds = true)); // turn off decoration bounds while following links since animations may occur, and DocDecorations is based on screenToLocal which is not always an observable value
+        runInAction(() => (LinkFollower.IsFollowing = true)); // turn off decoration bounds while following links since animations may occur, and DocDecorations is based on screenToLocal which is not always an observable value
         LinkFollower.traverseLink(
             linkDoc,
             sourceDoc,
             action(() => {
                 batch.end();
-                Doc.AddUnHighlightWatcher(action(() => (DocumentDecorations.Instance.overrideBounds = false)));
+                Doc.AddUnHighlightWatcher(action(() => (LinkFollower.IsFollowing = false)));
             }),
             altKey ? true : undefined
         );
@@ -124,3 +125,10 @@ ScriptingGlobals.add(function followLink(doc: Doc, altKey: boolean) {
     SelectionManager.DeselectAll();
     LinkFollower.FollowLink(undefined, doc, altKey);
 });
+
+export function FollowLinkScript() {
+    return ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' });
+}
+export function IsFollowLinkScript(field: FieldResult<Field>) {
+    return ScriptCast(field)?.script.originalScript.includes('followLink(');
+}
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 7e1b32398..8c2ced55a 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -1,16 +1,17 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@material-ui/core';
-import { action, computed, observable, runInAction, trace } from 'mobx';
+import { action, computed, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { Doc } from '../../fields/Doc';
 import { RichTextField } from '../../fields/RichTextField';
-import { Cast, DocCast, NumCast, ScriptCast } from '../../fields/Types';
+import { Cast, DocCast, NumCast } from '../../fields/Types';
 import { emptyFunction, returnFalse, setupMoveUpEvents, simulateMouseClick } from '../../Utils';
 import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
 import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
 import { Docs, DocUtils } from '../documents/Documents';
 import { DragManager } from '../util/DragManager';
+import { IsFollowLinkScript } from '../util/LinkFollower';
 import { SelectionManager } from '../util/SelectionManager';
 import { SharingManager } from '../util/SharingManager';
 import { undoBatch, UndoManager } from '../util/UndoManager';
@@ -24,11 +25,9 @@ import { DocumentLinksButton } from './nodes/DocumentLinksButton';
 import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from './nodes/DocumentView';
 import { DashFieldView } from './nodes/formattedText/DashFieldView';
 import { GoogleRef } from './nodes/formattedText/FormattedTextBox';
+import { PinProps } from './nodes/trails';
 import { TemplateMenu } from './TemplateMenu';
 import React = require('react');
-import { DocumentType } from '../documents/DocumentTypes';
-import { FontIconBox } from './nodes/button/FontIconBox';
-import { PinProps } from './nodes/trails';
 const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -238,7 +237,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                 </Tooltip>
             );
         };
-        const followLink = ScriptCast(targetDoc?.onClick)?.script.originalScript.includes('followLink(');
+        const followLink = IsFollowLinkScript(targetDoc?.onClick);
         return !targetDoc ? null : (
             <Tooltip title={<div className="dash-tooltip">Set onClick to follow primary link</div>}>
                 <div
@@ -594,7 +593,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
                         <LinkPopup
                             key="popup"
                             showPopup={this._showLinkPopup}
-                            linkCreated={link => (link.linkDisplay = !ScriptCast(this.props.views().lastElement()?.rootDoc.onClick)?.script.originalScript.includes('followLink('))}
+                            linkCreated={link => (link.linkDisplay = !IsFollowLinkScript(this.props.views().lastElement()?.rootDoc.onClick))}
                             linkCreateAnchor={() => this.props.views().lastElement()?.ComponentView?.getAnchor?.(true)}
                             linkFrom={() => this.props.views().lastElement()?.rootDoc}
                         />
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9bc583ce5..9ffbe083f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -32,6 +32,7 @@ import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { ImageBox } from './nodes/ImageBox';
 import React = require('react');
 import { RichTextField } from '../../fields/RichTextField';
+import { LinkFollower } from '../util/LinkFollower';
 
 @observer
 export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> {
@@ -83,10 +84,9 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         );
     }
 
-    @observable overrideBounds = false;
     @computed
     get Bounds() {
-        if (this.overrideBounds) return { x: 0, y: 0, r: 0, b: 0 };
+        if (LinkFollower.IsFollowing) return { x: 0, y: 0, r: 0, b: 0 };
         const views = SelectionManager.Views();
         return views
             .filter(dv => dv.props.renderDepth > 0)
@@ -908,7 +908,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                     {this._isRotating ? null : (
                                         <Tooltip enterDelay={750} title={<div className="dash-tooltip">tap to set rotate center, drag to rotate</div>}>
                                             <div className="documentDecorations-rotation" style={{ pointerEvents: 'all' }} onPointerDown={this.onRotateDown} onContextMenu={e => e.preventDefault()}>
-                                                <IconButton icon={<FaUndo />} isCircle={true} hoverStyle={'lighten'} backgroundColor={Colors.DARK_GRAY} color={Colors.LIGHT_GRAY} />
+                                                <IconButton icon={<FaUndo />} color={Colors.LIGHT_GRAY} />
                                             </div>
                                         </Tooltip>
                                     )}
diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 6b4f8ad85..ede387927 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -15,6 +15,7 @@ import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { AnchorMenu } from './pdf/AnchorMenu';
 import React = require('react');
 import { ScriptField } from '../../fields/ScriptField';
+import { FollowLinkScript } from '../util/LinkFollower';
 const _global = (window /* browser */ || global) /* node */ as any;
 
 export interface MarqueeAnnotatorProps {
@@ -148,7 +149,7 @@ export class MarqueeAnnotator extends React.Component<MarqueeAnnotatorProps> {
             const anno = savedAnnos[0];
             const containerOffset = this.props.containerOffset?.() || [0, 0];
             const marqueeAnno = Docs.Create.FreeformDocument([], {
-                onClick: isLinkButton ? ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' }) : undefined,
+                onClick: isLinkButton ? FollowLinkScript() : undefined,
                 backgroundColor: color,
                 annotationOn: this.props.rootDoc,
                 title: 'Annotation on ' + this.props.rootDoc.title,
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 0723966e1..031d501ad 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -21,6 +21,7 @@ import { DocumentView, OpenWhere } from './nodes/DocumentView';
 import { pasteImageBitmap } from './nodes/WebBoxRenderer';
 import './PropertiesButtons.scss';
 import React = require('react');
+import { IsFollowLinkScript } from '../util/LinkFollower';
 const higflyout = require('@hig/flyout');
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -289,7 +290,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
             .filter(dv => dv.docView)
             .map(dv => dv.docView!)
             .forEach(docView => {
-                const linkButton = ScriptCast(docView.props.Document.onClick)?.script.originalScript.includes('followLink(');
+                const linkButton = IsFollowLinkScript(docView.props.Document.onClick);
                 docView.noOnClick();
                 switch (onClick) {
                     case 'enterPortal':
@@ -327,7 +328,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         ];
         const list = buttonList.map(value => {
             const click = () => this.handleOptionChange(value[0]);
-            const linkButton = BoolCast(ScriptCast(this.selectedDoc.onClick)?.script.originalScript.includes('followLink('));
+            const linkButton = IsFollowLinkScript(this.selectedDoc.onClick);
             const followLoc = this.selectedDoc._followLinkLocation;
             const linkedToLightboxView = () => LinkManager.Links(this.selectedDoc).some(link => LinkManager.getOppositeAnchor(link, this.selectedDoc)?._isLightbox);
 
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 8d67f0528..b950b4860 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -1,13 +1,15 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { Tooltip } from '@material-ui/core';
 import { Shadows } from 'browndash-components';
 import { action, runInAction } from 'mobx';
 import { extname } from 'path';
 import { Doc, Opt, StrListCast } from '../../fields/Doc';
-import { BoolCast, Cast, ImageCast, NumCast, ScriptCast, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, ImageCast, NumCast, StrCast } from '../../fields/Types';
 import { DashColor, lightOrDark, Utils } from '../../Utils';
 import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
 import { DocFocusOrOpen, DocumentManager } from '../util/DocumentManager';
+import { IsFollowLinkScript } from '../util/LinkFollower';
 import { LinkManager } from '../util/LinkManager';
 import { SelectionManager } from '../util/SelectionManager';
 import { ColorScheme, SettingsManager } from '../util/SettingsManager';
@@ -18,13 +20,10 @@ import { InkingStroke } from './InkingStroke';
 import { MainView } from './MainView';
 import { DocumentViewProps } from './nodes/DocumentView';
 import { FieldViewProps } from './nodes/FieldView';
+import { KeyValueBox } from './nodes/KeyValueBox';
 import { SliderBox } from './nodes/SliderBox';
 import './StyleProvider.scss';
 import React = require('react');
-import { KeyValueBox } from './nodes/KeyValueBox';
-import { listSpec } from '../../fields/Schema';
-import { AudioField } from '../../fields/URLField';
-import { Tooltip } from '@material-ui/core';
 
 export enum StyleProp {
     TreeViewIcon = 'treeViewIcon',
@@ -279,8 +278,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         case StyleProp.BoxShadow: {
             if (!doc || opacity() === 0 || doc.noShadow) return undefined; // if it's not visible, then no shadow)
             if (doc.boxShadow === 'standard') return Shadows.STANDARD_SHADOW;
-            if (ScriptCast(doc?.onClick)?.script.originalScript.includes('followLink(') && LinkManager.Links(doc).length && ![DocumentType.LINK, DocumentType.INK].includes(doc.type as any))
-                return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em');
+            if (IsFollowLinkScript(doc?.onClick) && LinkManager.Links(doc).length && ![DocumentType.LINK, DocumentType.INK].includes(doc.type as any)) return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em');
             switch (doc?.type) {
                 case DocumentType.COL:
                     return StrCast(
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index 5891cfe78..bbd81d06d 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -14,7 +14,7 @@ import { Docs } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from '../../util/DragManager';
-import { LinkFollower } from '../../util/LinkFollower';
+import { FollowLinkScript, IsFollowLinkScript, LinkFollower } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
 import { SelectionManager } from '../../util/SelectionManager';
@@ -406,7 +406,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
                 backgroundColor: 'rgba(128, 128, 128, 0.5)',
                 useLinkSmallAnchor: true,
                 hideLinkButton: true,
-                onClick: ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' }),
+                onClick: FollowLinkScript(),
                 annotationOn: rootDoc,
                 _timelineLabel: true,
                 borderRounding: anchorEndTime === undefined ? '100%' : undefined,
@@ -450,7 +450,7 @@ export class CollectionStackedTimeline extends CollectionSubView<CollectionStack
 
     @action
     clickAnchor = (anchorDoc: Doc, clientX: number) => {
-        if (ScriptCast(anchorDoc.onClick)?.script.originalScript.includes('followLink(')) {
+        if (IsFollowLinkScript(anchorDoc.onClick)) {
             LinkFollower.FollowLink(undefined, anchorDoc, false);
         }
         const seekTimeInSeconds = this.anchorStart(anchorDoc) - 0.05;
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 2d12005fb..dbcfe43cf 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -146,7 +146,7 @@ export class DocumentContentsView extends React.Component<
             (this.props.LayoutTemplateString && this.props.Document) ||
             (this.props.layoutKey && StrCast(this.props.Document[this.props.layoutKey]) && this.props.Document) ||
             Doc.Layout(this.props.Document, this.props.layoutKey ? Cast(this.props.Document[this.props.layoutKey], Doc, null) : undefined);
-        return Doc.expandTemplateLayout(template, this.props.Document, this.props.layoutKey);
+        return Doc.expandTemplateLayout(template, this.props.Document);
     }
 
     CreateBindings(onClick: Opt<ScriptField>, onInput: Opt<ScriptField>): JsxBindings {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a39c3cf8f..f161a7b9b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -22,7 +22,7 @@ import { DictationManager } from '../../util/DictationManager';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager, dropActionType } from '../../util/DragManager';
 import { InteractionUtils } from '../../util/InteractionUtils';
-import { LinkFollower } from '../../util/LinkFollower';
+import { FollowLinkScript, LinkFollower } from '../../util/LinkFollower';
 import { LinkManager } from '../../util/LinkManager';
 import { ScriptingGlobals } from '../../util/ScriptingGlobals';
 import { SelectionManager } from '../../util/SelectionManager';
@@ -560,14 +560,14 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => {
         const hadOnClick = this.rootDoc.onClick;
         this.noOnClick();
-        this.Document.onClick = hadOnClick ? undefined : ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' });
+        this.Document.onClick = hadOnClick ? undefined : FollowLinkScript();
         this.Document.waitForDoubleClickToClick = hadOnClick ? undefined : 'never';
     };
     @undoBatch
     @action
     followLinkOnClick = (): void => {
         this.Document.ignoreClick = false;
-        this.Document.onClick = ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' });
+        this.Document.onClick = FollowLinkScript();
         this.Document.followLinkToggle = false;
         this.Document.followLinkZoom = false;
         this.Document.followLinkLocation = undefined;
@@ -623,7 +623,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             );
         }
         this.Document.followLinkLocation = OpenWhere.lightbox;
-        this.Document.onClick = ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' });
+        this.Document.onClick = FollowLinkScript();
     };
 
     importDocument = () => {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 83ad5628c..b144c9318 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -34,6 +34,7 @@ import { RecordingBox } from './RecordingBox';
 import { PinProps, PresBox } from './trails';
 import './VideoBox.scss';
 import { ScriptField } from '../../../fields/ScriptField';
+import { FollowLinkScript } from '../../util/LinkFollower';
 const path = require('path');
 
 /**
@@ -325,7 +326,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
                 _width: 150,
                 _height: 50,
                 title: (this.layoutDoc._currentTimecode || 0).toString(),
-                onClick: ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' }),
+                onClick: FollowLinkScript(),
             });
             this.props.addDocument?.(b);
             DocUtils.MakeLink(b, this.rootDoc, { linkRelationship: 'video snapshot' });
@@ -369,7 +370,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
             _nativeHeight: Doc.NativeHeight(this.layoutDoc),
             x: NumCast(this.layoutDoc.x) + width,
             y: NumCast(this.layoutDoc.y),
-            onClick: ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' }),
+            onClick: FollowLinkScript(),
             _width: 150,
             _height: (height / width) * 150,
             title: '--snapshot' + NumCast(this.layoutDoc._currentTimecode) + ' image-',
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 61345f891..c00ab6a7e 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -77,7 +77,7 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
 
     updateDoc = action((dashDoc: Doc) => {
         this._dashDoc = dashDoc;
-        this._finalLayout = this.props.docId ? dashDoc : Doc.expandTemplateLayout(Doc.Layout(dashDoc), dashDoc, this.props.fieldKey);
+        this._finalLayout = this.props.docId ? dashDoc : Doc.expandTemplateLayout(Doc.Layout(dashDoc), dashDoc);
 
         if (this._finalLayout) {
             if (!Doc.AreProtosEqual(this._finalLayout, dashDoc)) {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 809315963..677c4662b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -64,6 +64,7 @@ import { schema } from './schema_rts';
 import { SummaryView } from './SummaryView';
 import applyDevTools = require('prosemirror-dev-tools');
 import React = require('react');
+import { IsFollowLinkScript } from '../../../util/LinkFollower';
 const translateGoogleApi = require('translate-google-api');
 
 export const GoogleRef = 'googleDocId';
@@ -1933,7 +1934,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                                 paddingRight: StrCast(this.layoutDoc._textBoxPaddingX, `${paddingX - selPad}px`),
                                 paddingTop: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY - selPad}px`),
                                 paddingBottom: StrCast(this.layoutDoc._textBoxPaddingY, `${paddingY - selPad}px`),
-                                pointerEvents: !active && !SnappingManager.GetIsDragging() ? (ScriptCast(this.layoutDoc.onClick)?.script.originalScript.includes('followLink(') ? 'none' : undefined) : undefined,
+                                pointerEvents: !active && !SnappingManager.GetIsDragging() ? (IsFollowLinkScript(this.layoutDoc.onClick) ? 'none' : undefined) : undefined,
                             }}
                         />
                     </div>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 3a5ba4f75..662792ff0 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -906,57 +906,40 @@ export namespace Doc {
             saveAs(content, doc.title + '.zip'); // glr: Possibly change the name of the document to match the title?
         });
     }
-    //
-    // Determines whether the layout needs to be expanded (as a template).
-    // template expansion is rquired when the layout is a template doc/field and there's a datadoc which isn't equal to the layout template
-    //
-    export function WillExpandTemplateLayout(layoutDoc: Doc, dataDoc?: Doc) {
-        return (layoutDoc.isTemplateForField || layoutDoc.isTemplateDoc) && dataDoc && layoutDoc !== dataDoc;
-    }
 
     const _pendingMap: Map<string, boolean> = new Map();
     //
     // Returns an expanded template layout for a target data document if there is a template relationship
     // between the two. If so, the layoutDoc is expanded into a new document that inherits the properties
     // of the original layout while allowing for individual layout properties to be overridden in the expanded layout.
-    // templateArgs should be equivalent to the layout key that generates the template since that's where the template parameters are stored in ()'s at the end of the key.
-    // NOTE:  the template will have references to "@params" -- the template arguments will be assigned to the '@params' field
-    // so that when the @params key is accessed, it will be rewritten as the key that is stored in the 'params' field and
-    // the derefence will then occur on the rootDocument (the original document).
-    // in the future, field references could be written as @<someparam> and then arguments would be passed in the layout key as:
-    //   layout_mytemplate(somparam=somearg).
-    // then any references to @someparam would be rewritten as accesses to 'somearg' on the rootDocument
-    export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc, templateArgs?: string) {
-        const args = templateArgs?.match(/\(([a-zA-Z0-9._\-]*)\)/)?.[1].replace('()', '') || '';
-        if ((!args && !WillExpandTemplateLayout(templateLayoutDoc, targetDoc)) || !targetDoc) return templateLayoutDoc;
-
-        const templateField = StrCast(templateLayoutDoc.isTemplateForField); // the field that the template renders
+    export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc) {
+        // nothing to do if the layout isn't a template or we don't have a target that's different than the template
+        if (!targetDoc || templateLayoutDoc === targetDoc || (!templateLayoutDoc.isTemplateForField && !templateLayoutDoc.isTemplateDoc)) {
+            return templateLayoutDoc;
+        }
+
+        const templateField = StrCast(templateLayoutDoc.isTemplateForField, Doc.LayoutFieldKey(templateLayoutDoc)); // the field that the template renders
         // First it checks if an expanded layout already exists -- if so it will be stored on the dataDoc
         // using the template layout doc's id as the field key.
         // If it doesn't find the expanded layout, then it makes a delegate of the template layout and
         // saves it on the data doc indexed by the template layout's id.
         //
-        const params = args.split('=').length > 1 ? args.split('=')[0] : '';
-        const layoutFielddKey = Doc.LayoutFieldKey(templateLayoutDoc);
-        const expandedLayoutFieldKey = (templateField || layoutFielddKey) + '-layout[' + templateLayoutDoc[Id] + (args ? `(${args})` : '') + ']';
+        const expandedLayoutFieldKey = templateField + '-layout[' + templateLayoutDoc[Id] + ']';
         let expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey];
 
         if (templateLayoutDoc.resolvedDataDoc instanceof Promise) {
             expandedTemplateLayout = undefined;
             _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey, true);
-        } else if (expandedTemplateLayout === undefined && !_pendingMap.get(targetDoc[Id] + expandedLayoutFieldKey + args)) {
+        } else if (expandedTemplateLayout === undefined && !_pendingMap.get(targetDoc[Id] + expandedLayoutFieldKey)) {
             if (templateLayoutDoc.resolvedDataDoc === (targetDoc.rootDocument || Doc.GetProto(targetDoc))) {
                 expandedTemplateLayout = templateLayoutDoc; // reuse an existing template layout if its for the same document with the same params
             } else {
                 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
                 if (!targetDoc[expandedLayoutFieldKey]) {
-                    _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey + args, true);
+                    _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey, true);
                     setTimeout(
                         action(() => {
                             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;
@@ -965,7 +948,7 @@ export namespace Doc {
                             }
                             targetDoc[expandedLayoutFieldKey] = newLayoutDoc;
 
-                            _pendingMap.delete(targetDoc[Id] + expandedLayoutFieldKey + args);
+                            _pendingMap.delete(targetDoc[Id] + expandedLayoutFieldKey);
                         })
                     );
                 }
@@ -982,7 +965,7 @@ export namespace Doc {
             return { layout: childDoc, data: childDoc };
         }
         const resolvedDataDoc = Doc.AreProtosEqual(containerDataDoc, containerDoc) || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc;
-        return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, '()'), data: resolvedDataDoc };
+        return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc };
     }
 
     export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc {
-- 
cgit v1.2.3-70-g09d2


From 5cd64622f14ede408d3baca4a10d155b60392e46 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 13 Apr 2023 22:22:07 -0400
Subject: lots of changes to get rid of ContainingCollectionDoc and
 ContainingCollectionView props.

---
 src/client/documents/Documents.ts                  |  8 +--
 src/client/util/CurrentUserUtils.ts                |  2 +-
 src/client/util/DocumentManager.ts                 | 83 ++++++++++------------
 src/client/util/DragManager.ts                     |  4 +-
 .../util/Import & Export/DirectoryImportBox.tsx    |  6 +-
 src/client/util/ReplayMovements.ts                 | 64 ++++++-----------
 src/client/util/SelectionManager.ts                |  6 +-
 src/client/util/SharingManager.tsx                 |  5 +-
 src/client/util/TrackMovements.ts                  | 36 +++++-----
 src/client/views/DashboardView.tsx                 | 17 ++---
 src/client/views/DocComponent.tsx                  |  1 -
 src/client/views/DocumentDecorations.tsx           |  8 +--
 src/client/views/GestureOverlay.tsx                |  4 +-
 src/client/views/InkStrokeProperties.ts            |  3 +-
 src/client/views/LightboxView.tsx                  |  4 +-
 src/client/views/MainView.tsx                      | 20 ++----
 src/client/views/OverlayView.tsx                   | 10 +--
 src/client/views/Palette.tsx                       | 31 ++++----
 src/client/views/PropertiesDocContextSelector.tsx  | 22 ++++--
 src/client/views/PropertiesView.tsx                |  2 -
 src/client/views/StyleProvider.tsx                 | 11 ++-
 src/client/views/TemplateMenu.tsx                  |  2 -
 .../views/collections/CollectionCarouselView.tsx   |  1 -
 src/client/views/collections/CollectionMenu.tsx    |  6 +-
 .../views/collections/CollectionNoteTakingView.tsx |  4 --
 .../views/collections/CollectionPileView.tsx       |  2 +-
 .../collections/CollectionStackedTimeline.tsx      |  2 -
 .../views/collections/CollectionStackingView.tsx   |  4 --
 .../views/collections/CollectionTreeView.tsx       | 10 +--
 src/client/views/collections/CollectionView.tsx    |  5 +-
 src/client/views/collections/TabDocView.tsx        |  6 +-
 src/client/views/collections/TreeView.tsx          | 54 ++++++--------
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 31 ++++----
 .../collectionLinear/CollectionLinearView.tsx      |  5 +-
 .../CollectionMulticolumnView.tsx                  |  2 -
 .../CollectionMultirowView.tsx                     |  2 -
 .../collectionSchema/CollectionSchemaView.tsx      |  6 +-
 .../collections/collectionSchema/SchemaRowBox.tsx  |  2 +-
 .../collectionSchema/SchemaTableCell.tsx           |  2 -
 src/client/views/linking/LinkMenuItem.tsx          | 21 +-----
 src/client/views/linking/LinkPopup.tsx             |  4 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  7 +-
 src/client/views/nodes/DocumentContentsView.tsx    |  1 -
 src/client/views/nodes/DocumentLinksButton.tsx     |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 12 ++--
 src/client/views/nodes/FieldView.tsx               |  1 +
 src/client/views/nodes/KeyValuePair.tsx            |  2 -
 src/client/views/nodes/LinkDocPreview.tsx          |  4 +-
 src/client/views/nodes/ScreenshotBox.tsx           |  5 +-
 src/client/views/nodes/button/FontIconBox.tsx      |  4 +-
 .../views/nodes/formattedText/DashDocView.tsx      |  7 +-
 .../views/nodes/formattedText/DashFieldView.tsx    |  5 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx | 20 ++++--
 src/client/views/nodes/trails/PresBox.tsx          |  1 -
 src/client/views/nodes/trails/PresElementBox.tsx   | 27 ++++---
 src/client/views/topbar/TopBar.tsx                 | 51 ++-----------
 src/mobile/AudioUpload.tsx                         | 76 ++++++++++----------
 src/mobile/MobileInterface.tsx                     |  4 +-
 58 files changed, 291 insertions(+), 456 deletions(-)

(limited to 'src/client/views/nodes/formattedText/DashDocView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8d97ce5af..09b45a481 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1285,10 +1285,6 @@ export namespace DocUtils {
         return rangeFilteredDocs;
     }
 
-    export function DefaultFocus(doc: Doc, options: DocFocusOptions) {
-        return undefined;
-    }
-
     export let ActiveRecordings: { props: FieldViewProps; getAnchor: (addAsAnnotation: boolean) => Doc }[] = [];
 
     export function MakeLinkToActiveAudio(getSourceDoc: () => Doc | undefined, broadcastEvent = true) {
@@ -1299,10 +1295,9 @@ export namespace DocUtils {
         });
     }
 
-    export function MakeLink(source: Doc, target: Doc, linkSettings: { linkRelationship?: string; description?: string; linkDisplay?: boolean }, id?: string, allowParCollectionLink?: boolean, showPopup?: number[]) {
+    export function MakeLink(source: Doc, target: Doc, linkSettings: { linkRelationship?: string; description?: string; linkDisplay?: boolean }, id?: string, showPopup?: number[]) {
         if (!linkSettings.linkRelationship) linkSettings.linkRelationship = target.type === DocumentType.RTF ? 'Commentary:Comments On' : 'link';
         const sv = DocumentManager.Instance.getDocumentView(source);
-        if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target) return;
         if (target.doc === Doc.UserDoc()) return undefined;
 
         const makeLink = action((linkDoc: Doc, showPopup?: number[]) => {
@@ -1371,7 +1366,6 @@ export namespace DocUtils {
                         value: 'any',
                         _readOnly_: 'boolean',
                         scriptContext: 'any',
-                        thisContainer: Doc.name,
                         documentView: Doc.name,
                         heading: Doc.name,
                         checked: 'boolean',
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 76ea3e3ea..abf7313a4 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -110,7 +110,7 @@ export class CurrentUserUtils {
         const tempClicks = DocCast(doc[field]);
         const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, system: true};
         const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [
-            { opts: { title: "Open In Target",        targetScriptKey: "onChildClick"},       script: "docCast(thisContainer.target).then((target) => target && (target.proto.data = new List([self])))"},
+            { opts: { title: "Open In Target",        targetScriptKey: "onChildClick"},       script: "docCast(documentView?.props.docViewPath().lastElement()?.rootDoc.target).then((target) => target && (target.proto.data = new List([self])))"},
             { opts: { title: "Open Detail On Right",  targetScriptKey: "onChildDoubleClick"}, script: `openDoc(self.doubleClickView.${OpenWhere.addRight})`}];
         const reqdClickList = reqdTempOpts.map(opts => {
             const allOpts = {...reqdClickOpts, ...opts.opts};
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index ccf370662..ad89e8653 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,15 +1,11 @@
-import { loadAsync } from 'jszip';
-import { action, observable, ObservableSet, runInAction } from 'mobx';
+import { action, observable, ObservableSet } from 'mobx';
 import { AnimationSym, Doc, Opt } from '../../fields/Doc';
 import { Id } from '../../fields/FieldSymbols';
 import { listSpec } from '../../fields/Schema';
 import { Cast, DocCast, StrCast } from '../../fields/Types';
 import { AudioField } from '../../fields/URLField';
-import { emptyFunction } from '../../Utils';
 import { CollectionViewType } from '../documents/DocumentTypes';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
-import { CollectionFreeFormView } from '../views/collections/collectionFreeForm';
-import { CollectionView } from '../views/collections/CollectionView';
 import { TabDocView } from '../views/collections/TabDocView';
 import { LightboxView } from '../views/LightboxView';
 import { MainView } from '../views/MainView';
@@ -39,7 +35,7 @@ export class DocumentManager {
     private _viewRenderedCbs: { doc: Doc; func: (dv: DocumentView) => any }[] = [];
     public AddViewRenderedCb = (doc: Opt<Doc>, func: (dv: DocumentView) => any) => {
         if (doc) {
-            const dv = this.getDocumentViewById(doc[Id]);
+            const dv = this.getDocumentView(doc);
             this._viewRenderedCbs.push({ doc, func });
             if (dv) {
                 this.callAddViewFuncs(dv);
@@ -129,42 +125,24 @@ export class DocumentManager {
         return this.getDocumentViewsById(doc[Id]);
     }
 
-    public getDocumentViewById(id: string, preferredCollection?: CollectionView): DocumentView | undefined {
-        if (!id) return undefined;
-        let toReturn: DocumentView | undefined;
-        const passes = preferredCollection ? [preferredCollection, undefined] : [undefined];
-
-        for (const pass of passes) {
-            Array.from(DocumentManager.Instance.DocumentViews).map(view => {
-                if (view.rootDoc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
-                    toReturn = view;
-                    return;
-                }
-            });
-            if (!toReturn) {
-                Array.from(DocumentManager.Instance.DocumentViews).map(view => {
-                    const doc = view.rootDoc.proto;
-                    if (doc && doc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
-                        toReturn = view;
-                    }
-                });
-            } else {
-                break;
-            }
-        }
-
-        return toReturn;
-    }
-
-    public getDocumentView(toFind: Doc, preferredCollection?: CollectionView): DocumentView | undefined {
-        const found =
+    public getDocumentView(toFind: Doc | undefined, preferredCollection?: DocumentView): DocumentView | undefined {
+        const doc =
+            // bcz: this was temporary code used to match documents by data url instead of by id. intended only for repairing the DB
             // Array.from(DocumentManager.Instance.DocumentViews).find(
             //     dv =>
             //         ((dv.rootDoc.data as any)?.url?.href && (dv.rootDoc.data as any)?.url?.href === (toFind.data as any)?.url?.href) ||
             //         ((DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href && (DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href === (DocCast(toFind.annotationOn)?.data as any)?.url?.href)
             // )?.rootDoc ??
             toFind;
-        return this.getDocumentViewById(found[Id], preferredCollection);
+        const docViewArray = Array.from(DocumentManager.Instance.DocumentViews);
+        const passes = !doc ? [] : preferredCollection ? [preferredCollection, undefined] : [undefined];
+        return passes.reduce(
+            (pass, toReturn) =>
+                toReturn ??
+                docViewArray.filter(view => view.rootDoc === doc).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection) ??
+                docViewArray.filter(view => Doc.GetProto(view.rootDoc) === doc).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection),
+            undefined as Opt<DocumentView>
+        );
     }
 
     public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => {
@@ -247,7 +225,8 @@ export class DocumentManager {
     public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => {
         const docViewPath = targetDocView.docViewPath.slice();
         let rootContextView = docViewPath.shift();
-        return rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined }));
+        await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined })));
+        if (options.toggleTarget && (!options.didMove || targetDocView.rootDoc.hidden)) targetDocView.rootDoc.hidden = !targetDocView.rootDoc.hidden;
     };
 
     // shows a document by first:
@@ -318,15 +297,25 @@ export class DocumentManager {
         }
     }
 }
-export function DocFocusOrOpen(doc: Doc, collectionDoc?: Doc) {
-    const cv = collectionDoc && DocumentManager.Instance.getDocumentView(collectionDoc);
-    const dv = DocumentManager.Instance.getDocumentView(doc, (cv?.ComponentView as CollectionFreeFormView)?.props.CollectionView);
-    if (dv) {
-        DocumentManager.Instance.showDocumentView(dv, { willZoomCentered: true });
-    } else {
-        const context = doc.context !== Doc.MyFilesystem && Cast(doc.context, Doc, null);
-        const showDoc = context || doc;
-        DocumentManager.Instance.showDocument(Doc.BestAlias(showDoc), { openLocation: OpenWhere.addRight }, () => DocumentManager.Instance.showDocument(doc, { willZoomCentered: true }));
-    }
+export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, openLocation: OpenWhere.addRight }, containingDoc?: Doc) {
+    const func = () => {
+        const cv = DocumentManager.Instance.getDocumentView(containingDoc);
+        const dv = DocumentManager.Instance.getDocumentView(doc, cv);
+        if (dv && (!containingDoc || dv.props.docViewPath().lastElement()?.Document === containingDoc)) {
+            DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.rootDoc));
+        } else {
+            const showDoc = Doc.BestAlias(DocCast((containingDoc ?? doc.context) !== Doc.MyFilesystem ? containingDoc ?? doc.context : undefined, doc));
+            DocumentManager.Instance.showDocument(showDoc, { ...options, toggleTarget: undefined }, () => DocumentManager.Instance.showDocument(doc, options)).then(() => {
+                const cv = DocumentManager.Instance.getDocumentView(containingDoc);
+                const dv = DocumentManager.Instance.getDocumentView(doc, cv);
+                dv && Doc.linkFollowHighlight(dv.rootDoc);
+            });
+        }
+    };
+    if (doc.hidden) {
+        doc.hidden = false;
+        options.toggleTarget = false;
+        setTimeout(func);
+    } else func();
 }
 ScriptingGlobals.add(DocFocusOrOpen);
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 7d2aa813f..7e6de5e67 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -3,10 +3,8 @@ import { DateField } from '../../fields/DateField';
 import { Doc, Field, Opt, StrListCast } from '../../fields/Doc';
 import { List } from '../../fields/List';
 import { PrefetchProxy } from '../../fields/Proxy';
-import { listSpec } from '../../fields/Schema';
-import { SchemaHeaderField } from '../../fields/SchemaHeaderField';
 import { ScriptField } from '../../fields/ScriptField';
-import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../fields/Types';
+import { BoolCast, ScriptCast, StrCast } from '../../fields/Types';
 import { emptyFunction, Utils } from '../../Utils';
 import { Docs, DocUtils } from '../documents/Documents';
 import * as globalCssVariables from '../views/global/globalCssVariables.scss';
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index 559958c2b..76b1323c4 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx	
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx	
@@ -14,12 +14,14 @@ import { AcceptableMedia, Upload } from '../../../server/SharedMediaTypes';
 import { Utils } from '../../../Utils';
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { Docs, DocumentOptions, DocUtils } from '../../documents/Documents';
+import { DocumentType } from '../../documents/DocumentTypes';
 import { Networking } from '../../Network';
 import { FieldView, FieldViewProps } from '../../views/nodes/FieldView';
 import { DocumentManager } from '../DocumentManager';
 import './DirectoryImportBox.scss';
 import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from './ImportMetadataEntry';
 import React = require('react');
+import _ = require('lodash');
 
 const unsupported = ['text/html', 'text/plain'];
 
@@ -155,8 +157,8 @@ export class DirectoryImportBox extends React.Component<FieldViewProps> {
             x: NumCast(doc.x),
             y: NumCast(doc.y) + offset,
         };
-        const parent = this.props.ContainingCollectionView;
-        if (parent) {
+        const parent = _.nth(this.props.docViewPath(), -2); // last element of path is this box's document view, 2nd to last is any collection or other document that may contain it.
+        if (parent?.rootDoc.type === DocumentType.COL) {
             let importContainer: Doc;
             if (docs.length < 50) {
                 importContainer = Docs.Create.MasonryDocument(docs, options);
diff --git a/src/client/util/ReplayMovements.ts b/src/client/util/ReplayMovements.ts
index d5bffc5e2..40261985a 100644
--- a/src/client/util/ReplayMovements.ts
+++ b/src/client/util/ReplayMovements.ts
@@ -7,6 +7,7 @@ import { CollectionDockingView } from '../views/collections/CollectionDockingVie
 import { DocServer } from '../DocServer';
 import { Movement, Presentation } from './TrackMovements';
 import { OpenWhereMod } from '../views/nodes/DocumentView';
+import { returnTransparent } from '../../Utils';
 
 export class ReplayMovements {
     private timers: NodeJS.Timeout[] | null;
@@ -60,17 +61,11 @@ export class ReplayMovements {
             return;
         }
 
-        let docIdtoDoc: Map<string, Doc> = new Map();
-        try {
-            docIdtoDoc = await this.loadPresentation(presentation);
-        } catch {
-            console.error('[recordingApi.ts] setVideoBox(): error loading presentation - no replay movements');
-            throw 'error loading docs from server';
-        }
+        const docIdtoDoc = this.loadPresentation(presentation);
 
         this.videoBoxDisposeFunc = reaction(
             () => ({ playing: videoBox._playing, timeViewed: videoBox.player?.currentTime || 0 }),
-            ({ playing, timeViewed }) => (playing ? this.playMovements(presentation, docIdtoDoc, timeViewed) : this.pauseMovements())
+            ({ playing, timeViewed }) => (playing ? this.playMovements(presentation, timeViewed) : this.pauseMovements())
         );
         this.videoBox = videoBox;
     };
@@ -93,45 +88,33 @@ export class ReplayMovements {
         this.pauseMovements();
     };
 
-    loadPresentation = async (presentation: Presentation) => {
+    loadPresentation = (presentation: Presentation) => {
         const { movements } = presentation;
         if (movements === null) {
             throw '[recordingApi.ts] followMovements() failed: no presentation data';
         }
 
         // generate a set of all unique docIds
-        const docIds = new Set<string>();
-        for (const { docId } of movements) {
-            if (!docIds.has(docId)) docIds.add(docId);
-        }
-
-        const docIdtoDoc = new Map<string, Doc>();
-
-        let refFields = await DocServer.GetRefFields([...docIds.keys()]);
-        for (const docId in refFields) {
-            if (!refFields[docId]) {
-                throw `one field was undefined`;
-            }
-            docIdtoDoc.set(docId, refFields[docId] as Doc);
+        const docs = new Set<Doc>();
+        for (const { doc } of movements) {
+            if (!docs.has(doc)) docs.add(doc);
         }
-        // console.info('loadPresentation refFields', refFields, docIdtoDoc);
 
-        return docIdtoDoc;
+        return docs;
     };
 
     // returns undefined if the docView isn't open on the screen
-    getCollectionFFView = (docId: string) => {
-        const isInView = DocumentManager.Instance.getDocumentViewById(docId);
+    getCollectionFFView = (doc: Doc) => {
+        const isInView = DocumentManager.Instance.getDocumentView(doc);
         if (isInView) {
             return isInView.ComponentView as CollectionFreeFormView;
         }
     };
 
     // will open the doc in a tab then return the CollectionFFView that holds it
-    openTab = (docId: string, docIdtoDoc: Map<string, Doc>) => {
-        const doc = docIdtoDoc.get(docId);
-        if (doc == undefined) {
-            console.error(`docIdtoDoc did not contain docId ${docId}`);
+    openTab = (doc: Doc) => {
+        if (doc === undefined) {
+            console.error(`doc undefined`);
             return undefined;
         }
         // console.log('openTab', docId, doc);
@@ -149,13 +132,12 @@ export class ReplayMovements {
         document.Document._panY = panY;
     };
 
-    getFirstMovements = (movements: Movement[]): Map<string, Movement> => {
+    getFirstMovements = (movements: Movement[]): Map<Doc, Movement> => {
         if (movements === null) return new Map();
         // generate a set of all unique docIds
-        const docIdtoFirstMove = new Map();
+        const docIdtoFirstMove = new Map<Doc, Movement>();
         for (const move of movements) {
-            const { docId } = move;
-            if (!docIdtoFirstMove.has(docId)) docIdtoFirstMove.set(docId, move);
+            if (!docIdtoFirstMove.has(move.doc)) docIdtoFirstMove.set(move.doc, move);
         }
         return docIdtoFirstMove;
     };
@@ -165,7 +147,7 @@ export class ReplayMovements {
         Doc.UserDoc().presentationMode = 'none';
     };
 
-    public playMovements = (presentation: Presentation, docIdtoDoc: Map<string, Doc>, timeViewed: number = 0) => {
+    public playMovements = (presentation: Presentation, timeViewed: number = 0) => {
         // console.info('playMovements', presentation, timeViewed, docIdtoDoc);
 
         if (presentation.movements === null || presentation.movements.length === 0) {
@@ -183,13 +165,13 @@ export class ReplayMovements {
         const handleFirstMovements = () => {
             // if the first movement is a closed tab, open it
             const firstMovement = filteredMovements[0];
-            const isClosed = this.getCollectionFFView(firstMovement.docId) === undefined;
-            if (isClosed) this.openTab(firstMovement.docId, docIdtoDoc);
+            const isClosed = this.getCollectionFFView(firstMovement.doc) === undefined;
+            if (isClosed) this.openTab(firstMovement.doc);
 
             // for the open tabs, set it to the first move
             const docIdtoFirstMove = this.getFirstMovements(filteredMovements);
-            for (const [docId, firstMove] of docIdtoFirstMove) {
-                const colFFView = this.getCollectionFFView(docId);
+            for (const [doc, firstMove] of docIdtoFirstMove) {
+                const colFFView = this.getCollectionFFView(doc);
                 if (colFFView) this.zoomAndPan(firstMove, colFFView);
             }
         };
@@ -200,12 +182,12 @@ export class ReplayMovements {
             const timeDiff = movement.time - timeViewed * 1000;
 
             return setTimeout(() => {
-                const collectionFFView = this.getCollectionFFView(movement.docId);
+                const collectionFFView = this.getCollectionFFView(movement.doc);
                 if (collectionFFView) {
                     this.zoomAndPan(movement, collectionFFView);
                 } else {
                     // tab wasn't open - open it and play the movement
-                    const openedColFFView = this.openTab(movement.docId, docIdtoDoc);
+                    const openedColFFView = this.openTab(movement.doc);
                     console.log('openedColFFView', openedColFFView);
                     openedColFFView && this.zoomAndPan(movement, openedColFFView);
                 }
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 313c255a0..bfad93334 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,4 +1,3 @@
-import { ModalManager } from '@material-ui/core';
 import { action, observable, ObservableMap } from 'mobx';
 import { computedFn } from 'mobx-utils';
 import { Doc, Opt } from '../../fields/Doc';
@@ -64,8 +63,9 @@ export namespace SelectionManager {
     export function DeselectView(docView?: DocumentView): void {
         manager.DeselectView(docView);
     }
-    export function SelectView(docView: DocumentView, ctrlPressed: boolean): void {
-        manager.SelectView(docView, ctrlPressed);
+    export function SelectView(docView: DocumentView | undefined, ctrlPressed: boolean): void {
+        if (!docView) DeselectAll();
+        else manager.SelectView(docView, ctrlPressed);
     }
     export function SelectSchemaViewDoc(document: Opt<Doc>, deselectAllFirst?: boolean): void {
         if (deselectAllFirst) manager.DeselectAll();
diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx
index 3c05af4bb..a73eda04c 100644
--- a/src/client/util/SharingManager.tsx
+++ b/src/client/util/SharingManager.tsx
@@ -370,11 +370,10 @@ export class SharingManager extends React.Component<{}> {
         const docs = SelectionManager.Views().length > 1 ? SelectionManager.Views().map(docView => docView.props.Document) : [this.targetDoc];
         return (
             <span
-                className={'focus-span'}
+                className="focus-span"
                 title={title}
                 onClick={() => {
-                    let context: Opt<CollectionView>;
-                    if (this.targetDoc && this.targetDocView && docs.length === 1 && (context = this.targetDocView.props.ContainingCollectionView)) {
+                    if (this.targetDoc && this.targetDocView && docs.length === 1) {
                         DocumentManager.Instance.showDocument(this.targetDoc, { willZoomCentered: true });
                     }
                 }}
diff --git a/src/client/util/TrackMovements.ts b/src/client/util/TrackMovements.ts
index 4a2ccd706..2f16307b3 100644
--- a/src/client/util/TrackMovements.ts
+++ b/src/client/util/TrackMovements.ts
@@ -9,7 +9,7 @@ export type Movement = {
     panX: number;
     panY: number;
     scale: number;
-    docId: string;
+    doc: Doc;
 };
 
 export type Presentation = {
@@ -28,7 +28,7 @@ export class TrackMovements {
     private tracking: boolean;
     private absoluteStart: number;
     // instance variable for holding the FFViews and their disposers
-    private recordingFFViews: Map<string, IReactionDisposer> | null;
+    private recordingFFViews: Map<Doc, IReactionDisposer> | null;
     private tabChangeDisposeFunc: IReactionDisposer | null;
 
     // create static instance and getter for global use
@@ -55,33 +55,33 @@ export class TrackMovements {
         return this.currentPresentation.movements === null;
     }
 
-    private addRecordingFFView(doc: Doc, key: string = doc[Id]): void {
+    private addRecordingFFView(doc: Doc): void {
         // console.info('adding dispose func : docId', key, 'doc', doc);
 
         if (this.recordingFFViews === null) {
             console.warn('addFFView on null RecordingApi');
             return;
         }
-        if (this.recordingFFViews.has(key)) {
-            console.warn('addFFView : key already in map');
+        if (this.recordingFFViews.has(doc)) {
+            console.warn('addFFView : doc already in map');
             return;
         }
 
         const disposeFunc = reaction(
             () => ({ x: NumCast(doc.panX, -1), y: NumCast(doc.panY, -1), scale: NumCast(doc.viewScale, 0) }),
-            res => res.x !== -1 && res.y !== -1 && this.tracking && this.trackMovement(res.x, res.y, key, res.scale)
+            res => res.x !== -1 && res.y !== -1 && this.tracking && this.trackMovement(res.x, res.y, doc, res.scale)
         );
-        this.recordingFFViews?.set(key, disposeFunc);
+        this.recordingFFViews?.set(doc, disposeFunc);
     }
 
-    private removeRecordingFFView = (key: string) => {
+    private removeRecordingFFView = (doc: Doc) => {
         // console.info('removing dispose func : docId', key);
         if (this.recordingFFViews === null) {
             console.warn('removeFFView on null RecordingApi');
             return;
         }
-        this.recordingFFViews.get(key)?.();
-        this.recordingFFViews.delete(key);
+        this.recordingFFViews.get(doc)?.();
+        this.recordingFFViews.delete(doc);
     };
 
     // in the case where only one tab was changed (updates not across dashboards), set only one to true
@@ -90,15 +90,15 @@ export class TrackMovements {
 
         // so that the size comparisons are correct, we must filter to only the FFViews
         const isFFView = (doc: Doc) => doc && 'viewType' in doc && doc.viewType === 'freeform';
-        const tabbedFFViews = new Set<string>();
+        const tabbedFFViews = new Set<Doc>();
         for (const DashDoc of tabbedDocs) {
-            if (isFFView(DashDoc)) tabbedFFViews.add(DashDoc[Id]);
+            if (isFFView(DashDoc)) tabbedFFViews.add(DashDoc);
         }
 
         // new tab was added - need to add it
         if (tabbedFFViews.size > this.recordingFFViews.size) {
             for (const DashDoc of tabbedDocs) {
-                if (!this.recordingFFViews.has(DashDoc[Id])) {
+                if (!this.recordingFFViews.has(DashDoc)) {
                     if (isFFView(DashDoc)) {
                         this.addRecordingFFView(DashDoc);
 
@@ -110,9 +110,9 @@ export class TrackMovements {
         }
         // tab was removed - need to remove it from recordingFFViews
         else if (tabbedFFViews.size < this.recordingFFViews.size) {
-            for (const [key] of this.recordingFFViews) {
-                if (!tabbedFFViews.has(key)) {
-                    this.removeRecordingFFView(key);
+            for (const [doc] of this.recordingFFViews) {
+                if (!tabbedFFViews.has(doc)) {
+                    this.removeRecordingFFView(doc);
                     if (onlyOne) return;
                 }
             }
@@ -214,7 +214,7 @@ export class TrackMovements {
         }
     };
 
-    private trackMovement = (panX: number, panY: number, docId: string, scale: number = 0) => {
+    private trackMovement = (panX: number, panY: number, doc: Doc, scale: number = 0) => {
         // ensure we are recording to track
         if (!this.tracking) {
             console.error('[recordingApi.ts] trackMovements(): tracking is false');
@@ -231,7 +231,7 @@ export class TrackMovements {
         // get the time
         const time = new Date().getTime() - this.absoluteStart;
         // make new movement object
-        const movement: Movement = { time, panX, panY, scale, docId };
+        const movement: Movement = { time, panX, panY, scale, doc };
 
         // add that movement to the current presentation data's movement array
         this.currentPresentation.movements && this.currentPresentation.movements.push(movement);
diff --git a/src/client/views/DashboardView.tsx b/src/client/views/DashboardView.tsx
index 2b586b0e2..dee161931 100644
--- a/src/client/views/DashboardView.tsx
+++ b/src/client/views/DashboardView.tsx
@@ -109,17 +109,8 @@ export class DashboardView extends React.Component {
                     />
                 </div>
                 <div className="button-bar">
-                    <Button text="Cancel" borderRadius={10} hoverStyle={'gray'} fontSize={FontSize.SECONDARY} onClick={this.abortCreateNewDashboard} />
-                    <Button
-                        text="Create"
-                        borderRadius={10}
-                        backgroundColor={Colors.LIGHT_BLUE}
-                        hoverStyle={'darken'}
-                        fontSize={FontSize.SECONDARY}
-                        onClick={() => {
-                            this.createNewDashboard(this.newDashboardName!, this.newDashboardColor);
-                        }}
-                    />
+                    <Button text="Cancel" onClick={this.abortCreateNewDashboard} />
+                    <Button text="Create" onClick={() => this.createNewDashboard(this.newDashboardName!, this.newDashboardColor)} />
                 </div>
             </div>
         );
@@ -163,7 +154,7 @@ export class DashboardView extends React.Component {
                 <div className="dashboard-view">
                     <div className="left-menu">
                         <div className="new-dashboard-button">
-                            <Button icon={<FaPlus />} hoverStyle="darken" backgroundColor={Colors.LIGHT_BLUE} size={Size.MEDIUM} fontSize={FontSize.HEADER} text="New" onClick={() => this.setNewDashboardName('')} borderRadius={50} />
+                            <Button icon={<FaPlus />} size={Size.MEDIUM} text="New" onClick={() => this.setNewDashboardName('')} />
                         </div>
                         <div className={`text-button ${this.selectedDashboardGroup === DashboardGroup.MyDashboards && 'selected'}`} onClick={() => this.selectDashboardGroup(DashboardGroup.MyDashboards)}>
                             My Dashboards
@@ -196,7 +187,7 @@ export class DashboardView extends React.Component {
                                                 e.stopPropagation();
                                                 this.onContextMenu(dashboard, e);
                                             }}>
-                                            <IconButton isCircle={true} size={Size.SMALL} hoverStyle="gray" icon={<FontAwesomeIcon color="black" size="lg" icon="bars" />} />
+                                            <Button size={Size.SMALL} icon={<FontAwesomeIcon color="black" size="lg" icon="bars" />} />
                                         </div>
                                     </div>
                                 </div>
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 9fc1487a0..a59189fd2 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -52,7 +52,6 @@ export function DocComponent<P extends DocComponentProps>() {
 interface ViewBoxBaseProps {
     Document: Doc;
     DataDoc?: Doc;
-    ContainingCollectionDoc: Opt<Doc>;
     DocumentView?: () => DocumentView;
     fieldKey: string;
     isSelected: (outsideReaction?: boolean) => boolean;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9ffbe083f..9a4aaf00e 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -33,6 +33,7 @@ import { ImageBox } from './nodes/ImageBox';
 import React = require('react');
 import { RichTextField } from '../../fields/RichTextField';
 import { LinkFollower } from '../util/LinkFollower';
+import _ = require('lodash');
 
 @observer
 export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> {
@@ -303,8 +304,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         SelectionManager.DeselectAll();
     };
 
-    onSelectorClick = () => SelectionManager.Views()?.[0]?.props.ContainingCollectionView?.props.select(false);
-
+    onSelectorClick = () => SelectionManager.Views()?.[0]?.props.docViewPath?.().lastElement()?.select(false);
     /**
      * Handles setting up events when user clicks on the border radius editor
      * @param e PointerEvent
@@ -744,7 +744,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
             seldocview.props.hideDeleteButton ||
             seldocview.rootDoc.hideDeleteButton ||
             SelectionManager.Views().some(docView => {
-                const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit;
+                const collectionAcl = docView.props.docViewPath()?.lastElement() ? GetEffectiveAcl(docView.props.docViewPath().lastElement().rootDoc[DataSym]) : AclEdit;
                 return docView.rootDoc.stayInCollection || (collectionAcl !== AclAdmin && collectionAcl !== AclEdit && GetEffectiveAcl(docView.rootDoc) !== AclAdmin);
             });
 
@@ -865,7 +865,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                                     <div key="b" className={`documentDecorations-bottomResizer ${resizerScheme}`} onPointerDown={this.onPointerDown} onContextMenu={e => e.preventDefault()} />
                                     <div key="br" className={`documentDecorations-bottomRightResizer ${resizerScheme}`} onPointerDown={this.onPointerDown} onContextMenu={e => e.preventDefault()} />
 
-                                    {seldocview.props.renderDepth <= 1 || !seldocview.props.ContainingCollectionView ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectorClick, 'tap to select containing document')}
+                                    {seldocview.props.renderDepth <= 1 || !seldocview.props.docViewPath().lastElement() ? null : topBtn('selector', 'arrow-alt-circle-up', undefined, this.onSelectorClick, 'tap to select containing document')}
                                 </>
                             )}
                             {useRounding && (
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 0feccb742..13faae783 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -1010,14 +1010,12 @@ export class GestureOverlay extends Touchable<GestureOverlayProps> {
                 renderDepth={0}
                 styleProvider={returnEmptyString}
                 docViewPath={returnEmptyDoclist}
-                focus={DocUtils.DefaultFocus}
+                focus={emptyFunction}
                 whenChildContentsActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
                 docRangeFilters={returnEmptyFilter}
                 docFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
-                ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
             />
         );
     };
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index e6df0801c..156825f41 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -373,10 +373,11 @@ export class InkStrokeProperties {
 
     snapToAllCurves = (screenDragPt: { X: number; Y: number }, inkView: DocumentView, snapData: { nearestPt: { X: number; Y: number }; distance: number }, ink: InkData, controlIndex: number) => {
         const containingCollection = inkView.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView;
+        const containingDocView = inkView.props.CollectionFreeFormDocumentView?.().props.DocumentView?.();
         containingCollection?.childDocs
             .filter(doc => doc.type === DocumentType.INK)
             .forEach(doc => {
-                const testInkView = DocumentManager.Instance.getDocumentView(doc, containingCollection?.props.CollectionView);
+                const testInkView = DocumentManager.Instance.getDocumentView(doc, containingDocView);
                 const snapped = testInkView?.ComponentView?.snapPt?.(screenDragPt, doc === inkView.rootDoc ? this.excludeSelfSnapSegs(ink, controlIndex) : []);
                 if (snapped && snapped.distance < snapData.distance) {
                     const snappedInkPt = doc === inkView.rootDoc ? snapped.nearestPt : inkView.ComponentView?.ptFromScreen?.(testInkView?.ComponentView?.ptToScreen?.(snapped.nearestPt) ?? { X: 0, Y: 0 }); // convert from snapped ink coordinate system to dragged ink coordinate system by converting to/from screen space
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index 976c8763e..69eec8456 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -266,8 +266,6 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             docFilters={this.docFilters}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined}
                             addDocument={undefined}
                             removeDocument={undefined}
                             whenChildContentsActiveChanged={emptyFunction}
@@ -275,7 +273,7 @@ export class LightboxView extends React.Component<LightboxViewProps> {
                             pinToPres={TabDocView.PinDoc}
                             bringToFront={emptyFunction}
                             onBrowseClick={MainView.Instance.exploreMode}
-                            focus={DocUtils.DefaultFocus}
+                            focus={emptyFunction}
                         />
                     </GestureOverlay>
                 </div>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 60459cf30..0384d925e 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -595,14 +595,12 @@ export class MainView extends React.Component {
                     PanelWidth={this.headerBarDocWidth}
                     PanelHeight={this.headerBarDocHeight}
                     renderDepth={0}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
@@ -626,14 +624,12 @@ export class MainView extends React.Component {
                     ScreenToLocalTransform={this._hideUI ? this.mainScreenToLocalXf : Transform.Identity}
                     PanelWidth={this.mainDocViewWidth}
                     PanelHeight={this.mainDocViewHeight}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     suppressSetHeight={true}
                     renderDepth={this._hideUI ? 0 : -1}
                 />
@@ -727,14 +723,12 @@ export class MainView extends React.Component {
                         renderDepth={0}
                         isContentActive={returnTrue}
                         scriptContext={CollectionDockingView.Instance?.props.Document}
-                        focus={DocUtils.DefaultFocus}
+                        focus={emptyFunction}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
                         docFilters={returnEmptyFilter}
                         docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
                 {this.docButtons}
@@ -758,7 +752,7 @@ export class MainView extends React.Component {
                     PanelHeight={this.leftMenuHeight}
                     renderDepth={0}
                     docViewPath={returnEmptyDoclist}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     styleProvider={DefaultStyleProvider}
                     isContentActive={returnTrue}
                     whenChildContentsActiveChanged={emptyFunction}
@@ -766,8 +760,6 @@ export class MainView extends React.Component {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     scriptContext={this}
                 />
             </div>
@@ -900,13 +892,11 @@ export class MainView extends React.Component {
                     PanelWidth={this.leftMenuFlyoutWidth}
                     PanelHeight={this.leftMenuFlyoutHeight}
                     renderDepth={0}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={emptyFunction}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
                 {['watching', 'recording'].includes(String(this.userDoc?.presentationMode) ?? '') ? <div style={{ border: '.5rem solid green', padding: '5px' }}>{StrCast(this.userDoc?.presentationMode)}</div> : <></>}
             </div>
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index ec22128d4..bdc48d03a 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable, trace } from 'mobx';
+import { action, computed, observable } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import * as React from 'react';
@@ -10,15 +10,13 @@ import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, retu
 import { DocUtils } from '../documents/Documents';
 import { DocumentType } from '../documents/DocumentTypes';
 import { DragManager } from '../util/DragManager';
-import { ScriptingGlobals } from '../util/ScriptingGlobals';
 import { Transform } from '../util/Transform';
 import { CollectionFreeFormLinksView } from './collections/collectionFreeForm/CollectionFreeFormLinksView';
 import { LightboxView } from './LightboxView';
 import { MainView } from './MainView';
 import { DocumentView } from './nodes/DocumentView';
 import './OverlayView.scss';
-import { ScriptingRepl } from './ScriptingRepl';
-import { DefaultStyleProvider, testDocProps } from './StyleProvider';
+import { DefaultStyleProvider } from './StyleProvider';
 
 export type OverlayDisposer = () => void;
 
@@ -223,7 +221,7 @@ export class OverlayView extends React.Component {
                             isDocumentActive={returnTrue}
                             isContentActive={returnTrue}
                             whenChildContentsActiveChanged={emptyFunction}
-                            focus={DocUtils.DefaultFocus}
+                            focus={emptyFunction}
                             styleProvider={DefaultStyleProvider}
                             docViewPath={returnEmptyDoclist}
                             addDocTab={d.type === DocumentType.PRES ? MainView.addDocTabFunc : returnFalse}
@@ -231,8 +229,6 @@ export class OverlayView extends React.Component {
                             docFilters={returnEmptyFilter}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined}
                         />
                     </div>
                 );
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 954529bc9..3ad28c418 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -1,12 +1,12 @@
-import { IReactionDisposer, observable, reaction } from "mobx";
-import { observer } from "mobx-react";
-import * as React from "react";
-import { Doc } from "../../fields/Doc";
-import { NumCast } from "../../fields/Types";
-import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from "../../Utils";
-import { Transform } from "../util/Transform";
-import { DocumentView } from "./nodes/DocumentView";
-import "./Palette.scss";
+import { IReactionDisposer, observable, reaction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as React from 'react';
+import { Doc } from '../../fields/Doc';
+import { NumCast } from '../../fields/Types';
+import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, emptyPath } from '../../Utils';
+import { Transform } from '../util/Transform';
+import { DocumentView } from './nodes/DocumentView';
+import './Palette.scss';
 
 export interface PaletteProps {
     x: number;
@@ -23,20 +23,20 @@ export default class Palette extends React.Component<PaletteProps> {
     componentDidMount = () => {
         this._selectedDisposer = reaction(
             () => NumCast(this.props.thumbDoc.selectedIndex),
-            (i) => this._selectedIndex = i,
+            i => (this._selectedIndex = i),
             { fireImmediately: true }
         );
-    }
+    };
 
     componentWillUnmount = () => {
         this._selectedDisposer?.();
-    }
+    };
 
     render() {
         return (
             <div className="palette-container" style={{ transform: `translate(${this.props.x}px, ${this.props.y}px)` }}>
                 <div className="palette-thumb" style={{ transform: `translate(${this.props.thumb[0] - this.props.x}px, ${this.props.thumb[1] - this.props.y}px)` }}>
-                    <div className="palette-thumbContent" style={{ transform: `translate(-${(this._selectedIndex * 50) + 10}px, 0px)` }}>
+                    <div className="palette-thumbContent" style={{ transform: `translate(-${this._selectedIndex * 50 + 10}px, 0px)` }}>
                         <DocumentView
                             Document={this.props.thumbDoc}
                             DataDoc={undefined}
@@ -59,12 +59,11 @@ export default class Palette extends React.Component<PaletteProps> {
                             docFilters={returnEmptyFilter}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined} />
+                        />
                         <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
                     </div>
                 </div>
             </div>
         );
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/PropertiesDocContextSelector.tsx b/src/client/views/PropertiesDocContextSelector.tsx
index 2c7da5931..93eec61f3 100644
--- a/src/client/views/PropertiesDocContextSelector.tsx
+++ b/src/client/views/PropertiesDocContextSelector.tsx
@@ -22,9 +22,9 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
     @computed get _docs() {
         if (!this.props.DocView) return [];
         const target = this.props.DocView.props.Document;
-        const targetContext = this.props.DocView.props.ContainingCollectionDoc;
+        const targetContext = this.props.DocView.props.docViewPath().lastElement()?.rootDoc;
         const aliases = DocListCast(target.aliases);
-        const containerProtos = aliases.filter(alias => alias.context && alias.context instanceof Doc && Cast(alias.context, Doc, null) !== targetContext).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set<Doc>());
+        const containerProtos = aliases.filter(alias => alias.context && alias.context instanceof Doc).reduce((set, alias) => set.add(Cast(alias.context, Doc, null)), new Set<Doc>());
         const containerSets = Array.from(containerProtos.keys()).map(container => DocListCast(container.aliases));
         const containers = containerSets.reduce((p, set) => {
             set.map(s => p.add(s));
@@ -42,6 +42,7 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
         return doclayouts
             .filter(doc => !Doc.AreProtosEqual(doc, CollectionDockingView.Instance?.props.Document))
             .filter(doc => !Doc.IsSystem(doc))
+            .filter(doc => doc !== targetContext)
             .map(doc => ({ col: doc, target }));
     }
 
@@ -53,8 +54,21 @@ export class PropertiesDocContextSelector extends React.Component<PropertiesDocC
             col._panY = NumCast(target.y) + NumCast(target._height) / 2;
         }
         col.hidden = false;
-        this.props.addDocTab(col, (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere);
-        setTimeout(() => DocFocusOrOpen(Doc.GetProto(this.props.DocView!.props.Document), col), 100);
+        //this.props.addDocTab(col, (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere);
+        setTimeout(
+            () =>
+                this.props.DocView &&
+                DocFocusOrOpen(
+                    Doc.GetProto(this.props.DocView.props.Document),
+                    {
+                        //
+                        willZoomCentered: true,
+                        openLocation: (OpenWhere.toggle + ':' + OpenWhereMod.right) as OpenWhere,
+                    },
+                    col
+                ),
+            100
+        );
     };
 
     render() {
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index fbc7d7696..6582c3f2a 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -341,8 +341,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
                         docFilters={returnEmptyFilter}
                         docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionDoc={undefined}
-                        ContainingCollectionView={undefined}
                         addDocument={returnFalse}
                         moveDocument={undefined}
                         removeDocument={returnFalse}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index b950b4860..739d6d819 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -18,7 +18,7 @@ import { TreeSort } from './collections/TreeView';
 import { Colors } from './global/globalEnums';
 import { InkingStroke } from './InkingStroke';
 import { MainView } from './MainView';
-import { DocumentViewProps } from './nodes/DocumentView';
+import { DocumentViewProps, OpenWhere } from './nodes/DocumentView';
 import { FieldViewProps } from './nodes/FieldView';
 import { KeyValueBox } from './nodes/KeyValueBox';
 import { SliderBox } from './nodes/SliderBox';
@@ -295,7 +295,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 default:
                     return doc.z
                         ? `#9c9396  ${StrCast(doc?.boxShadow, '10px 10px 0.9vw')}` // if it's a floating doc, give it a big shadow
-                        : props?.ContainingCollectionDoc?._useClusters
+                        : props?.docViewPath().lastElement()?.rootDoc._useClusters
                         ? `${backgroundCol()} ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
                         : NumCast(doc.group, -1) !== -1
                         ? `gray ${StrCast(doc.boxShadow, `0vw 0vw ${(lockedPosition() ? 100 : 50) / (docProps?.NativeDimScaling?.() || 1)}px`)}` // if it's just in a cluster, make the shadown roughly match the cluster border extent
@@ -316,7 +316,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             return undefined; // fixes problem with tree view elements getting pointer events when the tree view is not active
         case StyleProp.Decorations:
             const lock = () => {
-                if (props?.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform) {
+                if (props?.docViewPath().lastElement()?.rootDoc?._viewType === CollectionViewType.Freeform) {
                     return doc?.pointerEvents !== 'none' ? null : (
                         <div className="styleProvider-lock" onClick={() => toggleLockedPosition(doc)}>
                             <FontAwesomeIcon icon={'lock'} style={{ color: 'red' }} size="lg" />
@@ -383,10 +383,7 @@ export function DashboardStyleProvider(doc: Opt<Doc>, props: Opt<FieldViewProps
         return doc._viewType === CollectionViewType.Docking ? null : (
             <>
                 {DashboardToggleButton(doc, 'hidden', 'eye-slash', 'eye', () => {
-                    doc.hidden = doc.hidden ? undefined : true;
-                    if (!doc.hidden) {
-                        DocFocusOrOpen(doc, props?.ContainingCollectionDoc);
-                    }
+                    DocFocusOrOpen(doc, { toggleTarget: true, willPan: true, openLocation: OpenWhere.addRight }, props?.docViewPath().lastElement()?.rootDoc);
                 })}
             </>
         );
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 45db240a9..c5a501aa6 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -114,8 +114,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                 <CollectionTreeView
                     Document={Doc.MyTemplates}
                     CollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
-                    ContainingCollectionView={undefined}
                     styleProvider={DefaultStyleProvider}
                     setHeight={returnFalse}
                     docViewPath={returnEmptyDoclist}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index c0220f804..0e4556eb4 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -62,7 +62,6 @@ export class CollectionCarouselView extends CollectionSubView() {
                         onClick={this.onContentClick}
                         hideCaptions={showCaptions ? true : false}
                         renderDepth={this.props.renderDepth + 1}
-                        ContainingCollectionView={this.props.CollectionView}
                         LayoutTemplate={this.props.childLayoutTemplate}
                         LayoutTemplateString={this.props.childLayoutString}
                         Document={curDoc.layout}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 225743748..2007f73aa 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -134,8 +134,6 @@ export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
@@ -642,8 +640,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewMenu
                         key="float"
                         style={{
                             backgroundColor: this.props.docView.layoutDoc.z ? '121212' : undefined,
-                            pointerEvents: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? 'none' : undefined,
-                            color: this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? 'dimgrey' : undefined,
+                            pointerEvents: this.props.docView.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Freeform ? 'none' : undefined,
+                            color: this.props.docView.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Freeform ? 'dimgrey' : undefined,
                         }}
                         onClick={undoBatch(() => this.props.docView.props.CollectionFreeFormDocumentView?.().float())}>
                         <FontAwesomeIcon icon={['fab', 'buffer']} size={'lg'} />
diff --git a/src/client/views/collections/CollectionNoteTakingView.tsx b/src/client/views/collections/CollectionNoteTakingView.tsx
index aec0734b4..80e81bc1c 100644
--- a/src/client/views/collections/CollectionNoteTakingView.tsx
+++ b/src/client/views/collections/CollectionNoteTakingView.tsx
@@ -255,8 +255,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                 hideTitle={this.props.childHideTitle?.()}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
                 removeDocument={this.props.removeDocument}
@@ -632,8 +630,6 @@ export class CollectionNoteTakingView extends CollectionSubView() {
                         docFilters={this.props.docFilters}
                         docRangeFilters={this.props.docRangeFilters}
                         searchFilterDocs={this.props.searchFilterDocs}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
             );
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index ba90ed8cd..fd9b0c0ce 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -30,7 +30,7 @@ export class CollectionPileView extends CollectionSubView() {
         // pileups are designed to go away when they are empty.
         this._disposers.selected = reaction(
             () => this.childDocs.length,
-            num => !num && this.props.ContainingCollectionView?.removeDocument(this.props.Document)
+            num => !num && this.props.CollectionFreeFormDocumentView?.().props.removeDocument?.(this.props.Document)
         );
     }
     componentWillUnmount() {
diff --git a/src/client/views/collections/CollectionStackedTimeline.tsx b/src/client/views/collections/CollectionStackedTimeline.tsx
index bbd81d06d..22a575989 100644
--- a/src/client/views/collections/CollectionStackedTimeline.tsx
+++ b/src/client/views/collections/CollectionStackedTimeline.tsx
@@ -815,8 +815,6 @@ class StackedTimelineAnchor extends React.Component<StackedTimelineAnchorProps>
                     whenChildContentsActiveChanged={emptyFunction}
                     focus={focusFunc}
                     isContentActive={returnFalse}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     searchFilterDocs={returnEmptyDoclist}
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a85ee0e02..67f5dc9f4 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -346,8 +346,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                 hideTitle={this.props.childHideTitle?.()}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 xPadding={NumCast(this.layoutDoc._childXPadding, this.props.childXPadding)}
                 yPadding={NumCast(this.layoutDoc._childYPadding, this.props.childYPadding)}
                 addDocument={this.props.addDocument}
@@ -678,8 +676,6 @@ export class CollectionStackingView extends CollectionSubView<Partial<collection
                         docFilters={this.props.docFilters}
                         docRangeFilters={this.props.docRangeFilters}
                         searchFilterDocs={this.props.searchFilterDocs}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
             );
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4a11e8f0b..92932fb61 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -164,7 +164,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             this.props.removeDocument?.(doc);
             if (ind > 0) {
                 FormattedTextBox.SelectOnLoad = prev[Id];
-                DocumentManager.Instance.getDocumentView(prev, this.props.CollectionView)?.select(false);
+                DocumentManager.Instance.getDocumentView(prev, this.props.DocumentView?.())?.select(false);
             }
             return true;
         }
@@ -242,8 +242,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                 docFilters={returnEmptyFilter}
                 docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
-                ContainingCollectionDoc={this.doc}
-                ContainingCollectionView={this.props.CollectionView}
                 addDocument={returnFalse}
                 moveDocument={returnFalse}
                 removeDocument={returnFalse}
@@ -272,7 +270,7 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
             this,
             this.doc,
             this.props.DataDoc,
-            this.props.ContainingCollectionDoc,
+            undefined,
             undefined,
             addDoc,
             this.remove,
@@ -331,10 +329,10 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     isDocumentActive={returnTrue}
                     addDocument={this.props.addDocument}
                     moveDocument={this.props.moveDocument}
+                    removeDocument={this.props.removeDocument}
                     addDocTab={this.props.addDocTab}
                     pinToPres={emptyFunction}
                     rootSelected={this.props.isSelected}
-                    removeDocument={this.props.removeDocument}
                     ScreenToLocalTransform={Transform.Identity}
                     PanelWidth={this.return35}
                     PanelHeight={this.return35}
@@ -347,8 +345,6 @@ export class CollectionTreeView extends CollectionSubView<Partial<collectionTree
                     docFilters={this.props.docFilters}
                     docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index bc25ad43a..53fbcc3cc 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -279,7 +279,10 @@ export class CollectionView extends ViewBoxAnnotatableComponent<ViewBoxAnnotatab
             CollectionView: this,
         };
         return (
-            <div className={'collectionView'} onContextMenu={this.onContextMenu} style={{ pointerEvents: this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
+            <div
+                className="collectionView"
+                onContextMenu={this.onContextMenu}
+                style={{ pointerEvents: this.props.DocumentView?.()?.props.docViewPath().lastElement()?.rootDoc?._viewType === CollectionViewType.Freeform && this.rootDoc._lockedPosition ? 'none' : undefined }}>
                 {this.showIsTagged()}
                 {this.renderSubView(this.collectionViewType, props)}
             </div>
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 458712999..ef8f395c5 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -425,8 +425,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
                     hideTitle={this.props.keyValue}
                     Document={this._document}
                     DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     onBrowseClick={MainView.Instance.exploreMode}
                     waitForDoubleClickToClick={MainView.Instance.waitForDoubleClick}
                     isContentActive={returnTrue}
@@ -580,8 +578,6 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                 <CollectionFreeFormView
                     Document={this.props.document}
                     CollectionView={undefined}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     docViewPath={returnEmptyDoclist}
                     childLayoutTemplate={this.childLayoutTemplate} // bcz: Ugh .. should probably be rendering a CollectionView or the minimap should be part of the collectionFreeFormView to avoid having to set stuff like this.
                     noOverlay={true} // don't render overlay Docs since they won't scale
@@ -603,7 +599,7 @@ export class TabMinimapView extends React.Component<TabMinimapViewProps> {
                     ScreenToLocalTransform={Transform.Identity}
                     renderDepth={0}
                     whenChildContentsActiveChanged={emptyFunction}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     styleProvider={TabMinimapView.miniStyleProvider}
                     addDocTab={this.props.addDocTab}
                     pinToPres={TabDocView.PinDoc}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 75e76019e..8b1dfc767 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -42,7 +42,7 @@ export interface TreeViewProps {
     prevSibling?: Doc;
     document: Doc;
     dataDoc?: Doc;
-    containerCollection: Doc;
+    treeViewParent: Doc;
     renderDepth: number;
     dropAction: dropActionType;
     addDocTab: (doc: Doc, where: OpenWhere) => boolean;
@@ -143,7 +143,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return this.validExpandViewTypes.includes(StrCast(this.doc.treeViewExpandedView)) ? StrCast(this.doc.treeViewExpandedView) : this.defaultExpandedView;
     }
     @computed get MAX_EMBED_HEIGHT() {
-        return NumCast(this.props.containerCollection.maxEmbedHeight, 200);
+        return NumCast(this.props.treeViewParent.maxEmbedHeight, 200);
     }
     @computed get dataDoc() {
         return this.props.document.treeViewChildrenOnRoot ? this.doc : this.doc[DataSym];
@@ -194,7 +194,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         const ind = this.dataDoc[key].indexOf(doc);
 
         const res = (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && Doc.RemoveDocFromList(this.dataDoc, key, doc), true);
-        res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.CollectionView)?.select(false);
+        res && ind > 0 && DocumentManager.Instance.getDocumentView(this.dataDoc[key][ind - 1], this.props.treeView.props.DocumentView?.())?.select(false);
         return res;
     };
 
@@ -385,7 +385,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         };
         const addDoc = inside ? localAdd : parentAddDoc;
         const move = (!dropAction || dropAction === 'proto' || dropAction === 'move' || dropAction === 'same') && moveDocument;
-        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.containerCollection)?.freezeChildren).includes('add')) || forceAdd;
+        const canAdd = (!this.props.treeView.outlineMode && !StrCast((inside ? this.props.document : this.props.treeViewParent)?.freezeChildren).includes('add')) || forceAdd;
         if (canAdd) {
             this.props.parentTreeView instanceof TreeView && (this.props.parentTreeView.dropping = true);
             const res = UndoManager.RunInTempBatch(() => droppedDocuments.reduce((added, d) => (move ? move(d, undefined, addDoc) || (dropAction === 'proto' ? addDoc(d) : false) : addDoc(d)) || added, false));
@@ -406,7 +406,7 @@ export class TreeView extends React.Component<TreeViewProps> {
     getTransform = () => this.refTransform(this._tref.current);
     embeddedPanelWidth = () => this.props.panelWidth() / (this.props.treeView.props.NativeDimScaling?.() || 1);
     embeddedPanelHeight = () => {
-        const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document, ''))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
+        const layoutDoc = (temp => temp && Doc.expandTemplateLayout(temp, this.props.document))(this.props.treeView.props.childLayoutTemplate?.()) || this.layoutDoc;
         return Math.min(
             layoutDoc[HeightSym](),
             this.MAX_EMBED_HEIGHT,
@@ -416,7 +416,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 return layoutDoc._fitWidth
                     ? !Doc.NativeHeight(layoutDoc)
                         ? NumCast(layoutDoc._height)
-                        : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.containerCollection._height)))
+                        : Math.min((this.embeddedPanelWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc))) / (Doc.NativeWidth(layoutDoc) || NumCast(this.props.treeViewParent._height)))
                     : (this.embeddedPanelWidth() * layoutDoc[HeightSym]()) / layoutDoc[WidthSym]();
             })()
         );
@@ -452,7 +452,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     this,
                     doc,
                     undefined,
-                    this.props.containerCollection,
+                    this.props.treeViewParent,
                     this.props.prevSibling,
                     addDoc,
                     remDoc,
@@ -596,7 +596,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                                   this,
                                   this.layoutDoc,
                                   this.dataDoc,
-                                  this.props.containerCollection,
+                                  this.props.treeViewParent,
                                   this.props.prevSibling,
                                   addDoc,
                                   remDoc,
@@ -656,7 +656,7 @@ export class TreeView extends React.Component<TreeViewProps> {
             this.onCheckedClick?.script.run(
                 {
                     this: this.doc.isTemplateForField && this.props.dataDoc ? this.props.dataDoc : this.doc,
-                    heading: this.props.containerCollection.title,
+                    heading: this.props.treeViewParent.title,
                     checked: this.doc.treeViewChecked === 'check' ? 'x' : this.doc.treeViewChecked === 'x' ? 'remove' : 'check',
                     containingTreeView: this.props.treeView.props.Document,
                 },
@@ -724,9 +724,11 @@ export class TreeView extends React.Component<TreeViewProps> {
     };
 
     @observable headerEleWidth = 0;
-    @computed get headerElements() {
+    @computed get titleButtons() {
+        const customHeaderButtons = this.props.styleProvider?.(this.doc, this.props.treeView.props, StyleProp.Decorations);
         return this.props.treeViewHideHeaderFields() || this.doc.treeViewHideHeaderFields ? null : (
             <>
+                {customHeaderButtons} {/* e.g.,. hide button is set by dashboardStyleProvider */}
                 {this.doc.hideContextMenu ? null : (
                     <FontAwesomeIcon
                         title="context menu"
@@ -779,9 +781,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         return StrListCast(this.doc.childContextMenuLabels).map((label, i) => ({ script: customScripts[i], filter: customFilters[i], icon: icons[i], label }));
     };
 
-    onChildClick = () => {
-        return this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!);
-    };
+    onChildClick = () => this.props.onChildClick?.() ?? (this._editTitleScript?.() || ScriptField.MakeFunction(`DocFocusOrOpen(self)`)!);
 
     onChildDoubleClick = () => ScriptCast(this.props.treeView.Document.treeViewChildDoubleClick, !this.props.treeView.outlineMode ? this._openScript?.() : null);
 
@@ -906,7 +906,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                 styleProvider={this.titleStyleProvider}
                 enableDragWhenActive={true}
                 onClickScriptDisable="never" // tree docViews have a script to show fields, etc.
-                docViewPath={returnEmptyDoclist}
+                docViewPath={this.props.treeView.props.docViewPath}
                 treeViewDoc={this.props.treeView.props.Document}
                 addDocument={undefined}
                 addDocTab={this.props.addDocTab}
@@ -937,12 +937,8 @@ export class TreeView extends React.Component<TreeViewProps> {
                 docFilters={returnEmptyFilter}
                 docRangeFilters={returnEmptyFilter}
                 searchFilterDocs={returnEmptyDoclist}
-                ContainingCollectionView={this.props.treeView.props.CollectionView}
-                ContainingCollectionDoc={this.props.treeView.props.Document}
             />
         );
-
-        const buttons = this.props.styleProvider?.(this.doc, { ...this.props.treeView.props, ContainingCollectionDoc: this.props.parentTreeView?.doc }, StyleProp.Decorations + (Doc.IsSystem(this.props.containerCollection) ? ':afterHeader' : ''));
         return (
             <>
                 <div
@@ -958,8 +954,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     {view}
                 </div>
                 <div className="treeView-rightButtons" ref={action((r: any) => r && (this.headerEleWidth = r.getBoundingClientRect().width))}>
-                    {buttons} {/* hide and lock buttons */}
-                    {this.headerElements}
+                    {this.titleButtons}
                 </div>
             </>
         );
@@ -1017,8 +1012,6 @@ export class TreeView extends React.Component<TreeViewProps> {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionDoc={this.props.containerCollection}
-                    ContainingCollectionView={undefined}
                     addDocument={this.props.addDocument}
                     moveDocument={this.move}
                     removeDocument={this.props.removeDoc}
@@ -1131,7 +1124,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         childDocs: Doc[],
         treeView: CollectionTreeView,
         parentTreeView: CollectionTreeView | TreeView | undefined,
-        containerCollection: Doc,
+        treeViewParent: Doc,
         dataDoc: Doc | undefined,
         parentCollectionDoc: Doc | undefined,
         containerPrevSibling: Doc | undefined,
@@ -1162,19 +1155,19 @@ export class TreeView extends React.Component<TreeViewProps> {
         hierarchyIndex?: number[],
         renderCount?: number
     ) {
-        const viewSpecScript = Cast(containerCollection.viewSpecScript, ScriptField);
+        const viewSpecScript = Cast(treeViewParent.viewSpecScript, ScriptField);
         if (viewSpecScript) {
             childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
         }
 
-        const docs = TreeView.sortDocs(childDocs, StrCast(containerCollection.treeViewSortCriterion, TreeSort.None));
+        const docs = TreeView.sortDocs(childDocs, StrCast(treeViewParent.treeViewSortCriterion, TreeSort.None));
         const rowWidth = () => panelWidth() - treeBulletWidth() * (treeView.props.NativeDimScaling?.() || 1);
         const treeViewRefs = new Map<Doc, TreeView | undefined>();
         return docs
             .filter(child => child instanceof Doc)
             .map((child, i) => {
                 if (renderCount && i > renderCount) return null;
-                const pair = Doc.GetLayoutDataDocPair(containerCollection, dataDoc, child);
+                const pair = Doc.GetLayoutDataDocPair(treeViewParent, dataDoc, child);
                 if (!pair.layout || pair.data instanceof Promise) {
                     return null;
                 }
@@ -1192,10 +1185,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                     }
                 };
                 const indent = i === 0 ? undefined : (editTitle: boolean) => dentDoc(editTitle, docs[i - 1], undefined, treeViewRefs.get(docs[i - 1]));
-                const outdent =
-                    parentCollectionDoc?._viewType !== CollectionViewType.Tree
-                        ? undefined
-                        : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined);
+                const outdent = !parentCollectionDoc ? undefined : (editTitle: boolean) => dentDoc(editTitle, parentCollectionDoc, containerPrevSibling, parentTreeView instanceof TreeView ? parentTreeView.props.parentTreeView : undefined);
                 const addDocument = (doc: Doc | Doc[], relativeTo?: Doc, before?: boolean) => add(doc, relativeTo ?? docs[i], before !== undefined ? before : false);
                 const childLayout = Doc.Layout(pair.layout);
                 const rowHeight = () => {
@@ -1208,7 +1198,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         ref={r => treeViewRefs.set(child, r ? r : undefined)}
                         document={pair.layout}
                         dataDoc={pair.data}
-                        containerCollection={containerCollection}
+                        treeViewParent={treeViewParent}
                         prevSibling={docs[i]}
                         // TODO: [AL] add these
                         hierarchyIndex={hierarchyIndex ? [...hierarchyIndex, i + 1] : undefined}
@@ -1220,7 +1210,7 @@ export class TreeView extends React.Component<TreeViewProps> {
                         onCheckedClick={onCheckedClick}
                         onChildClick={onChildClick}
                         renderDepth={renderDepth}
-                        removeDoc={StrCast(containerCollection.freezeChildren).includes('remove') ? undefined : remove}
+                        removeDoc={StrCast(treeViewParent.freezeChildren).includes('remove') ? undefined : remove}
                         addDocument={addDocument}
                         styleProvider={styleProvider}
                         panelWidth={rowWidth}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 7ae7be3c8..a3f5e73fb 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -262,7 +262,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     };
     selectDocuments = (docs: Doc[]) => {
         SelectionManager.DeselectAll();
-        docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)).map(dv => dv && SelectionManager.SelectView(dv, true));
+        docs.map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.())).map(dv => dv && SelectionManager.SelectView(dv, true));
     };
     addDocument = (newBox: Doc | Doc[]) => {
         let retVal = false;
@@ -319,7 +319,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
         if (didMove) {
             const focusTime = options?.instant ? 0 : options.zoomTime ?? 500;
-            options.zoomScale && scale && (this.Document[this.scaleFieldKey] = scale);
+            (options.zoomScale || options.willZoomCentered) && scale && (this.Document[this.scaleFieldKey] = scale);
             this.setPan(panX, panY, focusTime, 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
             return focusTime;
         }
@@ -378,19 +378,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 1
             );
             if (sorted.length && refDoc && NumCast(sorted[0].layout.y) < NumCast(refDoc.y)) {
-                const topIndexed = NumCast(refDoc.y) < NumCast(sorted[0].layout.y) + NumCast(sorted[0].layout._height);
+                const topIndexed = NumCast(refDoc.y) < NumCast(sorted[0].layout.y) + NumCast(sorted[0].layout._height) / 2;
                 const deltay = sorted.length > 1 ? NumCast(refDoc.y) - (NumCast(sorted[0].layout.y) + (topIndexed ? 0 : NumCast(sorted[0].layout._height))) : 0;
                 const deltax = sorted.length > 1 ? NumCast(refDoc.x) - NumCast(sorted[0].layout.x) : 0;
 
                 let lastx = NumCast(refDoc.x);
                 let lasty = NumCast(refDoc.y) + (topIndexed ? 0 : NumCast(refDoc._height));
-                setTimeout(
-                    action(() =>
-                        sorted.slice(1).forEach((pair, i) => {
-                            lastx = pair.layout.x = lastx + deltax;
-                            lasty = (pair.layout.y = lasty + deltay) + (topIndexed ? 0 : NumCast(pair.layout._height));
-                        })
-                    )
+                runInAction(() =>
+                    sorted.slice(1).forEach((pair, i) => {
+                        lastx = pair.layout.x = lastx + deltax;
+                        lasty = (pair.layout.y = lasty + deltay) + (topIndexed ? 0 : NumCast(pair.layout._height));
+                    })
                 );
             }
         }
@@ -464,7 +462,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
             const ptsParent = e instanceof PointerEvent ? e : e.targetTouches.item(0);
             if (ptsParent) {
                 const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === cluster);
-                const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.CollectionView)!);
+                const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.DocumentView?.())!);
                 const { left, top } = clusterDocs[0].getBounds() || { left: 0, top: 0 };
                 const de = new DragManager.DocumentDragData(eles, e.ctrlKey || e.altKey ? 'alias' : undefined);
                 de.moveDocument = this.props.moveDocument;
@@ -872,7 +870,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         const eraserMax = { X: Math.max(lastPoint.X, currPoint.X), Y: Math.max(lastPoint.Y, currPoint.Y) };
 
         return this.childDocs
-            .map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView))
+            .map(doc => DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.()))
             .filter(inkView => inkView?.ComponentView instanceof InkingStroke)
             .map(inkView => ({ inkViewBounds: inkView!.getBounds(), inkStroke: inkView!.ComponentView as InkingStroke, inkView: inkView! }))
             .filter(
@@ -966,7 +964,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
         this.childDocs
             .filter(doc => doc.type === DocumentType.INK && !doc.dontIntersect)
             .forEach(doc => {
-                const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.CollectionView)?.ComponentView as InkingStroke;
+                const otherInk = DocumentManager.Instance.getDocumentView(doc, this.props.DocumentView?.())?.ComponentView as InkingStroke;
                 const { inkData: otherInkData } = otherInk?.inkScaledData() ?? { inkData: [] };
                 const otherScreenPts = otherInkData.map(point => otherInk.ptToScreen(point));
                 const otherCtrlPts = otherScreenPts.map(spt => (ink.ComponentView as InkingStroke).ptFromScreen(spt));
@@ -1121,7 +1119,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
     @action
     nudge = (x: number, y: number, nudgeTime: number = 500) => {
-        if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform || this.props.ContainingCollectionDoc._panX !== undefined) {
+        const collectionDoc = this.props.docViewPath().lastElement().rootDoc;
+        if (collectionDoc?._viewType !== CollectionViewType.Freeform || collectionDoc._panX !== undefined) {
             this.setPan(
                 NumCast(this.layoutDoc[this.panXFieldKey]) + ((this.props.PanelWidth() / 2) * x) / this.zoomScaling(), // nudge x,y as a function of panel dimension and scale
                 NumCast(this.layoutDoc[this.panYFieldKey]) + ((this.props.PanelHeight() / 2) * -y) / this.zoomScaling(),
@@ -1256,8 +1255,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 replica={entry.replica}
                 suppressSetHeight={this.layoutEngine ? true : false}
                 renderCutoffProvider={this.renderCutoffProvider}
-                ContainingCollectionView={this.props.CollectionView}
-                ContainingCollectionDoc={this.props.Document}
                 CollectionFreeFormView={this}
                 LayoutTemplate={childLayout.z ? undefined : this.props.childLayoutTemplate}
                 LayoutTemplateString={childLayout.z ? undefined : this.props.childLayoutString}
@@ -1779,7 +1776,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
                 const lines = text.split('\n');
                 const height = 30 + 15 * lines.length;
 
-                this.props.ContainingCollectionView?.addDocument(Docs.Create.TextDocument(text, { title: lines[0], x: NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width) + 20, y: NumCast(this.layoutDoc.y), _width: 200, _height: height }));
+                this.addDocument(Docs.Create.TextDocument(text, { title: lines[0], x: NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc._width) + 20, y: NumCast(this.layoutDoc.y), _width: 200, _height: height }));
             }
         }
     };
diff --git a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
index c7d9b6619..97eed7752 100644
--- a/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
+++ b/src/client/views/collections/collectionLinear/CollectionLinearView.tsx
@@ -209,8 +209,6 @@ export class CollectionLinearView extends CollectionSubView() {
                     docFilters={this.props.docFilters}
                     docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     hideResizeHandles={true}
                 />
             </div>
@@ -251,8 +249,7 @@ export class CollectionLinearView extends CollectionSubView() {
                                 self: this.rootDoc,
                                 _readOnly_: false,
                                 scriptContext: this.props.scriptContext,
-                                thisContainer: this.props.ContainingCollectionDoc,
-                                documentView: this.props.docViewPath().lastElement(),
+                                documentView: this.props.DocumentView?.(),
                             });
                             this.layoutDoc.linearViewIsExpanded = this.addMenuToggle.current!.checked;
                         })}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index b73b1d779..78d3d1b6e 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -262,8 +262,6 @@ export class CollectionMulticolumnView extends CollectionSubView() {
                 docFilters={this.childDocFilters}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 0cca83803..4d61dc272 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -261,8 +261,6 @@ export class CollectionMultirowView extends CollectionSubView() {
                 docFilters={this.childDocFilters}
                 docRangeFilters={this.childDocRangeFilters}
                 searchFilterDocs={this.searchFilterDocs}
-                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                ContainingCollectionView={this.props.CollectionView}
                 dontRegisterView={this.props.dontRegisterView}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
index fd9bcf681..6d5a73e55 100644
--- a/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
+++ b/src/client/views/collections/collectionSchema/CollectionSchemaView.tsx
@@ -793,7 +793,7 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 fitContentsToBox={returnTrue}
                                 dontCenter={'y'}
                                 onClickScriptDisable="always"
-                                focus={DocUtils.DefaultFocus}
+                                focus={emptyFunction}
                                 renderDepth={this.props.renderDepth + 1}
                                 rootSelected={this.rootSelected}
                                 PanelWidth={this.previewWidthFunc}
@@ -806,8 +806,6 @@ export class CollectionSchemaView extends CollectionSubView() {
                                 searchFilterDocs={this.searchFilterDocs}
                                 styleProvider={DefaultStyleProvider}
                                 docViewPath={returnEmptyDoclist}
-                                ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-                                ContainingCollectionView={this.props.CollectionView}
                                 moveDocument={this.props.moveDocument}
                                 addDocument={this.addRow}
                                 removeDocument={this.props.removeDocument}
@@ -849,8 +847,6 @@ class CollectionSchemaViewDocs extends React.Component<CollectionSchemaViewDocsP
                                 Document={doc}
                                 DataDoc={dataDoc}
                                 renderDepth={this.props.schema.props.renderDepth + 1}
-                                ContainingCollectionView={this.props.schema.props.CollectionView}
-                                ContainingCollectionDoc={this.props.schema.Document}
                                 PanelWidth={this.tableWidthFunc}
                                 PanelHeight={this.rowHeightFunc}
                                 styleProvider={DefaultStyleProvider}
diff --git a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
index 2defaae00..856537927 100644
--- a/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaRowBox.tsx
@@ -29,7 +29,7 @@ export class SchemaRowBox extends ViewBoxBaseComponent<FieldViewProps>() {
     }
 
     @computed get schemaDoc() {
-        return this.props.ContainingCollectionDoc!;
+        return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
 
     @computed get rowIndex() {
diff --git a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
index 13e45963e..5f8ffe8b0 100644
--- a/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
+++ b/src/client/views/collections/collectionSchema/SchemaTableCell.tsx
@@ -28,8 +28,6 @@ export class SchemaTableCell extends React.Component<SchemaTableCellProps> {
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
-            ContainingCollectionView: undefined,
-            ContainingCollectionDoc: undefined,
             fieldKey: this.props.fieldKey,
             rootSelected: returnFalse,
             isSelected: returnFalse,
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index 29e7cd3ad..d703c9595 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -44,25 +44,10 @@ export async function StartLinkTargetsDrag(dragEle: HTMLElement, docView: Docume
         }
 
         const dragData = new DragManager.DocumentDragData(moddrag.length ? moddrag : draggedDocs);
-        dragData.moveDocument = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (doc: Doc | Doc[]) => boolean): boolean => {
-            docView.props.removeDocument?.(doc);
-            addDocument(doc);
-            return true;
-        };
-        const containingView = docView.props.ContainingCollectionView;
-        const finishDrag = (e: DragManager.DragCompleteEvent) =>
-            e.docDragData &&
-            (e.docDragData.droppedDocuments = dragData.draggedDocuments.reduce((droppedDocs, d) => {
-                const dvs = DocumentManager.Instance.getDocumentViews(d).filter(dv => dv.props.ContainingCollectionView === containingView);
-                if (dvs.length) {
-                    dvs.forEach(dv => droppedDocs.push(dv.props.Document));
-                } else {
-                    droppedDocs.push(Doc.MakeAlias(d));
-                }
-                return droppedDocs;
-            }, [] as Doc[]));
+        dragData.canEmbed = true;
+        dragData.moveDocument = (docView.props.docViewPath().lastElement()?.ComponentView as any)?.props.CollectionView?.moveDocument; // this is equal to docView.props.moveDocument, but moveDocument is not a defined prop of a DocumentView .. but maybe it should be?
 
-        DragManager.StartDrag([dragEle], dragData, downX, downY, undefined, finishDrag);
+        DragManager.StartDocumentDrag([dragEle], dragData, downX, downY, undefined);
     }
 }
 
diff --git a/src/client/views/linking/LinkPopup.tsx b/src/client/views/linking/LinkPopup.tsx
index 7bdace2b6..5f2d4a7b6 100644
--- a/src/client/views/linking/LinkPopup.tsx
+++ b/src/client/views/linking/LinkPopup.tsx
@@ -85,15 +85,13 @@ export class LinkPopup extends React.Component<LinkPopupProps> {
                         PanelWidth={this.getPWidth}
                         PanelHeight={this.getPHeight}
                         renderDepth={0}
-                        focus={DocUtils.DefaultFocus}
+                        focus={emptyFunction}
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
                         docFilters={returnEmptyFilter}
                         docRangeFilters={returnEmptyFilter}
                         searchFilterDocs={returnEmptyDoclist}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
             </div>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 9bdb2cee7..24b9f3b25 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -160,8 +160,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     }
 
     @action public float = () => {
-        const { Document: topDoc, ContainingCollectionView: container } = this.props;
-        const screenXf = container?.screenToLocalTransform();
+        const topDoc = this.rootDoc;
+        const containerDocView = this.props.docViewPath().lastElement();
+        const screenXf = containerDocView?.screenToLocalTransform();
         if (screenXf) {
             SelectionManager.DeselectAll();
             if (topDoc.z) {
@@ -178,7 +179,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 topDoc.x = fpt[0];
                 topDoc.y = fpt[1];
             }
-            setTimeout(() => SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(topDoc, container)!, false), 0);
+            setTimeout(() => SelectionManager.SelectView(DocumentManager.Instance.getDocumentView(topDoc, containerDocView), false), 0);
         }
     };
 
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index dbcfe43cf..76a5ce7b3 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -154,7 +154,6 @@ export class DocumentContentsView extends React.Component<
             // these are the properties in  DocumentViewProps that need to be removed to pass on only DocumentSharedViewProps to the FieldViews
             'hideResizeHandles',
             'hideTitle',
-            'treeViewDoc',
             'contentPointerEvents',
             'radialMenu',
             'LayoutTemplateString',
diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx
index df3299eef..47705d53d 100644
--- a/src/client/views/nodes/DocumentLinksButton.tsx
+++ b/src/client/views/nodes/DocumentLinksButton.tsx
@@ -142,7 +142,7 @@ export class DocumentLinksButton extends React.Component<DocumentLinksButtonProp
             } else if (startLink !== endLink) {
                 endLink = endLinkView?.docView?._componentView?.getAnchor?.(true, pinProps) || endLink;
                 startLink = DocumentLinksButton.StartLinkView?.docView?._componentView?.getAnchor?.(true) || startLink;
-                const linkDoc = DocUtils.MakeLink(startLink, endLink, { linkRelationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined }, undefined, true);
+                const linkDoc = DocUtils.MakeLink(startLink, endLink, { linkRelationship: DocumentLinksButton.AnnotationId ? 'hypothes.is annotation' : undefined });
 
                 LinkManager.currentLink = linkDoc;
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f161a7b9b..be07f1fe5 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -148,8 +148,6 @@ export interface DocumentViewSharedProps {
     DataDoc?: Doc;
     contentBounds?: () => undefined | { x: number; y: number; r: number; b: number };
     fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitContentsToBox property on a Document
-    ContainingCollectionView: Opt<CollectionView>;
-    ContainingCollectionDoc: Opt<Doc>;
     suppressSetHeight?: boolean;
     thumbShown?: () => boolean;
     setContentView?: (view: DocComponentView) => any;
@@ -179,6 +177,7 @@ export interface DocumentViewSharedProps {
     ScreenToLocalTransform: () => Transform;
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
     canEmbedOnDrag?: boolean;
+    treeViewDoc?: Doc;
     xPadding?: number;
     yPadding?: number;
     dropAction?: dropActionType;
@@ -210,7 +209,6 @@ export interface DocumentViewProps extends DocumentViewSharedProps {
     hideOpenButton?: boolean;
     hideDeleteButton?: boolean;
     hideLinkAnchors?: boolean;
-    treeViewDoc?: Doc;
     isDocumentActive?: () => boolean | undefined; // whether a document should handle pointer events
     isContentActive: () => boolean | undefined; // whether document contents should handle pointer events
     contentPointerEvents?: string; // pointer events allowed for content of a document view.  eg. set to "none" in menuSidebar for sharedDocs so that you can select a document, but not interact with its contents
@@ -429,7 +427,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                             this: this.layoutDoc,
                             self: this.rootDoc,
                             scriptContext: this.props.scriptContext,
-                            thisContainer: this.props.ContainingCollectionDoc,
                             documentView: this.props.DocumentView(),
                             clientX, clientY,  altKey,  shiftKey,  ctrlKey,
                             value: undefined,
@@ -456,7 +453,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                                 self: this.rootDoc,
                                 _readOnly_: false,
                                 scriptContext: this.props.scriptContext,
-                                thisContainer: this.props.ContainingCollectionDoc,
                                 documentView: this.props.DocumentView(),
                                 clientX,
                                 clientY,
@@ -605,7 +601,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 }
                 if (de.complete.annoDragData || this.rootDoc !== linkdrag.linkSourceDoc.context) {
                     const dropDoc = de.complete.annoDragData?.dropDocument ?? this._componentView?.getAnchor?.(true) ?? this.rootDoc;
-                    de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, undefined, [de.x, de.y - 50]);
+                    de.complete.linkDocument = DocUtils.MakeLink(linkdrag.linkSourceDoc, dropDoc, {}, undefined, [de.x, de.y - 50]);
                 }
             }
         }
@@ -697,7 +693,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             !Doc.noviceMode && templateDoc && appearanceItems.push({ description: 'Open Template   ', event: () => this.props.addDocTab(templateDoc, OpenWhere.addRight), icon: 'eye' });
             !appearance && appearanceItems.length && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' });
 
-            if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Tree) {
+            if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.docViewPath().lastElement()?.rootDoc?._viewType !== CollectionViewType.Tree) {
                 const existingOnClick = cm.findByDescription('OnClick...');
                 const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
 
@@ -1446,7 +1442,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     scaleToScreenSpace = () => (1 / (this.props.NativeDimScaling?.() || 1)) * this.screenToLocalTransform().Scale;
     docViewPathFunc = () => this.docViewPath;
     isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
-    select = (extendSelection: boolean) => SelectionManager.SelectView(this, !SelectionManager.Views().some(v => v.props.Document === this.props.ContainingCollectionDoc) && extendSelection);
+    select = (extendSelection: boolean) => SelectionManager.SelectView(this, extendSelection);
     NativeWidth = () => this.effectiveNativeWidth;
     NativeHeight = () => this.effectiveNativeHeight;
     PanelWidth = () => this.panelWidth;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 8d3534a5c..86779e0dd 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -32,6 +32,7 @@ export interface FieldViewProps extends DocumentViewSharedProps {
     // See currentUserUtils headerTemplate for examples of creating text boxes from html which set some of these fields
     // Also, see InkingStroke for examples of creating text boxes from render() methods which set some of these fields
     backgroundColor?: string;
+    treeViewDoc?: Doc;
     color?: string;
     fontSize?: number;
     height?: number;
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 94434dce7..7ea6d42ff 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -61,8 +61,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             searchFilterDocs: returnEmptyDoclist,
             styleProvider: DefaultStyleProvider,
             docViewPath: returnEmptyDoclist,
-            ContainingCollectionView: undefined,
-            ContainingCollectionDoc: undefined,
             fieldKey: this.props.keyName,
             rootSelected: returnFalse,
             isSelected: returnFalse,
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index fcc5b6975..c58b5dd8c 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -271,14 +271,12 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> {
                             docFilters={returnEmptyFilter}
                             docRangeFilters={returnEmptyFilter}
                             searchFilterDocs={returnEmptyDoclist}
-                            ContainingCollectionDoc={undefined}
-                            ContainingCollectionView={undefined}
                             renderDepth={0}
                             suppressSetHeight={true}
                             PanelWidth={this.width}
                             PanelHeight={this.height}
                             pointerEvents={returnNone}
-                            focus={DocUtils.DefaultFocus}
+                            focus={emptyFunction}
                             whenChildContentsActiveChanged={returnFalse}
                             ignoreAutoHeight={true} // need to ignore autoHeight otherwise autoHeight text boxes will expand beyond the preview panel size.
                             bringToFront={returnFalse}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index db11a7776..e015024fd 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -305,8 +305,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                             addDocument={returnFalse}
                             CollectionView={undefined}
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform}
-                            renderDepth={this.props.renderDepth + 1}
-                            ContainingCollectionDoc={this.props.ContainingCollectionDoc}>
+                            renderDepth={this.props.renderDepth + 1}>
                             <>
                                 {this.threed}
                                 {this.content}
@@ -330,7 +329,7 @@ export class ScreenshotBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatabl
                                 moveDocument={returnFalse}
                                 addDocument={returnFalse}
                                 renderDepth={this.props.renderDepth + 1}
-                                ContainingCollectionDoc={this.props.ContainingCollectionDoc}></FormattedTextBox>
+                            />
                         )}
                     </div>
                 </div>
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index 8eacfbc51..1a75a7e76 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -568,12 +568,12 @@ ScriptingGlobals.add(function setBackgroundColor(color?: string, checkResult?: b
     if (selectedViews.length) {
         if (checkResult) {
             const selView = selectedViews.lastElement();
-            const layoutFrameNumber = Cast(selView.props.ContainingCollectionDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+            const layoutFrameNumber = Cast(selView.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
             const contentFrameNumber = Cast(selView.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
             return CollectionFreeFormDocumentView.getStringValues(selView?.rootDoc, contentFrameNumber).backgroundColor ?? 'transparent';
         }
         selectedViews.forEach(dv => {
-            const layoutFrameNumber = Cast(dv.props.ContainingCollectionDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
+            const layoutFrameNumber = Cast(dv.props.docViewPath().lastElement()?.rootDoc?._currentFrame, 'number'); // frame number that container is at which determines layout frame values
             const contentFrameNumber = Cast(dv.rootDoc?._currentFrame, 'number', layoutFrameNumber ?? null); // frame number that content is at which determines what content is displayed
             if (contentFrameNumber !== undefined) {
                 CollectionFreeFormDocumentView.setStringValues(contentFrameNumber, dv.rootDoc, { backgroundColor: color });
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index c00ab6a7e..b31fc01ff 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -9,10 +9,9 @@ import { DocServer } from '../../../DocServer';
 import { Docs, DocUtils } from '../../../documents/Documents';
 import { ColorScheme } from '../../../util/SettingsManager';
 import { Transform } from '../../../util/Transform';
-import { DocumentView } from '../DocumentView';
+import { DocFocusOptions, DocumentView } from '../DocumentView';
 import { FormattedTextBox } from './FormattedTextBox';
 import React = require('react');
-import { SelectionManager } from '../../../util/SelectionManager';
 
 export class DashDocView {
     dom: HTMLSpanElement; // container for label and value
@@ -151,7 +150,7 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
         const { scale, translateX, translateY } = Utils.GetScreenTransform(this._spanRef.current);
         return new Transform(-translateX, -translateY, 1).scale(1 / scale);
     };
-    outerFocus = (target: Doc) => this._textBox.props.focus(this._textBox.props.Document, {}); // ideally, this would scroll to show the focus target
+    outerFocus = (target: Doc, options: DocFocusOptions) => this._textBox.focus(target, options); // ideally, this would scroll to show the focus target
 
     onKeyDown = (e: any) => {
         e.stopPropagation();
@@ -212,8 +211,6 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> {
                     docFilters={this.props.tbox?.props.docFilters}
                     docRangeFilters={this.props.tbox?.props.docRangeFilters}
                     searchFilterDocs={this.props.tbox?.props.searchFilterDocs}
-                    ContainingCollectionView={this._textBox.props.ContainingCollectionView}
-                    ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
                 />
             </div>
         );
diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx
index f23426bb3..c43206629 100644
--- a/src/client/views/nodes/formattedText/DashFieldView.tsx
+++ b/src/client/views/nodes/formattedText/DashFieldView.tsx
@@ -235,10 +235,7 @@ export class DashFieldViewInternal extends React.Component<IDashFieldViewInterna
     };
 
     createPivotForField = (e: React.MouseEvent) => {
-        let container = this.props.tbox.props.ContainingCollectionView;
-        while (container?.props.Document.isTemplateForField || container?.props.Document.isTemplateDoc) {
-            container = container.props.ContainingCollectionView;
-        }
+        let container = this.props.tbox.props.DocumentView?.().props.docViewPath().lastElement();
         if (container) {
             const alias = Doc.MakeAlias(container.props.Document);
             alias._viewType = CollectionViewType.Time;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 677c4662b..bc2a5d797 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -541,7 +541,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 // embed document when dragg marked as embed
             } else if (de.embedKey) {
                 const target = dragData.droppedDocuments[0];
-                target._fitContentsToBox = true;
                 const node = schema.nodes.dashDoc.create({
                     width: target[WidthSym](),
                     height: target[HeightSym](),
@@ -552,6 +551,8 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 if (!['alias', 'copy'].includes((dragData.dropAction ?? '') as any)) {
                     dragData.removeDocument?.(dragData.draggedDocuments[0]);
                 }
+                target._fitContentsToBox = true;
+                target.context = this.rootDoc;
                 const view = this._editorView!;
                 view.dispatch(view.state.tr.insert(view.posAtCoords({ left: de.x, top: de.y })!.pos, node));
                 e.stopPropagation();
@@ -880,7 +881,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
         if (this._editorView && this._recordingStart) {
             if (this._break) {
                 const textanchorFunc = () => {
-                    const tanch = Docs.Create.TextanchorDocument({ title: 'dictation anchor' });
+                    const tanch = Docs.Create.TextanchorDocument({ title: 'dictation anchor', unrendered: true });
                     return this.addDocument(tanch) ? tanch : undefined;
                 };
                 const link = DocUtils.MakeLinkToActiveAudio(textanchorFunc, false).lastElement();
@@ -956,7 +957,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             let hadStart = start !== 0;
             frag.forEach((node, index) => {
                 const examinedNode = findAnchorNode(node, editor);
-                if (examinedNode?.node && (examinedNode.node.textContent || examinedNode.node.type === this._editorView?.state.schema.nodes.audiotag)) {
+                if (examinedNode?.node && (examinedNode.node.textContent || examinedNode.node.type === this._editorView?.state.schema.nodes.dashDoc || examinedNode.node.type === this._editorView?.state.schema.nodes.audiotag)) {
                     nodes.push(examinedNode.node);
                     !hadStart && (start = index + examinedNode.start);
                     hadStart = true;
@@ -971,9 +972,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 }
                 return undefined;
             }
+            if (node.type === this._editorView?.state.schema.nodes.dashDoc) {
+                if (node.attrs.docId === textAnchorId) {
+                    return { node, start: 0 };
+                }
+                return undefined;
+            }
             if (!node.isText) {
                 const content = findAnchorFrag(node.content, editor);
-                return { node: node.copy(content.frag), start: content.start };
+                if (content.frag.childCount) return { node: content.frag.childCount ? content.frag.child(0) : node, start: content.start };
             }
             const marks = [...node.marks];
             const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.linkAnchor);
@@ -987,7 +994,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
             const ret = findAnchorFrag(editor.state.doc.content, editor);
 
             const content = (ret.frag as any)?.content;
-            if ((ret.frag.size > 2 || (content?.length && content[0].type === this._editorView.state.schema.nodes.audiotag)) && ret.start >= 0) {
+            if ((ret.frag.size || (content?.length && content[0].type === this._editorView.state.schema.nodes.dashDoc) || (content?.length && content[0].type === this._editorView.state.schema.nodes.audiotag)) && ret.start >= 0) {
                 !options.instant && (this._focusSpeed = focusSpeed);
                 let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start
                 if (ret.frag.firstChild) {
@@ -998,6 +1005,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
                 addStyleSheetRule(FormattedTextBox._highlightStyleSheet, `${escAnchorId}`, { background: 'yellow', transform: 'scale(3)', 'transform-origin': 'left bottom' });
                 setTimeout(() => (this._focusSpeed = undefined), this._focusSpeed);
                 setTimeout(() => clearStyleSheetRules(FormattedTextBox._highlightStyleSheet), Math.max(this._focusSpeed || 0, 3000));
+                return focusSpeed;
+            } else {
+                return this.props.focus(this.rootDoc, options);
             }
         }
     };
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 3589a9065..807a19771 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -2457,7 +2457,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         {mode !== CollectionViewType.Invalid ? (
                             <CollectionView
                                 {...this.props}
-                                ContainingCollectionDoc={this.props.Document}
                                 PanelWidth={this.props.PanelWidth}
                                 PanelHeight={this.panelHeight}
                                 childIgnoreNativeSize={true}
diff --git a/src/client/views/nodes/trails/PresElementBox.tsx b/src/client/views/nodes/trails/PresElementBox.tsx
index 92696240b..502eef373 100644
--- a/src/client/views/nodes/trails/PresElementBox.tsx
+++ b/src/client/views/nodes/trails/PresElementBox.tsx
@@ -39,7 +39,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     // Idea: this boolean will determine whether to automatically show the video when this preselement is selected.
     // @observable static showVideo: boolean = false;
     @computed get indexInPres() {
-        return DocListCast(this.presBox[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc);
+        return DocListCast(this.presBox?.[StrCast(this.presBox.presFieldKey, 'data')]).indexOf(this.rootDoc);
     } // the index field is where this document is in the presBox display list (since this value is different for each presentation element, the value can't be stored on the layout template which is used by all display elements)
     @computed get expandViewHeight() {
         return 100;
@@ -51,11 +51,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         return this.presBoxView?.selectedArray;
     }
     @computed get presBoxView() {
-        const vpath = this.props.docViewPath();
-        return vpath.length > 1 ? (vpath[vpath.length - 2].ComponentView as PresBox) : undefined;
+        return this.props.DocumentView?.()?.props.docViewPath().lastElement()?.ComponentView as PresBox;
     }
     @computed get presBox() {
-        return this.props.ContainingCollectionDoc!;
+        return this.props.DocumentView?.().props.docViewPath().lastElement()?.rootDoc;
     }
     @computed get targetDoc() {
         return Cast(this.rootDoc.presentationTargetDoc, Doc, null) || this.rootDoc;
@@ -110,14 +109,12 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
                     docFilters={this.props.docFilters}
                     docRangeFilters={this.props.docRangeFilters}
                     searchFilterDocs={this.props.searchFilterDocs}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                     rootSelected={returnTrue}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
                     fitContentsToBox={returnTrue}
                     moveDocument={this.props.moveDocument!}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     whenChildContentsActiveChanged={returnFalse}
                     addDocTab={returnFalse}
                     pinToPres={returnFalse}
@@ -195,7 +192,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
         const dragData = new DragManager.DocumentDragData(this.presBoxView?.sortArray() ?? []);
         if (!dragData.draggedDocuments.length) dragData.draggedDocuments.push(this.rootDoc);
         dragData.dropAction = 'move';
-        dragData.treeViewDoc = this.presBox._viewType === CollectionViewType.Tree ? this.props.ContainingCollectionDoc : undefined; // this.props.DocumentView?.()?.props.treeViewDoc;
+        dragData.treeViewDoc = this.presBox?._viewType === CollectionViewType.Tree ? this.presBox : undefined; // this.props.DocumentView?.()?.props.treeViewDoc;
         dragData.moveDocument = this.props.moveDocument;
         const dragItem: HTMLElement[] = [];
         if (dragArray.length === 1) {
@@ -269,7 +266,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @undoBatch
     removeItem = action((e: React.MouseEvent) => {
         e.stopPropagation();
-        if (this.indexInPres < (this.presBoxView?.itemIndex || 0)) {
+        if (this.presBox && this.indexInPres < (this.presBoxView?.itemIndex || 0)) {
             this.presBox.itemIndex = (this.presBoxView?.itemIndex || 0) - 1;
         }
         this.props.removeDocument?.(this.rootDoc);
@@ -406,15 +403,15 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @computed
     get toolbarWidth(): number {
         const presBoxDocView = DocumentManager.Instance.getDocumentView(this.presBox);
-        let width: number = NumCast(this.presBox._width);
+        let width: number = NumCast(this.presBox?._width);
         if (presBoxDocView) width = presBoxDocView.props.PanelWidth();
         if (width === 0) width = 300;
         return width;
     }
 
     @computed get presButtons() {
-        const presBox: Doc = this.presBox; //presBox
-        const presBoxColor: string = StrCast(presBox._backgroundColor);
+        const presBox = this.presBox; //presBox
+        const presBoxColor: string = StrCast(presBox?._backgroundColor);
         const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false;
         const targetDoc: Doc = this.targetDoc;
         const activeItem: Doc = this.rootDoc;
@@ -494,10 +491,10 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
     @computed get mainItem() {
         const isSelected: boolean = this.selectedArray?.has(this.rootDoc) ? true : false;
-        const isCurrent: boolean = this.presBox._itemIndex === this.indexInPres;
+        const isCurrent: boolean = this.presBox?._itemIndex === this.indexInPres;
         const miniView: boolean = this.toolbarWidth <= 110;
-        const presBox: Doc = this.presBox; //presBox
-        const presBoxColor: string = StrCast(presBox._backgroundColor);
+        const presBox = this.presBox; //presBox
+        const presBoxColor: string = StrCast(presBox?._backgroundColor);
         const presColorBool: boolean = presBoxColor ? presBoxColor !== Colors.WHITE && presBoxColor !== 'transparent' : false;
         const activeItem: Doc = this.rootDoc;
 
diff --git a/src/client/views/topbar/TopBar.tsx b/src/client/views/topbar/TopBar.tsx
index f2e9be61d..d63c25dbe 100644
--- a/src/client/views/topbar/TopBar.tsx
+++ b/src/client/views/topbar/TopBar.tsx
@@ -46,7 +46,7 @@ export class TopBar extends React.Component {
         return (
             <div className="topbar-left">
                 {Doc.ActiveDashboard ? (
-                    <IconButton onClick={this.navigateToHome} icon={<FontAwesomeIcon icon="home" />} isCircle={true} hoverStyle="gray" color={this.textColor} />
+                    <IconButton onClick={this.navigateToHome} icon={<FontAwesomeIcon icon="home" />} color={this.textColor} />
                 ) : (
                     <div className="logo-container">
                         <img className="logo" src="/assets/medium-blue-light-blue-circle.png" alt="dash logo"></img>
@@ -55,18 +55,7 @@ export class TopBar extends React.Component {
                     </div>
                 )}
                 {Doc.ActiveDashboard && (
-                    <Button
-                        text="Explore"
-                        tooltip="Browsing mode for directly navigating to documents"
-                        fontSize={FontSize.SECONDARY}
-                        isActive={MainView.Instance._exploreMode}
-                        size={Size.SMALL}
-                        color={this.textColor}
-                        borderRadius={5}
-                        hoverStyle="gray"
-                        iconPosition="right"
-                        onClick={action(() => (MainView.Instance._exploreMode = !MainView.Instance._exploreMode))}
-                    />
+                    <Button text="Explore" tooltip="Browsing mode for directly navigating to documents" size={Size.SMALL} color={this.textColor} onClick={action(() => (MainView.Instance._exploreMode = !MainView.Instance._exploreMode))} />
                 )}
             </div>
         );
@@ -94,13 +83,8 @@ export class TopBar extends React.Component {
                 <Button
                     text={StrCast(Doc.ActiveDashboard.title)}
                     tooltip="Browsing mode for directly navigating to documents"
-                    fontSize={FontSize.SECONDARY}
                     size={Size.SMALL}
                     color={'white'}
-                    type="outline"
-                    backgroundColor={Colors.MEDIUM_BLUE}
-                    borderRadius={5}
-                    hoverStyle="none"
                     onClick={(e: React.MouseEvent) => {
                         const dashView = Doc.ActiveDashboard && DocumentManager.Instance.getDocumentView(Doc.ActiveDashboard);
                         ContextMenu.Instance.addItem({ description: 'Open Dashboard View', event: this.navigateToHome, icon: 'edit' });
@@ -121,21 +105,13 @@ export class TopBar extends React.Component {
                     onClick={() => {
                         SharingManager.Instance.open(undefined, Doc.ActiveDashboard);
                     }}
-                    type="outline"
-                    fontSize={FontSize.SECONDARY}
                     size={Size.SMALL}
-                    borderRadius={5}
-                    hoverStyle="gray"
                 />
                 {!Doc.noviceMode && (
                     <IconButton
-                        fontSize={FontSize.SECONDARY}
-                        isCircle={true}
                         tooltip="Work on a copy of the dashboard layout"
                         size={Size.SMALL}
                         color={this.textColor}
-                        borderRadius={Borders.STANDARD}
-                        hoverStyle="gray"
                         onClick={async () => {
                             const batch = UndoManager.StartBatch('snapshot');
                             await DashboardView.snapshotDashboard();
@@ -156,26 +132,9 @@ export class TopBar extends React.Component {
     @computed get topbarRight() {
         return (
             <div className="topbar-right">
-                <IconButton size={Size.SMALL} isCircle={true} color={Colors.LIGHT_GRAY} backgroundColor={Colors.DARK_GRAY} hoverStyle="gray" onClick={() => ReportManager.Instance.open()} icon={<FaBug />} />
-                <IconButton
-                    size={Size.SMALL}
-                    isCircle={true}
-                    color={Colors.LIGHT_GRAY}
-                    backgroundColor={Colors.DARK_GRAY}
-                    hoverStyle="gray"
-                    onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')}
-                    icon={<FontAwesomeIcon icon="question-circle" />}
-                />
-                <IconButton
-                    size={Size.SMALL}
-                    isCircle={true}
-                    color={Colors.LIGHT_GRAY}
-                    backgroundColor={Colors.DARK_GRAY}
-                    hoverStyle="gray"
-                    isActive={SettingsManager.Instance.isOpen}
-                    onClick={() => SettingsManager.Instance.open()}
-                    icon={<FontAwesomeIcon icon="cog" />}
-                />
+                <IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => ReportManager.Instance.open()} icon={<FaBug />} />
+                <IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => window.open('https://brown-dash.github.io/Dash-Documentation/', '_blank')} icon={<FontAwesomeIcon icon="question-circle" />} />
+                <IconButton size={Size.SMALL} color={Colors.LIGHT_GRAY} onClick={() => SettingsManager.Instance.open()} icon={<FontAwesomeIcon icon="cog" />} />
                 {/* <Button text={'Logout'} borderRadius={5} hoverStyle={'gray'} backgroundColor={Colors.DARK_GRAY} color={this.textColor} fontSize={FontSize.SECONDARY} onClick={() => window.location.assign(Utils.prepend('/logout'))} /> */}
             </div>
         );
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 64baa351c..a0b437354 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -13,13 +13,18 @@ import { listSpec } from '../fields/Schema';
 import { Cast, FieldValue } from '../fields/Types';
 import { nullAudio } from '../fields/URLField';
 import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, emptyPath } from '../Utils';
-import "./ImageUpload.scss";
+import './ImageUpload.scss';
 import { MobileInterface } from './MobileInterface';
 import React = require('react');
 
 @observer
 export class AudioUpload extends React.Component {
-    @observable public _audioCol: Doc = FieldValue(Cast(Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: "mobile audio", _width: 500, _height: 100 }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: "0 0" }), Doc)) as Doc;
+    @observable public _audioCol: Doc = FieldValue(
+        Cast(
+            Docs.Create.FreeformDocument([Cast(Docs.Create.AudioDocument(nullAudio, { title: 'mobile audio', _width: 500, _height: 100 }), Doc) as Doc], { title: 'mobile audio', _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: '0 0' }),
+            Doc
+        )
+    ) as Doc;
 
     /**
      * Handles the onclick functionality for the 'Restart' button
@@ -28,25 +33,36 @@ export class AudioUpload extends React.Component {
     @action
     clearUpload = () => {
         for (let i = 1; i < 8; i++) {
-            this.setOpacity(i, "0.2");
+            this.setOpacity(i, '0.2');
         }
-        this._audioCol = FieldValue(Cast(
-            Docs.Create.FreeformDocument(
-                [Cast(Docs.Create.AudioDocument(nullAudio, {
-                    title: "mobile audio",
-                    _width: 500,
-                    _height: 100
-                }), Doc) as Doc], { title: "mobile audio", _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: "0 0" }), Doc)) as Doc;
-    }
+        this._audioCol = FieldValue(
+            Cast(
+                Docs.Create.FreeformDocument(
+                    [
+                        Cast(
+                            Docs.Create.AudioDocument(nullAudio, {
+                                title: 'mobile audio',
+                                _width: 500,
+                                _height: 100,
+                            }),
+                            Doc
+                        ) as Doc,
+                    ],
+                    { title: 'mobile audio', _width: 300, _height: 300, _fitContentsToBox: true, boxShadow: '0 0' }
+                ),
+                Doc
+            )
+        ) as Doc;
+    };
 
-    /** 
+    /**
      * Handles the onClick of the 'Close' button
      * Reset upload interface and toggle audio
      */
     closeUpload = () => {
         this.clearUpload();
         MobileInterface.Instance.toggleAudio();
-    }
+    };
 
     /**
      * Handles the on click of the 'Upload' button.
@@ -57,14 +73,14 @@ export class AudioUpload extends React.Component {
         const audioDoc = this._audioCol;
         const data = Cast(audioRightSidebar.data, listSpec(Doc));
         for (let i = 1; i < 8; i++) {
-            setTimeout(() => this.setOpacity(i, "1"), i * 200);
+            setTimeout(() => this.setOpacity(i, '1'), i * 200);
         }
         if (data) {
             data.push(audioDoc);
         }
         // Resets uploader after 3 seconds
         setTimeout(this.clearUpload, 3000);
-    }
+    };
 
     // Returns the upload audio menu
     private get uploadInterface() {
@@ -72,11 +88,13 @@ export class AudioUpload extends React.Component {
             <>
                 <ContextMenu />
                 <DictationOverlay />
-                <div style={{ display: "none" }}><RichTextMenu key="rich" /></div>
+                <div style={{ display: 'none' }}>
+                    <RichTextMenu key="rich" />
+                </div>
                 <div className="closeUpload" onClick={() => this.closeUpload()}>
-                    <FontAwesomeIcon icon="window-close" size={"lg"} />
+                    <FontAwesomeIcon icon="window-close" size={'lg'} />
                 </div>
-                <FontAwesomeIcon icon="microphone" size="lg" style={{ fontSize: "130" }} />
+                <FontAwesomeIcon icon="microphone" size="lg" style={{ fontSize: '130' }} />
                 <div className="audioUpload_cont">
                     <DocumentView
                         Document={this._audioCol}
@@ -96,12 +114,10 @@ export class AudioUpload extends React.Component {
                         isDocumentActive={returnTrue}
                         isContentActive={emptyFunction}
                         focus={emptyFunction}
-                        styleProvider={() => "rgba(0,0,0,0)"}
+                        styleProvider={() => 'rgba(0,0,0,0)'}
                         docViewPath={returnEmptyDoclist}
                         whenChildContentsActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
-                        ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
                     />
                 </div>
                 <div className="restart_label" onClick={this.clearUpload}>
@@ -125,28 +141,16 @@ export class AudioUpload extends React.Component {
 
     // Handles the setting of the loading bar
     setOpacity = (index: number, opacity: string) => {
-        const slab = document.getElementById("slab0" + index);
+        const slab = document.getElementById('slab0' + index);
         if (slab) {
             slab.style.opacity = opacity;
         }
-    }
+    };
 
     @observable private dialogueBoxOpacity = 1;
     @observable private overlayOpacity = 0.4;
 
     render() {
-        return (
-            <MainViewModal
-                contents={this.uploadInterface}
-                isDisplayed={true}
-                interactive={true}
-                dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity}
-                overlayDisplayedOpacity={this.overlayOpacity}
-                closeOnExternalClick={this.closeUpload}
-            />
-        );
+        return <MainViewModal contents={this.uploadInterface} isDisplayed={true} interactive={true} dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} overlayDisplayedOpacity={this.overlayOpacity} closeOnExternalClick={this.closeUpload} />;
     }
-
 }
-
-
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 2ae597b0b..a543c2f70 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -397,7 +397,7 @@ export class MobileInterface extends React.Component {
                     renderDepth={0}
                     isDocumentActive={returnTrue}
                     isContentActive={emptyFunction}
-                    focus={DocUtils.DefaultFocus}
+                    focus={emptyFunction}
                     styleProvider={this.whitebackground}
                     docViewPath={returnEmptyDoclist}
                     whenChildContentsActiveChanged={emptyFunction}
@@ -405,8 +405,6 @@ export class MobileInterface extends React.Component {
                     docFilters={returnEmptyFilter}
                     docRangeFilters={returnEmptyFilter}
                     searchFilterDocs={returnEmptyDoclist}
-                    ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
                 />
             </div>
         );
-- 
cgit v1.2.3-70-g09d2

