From 5aecc6d75868dcafd0b1bb560ad5a4ad8ab976fa Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 14 Feb 2020 14:25:53 -0500
Subject: cleaned up backgroundColor settings and cluster overrides.  added a
 darkScheme

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

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

diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index caffa7eb1..a3b1b5ec0 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -37,7 +37,8 @@ export interface CellProps {
     renderDepth: number;
     addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
     pinToPres: (document: Doc) => void;
-    moveDocument: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
+    moveDocument: (document: Doc, targetCollection: Doc | undefined, 
+    addDocument: (document: Doc) => boolean) => boolean;
     isFocused: boolean;
     changeFocusedCellByIndex: (row: number, col: number) => void;
     setIsEditing: (isEditing: boolean) => void;
-- 
cgit v1.2.3-70-g09d2


From d53ae2d90e7d7de8135ff19e18535cccd7a90ed0 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 19 Feb 2020 00:45:23 -0500
Subject: getting rid of data docs from many places

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/DictationManager.ts                |  4 +-
 src/client/util/DocumentManager.ts                 |  6 +--
 src/client/util/RichTextSchema.tsx                 |  2 +-
 src/client/views/DocComponent.tsx                  |  4 +-
 src/client/views/DocumentButtonBar.tsx             |  8 +--
 src/client/views/GlobalKeyHandler.ts               |  2 +-
 src/client/views/MainView.tsx                      |  6 +--
 src/client/views/MainViewNotifs.tsx                |  2 +-
 .../views/collections/CollectionDockingView.tsx    | 60 +++++++++-------------
 .../views/collections/CollectionSchemaCells.tsx    |  2 +-
 .../views/collections/CollectionSchemaView.tsx     |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  6 +--
 .../views/collections/CollectionTreeView.tsx       | 12 ++---
 src/client/views/collections/CollectionView.tsx    |  4 +-
 .../views/collections/ParentDocumentSelector.tsx   |  4 +-
 src/client/views/linking/LinkFollowBox.tsx         | 16 +++---
 src/client/views/linking/LinkMenu.tsx              |  2 +-
 src/client/views/linking/LinkMenuGroup.tsx         |  2 +-
 src/client/views/linking/LinkMenuItem.tsx          |  2 +-
 .../views/nodes/ContentFittingDocumentView.tsx     |  2 +-
 src/client/views/nodes/DocuLinkBox.tsx             |  2 +-
 src/client/views/nodes/DocumentContentsView.tsx    |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 22 ++++----
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/nodes/FontIconBox.tsx             |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  2 +-
 src/client/views/nodes/FormattedTextBoxComment.tsx |  4 +-
 src/client/views/nodes/KeyValuePair.tsx            |  4 +-
 src/client/views/nodes/PresBox.tsx                 |  4 +-
 src/client/views/nodes/VideoBox.tsx                |  2 +-
 src/client/views/pdf/Annotation.tsx                |  6 +--
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 .../views/presentationview/PresElementBox.tsx      |  3 +-
 src/client/views/search/SearchItem.tsx             |  6 +--
 src/new_fields/Doc.ts                              |  4 +-
 36 files changed, 105 insertions(+), 112 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 669aa97b5..650538e93 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -654,7 +654,7 @@ export namespace Docs {
                     {
                         type: type,
                         content: [
-                            ...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, undefined, config.initialWidth, config.path))
+                            ...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, config.initialWidth, config.path))
                         ]
                     }
                 ]
diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts
index 3394cb93d..569c1ef6d 100644
--- a/src/client/util/DictationManager.ts
+++ b/src/client/util/DictationManager.ts
@@ -326,7 +326,7 @@ export namespace DictationManager {
             ["open fields", {
                 action: (target: DocumentView) => {
                     const kvp = Docs.Create.KVPDocument(target.props.Document, { _width: 300, _height: 300 });
-                    target.props.addDocTab(kvp, target.props.DataDoc, "onRight");
+                    target.props.addDocTab(kvp, "onRight");
                 }
             }],
 
@@ -340,7 +340,7 @@ export namespace DictationManager {
                     const proseMirrorState = `{"doc":{"type":"doc","content":[{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"type":"text","text":"${prompt}"}]}]}]}]},"selection":{"type":"text","anchor":${anchor},"head":${head}}}`;
                     proto.data = new RichTextField(proseMirrorState);
                     proto.backgroundColor = "#eeffff";
-                    target.props.addDocTab(newBox, proto, "onRight");
+                    target.props.addDocTab(newBox, "onRight");
                 }
             }]
 
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index bfda8e75b..c639f07f5 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -148,7 +148,7 @@ export class DocumentManager {
             const targetDocContext = (annotatedDoc ? annotatedDoc : contextDoc);
 
             if (!targetDocContext) { // we don't have a view and there's no context specified ... create a new view of the target using the dockFunc or default
-                (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc)), undefined);
+                (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc)));
                 highlight();
             } else {
                 const targetDocContextView = DocumentManager.Instance.getFirstDocumentView(targetDocContext);
@@ -164,12 +164,12 @@ export class DocumentManager {
                             retryDocView.props.focus(targetDoc, willZoom); // focus on the target if it now exists in the context
                         } else {
                             if (closeContextIfNotFound && targetDocContextView.props.removeDocument) targetDocContextView.props.removeDocument(targetDocContextView.props.Document);
-                            targetDoc.layout && (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc)), undefined); // otherwise create a new view of the target
+                            targetDoc.layout && (dockFunc || CollectionDockingView.AddRightSplit)(Doc.BrushDoc(Doc.MakeAlias(targetDoc))); // otherwise create a new view of the target
                         }
                         highlight();
                     }, 0);
                 } else {  // there's no context view so we need to create one first and try again
-                    (dockFunc || CollectionDockingView.AddRightSplit)(targetDocContext, undefined);
+                    (dockFunc || CollectionDockingView.AddRightSplit)(targetDocContext);
                     setTimeout(() => {
                         const finalDocView = DocumentManager.Instance.getFirstDocumentView(targetDoc);
                         const finalDocContextView = DocumentManager.Instance.getFirstDocumentView(targetDocContext);
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 23b0a56a8..cfbae5dca 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -613,7 +613,7 @@ export class ImageResizeView {
                 DocServer.GetRefField(node.attrs.docid).then(async linkDoc =>
                     (linkDoc instanceof Doc) &&
                     DocumentManager.Instance.FollowLink(linkDoc, view.state.schema.Document,
-                        document => addDocTab(document, undefined, node.attrs.location ? node.attrs.location : "inTab"), false));
+                        document => addDocTab(document, node.attrs.location ? node.attrs.location : "inTab"), false));
             }
         };
         this._handle.onpointerdown = function (e: any) {
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 0bf944f22..61b1f9e0f 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -1,4 +1,4 @@
-import { Doc, Opt } from '../../new_fields/Doc';
+import { Doc, Opt, DataSym } from '../../new_fields/Doc';
 import { Touchable } from './Touchable';
 import { computed, action, observable } from 'mobx';
 import { Cast } from '../../new_fields/Types';
@@ -58,7 +58,7 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema
         //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then
         @computed get Document(): T { return schemaCtor(this.props.Document); }
         @computed get layoutDoc() { return Doc.Layout(this.props.Document); }
-        @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; }
+        @computed get dataDoc() { return this.props.Document[DataSym]; }
 
         _annotationKey: string = "annotations";
         public set annotationKey(val: string) { this._annotationKey = val; }
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index b530d8a42..c8ad78f47 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -251,10 +251,10 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
 
     @computed
     get contextButton() {
-        return !this.view0 ? (null) : <ParentDocSelector Views={this.props.views.filter(v => v).map(v => v as DocumentView)} Document={this.view0.props.Document} addDocTab={(doc, data, where) => {
-            where === "onRight" ? CollectionDockingView.AddRightSplit(doc, data) :
-                this.props.stack ? CollectionDockingView.Instance.AddTab(this.props.stack, doc, data) :
-                    this.view0?.props.addDocTab(doc, data, "onRight");
+        return !this.view0 ? (null) : <ParentDocSelector Views={this.props.views.filter(v => v).map(v => v as DocumentView)} Document={this.view0.props.Document} addDocTab={(doc, where) => {
+            where === "onRight" ? CollectionDockingView.AddRightSplit(doc) :
+                this.props.stack ? CollectionDockingView.Instance.AddTab(this.props.stack, doc) :
+                    this.view0?.props.addDocTab(doc, "onRight");
             return true;
         }} />;
     }
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 979687ffb..d0900251d 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -156,7 +156,7 @@ export default class KeyManager {
                         return { stopPropagation: false, preventDefault: false };
                     }
                 }
-                MainView.Instance.mainFreeform && CollectionDockingView.AddRightSplit(MainView.Instance.mainFreeform, undefined);
+                MainView.Instance.mainFreeform && CollectionDockingView.AddRightSplit(MainView.Instance.mainFreeform);
                 break;
             case "arrowleft":
                 if (document.activeElement) {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 7948da3c5..1849ec250 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -185,7 +185,7 @@ export class MainView extends React.Component {
                 reaction(() => CollectionDockingView.Instance && CollectionDockingView.Instance.initialized,
                     initialized => initialized && received && DocServer.GetRefField(received).then(docField => {
                         if (docField instanceof Doc && docField._viewType !== CollectionViewType.Docking) {
-                            CollectionDockingView.AddRightSplit(docField, undefined);
+                            CollectionDockingView.AddRightSplit(docField);
                         }
                     }),
                 );
@@ -379,10 +379,10 @@ export class MainView extends React.Component {
         document.removeEventListener("pointerup", this.onPointerUp);
     }
     flyoutWidthFunc = () => this.flyoutWidth;
-    addDocTabFunc = (doc: Doc, data: Opt<Doc>, where: string, libraryPath?: Doc[]): boolean => {
+    addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => {
         return where === "close" ? CollectionDockingView.CloseRightSplit(doc) :
             doc.dockingConfig ? this.openWorkspace(doc) :
-                CollectionDockingView.AddRightSplit(doc, undefined, libraryPath);
+                CollectionDockingView.AddRightSplit(doc, libraryPath);
     }
     mainContainerXf = () => new Transform(0, -this._buttonBarHeight, 1);
 
diff --git a/src/client/views/MainViewNotifs.tsx b/src/client/views/MainViewNotifs.tsx
index 09fa1cb0c..82e07c449 100644
--- a/src/client/views/MainViewNotifs.tsx
+++ b/src/client/views/MainViewNotifs.tsx
@@ -15,7 +15,7 @@ export class MainViewNotifs extends React.Component {
     @observable static NotifsCol: Opt<Doc>;
     openNotifsCol = () => {
         if (MainViewNotifs.NotifsCol) {
-            CollectionDockingView.AddRightSplit(MainViewNotifs.NotifsCol, undefined);
+            CollectionDockingView.AddRightSplit(MainViewNotifs.NotifsCol);
         }
     }
     render() {
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 26b65c898..6e1d522fc 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -8,7 +8,7 @@ import * as ReactDOM from 'react-dom';
 import Measure from "react-measure";
 import * as GoldenLayout from "../../../client/goldenLayout";
 import { DateField } from '../../../new_fields/DateField';
-import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Field, Opt, DataSym } from "../../../new_fields/Doc";
 import { Id } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
 import { FieldId } from "../../../new_fields/RefField";
@@ -38,7 +38,7 @@ const _global = (window /* browser */ || global /* node */) as any;
 export class CollectionDockingView extends React.Component<SubCollectionViewProps> {
     @observable public static Instances: CollectionDockingView[] = [];
     @computed public static get Instance() { return CollectionDockingView.Instances[0]; }
-    public static makeDocumentConfig(document: Doc, dataDoc: Doc | undefined, width?: number, libraryPath?: Doc[]) {
+    public static makeDocumentConfig(document: Doc, width?: number, libraryPath?: Doc[]) {
         return {
             type: 'react-component',
             component: 'DocumentFrameRenderer',
@@ -46,8 +46,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
             width: width,
             props: {
                 documentId: document[Id],
-                dataDocumentId: dataDoc && dataDoc[Id] !== document[Id] ? dataDoc[Id] : "",
-                libraryPath: libraryPath ? libraryPath.map(d => d[Id]) : []
+                libraryPath: libraryPath?.map(d => d[Id])
                 //collectionDockingView: CollectionDockingView.Instance
             }
         };
@@ -76,12 +75,12 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     public StartOtherDrag(e: any, dragDocs: Doc[]) {
         let config: any;
         if (dragDocs.length === 1) {
-            config = CollectionDockingView.makeDocumentConfig(dragDocs[0], undefined);
+            config = CollectionDockingView.makeDocumentConfig(dragDocs[0]);
         } else {
             config = {
                 type: 'row',
                 content: dragDocs.map((doc, i) => {
-                    CollectionDockingView.makeDocumentConfig(doc, undefined);
+                    CollectionDockingView.makeDocumentConfig(doc);
                 })
             };
         }
@@ -97,10 +96,9 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     @action
     public OpenFullScreen(docView: DocumentView, libraryPath?: Doc[]) {
         const document = Doc.MakeAlias(docView.props.Document);
-        const dataDoc = docView.props.DataDoc;
         const newItemStackConfig = {
             type: 'stack',
-            content: [CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath)]
+            content: [CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath)]
         };
         const docconfig = this._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, this._goldenLayout);
         this._goldenLayout.root.contentItems[0].addChild(docconfig);
@@ -172,7 +170,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     }
     @undoBatch
     @action
-    public static ReplaceRightSplit(document: Doc, dataDoc: Doc | undefined, libraryPath?: Doc[], addToSplit?: boolean): boolean {
+    public static ReplaceRightSplit(document: Doc, libraryPath?: Doc[], addToSplit?: boolean): boolean {
         if (!CollectionDockingView.Instance) return false;
         const instance = CollectionDockingView.Instance;
         let retVal = false;
@@ -180,7 +178,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
             retVal = Array.from(instance._goldenLayout.root.contentItems[0].contentItems).some((child: any) => {
                 if (child.contentItems.length === 1 && child.contentItems[0].config.component === "DocumentFrameRenderer" &&
                     DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)?.Document.isDisplayPanel) {
-                    const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath);
+                    const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath);
                     child.addChild(newItemStackConfig, undefined);
                     !addToSplit && child.contentItems[0].remove();
                     instance.layoutChanged(document);
@@ -188,7 +186,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                 }
                 return Array.from(child.contentItems).filter((tab: any) => tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => {
                     if (DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)?.Document.isDisplayPanel) {
-                        const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath);
+                        const newItemStackConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath);
                         child.addChild(newItemStackConfig, undefined);
                         !addToSplit && child.contentItems[j].remove();
                         instance.layoutChanged(document);
@@ -210,12 +208,12 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     //
     @undoBatch
     @action
-    public static AddRightSplit(document: Doc, dataDoc: Doc | undefined, libraryPath?: Doc[]) {
+    public static AddRightSplit(document: Doc, libraryPath?: Doc[]) {
         if (!CollectionDockingView.Instance) return false;
         const instance = CollectionDockingView.Instance;
         const newItemStackConfig = {
             type: 'stack',
-            content: [CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath)]
+            content: [CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath)]
         };
 
         const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
@@ -245,18 +243,18 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     //
     @undoBatch
     @action
-    public static UseRightSplit(document: Doc, dataDoc: Doc | undefined, libraryPath?: Doc[], shiftKey?: boolean) {
+    public static UseRightSplit(document: Doc, libraryPath?: Doc[], shiftKey?: boolean) {
         document.isDisplayPanel = true;
-        if (shiftKey || !CollectionDockingView.ReplaceRightSplit(document, dataDoc, libraryPath, shiftKey)) {
-            CollectionDockingView.AddRightSplit(document, dataDoc, libraryPath);
+        if (shiftKey || !CollectionDockingView.ReplaceRightSplit(document, libraryPath, shiftKey)) {
+            CollectionDockingView.AddRightSplit(document, libraryPath);
         }
     }
 
     @undoBatch
     @action
-    public AddTab = (stack: any, document: Doc, dataDocument: Doc | undefined, libraryPath?: Doc[]) => {
+    public AddTab = (stack: any, document: Doc, libraryPath?: Doc[]) => {
         Doc.GetProto(document).lastOpened = new DateField;
-        const docContentConfig = CollectionDockingView.makeDocumentConfig(document, dataDocument, undefined, libraryPath);
+        const docContentConfig = CollectionDockingView.makeDocumentConfig(document, undefined, libraryPath);
         if (stack === undefined) {
             let stack: any = this._goldenLayout.root;
             while (!stack.isStack) {
@@ -427,7 +425,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
             }
 
             const doc = await DocServer.GetRefField(tab.contentItem.config.props.documentId) as Doc;
-            const dataDoc = await DocServer.GetRefField(tab.contentItem.config.props.dataDocumentId) as Doc;
             if (doc instanceof Doc) {
                 //tab.titleElement[0].outerHTML = `<input class='lm_title' style="background:black" value='${doc.title}' />`;
                 tab.titleElement[0].onclick = (e: any) => tab.titleElement[0].focus();
@@ -507,7 +504,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
         stack.header.element[0].style.backgroundColor = DocServer.Control.isReadOnly() ? "#228540" : undefined;
         stack.header.element.on('mousedown', (e: any) => {
             if (e.target === stack.header.element[0] && e.button === 1) {
-                this.AddTab(stack, Docs.Create.FreeformDocument([], { _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), title: "Untitled Collection" }), undefined);
+                this.AddTab(stack, Docs.Create.FreeformDocument([], { _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), title: "Untitled Collection" }));
             }
         });
 
@@ -580,7 +577,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
 
 interface DockedFrameProps {
     documentId: FieldId;
-    dataDocumentId: FieldId;
     glContainer: any;
     libraryPath: (FieldId[]);
     backgroundColor?: (doc: Doc) => string | undefined;
@@ -593,7 +589,6 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     @observable private _panelWidth = 0;
     @observable private _panelHeight = 0;
     @observable private _document: Opt<Doc>;
-    @observable private _dataDoc: Opt<Doc>;
     @observable private _isActive: boolean = false;
 
     get _stack(): any {
@@ -601,12 +596,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     }
     constructor(props: any) {
         super(props);
-        DocServer.GetRefField(this.props.documentId).then(action((f: Opt<Field>) => {
-            this._document = f as Doc;
-            if (this.props.dataDocumentId && this.props.documentId !== this.props.dataDocumentId) {
-                DocServer.GetRefField(this.props.dataDocumentId).then(action((f: Opt<Field>) => this._dataDoc = f as Doc));
-            }
-        }));
+        DocServer.GetRefField(this.props.documentId).then(action((f: Opt<Field>) => this._document = f as Doc));
         this.props.libraryPath && this.setupLibraryPath();
     }
 
@@ -630,7 +620,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             pinDoc.presentationTargetDoc = doc;
             Doc.AddDocToList(curPres, "data", pinDoc);
             if (!DocumentManager.Instance.getDocumentView(curPres)) {
-                CollectionDockingView.AddRightSplit(curPres, undefined);
+                CollectionDockingView.AddRightSplit(curPres);
             }
         }
     }
@@ -708,16 +698,16 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     get previewPanelCenteringOffset() { return this.nativeWidth() ? (this._panelWidth - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
     get widthpercent() { return this.nativeWidth() ? `${(this.nativeWidth() * this.contentScaling()) / this.panelWidth() * 100}%` : undefined; }
 
-    addDocTab = (doc: Doc, dataDoc: Opt<Doc>, location: string, libraryPath?: Doc[]) => {
+    addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => {
         SelectionManager.DeselectAll();
         if (doc.dockingConfig) {
             return MainView.Instance.openWorkspace(doc);
         } else if (location === "onRight") {
-            return CollectionDockingView.AddRightSplit(doc, dataDoc, libraryPath);
+            return CollectionDockingView.AddRightSplit(doc, libraryPath);
         } else if (location === "close") {
             return CollectionDockingView.CloseRightSplit(doc);
         } else {
-            return CollectionDockingView.Instance.AddTab(this._stack, doc, dataDoc, libraryPath);
+            return CollectionDockingView.Instance.AddTab(this._stack, doc, libraryPath);
         }
     }
 
@@ -725,7 +715,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         TraceMobx();
         if (!this._document) return (null);
         const document = this._document;
-        const resolvedDataDoc = document.layout instanceof Doc ? document : this._dataDoc;
+        const resolvedDataDoc = this._document[DataSym] !== this._document && this._document[DataSym];// document.layout instanceof Doc ? document : this._dataDoc;
         return <DocumentView key={document[Id]}
             LibraryPath={this._libraryPath}
             Document={document}
@@ -762,5 +752,5 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             </div >);
     }
 }
-Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddRightSplit(doc, undefined); });
-Scripting.addGlobal(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.UseRightSplit(doc, undefined, undefined, shiftKey); });
+Scripting.addGlobal(function openOnRight(doc: any) { CollectionDockingView.AddRightSplit(doc); });
+Scripting.addGlobal(function useRightSplit(doc: any, shiftKey?: boolean) { CollectionDockingView.UseRightSplit(doc, undefined, shiftKey); });
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index a3b1b5ec0..851fded71 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -35,7 +35,7 @@ export interface CellProps {
     Document: Doc;
     fieldKey: string;
     renderDepth: number;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     moveDocument: (document: Doc, targetCollection: Doc | undefined, 
     addDocument: (document: Doc) => boolean) => boolean;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index c422c38f1..7dee7f18f 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -224,7 +224,7 @@ export interface SchemaTableProps {
     ScreenToLocalTransform: () => Transform;
     active: (outsideReaction: boolean) => boolean;
     onDrop: (e: React.DragEvent<Element>, options: DocumentOptions, completed?: (() => void) | undefined) => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     isSelected: (outsideReaction?: boolean) => boolean;
     isFocused: (document: Doc) => boolean;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index ad9dc8f7c..0d5d3e449 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -4,7 +4,7 @@ import { CursorProperty } from "csstype";
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import Switch from 'rc-switch';
-import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
+import { Doc, HeightSym, WidthSym, DataSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
@@ -62,7 +62,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             const rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
             const style = this.isStackingView ? { width: width(), marginTop: i === 0 ? 0 : this.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
             return <div className={`collectionStackingView-${this.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} >
-                {this.getDisplayDoc(d, Cast(d.resolvedDataDoc, Doc, null) || this.props.DataDoc, dxf, width)}
+                {this.getDisplayDoc(d, this.props.DataDoc, dxf, width)}
             </div>;
         });
     }
@@ -158,7 +158,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const height = () => this.getDocHeight(doc);
         return <ContentFittingDocumentView
             Document={doc}
-            DataDocument={dataDoc}
+            DataDocument={doc[DataSym] !== doc && doc[DataSym]}
             backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 13ab7c1a4..dd622bf9d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -47,7 +47,7 @@ export interface TreeViewProps {
     deleteDoc: (doc: Doc) => boolean;
     moveDocument: DragManager.MoveFunction;
     dropAction: "alias" | "copy" | undefined;
-    addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string, libraryPath?: Doc[]) => boolean;
+    addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
     pinToPres: (document: Doc) => void;
     panelWidth: () => number;
     panelHeight: () => number;
@@ -128,7 +128,7 @@ class TreeView extends React.Component<TreeViewProps> {
     }
 
     @undoBatch delete = () => this.props.deleteDoc(this.props.document);
-    @undoBatch openRight = () => this.props.addDocTab(this.props.document, this.templateDataDoc, "onRight", this.props.libraryPath);
+    @undoBatch openRight = () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath);
     @undoBatch indent = () => this.props.addDocument(this.props.document) && this.delete();
     @undoBatch move = (doc: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => {
         return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc);
@@ -201,8 +201,8 @@ class TreeView extends React.Component<TreeViewProps> {
                 ContextMenu.Instance.addItem({ description: "Clear All", event: () => Doc.GetProto(CurrentUserUtils.UserDocument.recentlyClosed as Doc).data = new List<Doc>(), icon: "plus" });
             } else if (this.props.document !== CurrentUserUtils.UserDocument.workspaces) {
                 ContextMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.document), icon: "tv" });
-                ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.templateDataDoc, "inTab", this.props.libraryPath), icon: "folder" });
-                ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.templateDataDoc, "onRight", this.props.libraryPath), icon: "caret-square-right" });
+                ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, "inTab", this.props.libraryPath), icon: "folder" });
+                ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight", this.props.libraryPath), icon: "caret-square-right" });
                 if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) {
                     ContextMenu.Instance.addItem({ description: "Focus", event: () => (view => view && view.props.focus(this.props.document, true))(DocumentManager.Instance.getFirstDocumentView(this.props.document)), icon: "camera" });
                 }
@@ -212,7 +212,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 ContextMenu.Instance.addItem({ description: "Create New Workspace", event: () => MainView.Instance.createNewWorkspace(), icon: "plus" });
             }
             ContextMenu.Instance.addItem({ description: "Toggle Theme Colors", event: () => this.props.document.darkScheme = !this.props.document.darkScheme, icon: "minus" });
-            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { const kvp = Docs.Create.KVPDocument(this.props.document, { _width: 300, _height: 300 }); this.props.addDocTab(kvp, this.props.dataDoc ? this.props.dataDoc : kvp, "onRight"); }, icon: "layer-group" });
+            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { const kvp = Docs.Create.KVPDocument(this.props.document, { _width: 300, _height: 300 }); this.props.addDocTab(kvp, "onRight"); }, icon: "layer-group" });
             ContextMenu.Instance.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.document, StrCast(this.props.document.title), () => { }, () => { }), icon: "file" });
             ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15);
             e.stopPropagation();
@@ -457,7 +457,7 @@ class TreeView extends React.Component<TreeViewProps> {
         remove: ((doc: Doc) => boolean),
         move: DragManager.MoveFunction,
         dropAction: dropActionType,
-        addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => boolean,
+        addDocTab: (doc: Doc, where: string) => boolean,
         pinToPres: (document: Doc) => void,
         backgroundColor: undefined | ((document: Doc) => string | undefined),
         screenToLocalXf: () => Transform,
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 79fd7d792..95f9fa62f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -229,10 +229,10 @@ export class CollectionView extends Touchable<FieldViewProps> {
             const layoutItems = existing && "subitems" in existing ? existing.subitems : [];
             layoutItems.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
             if (this.props.Document.childLayout instanceof Doc) {
-                layoutItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, undefined, "onRight"), icon: "project-diagram" });
+                layoutItems.push({ description: "View Child Layout", event: () => this.props.addDocTab(this.props.Document.childLayout as Doc, "onRight"), icon: "project-diagram" });
             }
             if (this.props.Document.childDetailed instanceof Doc) {
-                layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailed as Doc, undefined, "onRight"), icon: "project-diagram" });
+                layoutItems.push({ description: "View Child Detailed Layout", event: () => this.props.addDocTab(this.props.Document.childDetailed as Doc, "onRight"), icon: "project-diagram" });
             }
             !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" });
 
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 027ac5a0e..43ba5c614 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -24,7 +24,7 @@ type SelectorProps = {
     Document: Doc,
     Views: DocumentView[],
     Stack?: any,
-    addDocTab(doc: Doc, dataDoc: Doc | undefined, location: string): void
+    addDocTab(doc: Doc, location: string): void
 };
 
 @observer
@@ -60,7 +60,7 @@ export class SelectorContextMenu extends React.Component<SelectorProps> {
                 col._panX = newPanX;
                 col._panY = newPanY;
             }
-            this.props.addDocTab(col, undefined, "inTab"); // bcz: dataDoc?
+            this.props.addDocTab(col, "inTab"); // bcz: dataDoc?
         };
     }
 
diff --git a/src/client/views/linking/LinkFollowBox.tsx b/src/client/views/linking/LinkFollowBox.tsx
index 325c92413..b47464517 100644
--- a/src/client/views/linking/LinkFollowBox.tsx
+++ b/src/client/views/linking/LinkFollowBox.tsx
@@ -183,9 +183,9 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
 
     }
 
-    static _addDocTab: (undefined | ((doc: Doc, dataDoc: Opt<Doc>, where: string) => boolean));
+    static _addDocTab: (undefined | ((doc: Doc, where: string) => boolean));
 
-    static setAddDocTab = (addFunc: (doc: Doc, dataDoc: Opt<Doc>, where: string) => boolean) => {
+    static setAddDocTab = (addFunc: (doc: Doc, where: string) => boolean) => {
         LinkFollowBox._addDocTab = addFunc;
     }
 
@@ -199,7 +199,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
                 options.context._panX = newPanX;
                 options.context._panY = newPanY;
             }
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, undefined, "onRight");
+            (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, "onRight");
 
             if (options.shouldZoom) this.jumpToLink({ shouldZoom: options.shouldZoom });
 
@@ -212,7 +212,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
     openLinkRight = () => {
         if (LinkFollowBox.destinationDoc) {
             const alias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(alias, undefined, "onRight");
+            (LinkFollowBox._addDocTab || this.props.addDocTab)(alias, "onRight");
             this.highlightDoc();
             SelectionManager.DeselectAll();
         }
@@ -222,8 +222,8 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
     @undoBatch
     jumpToLink = async (options: { shouldZoom: boolean }) => {
         if (LinkFollowBox.sourceDoc && LinkFollowBox.linkDoc) {
-            const focus = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, undefined, "inTab"); SelectionManager.DeselectAll(); };
-            //let focus = (doc: Doc, maxLocation: string) => this.props.focus(docthis.props.focus(LinkFollowBox.destinationDoc, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation));
+            const focus = (document: Doc) => { (LinkFollowBox._addDocTab || this.props.addDocTab)(document, "inTab"); SelectionManager.DeselectAll(); };
+            //let focus = (doc: Doc, maxLocation: string) => this.props.focus(docthis.props.focus(LinkFollowBox.destinationDoc, true, 1, () => this.props.addDocTab(doc, maxLocation));
 
             DocumentManager.Instance.FollowLink(LinkFollowBox.linkDoc, LinkFollowBox.sourceDoc, focus, options && options.shouldZoom, false, undefined);
         }
@@ -234,7 +234,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
         if (LinkFollowBox.destinationDoc) {
             const fullScreenAlias = Doc.MakeAlias(LinkFollowBox.destinationDoc);
             // this.prosp.addDocTab is empty -- use the link source's addDocTab 
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(fullScreenAlias, undefined, "inTab");
+            (LinkFollowBox._addDocTab || this.props.addDocTab)(fullScreenAlias, "inTab");
 
             this.highlightDoc();
             SelectionManager.DeselectAll();
@@ -251,7 +251,7 @@ export class LinkFollowBox extends React.Component<FieldViewProps> {
                 options.context._panX = newPanX;
                 options.context._panY = newPanY;
             }
-            (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, undefined, "inTab");
+            (LinkFollowBox._addDocTab || this.props.addDocTab)(options.context, "inTab");
             if (options.shouldZoom) this.jumpToLink({ shouldZoom: options.shouldZoom });
 
             this.highlightDoc();
diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx
index 1a40f0c55..a8aa01306 100644
--- a/src/client/views/linking/LinkMenu.tsx
+++ b/src/client/views/linking/LinkMenu.tsx
@@ -16,7 +16,7 @@ library.add(faTrash);
 interface Props {
     docView: DocumentView;
     changeFlyout: () => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
 }
 
 @observer
diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx
index 0c38ff45c..78c77e106 100644
--- a/src/client/views/linking/LinkMenuGroup.tsx
+++ b/src/client/views/linking/LinkMenuGroup.tsx
@@ -17,7 +17,7 @@ interface LinkMenuGroupProps {
     group: Doc[];
     groupType: string;
     showEditor: (linkDoc: Doc) => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     docView: DocumentView;
 }
 
diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx
index b7d27ee30..54f5636e4 100644
--- a/src/client/views/linking/LinkMenuItem.tsx
+++ b/src/client/views/linking/LinkMenuItem.tsx
@@ -20,7 +20,7 @@ interface LinkMenuItemProps {
     sourceDoc: Doc;
     destinationDoc: Doc;
     showEditor: (linkDoc: Doc) => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
 }
 
 @observer
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 73fe4fb5d..36233a7e6 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -34,7 +34,7 @@ interface ContentFittingDocumentViewProps {
     removeDocument?: (document: Doc) => boolean;
     active: (outsideReaction: boolean) => boolean;
     whenActiveChanged: (isActive: boolean) => void;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     dontRegisterView?: boolean;
 }
diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/DocuLinkBox.tsx
index 156b16ec8..a0b5cd8ec 100644
--- a/src/client/views/nodes/DocuLinkBox.tsx
+++ b/src/client/views/nodes/DocuLinkBox.tsx
@@ -61,7 +61,7 @@ export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(Doc
     onClick = (e: React.MouseEvent) => {
         if (!this.props.Document.onClick) {
             if (Math.abs(e.clientX - this._downx) < 3 && Math.abs(e.clientY - this._downy) < 3 && (e.button !== 2 && !e.ctrlKey && this.props.Document.isButton)) {
-                DocumentManager.Instance.FollowLink(this.props.Document, this.props.ContainingCollectionDoc as Doc, document => this.props.addDocTab(document, undefined, "inTab"), false);
+                DocumentManager.Instance.FollowLink(this.props.Document, this.props.ContainingCollectionDoc as Doc, document => this.props.addDocTab(document, "inTab"), false);
             }
             e.stopPropagation();
         }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 11a33b70a..c0f603171 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -82,7 +82,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         return this.props.DataDoc instanceof Promise ? undefined : this.props.DataDoc;
     }
     get layoutDoc() {
-        if (this.props.DataDoc === undefined && (this.props.LayoutDoc || typeof Doc.LayoutField(this.props.Document) !== "string")) {
+        if (this.props.LayoutDoc || (this.props.DataDoc === undefined && typeof Doc.LayoutField(this.props.Document) !== "string")) {
             // if there is no dataDoc (ie, we're not rendering a template layout), but this document has a layout document (not a layout string), 
             // then we render the layout document as a template and use this document as the data context for the template layout.
             return Doc.expandTemplateLayout(this.props.LayoutDoc?.() || Doc.Layout(this.props.Document), this.props.Document);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 566c0d5de..dea08600a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -71,7 +71,7 @@ export interface DocumentViewProps {
     parentActive: (outsideReaction: boolean) => boolean;
     whenActiveChanged: (isActive: boolean) => void;
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
-    addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string, libraryPath?: Doc[]) => boolean;
+    addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
     pinToPres: (document: Doc) => void;
     zoomToScale: (scale: number) => void;
     backgroundHalo?: () => boolean;
@@ -152,9 +152,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     //     RadialMenu.Instance.openMenu();
 
-    //     RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), undefined, "onRight"), icon: "layer-group", selected: -1 });
+    //     RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight"), icon: "layer-group", selected: -1 });
     //     RadialMenu.Instance.addItem({ description: "Delete this document", event: () => this.props.ContainingCollectionView?.removeDocument(this.props.Document), icon: "trash", selected: -1 });
-    //     RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, undefined, "onRight"), icon: "folder", selected: -1 });
+    //     RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "onRight"), icon: "folder", selected: -1 });
     //     RadialMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "map-pin", selected: -1 });
 
     //     RadialMenu.Instance.displayMenu(pt.pageX - 15, pt.pageY - 15);
@@ -253,7 +253,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) {
                     fullScreenAlias.layoutKey = "layout_fullScreen";
                 }
-                UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, undefined, "inTab"), "double tap");
+                UndoManager.RunInBatch(() => this.props.addDocTab(fullScreenAlias, "inTab"), "double tap");
                 SelectionManager.DeselectAll();
                 Doc.UnBrushDoc(this.props.Document);
             } else if (this.onClickHandler && this.onClickHandler.script) {
@@ -277,7 +277,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         if (linkDocs.length) {
             DocumentManager.Instance.FollowLink(undefined, this.props.Document,
                 // open up target if it's not already in view ... by zooming into the button document first and setting flag to reset zoom afterwards
-                (doc: Doc, maxLocation: string) => this.props.focus(this.props.Document, true, 1, () => this.props.addDocTab(doc, undefined, maxLocation)),
+                (doc: Doc, maxLocation: string) => this.props.focus(this.props.Document, true, 1, () => this.props.addDocTab(doc, maxLocation)),
                 ctrlKey, altKey, this.props.ContainingCollectionDoc);
         }
     }
@@ -644,12 +644,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const open = ContextMenu.Instance.findByDescription("Open...");
         const openItems: ContextMenuProps[] = open && "subitems" in open ? open.subitems : [];
         openItems.push({ description: "Open Full Screen", event: () => CollectionDockingView.Instance && CollectionDockingView.Instance.OpenFullScreen(this, this.props.LibraryPath), icon: "desktop" });
-        openItems.push({ description: "Open Tab        ", event: () => this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab", this.props.LibraryPath), icon: "folder" });
-        openItems.push({ description: "Open Right      ", event: () => this.props.addDocTab(this.props.Document, this.props.DataDoc, "onRight", this.props.LibraryPath), icon: "caret-square-right" });
-        openItems.push({ description: "Open Alias Tab  ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "inTab"), icon: "folder" });
-        openItems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.props.DataDoc, "onRight"), icon: "caret-square-right" });
-        openItems.push({ description: "Open Fields     ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), undefined, "onRight"), icon: "layer-group" });
-        templateDoc && openItems.push({ description: "Open Template   ", event: () => this.props.addDocTab(templateDoc, undefined, "onRight"), icon: "eye" });
+        openItems.push({ description: "Open Tab        ", event: () => this.props.addDocTab(this.props.Document, "inTab", this.props.LibraryPath), icon: "folder" });
+        openItems.push({ description: "Open Right      ", event: () => this.props.addDocTab(this.props.Document, "onRight", this.props.LibraryPath), icon: "caret-square-right" });
+        openItems.push({ description: "Open Alias Tab  ", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "inTab"), icon: "folder" });
+        openItems.push({ description: "Open Alias Right", event: () => this.props.addDocTab(Doc.MakeAlias(this.props.Document), "onRight"), icon: "caret-square-right" });
+        openItems.push({ description: "Open Fields     ", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
+        templateDoc && openItems.push({ description: "Open Template   ", event: () => this.props.addDocTab(templateDoc, "onRight"), icon: "eye" });
         openItems.push({ description: "Open Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
         !open && cm.addItem({ description: "Open...", subitems: openItems, icon: "external-link-alt" });
 
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 00f00dd52..f5c85e143 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -29,7 +29,7 @@ export interface FieldViewProps {
     select: (isCtrlPressed: boolean) => void;
     renderDepth: number;
     addDocument?: (document: Doc) => boolean;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     removeDocument?: (document: Doc) => boolean;
     moveDocument?: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index a191ac4f4..d4da21239 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -36,7 +36,7 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
 
     showTemplate = (): void => {
         const dragFactory = Cast(this.props.Document.dragFactory, Doc, null);
-        dragFactory && this.props.addDocTab(dragFactory, undefined, "onRight");
+        dragFactory && this.props.addDocTab(dragFactory, "onRight");
     }
 
     specificContextMenu = (): void => {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index fd288f720..842ccdd7b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -916,7 +916,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
         //             if (linkClicked) {
         //                 DocServer.GetRefField(linkClicked).then(async linkDoc => {
         //                     (linkDoc instanceof Doc) &&
-        //                         DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, undefined, location ? location : "inTab"), false);
+        //                         DocumentManager.Instance.FollowLink(linkDoc, this.props.Document, document => this.props.addDocTab(document, location ? location : "inTab"), false);
         //                 });
         //             }
         //         } else {
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index fda3e3285..1174110e7 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -84,9 +84,9 @@ export class FormattedTextBoxComment {
                 const textBox = FormattedTextBoxComment.textBox;
                 if (FormattedTextBoxComment.linkDoc && !keep && textBox) {
                     DocumentManager.Instance.FollowLink(FormattedTextBoxComment.linkDoc, textBox.props.Document,
-                        (doc: Doc, maxLocation: string) => textBox.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight"));
+                        (doc: Doc, maxLocation: string) => textBox.props.addDocTab(doc, e.ctrlKey ? "inTab" : "onRight"));
                 } else if (textBox && (FormattedTextBoxComment.tooltipText as any).href) {
-                    textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400 }), undefined, "onRight");
+                    textBox.props.addDocTab(Docs.Create.WebDocument((FormattedTextBoxComment.tooltipText as any).href, { title: (FormattedTextBoxComment.tooltipText as any).href, _width: 200, _height: 400 }), "onRight");
                 }
                 keep && textBox && FormattedTextBoxComment.start !== undefined && textBox.adoptAnnotation(
                     FormattedTextBoxComment.start, FormattedTextBoxComment.end, FormattedTextBoxComment.mark);
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index e6b512adf..93bda6d02 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -22,7 +22,7 @@ export interface KeyValuePairProps {
     keyWidth: number;
     PanelHeight: () => number;
     PanelWidth: () => number;
-    addDocTab: (doc: Doc, data: Opt<Doc>, where: string) => boolean;
+    addDocTab: (doc: Doc, where: string) => boolean;
 }
 @observer
 export class KeyValuePair extends React.Component<KeyValuePairProps> {
@@ -46,7 +46,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
         if (value instanceof Doc) {
             e.stopPropagation();
             e.preventDefault();
-            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), undefined, "onRight"), icon: "layer-group" });
+            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(value, { _width: 300, _height: 300 }), "onRight"), icon: "layer-group" });
             ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
         }
     }
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index d4a47c159..8d20bbe59 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -327,12 +327,12 @@ export class PresBox extends React.Component<FieldViewProps> {
         if (toggle) {
             if (this.props.Document.inOverlay) {
                 Doc.RemoveDocFromList((CurrentUserUtils.UserDocument.overlays as Doc), this.props.fieldKey, this.props.Document);
-                CollectionDockingView.AddRightSplit(this.props.Document, this.props.DataDoc);
+                CollectionDockingView.AddRightSplit(this.props.Document);
                 this.props.Document.inOverlay = false;
             } else {
                 this.props.Document.x = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[0];// 500;//e.clientX + 25;
                 this.props.Document.y = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0)[1];////e.clientY - 25;
-                this.props.addDocTab && this.props.addDocTab(this.props.Document, this.props.DataDoc, "close");
+                this.props.addDocTab?.(this.props.Document, "close");
                 Doc.AddDocToList((CurrentUserUtils.UserDocument.overlays as Doc), this.props.fieldKey, this.props.Document);
             }
         }
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 6695e04c3..69c6f2617 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -90,7 +90,7 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
     @action public FullScreen() {
         this._fullScreen = true;
         this.player && this.player.requestFullscreen();
-        this._youtubePlayer && this.props.addDocTab(this.props.Document, this.props.DataDoc, "inTab");
+        this._youtubePlayer && this.props.addDocTab(this.props.Document, "inTab");
     }
 
     choosePath(url: string) {
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index d8b340db6..58823c93d 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -11,7 +11,7 @@ import "./Annotation.scss";
 
 interface IAnnotationProps {
     anno: Doc;
-    addDocTab: (document: Doc, dataDoc: Opt<Doc>, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     focus: (doc: Doc) => void;
     dataDoc: Doc;
@@ -30,7 +30,7 @@ interface IRegionAnnotationProps {
     y: number;
     width: number;
     height: number;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     document: Doc;
     dataDoc: Doc;
@@ -98,7 +98,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
             const annoGroup = await Cast(this.props.document.group, Doc);
             if (annoGroup) {
                 DocumentManager.Instance.FollowLink(undefined, annoGroup,
-                    (doc: Doc, maxLocation: string) => this.props.addDocTab(doc, undefined, e.ctrlKey ? "inTab" : "onRight"),
+                    (doc: Doc, maxLocation: string) => this.props.addDocTab(doc, e.ctrlKey ? "inTab" : "onRight"),
                     false, false, undefined);
                 e.stopPropagation();
             }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index a9b8c6bbe..198aeb856 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -65,7 +65,7 @@ interface IViewerProps {
     loaded: (nw: number, nh: number, np: number) => void;
     active: (outsideReaction?: boolean) => boolean;
     isChildActive: (outsideReaction?: boolean) => boolean;
-    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
+    addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     addDocument?: (doc: Doc) => boolean;
     setPdfViewer: (view: PDFViewer) => void;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 888707ee3..8d62c34c5 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -4,7 +4,7 @@ import { faArrowDown, faArrowUp, faFile as fileSolid, faFileDownload, faLocation
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, IReactionDisposer, reaction } from "mobx";
 import { observer } from "mobx-react";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, DataSym } from "../../../new_fields/Doc";
 import { documentSchema } from '../../../new_fields/documentSchemas';
 import { Id } from "../../../new_fields/FieldSymbols";
 import { createSchema, makeInterface } from '../../../new_fields/Schema';
@@ -173,6 +173,7 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
             <div className="presElementBox-embedded" style={{ height: this.embedHeight() }}>
                 <ContentFittingDocumentView
                     Document={this.targetDoc}
+                    DataDocument={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
                     LibraryPath={emptyPath}
                     fitToBox={true}
                     addDocument={returnFalse}
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 827cb80c6..2cbb24da7 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -74,7 +74,7 @@ export class SelectorContextMenu extends React.Component<SearchItemProps> {
                 col._panX = newPanX;
                 col._panY = newPanY;
             }
-            CollectionDockingView.AddRightSplit(col, undefined);
+            CollectionDockingView.AddRightSplit(col);
         };
     }
     render() {
@@ -108,7 +108,7 @@ export class LinkContextMenu extends React.Component<LinkMenuProps> {
 
     unHighlightDoc = (doc: Doc) => () => Doc.UnBrushDoc(doc);
 
-    getOnClick = (col: Doc) => () => CollectionDockingView.AddRightSplit(col, undefined);
+    getOnClick = (col: Doc) => () => CollectionDockingView.AddRightSplit(col);
 
     render() {
         return (
@@ -272,7 +272,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
 
     @computed
     get contextButton() {
-        return <ParentDocSelector Views={DocumentManager.Instance.DocumentViews} Document={this.props.doc} addDocTab={(doc, data, where) => CollectionDockingView.AddRightSplit(doc, data)} />;
+        return <ParentDocSelector Views={DocumentManager.Instance.DocumentViews} Document={this.props.doc} addDocTab={(doc, where) => CollectionDockingView.AddRightSplit(doc)} />;
     }
 
     render() {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 43bbea623..1f2dd1c8f 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -17,6 +17,7 @@ import { listSpec } from "./Schema";
 import { ComputedField } from "./ScriptField";
 import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types";
 import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util";
+import { DatasetAbout } from "../client/northstar/model/idea/idea";
 
 export namespace Field {
     export function toKeyValueString(doc: Doc, key: string): string {
@@ -495,7 +496,8 @@ export namespace Doc {
     // if the childDoc is a template for a field, then this will return the expanded layout with its data doc.
     // otherwise, it just returns the childDoc
     export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt<Doc>, childDoc: Doc) {
-        const resolvedDataDoc = containerDataDoc === containerDoc || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc;
+        const existingResolvedDataDoc = childDoc[DataSym] !== Doc.GetProto(childDoc)[DataSym] && childDoc[DataSym];
+        const resolvedDataDoc = existingResolvedDataDoc || (containerDataDoc === containerDoc || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc);
         return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc };
     }
     export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) {
-- 
cgit v1.2.3-70-g09d2


From 13e6971c50d4efbb71c551a4570bf59fd5e091c2 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 24 Feb 2020 18:23:41 -0500
Subject: fixed scripting in schema's to allow documents to be assigned

---
 src/client/util/type_decls.d                           | 1 +
 src/client/views/collections/CollectionSchemaCells.tsx | 8 +++++---
 src/new_fields/Doc.ts                                  | 6 ++++++
 3 files changed, 12 insertions(+), 3 deletions(-)

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

diff --git a/src/client/util/type_decls.d b/src/client/util/type_decls.d
index 127f7b798..97f6b79fb 100644
--- a/src/client/util/type_decls.d
+++ b/src/client/util/type_decls.d
@@ -207,4 +207,5 @@ declare const Docs: {
     StackingDocument(documents: Doc[], options?: DocumentOptions): Doc;
 };
 
+declare function assignDoc(doc:Doc, field:any, id:any):string;
 declare function d(...args:any[]):any;
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 851fded71..facde3648 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -37,8 +37,8 @@ export interface CellProps {
     renderDepth: number;
     addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
-    moveDocument: (document: Doc, targetCollection: Doc | undefined, 
-    addDocument: (document: Doc) => boolean) => boolean;
+    moveDocument: (document: Doc, targetCollection: Doc | undefined,
+        addDocument: (document: Doc) => boolean) => boolean;
     isFocused: boolean;
     changeFocusedCellByIndex: (row: number, col: number) => void;
     setIsEditing: (isEditing: boolean) => void;
@@ -236,7 +236,9 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
                                 const script = CompileScript(value, { requiredType: type, typecheck: false, editable: true, addReturn: true, params: { this: Doc.name, $r: "number", $c: "number", $: "any" } });
                                 if (script.compiled) {
                                     DocListCast(this.props.Document[this.props.fieldKey]).
-                                        forEach((doc, i) => this.applyToDoc(doc, i, this.props.col, script.run));
+                                        forEach((doc, i) => value.startsWith(":=") ?
+                                            this.props.setComputed(value.substring(2), doc, this.props.rowProps.column.id!, i, this.props.col) :
+                                            this.applyToDoc(doc, i, this.props.col, script.run));
                                 }
                             }}
                         />
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index a24746caf..6142ebb36 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -17,6 +17,7 @@ import { listSpec } from "./Schema";
 import { ComputedField } from "./ScriptField";
 import { Cast, FieldValue, NumCast, StrCast, ToConstructor } from "./Types";
 import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util";
+import { DocumentManager } from "../client/util/DocumentManager";
 
 export namespace Field {
     export function toKeyValueString(doc: Doc, key: string): string {
@@ -833,6 +834,10 @@ export namespace Doc {
             layoutDoc._nativeHeight = NumCast(layoutDoc._height, height);
         }
     }
+    export function assignDocToField(doc: Doc, field: string, id: string) {
+        DocServer.GetRefField(id).then(layout => layout instanceof Doc && (doc[field] = layout));
+        return id;
+    }
 }
 
 Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; });
@@ -849,6 +854,7 @@ Scripting.addGlobal(function setNativeView(doc: any) { Doc.setNativeView(doc); }
 Scripting.addGlobal(function undo() { return UndoManager.Undo(); });
 Scripting.addGlobal(function redo() { return UndoManager.Redo(); });
 Scripting.addGlobal(function DOC(id: string) { console.log("Can't parse a document id in a script"); return "invalid"; });
+Scripting.addGlobal(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); });
 Scripting.addGlobal(function curPresentationItem() {
     const curPres = Doc.UserDoc().curPresentation as Doc;
     return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)];
-- 
cgit v1.2.3-70-g09d2


From 4863b1ef9ec3160b0888a5ab8bb1a62274aed5ec Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 6 Mar 2020 17:29:27 -0500
Subject: made tree views display documentViews instead of just strings

---
 src/client/documents/Documents.ts                  |  1 +
 src/client/util/DocumentManager.ts                 | 11 ++++-
 src/client/views/DocumentDecorations.tsx           |  3 +-
 .../views/collections/CollectionSchemaCells.tsx    |  3 +-
 .../views/collections/CollectionTreeView.scss      |  3 ++
 .../views/collections/CollectionTreeView.tsx       | 52 +++++++++++++++++++---
 src/client/views/nodes/DocuLinkBox.scss            |  7 ++-
 src/client/views/nodes/DocuLinkBox.tsx             | 11 +++--
 src/client/views/nodes/DocumentView.scss           |  2 +
 src/client/views/nodes/DocumentView.tsx            | 14 ++++--
 .../authentication/models/current_user_utils.ts    | 14 +++---
 11 files changed, 95 insertions(+), 26 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 5f0e63b56..1f351e93f 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -123,6 +123,7 @@ export interface DocumentOptions {
     displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video)
     borderRounding?: string;
     boxShadow?: string;
+    dontRegisterChildren?: boolean;
     _pivotField?: string; // field key used to determine headings for sections in stacking, masonry, pivot views
     schemaColumns?: List<SchemaHeaderField>;
     dockingConfig?: string;
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 323d31af2..6711947ad 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -92,10 +92,17 @@ export class DocumentManager {
     public getDocumentViews(toFind: Doc): DocumentView[] {
         const toReturn: DocumentView[] = [];
 
+        // heurstic to return the "best" documents first:
+        //   choose an exact match over an alias match
+        //   choose documents that have a PanelWidth() over those that don't (the treeview documents have no panelWidth)
         DocumentManager.Instance.DocumentViews.map(view =>
-            view.props.Document.presBox === undefined && view.props.Document === toFind && toReturn.push(view));
+            view.props.Document.presBox === undefined && view.props.PanelWidth() > 1 && view.props.Document === toFind && toReturn.push(view));
         DocumentManager.Instance.DocumentViews.map(view =>
-            view.props.Document.presBox === undefined && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view));
+            view.props.Document.presBox === undefined && view.props.PanelWidth() <= 1 && view.props.Document === toFind && toReturn.push(view));
+        DocumentManager.Instance.DocumentViews.map(view =>
+            view.props.Document.presBox === undefined && view.props.PanelWidth() > 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view));
+        DocumentManager.Instance.DocumentViews.map(view =>
+            view.props.Document.presBox === undefined && view.props.PanelWidth() <= 1 && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view));
 
         return toReturn;
     }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index c98be0d4a..39d078a36 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -43,7 +43,7 @@ export type CloseCall = (toBeDeleted: DocumentView[]) => void;
 export class DocumentDecorations extends React.Component<{}, { value: string }> {
     static Instance: DocumentDecorations;
     private _resizeHdlId = "";
-    private _keyinput: React.RefObject<HTMLInputElement>;
+    private _keyinput = React.createRef<HTMLInputElement>();
     private _resizeBorderWidth = 16;
     private _linkBoxHeight = 20 + 3; // link button height + margin
     private _titleHeight = 20;
@@ -62,7 +62,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     constructor(props: Readonly<{}>) {
         super(props);
         DocumentDecorations.Instance = this;
-        this._keyinput = React.createRef();
         reaction(() => SelectionManager.SelectedDocuments().slice(), docs => this.titleBlur(false));
     }
 
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index df7abad61..79b5d7bb7 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -77,7 +77,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
 
     @action
     isEditingCallback = (isEditing: boolean): void => {
-        document.addEventListener("keydown", this.onKeyDown);
+        document.removeEventListener("keydown", this.onKeyDown);
+        isEditing && document.addEventListener("keydown", this.onKeyDown);
         this._isEditing = isEditing;
         this.props.setIsEditing(isEditing);
         this.props.changeFocusedCellByIndex(this.props.row, this.props.col);
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index 6ebe81545..fd4a963c3 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -123,6 +123,9 @@
     .editableView-container-editing-oneLine {
         min-width: 15px;
     }
+    .documentView-node-topmost {
+        width: unset;
+    }
 }
 
 .treeViewItem-header-above {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index deff3d177..54ad2ad48 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -10,7 +10,7 @@ import { Document, listSpec } from '../../../new_fields/Schema';
 import { ComputedField, ScriptField } from '../../../new_fields/ScriptField';
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../new_fields/Types';
 import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
-import { emptyFunction, emptyPath, returnFalse, Utils } from '../../../Utils';
+import { emptyFunction, emptyPath, returnFalse, Utils, returnOne, returnZero, returnTransparent, returnTrue } from '../../../Utils';
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentType } from "../../documents/DocumentTypes";
 import { DocumentManager } from '../../util/DocumentManager';
@@ -34,6 +34,7 @@ import "./CollectionTreeView.scss";
 import React = require("react");
 import { CollectionViewType } from './CollectionView';
 import { RichTextField } from '../../../new_fields/RichTextField';
+import { DocumentView } from '../nodes/DocumentView';
 
 
 export interface TreeViewProps {
@@ -92,6 +93,7 @@ class TreeView extends React.Component<TreeViewProps> {
     private _header?: React.RefObject<HTMLDivElement> = React.createRef();
     private _treedropDisposer?: DragManager.DragDropDisposer;
     private _dref = React.createRef<HTMLDivElement>();
+    private _tref = React.createRef<HTMLDivElement>();
 
     get displayName() { return "TreeView(" + this.props.document.title + ")"; }  // this makes mobx trace() statements more descriptive
 
@@ -171,13 +173,16 @@ class TreeView extends React.Component<TreeViewProps> {
     editableView = (key: string, style?: string) => (<EditableView
         oneLine={true}
         display={"inline-block"}
-        editing={this.dataDoc[Id] === EditableView.loadId}
+        editing={true /*this.dataDoc[Id] === EditableView.loadId*/}
         contents={StrCast(this.props.document[key])}
         height={12}
         fontStyle={style}
         fontSize={12}
         GetValue={() => StrCast(this.props.document[key])}
-        SetValue={undoBatch((value: string) => Doc.SetInPlace(this.props.document, key, value, false) || true)}
+        SetValue={undoBatch((value: string) => {
+            Doc.SetInPlace(this.props.document, key, value, false) || true;
+            this.props.document.editTitle = undefined;
+        })}
         OnFillDown={undoBatch((value: string) => {
             Doc.SetInPlace(this.props.document, key, value, false);
             const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
@@ -263,6 +268,13 @@ class TreeView extends React.Component<TreeViewProps> {
         const finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1] + (this.props.ChromeHeight && this.props.ChromeHeight() < 0 ? this.props.ChromeHeight() : 0));
         return finalXf;
     }
+    getTransform = () => {
+        const { scale, translateX, translateY } = Utils.GetScreenTransform(this._tref.current!);
+        const outerXf = this.props.outerXf();
+        const offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
+        const finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]);
+        return finalXf;
+    }
     docWidth = () => {
         const layoutDoc = Doc.Layout(this.props.document);
         const aspect = NumCast(layoutDoc._nativeHeight) / NumCast(layoutDoc._nativeWidth);
@@ -404,8 +416,8 @@ class TreeView extends React.Component<TreeViewProps> {
      */
     @computed
     get renderTitle() {
-        const reference = React.createRef<HTMLDivElement>();
-        const onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true);
+        const onItemDown = SetupDrag(this._tref, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId[Id], true);
+        const editTitle = ScriptField.MakeFunction("this.editTitle=true", { this: Doc.name });
 
         const headerElements = (
             <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
@@ -424,14 +436,40 @@ class TreeView extends React.Component<TreeViewProps> {
             <FontAwesomeIcon title="open in pane on right" icon="angle-right" size="lg" />
         </div>);
         return <>
-            <div className="docContainer" title="click to edit title" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
+            <div className="docContainer" ref={this._tref} title="click to edit title" id={`docContainer-${this.props.parentKey}`} onPointerDown={onItemDown}
                 style={{
                     background: Doc.IsHighlighted(this.props.document) ? "orange" : Doc.IsBrushed(this.props.document) ? "#06121212" : "0",
                     fontWeight: this.props.document.searchMatch ? "bold" : undefined,
                     outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
                     pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
                 }} >
-                {this.editableView("title")}
+                {this.props.document.editTitle ?
+                    this.editableView("title") :
+                    <DocumentView
+                        Document={this.props.document}
+                        DataDoc={undefined}
+                        LibraryPath={this.props.libraryPath || []}
+                        addDocument={undefined}
+                        addDocTab={this.props.addDocTab}
+                        pinToPres={emptyFunction}
+                        onClick={editTitle}
+                        moveDocument={this.props.moveDocument}
+                        removeDocument={undefined}
+                        ScreenToLocalTransform={this.getTransform}
+                        ContentScaling={returnOne}
+                        PanelWidth={returnZero}
+                        PanelHeight={returnZero}
+                        renderDepth={1}
+                        focus={emptyFunction}
+                        parentActive={returnTrue}
+                        whenActiveChanged={emptyFunction}
+                        bringToFront={emptyFunction}
+                        dontRegisterView={BoolCast(this.props.treeViewId.dontRegisterChildren)}
+                        ContainingCollectionView={undefined}
+                        ContainingCollectionDoc={undefined}
+                        zoomToScale={emptyFunction}
+                        getScale={returnOne}
+                    />}
             </div >
             {this.props.treeViewHideHeaderFields() ? (null) : headerElements}
             {openRight}
diff --git a/src/client/views/nodes/DocuLinkBox.scss b/src/client/views/nodes/DocuLinkBox.scss
index 286033475..f2c203548 100644
--- a/src/client/views/nodes/DocuLinkBox.scss
+++ b/src/client/views/nodes/DocuLinkBox.scss
@@ -1,4 +1,4 @@
-.docuLinkBox-cont {
+.docuLinkBox-cont, .docuLinkBox-cont-small {
     cursor: default;
     position: absolute;
     width: 15;
@@ -21,4 +21,9 @@
         padding-left: 2px;
         padding-top: 1px;
     }
+}
+
+.docuLinkBox-cont-small {
+    width:5px;
+    height:5px;
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/DocuLinkBox.tsx
index 882e57006..776d2019d 100644
--- a/src/client/views/nodes/DocuLinkBox.tsx
+++ b/src/client/views/nodes/DocuLinkBox.tsx
@@ -124,8 +124,8 @@ export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(Doc
     }
 
     render() {
-        const x = NumCast(this.props.Document[this.props.fieldKey + "_x"], 100);
-        const y = NumCast(this.props.Document[this.props.fieldKey + "_y"], 100);
+        const x = this.props.PanelWidth() > 1 ? NumCast(this.props.Document[this.props.fieldKey + "_x"], 100) : 0;
+        const y = this.props.PanelWidth() > 1 ? NumCast(this.props.Document[this.props.fieldKey + "_y"], 100) : 0;
         const c = StrCast(this.props.Document.backgroundColor, "lightblue");
         const anchor = this.props.fieldKey === "anchor1" ? "anchor2" : "anchor1";
         const anchorScale = (x === 0 || x === 100 || y === 0 || y === 100) ? 1 : .15;
@@ -140,9 +140,12 @@ export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(Doc
                 </div>}
             </div>
         );
-        return <div className="docuLinkBox-cont" onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu}
+        const small = this.props.PanelWidth() <= 1;
+        return <div className={`docuLinkBox-cont${small ? "-small" : ""}`} onPointerDown={this.onPointerDown} onClick={this.onClick} title={targetTitle} onContextMenu={this.specificContextMenu}
             ref={this._ref} style={{
-                background: c, left: `calc(${x}% - 7.5px)`, top: `calc(${y}% - 7.5px)`,
+                background: c,
+                left: !small ? `calc(${x}% - 7.5px)` : undefined,
+                top: !small ? `calc(${y}% - 7.5px)` : undefined,
                 transform: `scale(${anchorScale / this.props.ContentScaling()})`
             }} >
             {!this._editing && !this._forceOpen ? (null) :
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 56e3eb220..d1d96f0a1 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -5,6 +5,8 @@
     position: inherit;
     top: 0;
     left: 0;
+    width: 100%;
+    height: 100%;
     border-radius: inherit;
     transition: outline .3s linear;
     cursor: grab;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7d2940df5..463c6b5bd 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1018,6 +1018,16 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     @computed get innards() {
         TraceMobx();
+        if (!this.props.PanelWidth()) {
+            return <div style={{ display: "flex" }}>
+                {StrCast(this.props.Document.title)}
+                {this.Document.links && DocListCast(this.Document.links).filter(d => !d.hidden).filter(this.isNonTemporalLink).map((d, i) =>
+                    <div className="documentView-docuLinkWrapper" style={{ position: "absolute", top: 0, left: 0 }} key={`${d[Id]}`}>
+                        <DocumentView {...this.props} ContentScaling={returnOne} ContainingCollectionDoc={this.props.Document}
+                            PanelWidth={returnOne} PanelHeight={returnOne} Document={d} layoutKey={this.linkEndpoint(d)} backgroundColor={returnTransparent} removeDocument={undoBatch(doc => doc.hidden = true)} />
+                    </div>)}
+            </div>;
+        }
         const showTitle = StrCast(this.layoutDoc._showTitle);
         const showTitleHover = StrCast(this.layoutDoc._showTitleHover);
         const showCaption = StrCast(this.layoutDoc._showCaption);
@@ -1116,8 +1126,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
                 boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined,
                 background: finalColor,
-                width: "100%",
-                height: "100%",
                 opacity: this.Document.opacity
             }}>
             {this.Document.isBackground ? <div className="documentView-lock"> <FontAwesomeIcon icon="unlock" size="lg" /> </div> : (null)}
@@ -1131,7 +1139,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 }
 
-Scripting.addGlobal(function toggleDetail(doc: any, layoutKey: string, otherKey: string="layout") {
+Scripting.addGlobal(function toggleDetail(doc: any, layoutKey: string, otherKey: string = "layout") {
     const dv = DocumentManager.Instance.getDocumentView(doc);
     if (dv?.props.Document.layoutKey === layoutKey) dv?.switchViews(otherKey !== "layout", otherKey.replace("layout_", ""));
     else dv?.switchViews(true, layoutKey.replace("layout_", ""));
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index f672da085..5d93f208a 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -37,17 +37,19 @@ export class CurrentUserUtils {
     @observable public static GuestMobile: Doc | undefined;
 
     static setupDefaultDocTemplates(doc: Doc, buttons?: string[]) {
-        const taskStatusValues = [  { title: "todo", _backgroundColor: "blue", color: "white" },
-                                    { title: "in progress", _backgroundColor: "yellow", color: "black" },
-                                    { title: "completed", _backgroundColor: "green", color: "white" }
+        const taskStatusValues = [{ title: "todo", _backgroundColor: "blue", color: "white" },
+        { title: "in progress", _backgroundColor: "yellow", color: "black" },
+        { title: "completed", _backgroundColor: "green", color: "white" }
         ];
         const noteTemplates = [
             Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow" }),
             Docs.Create.TextDocument("", { title: "text", style: "Idea", isTemplateDoc: true, backgroundColor: "pink" }),
             Docs.Create.TextDocument("", { title: "text", style: "Topic", isTemplateDoc: true, backgroundColor: "lightBlue" }),
             Docs.Create.TextDocument("", { title: "text", style: "Person", isTemplateDoc: true, backgroundColor: "lightGreen" }),
-            Docs.Create.TextDocument("", { title: "text", style: "Todo", isTemplateDoc: true, backgroundColor: "orange",_autoHeight: false, 
-                layout:FormattedTextBox.LayoutString("Todo"), _height: 100, _showCaption: "caption",caption: RichTextField.DashField("taskStatus") })
+            Docs.Create.TextDocument("", {
+                title: "text", style: "Todo", isTemplateDoc: true, backgroundColor: "orange", _autoHeight: false,
+                layout: FormattedTextBox.LayoutString("Todo"), _height: 100, _showCaption: "caption", caption: RichTextField.DashField("taskStatus")
+            })
         ];
         doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" });
         Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues);
@@ -221,7 +223,7 @@ export class CurrentUserUtils {
             _width: 50, _height: 25, title: "Library", fontSize: 10,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
             sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], {
-                title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, dropAction: "alias", lockedPosition: true, boxShadow: "0 0",
+                title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, dropAction: "alias", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true
             }),
             targetContainer: sidebarContainer,
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;")
-- 
cgit v1.2.3-70-g09d2


From 4859d4e3f5827c3341d43d19a5309d2ec25ab67b Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 1 Apr 2020 17:15:14 -0400
Subject: fixed warnings and some compile errors.  Made a key value layout and
 extened DocumentBox to have a childLayoutKey field

---
 src/client/ClientRecommender.tsx                   |  54 +++++-----
 src/client/cognitive_services/CognitiveServices.ts |  36 +++----
 src/client/documents/Documents.ts                  |   3 +-
 src/client/util/RichTextSchema.tsx                 |  18 ++--
 src/client/views/DocumentButtonBar.tsx             |   2 +-
 src/client/views/EditableView.tsx                  |  22 ++--
 src/client/views/GestureOverlay.tsx                |   8 +-
 src/client/views/GlobalKeyHandler.ts               |   4 +-
 src/client/views/MainView.tsx                      |   2 +
 src/client/views/RecommendationsBox.tsx            |  16 +--
 src/client/views/TemplateMenu.tsx                  |   8 +-
 src/client/views/TouchScrollableMenu.tsx           |   4 +-
 .../views/collections/CollectionDockingView.tsx    |   2 +-
 .../views/collections/CollectionSchemaCells.tsx    |   2 +
 .../views/collections/CollectionSchemaView.tsx     |   8 +-
 .../views/collections/CollectionStackingView.tsx   |   2 +-
 .../CollectionStackingViewFieldColumn.tsx          |   3 +-
 .../views/collections/CollectionStaffView.tsx      |  12 +--
 src/client/views/collections/CollectionSubView.tsx |   3 +-
 .../views/collections/CollectionTimeView.tsx       |   2 +-
 src/client/views/collections/CollectionView.tsx    |   2 +-
 .../views/collections/CollectionViewChromes.tsx    |  10 +-
 .../CollectionFreeFormLinksView.tsx                | 116 ++++++++++-----------
 .../collections/collectionFreeForm/MarqueeView.tsx |   4 +-
 src/client/views/nodes/ButtonBox.tsx               |   2 +-
 .../views/nodes/ContentFittingDocumentView.tsx     |   2 +
 src/client/views/nodes/DocumentBox.tsx             |   3 +-
 src/client/views/nodes/DocumentContentsView.tsx    |  24 +++--
 src/client/views/nodes/KeyValuePair.tsx            |   2 +
 src/client/views/nodes/RadialMenuItem.tsx          |  30 +++---
 src/client/views/nodes/ScreenshotBox.tsx           |   2 +-
 src/client/views/nodes/WebBox.tsx                  |   2 +-
 src/client/views/pdf/PDFViewer.tsx                 |   2 +-
 src/client/views/webcam/DashWebRTCVideo.tsx        |   8 +-
 src/mobile/MobileInterface.tsx                     |   2 +
 src/new_fields/Doc.ts                              |   4 +-
 src/new_fields/util.ts                             |   2 +-
 .../Session/agents/applied_session_agent.ts        |   2 +-
 src/server/DashSession/Session/agents/monitor.ts   |   2 +-
 .../Session/agents/promisified_ipc_manager.ts      |   6 +-
 src/server/Websocket/Websocket.ts                  |   8 +-
 src/server/database.ts                             |   2 +-
 src/server/server_Initialization.ts                |   2 +-
 43 files changed, 232 insertions(+), 218 deletions(-)

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

diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx
index 0e67a6e57..537e331ab 100644
--- a/src/client/ClientRecommender.tsx
+++ b/src/client/ClientRecommender.tsx
@@ -69,7 +69,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     private distance(vector1: number[], vector2: number[], metric: string = "cosine") {
-        assert(vector1.length === vector2.length, "Vectors are not the same length");
+        // assert(vector1.length === vector2.length, "Vectors are not the same length");
         let similarity: number;
         switch (metric) {
             case "cosine":
@@ -113,7 +113,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
             }
         }
         );
-        let doclist = Array.from(ClientRecommender.Instance.docVectors);
+        const doclist = Array.from(ClientRecommender.Instance.docVectors);
         if (distance_metric === "euclidian") {
             doclist.sort((a: RecommenderDocument, b: RecommenderDocument) => a.score - b.score);
         }
@@ -169,12 +169,12 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     generateMetadata = async (dataDoc: Doc, extDoc: Doc, threshold: Confidence = Confidence.Excellent) => {
-        let converter = (results: any) => {
-            let tagDoc = new Doc;
-            let tagsList = new List();
+        const converter = (results: any) => {
+            const tagDoc = new Doc;
+            const tagsList = new List();
             results.tags.map((tag: Tag) => {
                 tagsList.push(tag.name);
-                let sanitized = tag.name.replace(" ", "_");
+                const sanitized = tag.name.replace(" ", "_");
                 tagDoc[sanitized] = ComputedField.MakeFunction(`(${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`);
             });
             extDoc.generatedTags = tagsList;
@@ -193,7 +193,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     private url(dataDoc: Doc) {
-        let data = Cast(Doc.GetProto(dataDoc)[fieldkey], ImageField);
+        const data = Cast(Doc.GetProto(dataDoc)[fieldkey], ImageField);
         return data ? data.url.href : undefined;
     }
 
@@ -215,14 +215,14 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
             }
         }
         else {
-            let fielddata = Cast(dataDoc.data, RichTextField);
-            fielddata ? data = fielddata[ToPlainText]() : data = "";
+            const fielddata = Cast(dataDoc.data, RichTextField, null);
+            data = fielddata?.Text || "";
         }
 
         // STEP 2. Upon receiving response from Text Cognitive Services, do additional processing on keywords.
         // Currently we are still using Cognitive Services for internal recommendations, but in the future this might not be necessary. 
 
-        let converter = async (results: any, data: string, isImage: boolean = false) => {
+        const converter = async (results: any, data: string, isImage: boolean = false) => {
             let keyterms = new List<string>(); // raw keywords
             let kp_string: string = ""; // keywords*frequency concatenated into a string. input into TF
             let highKP: string[] = [""]; // most frequent keyphrase
@@ -237,7 +237,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
             }
             else { // text processing
                 results.documents.forEach((doc: any) => {
-                    let keyPhrases = doc.keyPhrases; // returned by Cognitive Services
+                    const keyPhrases = doc.keyPhrases; // returned by Cognitive Services
                     keyPhrases.map((kp: string) => {
                         keyterms.push(kp);
                         const frequency = this.countFrequencies(kp, data); // frequency of keyphrase in paragraph
@@ -308,10 +308,10 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     private countFrequencies(keyphrase: string, paragraph: string) {
-        let data = paragraph.split(/ |\n/); // splits by new lines and spaces
-        let kp_array = keyphrase.split(" ");
-        let num_keywords = kp_array.length;
-        let par_length = data.length;
+        const data = paragraph.split(/ |\n/); // splits by new lines and spaces
+        const kp_array = keyphrase.split(" ");
+        const num_keywords = kp_array.length;
+        const par_length = data.length;
         let frequency = 0;
         // slides keyphrase windows across paragraph and checks if it matches with corresponding paragraph slice
         for (let i = 0; i <= par_length - num_keywords; i++) {
@@ -353,8 +353,8 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
 
     bingWebSearch = async (query: string) => {
         const converter = async (results: any) => {
-            let title_vals: string[] = [];
-            let url_vals: string[] = [];
+            const title_vals: string[] = [];
+            const url_vals: string[] = [];
             results.webPages.value.forEach((doc: any) => {
                 title_vals.push(doc.name);
                 url_vals.push(doc.url);
@@ -369,23 +369,23 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
      */
 
     arxivrequest = async (query: string) => {
-        let xhttp = new XMLHttpRequest();
-        let serveraddress = "http://export.arxiv.org/api";
+        const xhttp = new XMLHttpRequest();
+        const serveraddress = "http://export.arxiv.org/api";
         const maxresults = 5;
-        let endpoint = serveraddress + "/query?search_query=all:" + query + "&start=0&max_results=" + maxresults.toString();
-        let promisified = (resolve: any, reject: any) => {
+        const endpoint = serveraddress + "/query?search_query=all:" + query + "&start=0&max_results=" + maxresults.toString();
+        const promisified = (resolve: any, reject: any) => {
             xhttp.onreadystatechange = function () {
                 if (this.readyState === 4) {
-                    let result = xhttp.response;
-                    let xml = xhttp.responseXML;
+                    const result = xhttp.response;
+                    const xml = xhttp.responseXML;
                     console.log("arXiv Result: ", xml);
                     switch (this.status) {
                         case 200:
-                            let title_vals: string[] = [];
-                            let url_vals: string[] = [];
+                            const title_vals: string[] = [];
+                            const url_vals: string[] = [];
                             //console.log(result);
                             if (xml) {
-                                let titles = xml.getElementsByTagName("title");
+                                const titles = xml.getElementsByTagName("title");
                                 let counter = 1;
                                 if (titles && titles.length > 1) {
                                     while (counter <= maxresults) {
@@ -394,7 +394,7 @@ export class ClientRecommender extends React.Component<RecommenderProps> {
                                         counter++;
                                     }
                                 }
-                                let ids = xml.getElementsByTagName("id");
+                                const ids = xml.getElementsByTagName("id");
                                 counter = 1;
                                 if (ids && ids.length > 1) {
                                     while (counter <= maxresults) {
diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts
index 542ccf04d..3f3726621 100644
--- a/src/client/cognitive_services/CognitiveServices.ts
+++ b/src/client/cognitive_services/CognitiveServices.ts
@@ -208,7 +208,7 @@ export namespace CognitiveServices {
                     results.recognitionUnits && (results = results.recognitionUnits);
                 }
                 return results;
-            }
+            };
         }
 
         export interface AzureStrokeData {
@@ -232,13 +232,13 @@ export namespace CognitiveServices {
                 return data;
             },
             requester: async (apiKey: string, query: string) => {
-                let xhttp = new XMLHttpRequest();
-                let serverAddress = "https://api.cognitive.microsoft.com";
-                let endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query);
-                let promisified = (resolve: any, reject: any) => {
+                const xhttp = new XMLHttpRequest();
+                const serverAddress = "https://api.cognitive.microsoft.com";
+                const endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query);
+                const promisified = (resolve: any, reject: any) => {
                     xhttp.onreadystatechange = function () {
                         if (this.readyState === 4) {
-                            let result = xhttp.responseText;
+                            const result = xhttp.responseText;
                             switch (this.status) {
                                 case 200:
                                     return resolve(result);
@@ -266,7 +266,7 @@ export namespace CognitiveServices {
 
         export namespace Appliers {
             export const analyzer = async (query: string, converter: BingConverter) => {
-                let results = await ExecuteQuery(Service.Bing, Manager, query);
+                const results = await ExecuteQuery(Service.Bing, Manager, query);
                 console.log("Bing results: ", results);
                 const { title_vals, url_vals } = await converter(results);
                 return { title_vals, url_vals };
@@ -281,13 +281,13 @@ export namespace CognitiveServices {
                 return data;
             },
             requester: async (apiKey: string, query: string) => {
-                let xhttp = new XMLHttpRequest();
-                let serverAddress = "https://babel.hathitrust.org/cgi/htd/​";
-                let endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query);
-                let promisified = (resolve: any, reject: any) => {
+                const xhttp = new XMLHttpRequest();
+                const serverAddress = "https://babel.hathitrust.org/cgi/htd/​";
+                const endpoint = serverAddress + '/bing/v5.0/search?q=' + encodeURIComponent(query);
+                const promisified = (resolve: any, reject: any) => {
                     xhttp.onreadystatechange = function () {
                         if (this.readyState === 4) {
-                            let result = xhttp.responseText;
+                            const result = xhttp.responseText;
                             switch (this.status) {
                                 case 200:
                                     return resolve(result);
@@ -315,7 +315,7 @@ export namespace CognitiveServices {
 
         export namespace Appliers {
             export const analyzer = async (query: string, converter: BingConverter) => {
-                let results = await ExecuteQuery(Service.Bing, Manager, query);
+                const results = await ExecuteQuery(Service.Bing, Manager, query);
                 console.log("Bing results: ", results);
                 const { title_vals, url_vals } = await converter(results);
                 return { title_vals, url_vals };
@@ -337,9 +337,9 @@ export namespace CognitiveServices {
                 });
             },
             requester: async (apiKey: string, body: string, service: Service) => {
-                let serverAddress = "https://eastus.api.cognitive.microsoft.com";
-                let endpoint = serverAddress + "/text/analytics/v2.1/keyPhrases";
-                let sampleBody = {
+                const serverAddress = "https://eastus.api.cognitive.microsoft.com";
+                const endpoint = serverAddress + "/text/analytics/v2.1/keyPhrases";
+                const sampleBody = {
                     "documents": [
                         {
                             "language": "en",
@@ -348,7 +348,7 @@ export namespace CognitiveServices {
                         }
                     ]
                 };
-                let actualBody = body;
+                const actualBody = body;
                 const options = {
                     uri: endpoint,
                     body: actualBody,
@@ -368,7 +368,7 @@ export namespace CognitiveServices {
                 console.log("vectorizing...");
                 //keyterms = ["father", "king"];
 
-                let args = { method: 'POST', uri: Utils.prepend("/recommender"), body: { keyphrases: keyterms }, json: true };
+                const args = { method: 'POST', uri: Utils.prepend("/recommender"), body: { keyphrases: keyterms }, json: true };
                 await requestPromise.post(args).then(async (wordvecs) => {
                     if (wordvecs) {
                         const indices = Object.keys(wordvecs);
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index dbea8062e..96425ba30 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -266,7 +266,7 @@ export namespace Docs {
                 options: { _width: 40, _height: 40, borderRounding: "100%" },
             }],
             [DocumentType.RECOMMENDATION, {
-                layout: { view: RecommendationsBox },
+                layout: { view: RecommendationsBox, dataField: data },
                 options: { width: 200, height: 200 },
             }],
             [DocumentType.WEBCAM, {
@@ -365,6 +365,7 @@ export namespace Docs {
             const options = { title, type, baseProto: true, ...defaultOptions, ...(template.options || {}) };
             options.layout = layout.view.LayoutString(layout.dataField);
             const doc = Doc.assign(new Doc(prototypeId, true), { layoutKey: "layout", ...options });
+            doc.layout_keyValue = KeyValueBox.LayoutString("");
             return doc;
         }
 
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index a2fb7c11b..81ab95ff5 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -810,7 +810,7 @@ export class DashDocView {
                 this._dashSpan.style.height = this._outer.style.height = Math.max(20, dim[1]) + "px";
                 this._outer.style.border = "1px solid " + StrCast(finalLayout.color, (Cast(Doc.UserDoc().activeWorkspace, Doc, null).darkScheme ? "dimGray" : "lightGray"));
             }, { fireImmediately: true });
-            let doReactRender = (finalLayout: Doc, resolvedDataDoc: Doc) => {
+            const doReactRender = (finalLayout: Doc, resolvedDataDoc: Doc) => {
                 ReactDOM.unmountComponentAtNode(this._dashSpan);
                 ReactDOM.render(<DocumentView
                     Document={finalLayout}
@@ -844,7 +844,7 @@ export class DashDocView {
                         console.log(e);
                     }
                 }
-            }
+            };
             this._renderDisposer?.();
             this._renderDisposer = reaction(() => {
                 if (!Doc.AreProtosEqual(finalLayout, dashDoc)) {
@@ -939,7 +939,7 @@ export class DashFieldView {
         this._fieldCheck.style.backgroundColor = "rgba(155, 155, 155, 0.24)";
         this._fieldCheck.onchange = function (e: any) {
             self._dashDoc![self._fieldKey] = e.target.checked;
-        }
+        };
 
         this._fieldSpan = document.createElement("div");
         this._fieldSpan.id = Utils.GenerateGuid();
@@ -1095,12 +1095,12 @@ export class FootnoteView {
                     "Mod-y": () => redo(this.outerView.state, this.outerView.dispatch),
                     "Mod-b": toggleMark(schema.marks.strong)
                 }),
-                new Plugin({
-                    view(newView) {
-                        // TODO -- make this work with RichTextMenu
-                        // return FormattedTextBox.getToolTip(newView);
-                    }
-                })
+                    // new Plugin({
+                    //     view(newView) {
+                    //         // TODO -- make this work with RichTextMenu
+                    //         // return FormattedTextBox.getToolTip(newView);
+                    //     }
+                    // })
                 ],
 
             }),
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index e673189f9..c6fb9ad0b 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -39,7 +39,7 @@ library.add(faCheckCircle);
 library.add(faCloudUploadAlt);
 library.add(faSyncAlt);
 library.add(faShare);
-library.add(faPhotoVideo)
+library.add(faPhotoVideo);
 
 const cloud: IconProp = "cloud-upload-alt";
 const fetch: IconProp = "sync-alt";
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index 4a27425e8..2219966e5 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -4,10 +4,7 @@ import { observer } from 'mobx-react';
 import * as Autosuggest from 'react-autosuggest';
 import { ObjectField } from '../../new_fields/ObjectField';
 import { SchemaHeaderField } from '../../new_fields/SchemaHeaderField';
-import { ContextMenu } from './ContextMenu';
-import { ContextMenuProps } from './ContextMenuItem';
 import "./EditableView.scss";
-import { CollectionTreeView } from './collections/CollectionTreeView';
 
 export interface EditableProps {
     /**
@@ -88,12 +85,12 @@ export class EditableView extends React.Component<EditableProps> {
     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.key === "Tab") {
             e.stopPropagation();
-            this.finalizeEdit(e.currentTarget.value, e.shiftKey);
+            this.finalizeEdit(e.currentTarget.value, e.shiftKey, false);
             this.props.OnTab && this.props.OnTab(e.shiftKey);
         } else if (e.key === "Enter") {
             e.stopPropagation();
             if (!e.ctrlKey) {
-                this.finalizeEdit(e.currentTarget.value, e.shiftKey);
+                this.finalizeEdit(e.currentTarget.value, e.shiftKey, false);
             } else if (this.props.OnFillDown) {
                 this.props.OnFillDown(e.currentTarget.value);
                 this._editing = false;
@@ -123,10 +120,17 @@ export class EditableView extends React.Component<EditableProps> {
     }
 
     @action
-    private finalizeEdit(value: string, shiftDown: boolean) {
-        this._editing = false;
+    private finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean) {
         if (this.props.SetValue(value, shiftDown)) {
+            this._editing = false;
+            this.props.isEditingCallback?.(false);
+        } else {
+            this._editing = false;
             this.props.isEditingCallback?.(false);
+            !lostFocus && setTimeout(action(() => {
+                this._editing = true;
+                this.props.isEditingCallback?.(true);
+            }), 0);
         }
     }
 
@@ -151,7 +155,7 @@ export class EditableView extends React.Component<EditableProps> {
                         className: "editableView-input",
                         onKeyDown: this.onKeyDown,
                         autoFocus: true,
-                        onBlur: e => this.finalizeEdit(e.currentTarget.value, false),
+                        onBlur: e => this.finalizeEdit(e.currentTarget.value, false, true),
                         onPointerDown: this.stopPropagation,
                         onClick: this.stopPropagation,
                         onPointerUp: this.stopPropagation,
@@ -163,7 +167,7 @@ export class EditableView extends React.Component<EditableProps> {
                     defaultValue={this.props.GetValue()}
                     onKeyDown={this.onKeyDown}
                     autoFocus={true}
-                    onBlur={e => this.finalizeEdit(e.currentTarget.value, false)}
+                    onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true)}
                     onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation}
                     style={{ display: this.props.display, fontSize: this.props.fontSize }}
                 />;
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 1eff58948..ea60907f6 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -165,7 +165,7 @@ export default class GestureOverlay extends Touchable {
                 this._holdTimer = setTimeout(() => {
                     console.log("hold");
                     const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY);
-                    let pt: any = te.touches[te.touches.length - 1];
+                    const pt: any = te.touches[te.touches.length - 1];
                     if (nts.nt.length === 1 && pt.radiusX > 1 && pt.radiusY > 1) {
                         target?.dispatchEvent(
                             new CustomEvent<InteractionUtils.MultiTouchEvent<React.TouchEvent>>("dashOnTouchHoldStart",
@@ -589,7 +589,7 @@ export default class GestureOverlay extends Touchable {
                             for (const wR of wordResults) {
                                 console.log(wR);
                                 if (wR?.recognizedText) {
-                                    possibilities.push(wR?.recognizedText)
+                                    possibilities.push(wR?.recognizedText);
                                 }
                                 possibilities.push(...wR?.alternates?.map((a: any) => a.recognizedString));
                             }
@@ -743,16 +743,16 @@ export default class GestureOverlay extends Touchable {
                 {this.elements}
 
                 <div className="clipboardDoc-cont" style={{
-                    transform: `translate(${this._thumbX}px, ${(this._thumbY ?? 0) - this.height}px)`,
                     height: this.height,
                     width: this.height,
                     pointerEvents: this._clipboardDoc ? "unset" : "none",
                     touchAction: this._clipboardDoc ? "unset" : "none",
+                    transform: `translate(${this._thumbX}px, ${(this._thumbY || 0) - this.height} px)`,
                 }}>
                     {this._clipboardDoc}
                 </div>
                 <div className="filter-cont" style={{
-                    transform: `translate(${this._thumbX}px, ${(this._thumbY ?? 0) - this.height}px)`,
+                    transform: `translate(${this._thumbX}px, ${(this._thumbY || 0) - this.height}px)`,
                     height: this.height,
                     width: this.height,
                     pointerEvents: "none",
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index b59ee7a87..52801b570 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -106,8 +106,8 @@ export default class KeyManager {
     });
 
     private shift = async (keyname: string) => {
-        let stopPropagation = false;
-        let preventDefault = false;
+        const stopPropagation = false;
+        const preventDefault = false;
 
         switch (keyname) {
             // case "~":
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index a81e0cc2c..8d9be5980 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -521,7 +521,9 @@ export class MainView extends React.Component {
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     fieldKey={"data"}
+                    dropAction={"alias"}
                     annotationsKey={""}
+                    bringToFront={emptyFunction}
                     select={emptyFunction}
                     active={returnFalse}
                     isSelected={returnFalse}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index 262226bac..5ebba0abb 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -6,7 +6,7 @@ import "./RecommendationsBox.scss";
 import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc";
 import { DocumentIcon } from "./nodes/DocumentIcon";
 import { StrCast, NumCast } from "../../new_fields/Types";
-import { returnFalse, emptyFunction, returnEmptyString, returnOne } from "../../Utils";
+import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { ObjectField } from "../../new_fields/ObjectField";
 import { DocumentView } from "./nodes/DocumentView";
@@ -31,7 +31,7 @@ library.add(faBullseye, faLink);
 @observer
 export class RecommendationsBox extends React.Component<FieldViewProps> {
 
-    public static LayoutString(fieldKey?: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); }
+    public static LayoutString(fieldKey: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); }
 
     // @observable private _display: boolean = false;
     @observable private _pageX: number = 0;
@@ -48,17 +48,17 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
 
     @action
     private DocumentIcon(doc: Doc) {
-        let layoutresult = StrCast(doc.type);
+        const layoutresult = StrCast(doc.type);
         let renderDoc = doc;
         //let box: number[] = [];
         if (layoutresult.indexOf(DocumentType.COL) !== -1) {
             renderDoc = Doc.MakeDelegate(renderDoc);
         }
-        let returnXDimension = () => 150;
-        let returnYDimension = () => 150;
-        let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
+        const returnXDimension = () => 150;
+        const returnYDimension = () => 150;
+        const scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
         //let scale = () => 1;
-        let newRenderDoc = Doc.MakeAlias(renderDoc); ///   newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
+        const newRenderDoc = Doc.MakeAlias(renderDoc); ///   newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
         newRenderDoc.height = NumCast(this.props.Document.documentIconHeight);
         newRenderDoc.autoHeight = false;
         const docview = <div>
@@ -66,8 +66,8 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
                 fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1}
                 Document={newRenderDoc}
                 addDocument={returnFalse}
+                LibraryPath={emptyPath}
                 removeDocument={returnFalse}
-                ruleProvider={undefined}
                 ScreenToLocalTransform={Transform.Identity}
                 addDocTab={returnFalse}
                 pinToPres={returnFalse}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 83dbd3db3..996928cca 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -114,7 +114,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
         const templateName = StrCast(firstDoc.layoutKey, "layout").replace("layout_", "");
         const noteTypesDoc = Cast(Doc.UserDoc().noteTypes, Doc, null);
         const noteTypes = DocListCast(noteTypesDoc?.data);
-        const addedTypes = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data)
+        const addedTypes = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data);
         const layout = Doc.Layout(firstDoc);
         const templateMenu: Array<JSX.Element> = [];
         this.props.templates.forEach((checked, template) =>
@@ -170,8 +170,8 @@ Scripting.addGlobal(function switchView(doc: Doc, template: Doc) {
     if (template.dragFactory) {
         template = Cast(template.dragFactory, Doc, null);
     }
-    let templateTitle = StrCast(template?.title);
-    return templateTitle && DocumentView.makeCustomViewClicked(doc, undefined, Docs.Create.FreeformDocument, templateTitle, template)
+    const templateTitle = StrCast(template?.title);
+    return templateTitle && DocumentView.makeCustomViewClicked(doc, undefined, Docs.Create.FreeformDocument, templateTitle, template);
 });
 
 Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitlte: string) {
@@ -180,4 +180,4 @@ Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitlte: st
     const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title);
     return StrCast(firstDoc.layoutKey) === "layout_" + template ? 'check' : 'unchecked';
     // return SelectionManager.SelectedDocuments().some(view => StrCast(view.props.Document.layoutKey) === "layout_" + template) ? 'check' : 'unchecked'
-})
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/src/client/views/TouchScrollableMenu.tsx b/src/client/views/TouchScrollableMenu.tsx
index 4bda0818e..969605be9 100644
--- a/src/client/views/TouchScrollableMenu.tsx
+++ b/src/client/views/TouchScrollableMenu.tsx
@@ -44,7 +44,7 @@ export default class TouchScrollableMenu extends React.Component<TouchScrollable
                 <div className="shadow" style={{ height: `calc(100% - 25px - ${this.selectedIndex * 25}px)` }}>
                 </div>
             </div>
-        )
+        );
     }
 }
 
@@ -54,6 +54,6 @@ export class TouchScrollableMenuItem extends React.Component<TouchScrollableMenu
             <div className="menuItem-cont" onClick={this.props.onClick}>
                 {this.props.text}
             </div>
-        )
+        );
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 2ee39bc0d..4e1e76f39 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -513,7 +513,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                         dragData.dropAction = doc.dropAction as dropActionType;
                         DragManager.StartDocumentDrag([gearSpan], dragData, e.clientX, e.clientY);
                     }
-                }
+                };
                 let rendered = false;
                 tab.buttonDisposer = reaction(() => ((view: Opt<DocumentView>) => view ? [view] : [])(DocumentManager.Instance.getDocumentView(doc)),
                     (views) => {
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 79b5d7bb7..f124fe21b 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -157,6 +157,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             Document: this.props.rowProps.original,
             DataDoc: this.props.rowProps.original,
             LibraryPath: [],
+            dropAction: "alias",
+            bringToFront: emptyFunction,
             fieldKey: this.props.rowProps.column.id as string,
             ContainingCollectionView: this.props.CollectionView,
             ContainingCollectionDoc: this.props.CollectionView && this.props.CollectionView.props.Document,
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index a4502cced..981438513 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -51,8 +51,7 @@ const columnTypes: Map<string, ColumnType> = new Map([
 
 @observer
 export class CollectionSchemaView extends CollectionSubView(doc => doc) {
-    private _mainCont?: HTMLDivElement;
-    private _startPreviewWidth = 0;
+    private _previewCont?: HTMLDivElement;
     private DIVIDER_WIDTH = 4;
 
     @observable previewDoc: Doc | undefined = undefined;
@@ -64,7 +63,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     @computed get borderWidth() { return Number(COLLECTION_BORDER_WIDTH); }
 
     private createTarget = (ele: HTMLDivElement) => {
-        this._mainCont = ele;
+        this._previewCont = ele;
         super.CreateDropTarget(ele);
     }
 
@@ -81,12 +80,11 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     }
 
     onDividerDown = (e: React.PointerEvent) => {
-        this._startPreviewWidth = this.previewWidth();
         setupMoveUpEvents(this, e, this.onDividerMove, emptyFunction, action(() => this.toggleExpander()));
     }
     @action
     onDividerMove = (e: PointerEvent, down: number[], delta: number[]) => {
-        const nativeWidth = this._mainCont!.getBoundingClientRect();
+        const nativeWidth = this._previewCont!.getBoundingClientRect();
         const minWidth = 40;
         const maxWidth = 1000;
         const movedWidth = this.props.ScreenToLocalTransform().transformDirection(nativeWidth.right - e.clientX, 0)[0];
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 086e0842e..076dd3629 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -106,7 +106,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                 fields.delete(header);
                 sectionHeaders.splice(sectionHeaders.indexOf(header), 1);
                 changed = true;
-            })
+            });
         }
         changed && setTimeout(action(() => { if (this.sectionHeaders) { this.sectionHeaders.length = 0; this.sectionHeaders.push(...sectionHeaders); } }), 0);
         return fields;
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 646b433bf..0a48c95e4 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -131,7 +131,8 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         const maxHeading = this.props.docList.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0);
         const heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
         newDoc.heading = heading;
-        return this.props.parent.props.addDocument(newDoc);
+        this.props.parent.props.addDocument(newDoc);
+        return false;
     }
 
     @action
diff --git a/src/client/views/collections/CollectionStaffView.tsx b/src/client/views/collections/CollectionStaffView.tsx
index 8c7e113b2..5b9a69bf7 100644
--- a/src/client/views/collections/CollectionStaffView.tsx
+++ b/src/client/views/collections/CollectionStaffView.tsx
@@ -1,22 +1,20 @@
 import { CollectionSubView } from "./CollectionSubView";
-import { Transform } from "../../util/Transform";
 import React = require("react");
 import { computed, action, IReactionDisposer, reaction, runInAction, observable } from "mobx";
-import { Doc } from "../../../new_fields/Doc";
 import { NumCast } from "../../../new_fields/Types";
 import "./CollectionStaffView.scss";
 import { observer } from "mobx-react";
 
 @observer
 export class CollectionStaffView extends CollectionSubView(doc => doc) {
-    private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(0, -this._mainCont.current!.scrollTop);
-    private _mainCont = React.createRef<HTMLDivElement>();
     private _reactionDisposer: IReactionDisposer | undefined;
     @observable private _staves = NumCast(this.props.Document.staves);
 
+    componentWillUnmount() {
+        this._reactionDisposer?.();
+    }
     componentDidMount = () => {
-        this._reactionDisposer = reaction(
-            () => NumCast(this.props.Document.staves),
+        this._reactionDisposer = reaction(() => NumCast(this.props.Document.staves),
             (staves) => runInAction(() => this._staves = staves)
         );
 
@@ -47,7 +45,7 @@ export class CollectionStaffView extends CollectionSubView(doc => doc) {
     }
 
     render() {
-        return <div className="collectionStaffView" ref={this._mainCont}>
+        return <div className="collectionStaffView">
             {this.staves}
             {this.addStaffButton}
         </div>;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 88cfde0b6..70927cf22 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,5 +1,4 @@
 import { action, computed, IReactionDisposer, reaction } from "mobx";
-import * as rp from 'request-promise';
 import CursorField from "../../../new_fields/CursorField";
 import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
@@ -107,7 +106,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
             const { Document, DataDoc } = this.props;
             const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.annotationsKey ? DataDoc : undefined, doc)).filter(pair => pair.layout);
-            return validPairs.map(({ data, layout }) => ({ data, layout: layout! })); // this mapping is a bit of a hack to coerce types
+            return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
         }
         get childDocList() {
             return Cast(this.dataField, listSpec(Doc));
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 64832506b..0d2207b27 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -146,7 +146,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
                 back
             </button>
             <EditableView {...newEditableViewProps} display={"inline"} menuCallback={this.menuCallback} />
-        </div>
+        </div>;
     }
 
     render() {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index edb9fd930..b6ce2f3a9 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -299,7 +299,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
     get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
         const { Document, DataDoc } = this.props;
         const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, DataDoc, doc)).filter(pair => pair.layout);
-        return validPairs.map(({ data, layout }) => ({ data, layout: layout! })); // this mapping is a bit of a hack to coerce types
+        return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
     }
     get childDocList() {
         return Cast(this.dataField, listSpec(Doc));
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 960c6554e..2d565d9db 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -267,10 +267,10 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
         const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled";
         if (collapsed) return null;
         switch (this.props.type) {
-            case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
-            case CollectionViewType.Masonry: return (<CollectionStackingViewChrome key="collchrome" CollectionView={this.props.CollectionView} type={this.props.type} />);
+            case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
+            case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
+            case CollectionViewType.Tree: return (<CollectionTreeViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
+            case CollectionViewType.Masonry: return (<CollectionStackingViewChrome key="collchrome" PanelWidth={this.props.PanelWidth} CollectionView={this.props.CollectionView} type={this.props.type} />);
             default: return null;
         }
     }
@@ -355,7 +355,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                 immediate: (source: Doc[]) => Doc.setChildLayout(this.target, source?.[0]),
                 initialize: emptyFunction,
             };
-            DragManager.StartButtonDrag([this._viewRef.current!], c.script, c.title,
+            DragManager.StartButtonDrag([this._viewRef.current!], c.script, StrCast(c.title),
                 { target: this.props.CollectionView.props.Document }, c.params, c.initialize, e.clientX, e.clientY);
             return true;
         }, emptyFunction, emptyFunction);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index a1ec0daef..49ca024a2 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -1,4 +1,4 @@
-import { computed, IReactionDisposer } from "mobx";
+import { computed } from "mobx";
 import { observer } from "mobx-react";
 import { Doc } from "../../../../new_fields/Doc";
 import { Id } from "../../../../new_fields/FieldSymbols";
@@ -10,67 +10,9 @@ import React = require("react");
 import { Utils, emptyFunction } from "../../../../Utils";
 import { SelectionManager } from "../../../util/SelectionManager";
 import { DocumentType } from "../../../documents/DocumentTypes";
-import { StrCast } from "../../../../new_fields/Types";
 
 @observer
 export class CollectionFreeFormLinksView extends React.Component {
-
-    _brushReactionDisposer?: IReactionDisposer;
-    componentDidMount() {
-        // this._brushReactionDisposer = reaction(
-        //     () => {
-        //         let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
-        //         return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) };
-        //     },
-        //     () => {
-        //         let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
-        //         let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : [];
-        //         views.forEach((dstDoc, i) => {
-        //             views.forEach((srcDoc, j) => {
-        //                 let dstTarg = dstDoc;
-        //                 let srcTarg = srcDoc;
-        //                 let x1 = NumCast(srcDoc.x);
-        //                 let x2 = NumCast(dstDoc.x);
-        //                 let x1w = NumCast(srcDoc.width, -1);
-        //                 let x2w = NumCast(dstDoc.width, -1);
-        //                 if (x1w < 0 || x2w < 0 || i === j) { }
-        //                 else {
-        //                     let findBrush = (field: (Doc | Promise<Doc>)[]) => field.findIndex(brush => {
-        //                         let bdocs = brush instanceof Doc ? Cast(brush.brushingDocs, listSpec(Doc), []) : undefined;
-        //                         return bdocs && bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false;
-        //                     });
-        //                     let brushAction = (field: (Doc | Promise<Doc>)[]) => {
-        //                         let found = findBrush(field);
-        //                         if (found !== -1) {
-        //                             field.splice(found, 1);
-        //                         }
-        //                     };
-        //                     if (Math.abs(x1 + x1w - x2) < 20) {
-        //                         let linkDoc: Doc = new Doc();
-        //                         linkDoc.title = "Histogram Brush";
-        //                         linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title);
-        //                         linkDoc.brushingDocs = new List([dstTarg, srcTarg]);
-
-        //                         brushAction = (field: (Doc | Promise<Doc>)[]) => {
-        //                             if (findBrush(field) === -1) {
-        //                                 field.push(linkDoc);
-        //                             }
-        //                         };
-        //                     }
-        //                     if (dstTarg.brushingDocs === undefined) dstTarg.brushingDocs = new List<Doc>();
-        //                     if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List<Doc>();
-        //                     let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []);
-        //                     let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []);
-        //                     brushAction(dstBrushDocs);
-        //                     brushAction(srcBrushDocs);
-        //                 }
-        //             });
-        //         });
-        //     });
-    }
-    componentWillUnmount() {
-        this._brushReactionDisposer && this._brushReactionDisposer();
-    }
     @computed
     get uniqueConnections() {
         const connections = DocumentManager.Instance.LinkedDocumentViews.reduce((drawnPairs, connection) => {
@@ -101,4 +43,60 @@ export class CollectionFreeFormLinksView extends React.Component {
             {this.props.children}
         </div>;
     }
+    // _brushReactionDisposer?: IReactionDisposer;
+    // componentDidMount() {
+    //     this._brushReactionDisposer = reaction(
+    //         () => {
+    //             let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
+    //             return { doclist: doclist ? doclist : [], xs: doclist.map(d => d.x) };
+    //         },
+    //         () => {
+    //             let doclist = DocListCast(this.props.Document[this.props.fieldKey]);
+    //             let views = doclist ? doclist.filter(doc => StrCast(doc.backgroundLayout).indexOf("istogram") !== -1) : [];
+    //             views.forEach((dstDoc, i) => {
+    //                 views.forEach((srcDoc, j) => {
+    //                     let dstTarg = dstDoc;
+    //                     let srcTarg = srcDoc;
+    //                     let x1 = NumCast(srcDoc.x);
+    //                     let x2 = NumCast(dstDoc.x);
+    //                     let x1w = NumCast(srcDoc.width, -1);
+    //                     let x2w = NumCast(dstDoc.width, -1);
+    //                     if (x1w < 0 || x2w < 0 || i === j) { }
+    //                     else {
+    //                         let findBrush = (field: (Doc | Promise<Doc>)[]) => field.findIndex(brush => {
+    //                             let bdocs = brush instanceof Doc ? Cast(brush.brushingDocs, listSpec(Doc), []) : undefined;
+    //                             return bdocs && bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false;
+    //                         });
+    //                         let brushAction = (field: (Doc | Promise<Doc>)[]) => {
+    //                             let found = findBrush(field);
+    //                             if (found !== -1) {
+    //                                 field.splice(found, 1);
+    //                             }
+    //                         };
+    //                         if (Math.abs(x1 + x1w - x2) < 20) {
+    //                             let linkDoc: Doc = new Doc();
+    //                             linkDoc.title = "Histogram Brush";
+    //                             linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title);
+    //                             linkDoc.brushingDocs = new List([dstTarg, srcTarg]);
+
+    //                             brushAction = (field: (Doc | Promise<Doc>)[]) => {
+    //                                 if (findBrush(field) === -1) {
+    //                                     field.push(linkDoc);
+    //                                 }
+    //                             };
+    //                         }
+    //                         if (dstTarg.brushingDocs === undefined) dstTarg.brushingDocs = new List<Doc>();
+    //                         if (srcTarg.brushingDocs === undefined) srcTarg.brushingDocs = new List<Doc>();
+    //                         let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc), []);
+    //                         let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc), []);
+    //                         brushAction(dstBrushDocs);
+    //                         brushAction(srcBrushDocs);
+    //                     }
+    //                 });
+    //             });
+    //         });
+    // }
+    // componentWillUnmount() {
+    //     this._brushReactionDisposer?.();
+    // }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 0f94bffd6..276a49570 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -4,7 +4,7 @@ import { Doc, DocListCast, DataSym, WidthSym, HeightSym } from "../../../../new_
 import { InkField, InkData } from "../../../../new_fields/InkField";
 import { List } from "../../../../new_fields/List";
 import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField";
-import { Cast, NumCast, FieldValue } from "../../../../new_fields/Types";
+import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types";
 import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
 import { Utils } from "../../../../Utils";
 import { Docs, DocUtils } from "../../../documents/Documents";
@@ -107,7 +107,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             });
         } else if (!e.ctrlKey) {
             FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout ? e.key : "";
-            let tbox = Docs.Create.TextDocument("", { _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" });
+            const tbox = Docs.Create.TextDocument("", { _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" });
             const template = FormattedTextBox.DefaultLayout;
             if (template instanceof Doc) {
                 tbox._width = NumCast(template._width);
diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx
index de0b509eb..f1bf7cfcf 100644
--- a/src/client/views/nodes/ButtonBox.tsx
+++ b/src/client/views/nodes/ButtonBox.tsx
@@ -82,7 +82,7 @@ export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(Butt
                 style={{ boxShadow: this.Document.opacity === 0 ? undefined : StrCast(this.Document.boxShadow, "") }}>
                 <div className="buttonBox-mainButton" style={{
                     background: this.Document.backgroundColor, color: this.Document.color || "inherit",
-                    fontSize: this.Document.fontSize, letterSpacing: this.Document.letterSpacing || "", textTransform: this.Document.textTransform || ""
+                    fontSize: this.Document.fontSize, letterSpacing: this.Document.letterSpacing || "", textTransform: (this.Document.textTransform as any) || ""
                 }} >
                     <div className="buttonBox-mainButtonCenter">
                         {(this.Document.text || this.Document.title)}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 8632f9c9a..9494a4bc4 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -22,6 +22,7 @@ interface ContentFittingDocumentViewProps {
     childDocs?: Doc[];
     renderDepth: number;
     fitToBox?: boolean;
+    layoutKey?: string;
     dropAction?: dropActionType;
     PanelWidth: () => number;
     PanelHeight: () => number;
@@ -88,6 +89,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         LayoutDoc={this.props.LayoutDoc}
                         LibraryPath={this.props.LibraryPath}
                         fitToBox={this.props.fitToBox}
+                        layoutKey={this.props.layoutKey}
                         dropAction={this.props.dropAction}
                         onClick={this.props.onClick}
                         backgroundColor={this.props.backgroundColor}
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index 978480142..655dc5de2 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -117,13 +117,14 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
                 DataDocument={undefined}
                 LibraryPath={emptyPath}
                 fitToBox={this.props.fitToBox}
+                layoutKey={StrCast(this.props.Document.childLayoutKey)}
                 addDocument={this.props.addDocument}
                 moveDocument={this.props.moveDocument}
                 removeDocument={this.props.removeDocument}
                 addDocTab={this.props.addDocTab}
                 pinToPres={this.props.pinToPres}
                 getTransform={this.getTransform}
-                renderDepth={this.props.renderDepth + 1} // bcz: need a forceActive prop here ... not the same as renderDepth = 0
+                renderDepth={this.props.renderDepth + 1}
                 PanelWidth={this.pwidth}
                 PanelHeight={this.pheight}
                 focus={this.props.focus}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 8be6ab151..c250da874 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -64,15 +64,18 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         TraceMobx();
         if (!this.layoutDoc) return "<p>awaiting layout</p>";
         const layout = Cast(this.layoutDoc[StrCast(this.layoutDoc.layoutKey, this.layoutDoc === this.props.Document ? this.props.layoutKey : "layout")], "string");
-        if (layout === undefined) {
-            return this.props.Document.data ?
-                "<FieldView {...props} fieldKey='data' />" :
-                KeyValueBox.LayoutString(this.layoutDoc.proto ? "proto" : "");
-        } else if (typeof layout === "string") {
-            return layout;
-        } else {
-            return "<p>Loading layout</p>";
-        }
+        if (this.props.layoutKey === "layout_keyValue") {
+            return StrCast(this.props.Document.layout_keyValue, KeyValueBox.LayoutString("data"));
+        } else
+            if (layout === undefined) {
+                return this.props.Document.data ?
+                    "<FieldView {...props} fieldKey='data' />" :
+                    KeyValueBox.LayoutString(this.layoutDoc.proto ? "proto" : "");
+            } else if (typeof layout === "string") {
+                return layout;
+            } else {
+                return "<p>Loading layout</p>";
+            }
     }
 
     get dataDoc() {
@@ -81,7 +84,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
     }
     get layoutDoc() {
         const params = StrCast(this.props.Document.PARAMS);
-        return Doc.expandTemplateLayout(this.props.LayoutDoc?.() || Doc.Layout(this.props.Document), this.props.Document, params ? "(" + params + ")" : this.props.layoutKey);
+        const template: Doc = this.props.LayoutDoc?.() || 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, params ? "(" + params + ")" : this.props.layoutKey);
     }
 
     CreateBindings(): JsxBindings {
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 93bda6d02..3d59ea61a 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -61,6 +61,8 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             fieldKey: this.props.keyName,
             isSelected: returnFalse,
             select: emptyFunction,
+            dropAction:"alias",
+            bringToFront:emptyFunction,
             renderDepth: 1,
             active: returnFalse,
             whenActiveChanged: emptyFunction,
diff --git a/src/client/views/nodes/RadialMenuItem.tsx b/src/client/views/nodes/RadialMenuItem.tsx
index fdc732d3f..bd5b3bff4 100644
--- a/src/client/views/nodes/RadialMenuItem.tsx
+++ b/src/client/views/nodes/RadialMenuItem.tsx
@@ -44,12 +44,12 @@ export class RadialMenuItem extends React.Component<RadialMenuProps> {
 
     setcircle() {
         let circlemin = 0;
-        let circlemax = 1
+        let circlemax = 1;
         this.props.min ? circlemin = this.props.min : null;
         this.props.max ? circlemax = this.props.max : null;
         if (document.getElementById("myCanvas") !== null) {
-            var c: any = document.getElementById("myCanvas");
-            let color = "white"
+            const c: any = document.getElementById("myCanvas");
+            let color = "white";
             switch (circlemin % 3) {
                 case 1:
                     color = "#c2c2c5";
@@ -70,38 +70,38 @@ export class RadialMenuItem extends React.Component<RadialMenuProps> {
 
             }
             if (c.getContext) {
-                var ctx = c.getContext("2d");
+                const ctx = c.getContext("2d");
                 ctx.beginPath();
                 ctx.arc(150, 150, 150, (circlemin / circlemax) * 2 * Math.PI, ((circlemin + 1) / circlemax) * 2 * Math.PI);
                 ctx.arc(150, 150, 50, ((circlemin + 1) / circlemax) * 2 * Math.PI, (circlemin / circlemax) * 2 * Math.PI, true);
                 ctx.fillStyle = color;
-                ctx.fill()
+                ctx.fill();
             }
         }
     }
 
     calculatorx() {
         let circlemin = 0;
-        let circlemax = 1
+        let circlemax = 1;
         this.props.min ? circlemin = this.props.min : null;
         this.props.max ? circlemax = this.props.max : null;
-        let avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2;
-        let degrees = 360 * avg;
-        let x = 100 * Math.cos(degrees * Math.PI / 180);
-        let y = -125 * Math.sin(degrees * Math.PI / 180);
+        const avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2;
+        const degrees = 360 * avg;
+        const x = 100 * Math.cos(degrees * Math.PI / 180);
+        const y = -125 * Math.sin(degrees * Math.PI / 180);
         return x;
     }
 
     calculatory() {
 
         let circlemin = 0;
-        let circlemax = 1
+        let circlemax = 1;
         this.props.min ? circlemin = this.props.min : null;
         this.props.max ? circlemax = this.props.max : null;
-        let avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2;
-        let degrees = 360 * avg;
-        let x = 125 * Math.cos(degrees * Math.PI / 180);
-        let y = -100 * Math.sin(degrees * Math.PI / 180);
+        const avg = ((circlemin / circlemax) + ((circlemin + 1) / circlemax)) / 2;
+        const degrees = 360 * avg;
+        const x = 125 * Math.cos(degrees * Math.PI / 180);
+        const y = -100 * Math.sin(degrees * Math.PI / 180);
         return y;
     }
 
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 548066f1c..7c58a5148 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -142,7 +142,7 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
     toggleRecording = action(async () => {
         this._screenCapture = !this._screenCapture;
         this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
-    })
+    });
 
     private get uIButtons() {
         return (<div className="screenshotBox-uiButtons">
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 591864f2c..838fbefb1 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -63,7 +63,7 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
                 this.layoutDoc._height = NumCast(this.layoutDoc._width) / youtubeaspect;
             }
         } else if (field?.url) {
-            var result = await WebRequest.get(Utils.CorsProxy(field.url.href));
+            const result = await WebRequest.get(Utils.CorsProxy(field.url.href));
             this.dataDoc.text = htmlToText.fromString(result.content);
         }
 
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index a1e7d5c2a..cc187cd67 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -238,7 +238,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
         this._pdfViewer.currentScaleValue = this._zoomed = 1;
         this.gotoPage(this.Document.curPage || 1);
         document.removeEventListener("pagesinit", this.pagesinit);
-    })
+    });
 
     createPdfViewer() {
         if (!this._mainCont.current) { // bcz: I don't think this is ever triggered or needed
diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx
index 9c339e986..1d52ba38f 100644
--- a/src/client/views/webcam/DashWebRTCVideo.tsx
+++ b/src/client/views/webcam/DashWebRTCVideo.tsx
@@ -36,7 +36,7 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
       */
     private onEnterKeyDown = (e: React.KeyboardEvent) => {
         if (e.keyCode === 13) {
-            let submittedTitle = this.roomText!.value;
+            const submittedTitle = this.roomText!.value;
             this.roomText!.value = "";
             this.roomText!.blur();
             initialize(submittedTitle, this.changeUILook);
@@ -56,7 +56,7 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
     }
 
     render() {
-        let content =
+        const content =
             <div className="webcam-cont" style={{ width: "100%", height: "100%" }}>
                 <div className="webcam-header">DashWebRTC</div>
                 <input id="roomName" type="text" placeholder="Enter room name" ref={(e) => this.roomText = e!} onKeyDown={this.onEnterKeyDown} />
@@ -72,8 +72,8 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
                 </div>
             </div >;
 
-        let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
-        let classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
+        const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
+        const classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
 
 
         return (
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 5d3a517ae..1d2d57b96 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -199,6 +199,8 @@ export default class MobileInterface extends React.Component {
                         DataDoc={undefined}
                         LibraryPath={emptyPath}
                         fieldKey={""}
+                        dropAction={"alias"}
+                        bringToFront={emptyFunction }
                         addDocTab={returnFalse}
                         pinToPres={emptyFunction}
                         PanelHeight={() => window.innerHeight}
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 25b526168..440f13d6b 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -353,7 +353,7 @@ export namespace Doc {
     // and returns the document who's proto is undefined or whose proto is marked as a base prototype ('isPrototype').
     export function GetProto(doc: Doc): Doc {
         if (doc instanceof Promise) {
-            console.log("GetProto: error: got Promise insead of Doc")
+            console.log("GetProto: error: got Promise insead of Doc");
         }
         const proto = doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc));
         return proto === doc ? proto : Doc.GetProto(proto);
@@ -697,7 +697,7 @@ export namespace Doc {
     // the document containing the view layout information - will be the Document itself unless the Document has
     // a layout field or 'layout' is given.  
     export function Layout(doc: Doc, layout?: Doc): Doc {
-        const overrideLayout = layout && Cast(doc["data-layout[" + layout[Id] + "]"], Doc, null);
+        const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, "data")}-layout[` + layout[Id] + "]"], Doc, null);
         return overrideLayout || doc[LayoutSym] || doc;
     }
     export function SetLayout(doc: Doc, layout: Doc | string) { doc[StrCast(doc.layoutKey, "layout")] = layout; }
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 3a1fd41f8..8c719ccd8 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -12,7 +12,7 @@ function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
 }
 
-let tracing = false;
+const tracing = false;
 export function TraceMobx() {
     tracing && trace();
 }
diff --git a/src/server/DashSession/Session/agents/applied_session_agent.ts b/src/server/DashSession/Session/agents/applied_session_agent.ts
index 46c9e22ed..12064668b 100644
--- a/src/server/DashSession/Session/agents/applied_session_agent.ts
+++ b/src/server/DashSession/Session/agents/applied_session_agent.ts
@@ -44,7 +44,7 @@ export abstract class AppliedSessionAgent {
         if (!this.launched) {
             this.launched = true;
             if (isMaster) {
-                this.sessionMonitorRef = Monitor.Create()
+                this.sessionMonitorRef = Monitor.Create();
                 const sessionKey = await this.initializeMonitor(this.sessionMonitorRef);
                 this.sessionMonitorRef.finalize(sessionKey);
             } else {
diff --git a/src/server/DashSession/Session/agents/monitor.ts b/src/server/DashSession/Session/agents/monitor.ts
index 6f8d25614..ee8afee65 100644
--- a/src/server/DashSession/Session/agents/monitor.ts
+++ b/src/server/DashSession/Session/agents/monitor.ts
@@ -167,7 +167,7 @@ export class Monitor extends IPCMessageReceiver {
      * and pass down any variables the pertinent to the child processes as environment variables.
      */
     private loadAndValidateConfiguration = (): Configuration => {
-        let config: Configuration;
+        let config: Configuration | undefined;
         try {
             console.log(this.timestamp(), cyan("validating configuration..."));
             config = JSON.parse(readFileSync('./session.config.json', 'utf8'));
diff --git a/src/server/DashSession/Session/agents/promisified_ipc_manager.ts b/src/server/DashSession/Session/agents/promisified_ipc_manager.ts
index 9f0db8330..feff568e1 100644
--- a/src/server/DashSession/Session/agents/promisified_ipc_manager.ts
+++ b/src/server/DashSession/Session/agents/promisified_ipc_manager.ts
@@ -35,8 +35,8 @@ export type MessageHandler<T = any> = (args: T) => (any | Promise<any>);
  * When a message is emitted, it is embedded with private metadata
  * to facilitate the resolution of promises, etc.
  */
-interface InternalMessage extends Message { metadata: Metadata }
-interface Metadata { isResponse: boolean; id: string }
+interface InternalMessage extends Message { metadata: Metadata; }
+interface Metadata { isResponse: boolean; id: string; }
 type InternalMessageHandler = (message: InternalMessage) => (any | Promise<any>);
 
 /**
@@ -133,7 +133,7 @@ export class PromisifiedIPCManager {
         Object.keys(pendingMessages).forEach(id => {
             const error: ErrorLike = { name: "ManagerDestroyed", message: "The IPC manager was destroyed before the response could be returned." };
             const message: InternalMessage = { name: pendingMessages[id], args: { error }, metadata: { id, isResponse: true } };
-            this.target.send?.(message)
+            this.target.send?.(message);
         });
         this.pendingMessages = {};
     }
diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts
index c5dc22912..9f9fc9619 100644
--- a/src/server/Websocket/Websocket.ts
+++ b/src/server/Websocket/Websocket.ts
@@ -55,8 +55,8 @@ export namespace WebSocket {
             socket.on('create or join', function (room) {
                 console.log('Received request to create or join room ' + room);
 
-                var clientsInRoom = socket.adapter.rooms[room];
-                var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
+                const clientsInRoom = socket.adapter.rooms[room];
+                const numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
                 console.log('Room ' + room + ' now has ' + numClients + ' client(s)');
 
                 if (numClients === 0) {
@@ -76,8 +76,8 @@ export namespace WebSocket {
             });
 
             socket.on('ipaddr', function () {
-                var ifaces = networkInterfaces();
-                for (var dev in ifaces) {
+                const ifaces = networkInterfaces();
+                for (const dev in ifaces) {
                     ifaces[dev].forEach(function (details) {
                         if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
                             socket.emit('ipaddr', details.address);
diff --git a/src/server/database.ts b/src/server/database.ts
index 055f04c49..fc91ff3a2 100644
--- a/src/server/database.ts
+++ b/src/server/database.ts
@@ -328,7 +328,7 @@ export namespace Database {
 
         export const LogUpload = async (information: Upload.ImageInformation) => {
             const bundle = {
-                _id: Utils.GenerateDeterministicGuid(String(information.contentSize!)),
+                _id: Utils.GenerateDeterministicGuid(String(information.contentSize)),
                 ...information
             };
             return Instance.insert(bundle, AuxiliaryCollections.GooglePhotosUploadHistory);
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index 7b2228831..1150118f7 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -123,7 +123,7 @@ function registerCorsProxy(server: express.Express) {
     const headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/;
     server.use("/corsProxy", (req, res) => {
 
-        let requrl = decodeURIComponent(req.url.substring(1));
+        const requrl = decodeURIComponent(req.url.substring(1));
         const referer = req.headers.referer ? decodeURIComponent(req.headers.referer) : "";
         // cors weirdness here... 
         // if the referer is a cors page and the cors() route (I think) redirected to /corsProxy/<path> and the requested url path was relative, 
-- 
cgit v1.2.3-70-g09d2

