From be02a5529f472507512a127cd8de5cde300eff88 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 11 Feb 2020 14:19:56 -0500
Subject: added ability to pass a Layout as a prop.  changed presentations to
 use layout props.  fixed creating a template for just an empty collection
 representing one field.

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

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

diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index bd1b6166f..671f5b96e 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -2,7 +2,7 @@ import React = require("react");
 import { action, computed } from "mobx";
 import { observer } from "mobx-react";
 import "react-table/react-table.css";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, Opt } from "../../../new_fields/Doc";
 import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
 import { NumCast, StrCast } from "../../../new_fields/Types";
 import { emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
@@ -18,6 +18,7 @@ import { TraceMobx } from "../../../new_fields/util";
 interface ContentFittingDocumentViewProps {
     Document?: Doc;
     DataDocument?: Doc;
+    LayoutDoc?: () => Opt<Doc>;
     LibraryPath: Doc[];
     childDocs?: Doc[];
     renderDepth: number;
@@ -42,7 +43,7 @@ interface ContentFittingDocumentViewProps {
 @observer
 export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
     public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
-    private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); }
+    private get layoutDoc() { return this.props.Document && (this.props.LayoutDoc?.() || Doc.Layout(this.props.Document)); }
     private get nativeWidth() { return NumCast(this.layoutDoc?._nativeWidth, this.props.PanelWidth()); }
     private get nativeHeight() { return NumCast(this.layoutDoc?._nativeHeight, this.props.PanelHeight()); }
     @computed get scaling() {
@@ -97,6 +98,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                     <DocumentView {...this.props}
                         Document={this.props.Document}
                         DataDoc={this.props.DataDocument}
+                        LayoutDoc={this.props.LayoutDoc}
                         LibraryPath={this.props.LibraryPath}
                         fitToBox={this.props.fitToBox}
                         onClick={this.props.onClick}
-- 
cgit v1.2.3-70-g09d2


From 553fb2a11aa638c35192a1a2f7da99729867e542 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 13 Feb 2020 22:30:32 -0500
Subject: starting a broad cleanup of code.  trying to make standard doc field
 names be more regular

---
 src/client/documents/Documents.ts                  | 15 ++--
 src/client/util/DragManager.ts                     |  1 -
 src/client/util/RichTextRules.ts                   |  3 +-
 src/client/views/MainView.tsx                      |  7 +-
 .../views/collections/CollectionCarouselView.scss  |  1 +
 .../views/collections/CollectionCarouselView.tsx   |  1 -
 .../views/collections/CollectionLinearView.tsx     | 10 +--
 src/client/views/collections/CollectionSubView.tsx |  5 +-
 .../views/collections/CollectionTreeView.tsx       | 35 ++++-----
 src/client/views/collections/CollectionView.tsx    |  5 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  3 +-
 .../views/nodes/ContentFittingDocumentView.tsx     | 24 +-----
 src/client/views/nodes/DocumentView.tsx            | 36 ++-------
 src/client/views/nodes/FormattedTextBox.tsx        | 11 ---
 src/client/views/nodes/ImageBox.tsx                |  9 ++-
 src/new_fields/Doc.ts                              | 90 +++++++++-------------
 src/new_fields/documentSchemas.ts                  | 12 ++-
 .../authentication/models/current_user_utils.ts    |  8 +-
 18 files changed, 96 insertions(+), 180 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8304c2a7f..adcdf260d 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -22,7 +22,6 @@ import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField }
 import { HtmlField } from "../../new_fields/HtmlField";
 import { List } from "../../new_fields/List";
 import { Cast, NumCast } from "../../new_fields/Types";
-import { IconField } from "../../new_fields/IconField";
 import { listSpec } from "../../new_fields/Schema";
 import { DocServer } from "../DocServer";
 import { dropActionType } from "../util/DragManager";
@@ -53,7 +52,6 @@ import { InkingStroke } from "../views/InkingStroke";
 import { InkField } from "../../new_fields/InkField";
 import { InkingControl } from "../views/InkingControl";
 import { RichTextField } from "../../new_fields/RichTextField";
-import { Networking } from "../Network";
 import { extname } from "path";
 import { MessageStore } from "../../server/Message";
 const requestImageSize = require('../util/request-image-size');
@@ -92,7 +90,6 @@ export interface DocumentOptions {
     scale?: number;
     isDisplayPanel?: boolean; // whether the panel functions as GoldenLayout "stack" used to display documents
     forceActive?: boolean;
-    preventTreeViewOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expande/collapse state to be independent of other views of the same document in the tree view
     layout?: string | Doc;
     hideHeadings?: boolean; // whether stacking view column headings should be hidden
     isTemplateForField?: string; // the field key for which the containing document is a rendering template
@@ -109,7 +106,6 @@ export interface DocumentOptions {
     curPage?: number;
     currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video)  value is in seconds
     displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video)
-    documentText?: string;
     borderRounding?: string;
     boxShadow?: string;
     sectionFilter?: string; // field key used to determine headings for sections in stacking and masonry views
@@ -124,15 +120,16 @@ export interface DocumentOptions {
     onChildClick?: ScriptField; // script given to children of a collection to execute when they are clicked
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
+    dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
     dragFactory?: Doc; // document to create when dragging with a suitable onDragStart script
     onDragStart?: ScriptField; //script to execute at start of drag operation --  e.g., when a "creator" button is dragged this script generates a different document to drop
-    clipboard?: Doc; //script to execute at start of drag operation --  e.g., when a "creator" button is dragged this script generates a different document to drop
+    clipboard?: Doc;
     icon?: string;
     sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script
     targetContainer?: Doc; // document whose proto will be set to 'panel' as the result of a onClick click script
-    dropConverter?: ScriptField; // script to run when documents are dropped on this Document.
     strokeWidth?: number;
     color?: string;
+    treeViewPreventOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expand/collapse state to be independent of other views of the same document in the tree view
     treeViewHideTitle?: boolean; // whether to hide the title of a tree view
     treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items.
     treeViewOpen?: boolean; // whether this document is expanded in a tree view
@@ -141,9 +138,9 @@ export interface DocumentOptions {
     limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents
     // [key: string]: Opt<Field>;
     pointerHack?: boolean; // for buttons, allows onClick handler to fire onPointerDown
-    isExpanded?: boolean; // is linear view expanded
-    textTransform?: string; // is linear view expanded
-    letterSpacing?: string; // is linear view expanded
+    linearViewIsExpanded?: boolean; // is linear view expanded
+    textTransform?: string;
+    letterSpacing?: string;
 }
 
 class EmptyBox {
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index e572f0fcb..2877d5fd7 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -134,7 +134,6 @@ export namespace DragManager {
         embedDoc?: boolean;
         moveDocument?: MoveFunction;
         isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged.  this will suppress onDragStart scripts
-        applyAsTemplate?: boolean;
     }
     export class LinkDragData {
         constructor(linkSourceDoc: Doc) {
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index 6b8762a5e..de0f46202 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -121,8 +121,7 @@ export class RichTextRules {
             new InputRule(
                 new RegExp(/##$/),
                 (state, match, start, end) => {
-                    const schemaDoc = Doc.GetDataDoc(this.Document);
-                    const textDoc = Doc.GetProto(Cast(schemaDoc[DataSym], Doc, null)!);
+                    const textDoc = this.Document[DataSym];
                     const numInlines = NumCast(textDoc.inlineTextCount);
                     textDoc.inlineTextCount = numInlines + 1;
                     const inlineFieldKey = "inline" + numInlines; // which field on the text document this annotation will write to
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 401a4b15c..192f3b8fb 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -482,12 +482,13 @@ export class MainView extends React.Component {
         return new Transform(-translateX, -translateY, 1 / scale);
     }
     @computed get docButtons() {
-        if (CurrentUserUtils.UserDocument?.expandingButtons instanceof Doc) {
+        const expandingBtns = Doc.UserDoc()?.expandingButtons;
+        if (expandingBtns instanceof Doc) {
             return <div className="mainView-docButtons" ref={this._docBtnRef}
-                style={{ height: !CurrentUserUtils.UserDocument.expandingButtons.isExpanded ? "42px" : undefined }} >
+                style={{ height: !expandingBtns.linearViewIsExpanded ? "42px" : undefined }} >
                 <MainViewNotifs />
                 <CollectionLinearView
-                    Document={CurrentUserUtils.UserDocument.expandingButtons}
+                    Document={expandingBtns}
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     fieldKey={"data"}
diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss
index ad369bbff..fd1296286 100644
--- a/src/client/views/collections/CollectionCarouselView.scss
+++ b/src/client/views/collections/CollectionCarouselView.scss
@@ -1,6 +1,7 @@
 
 .collectionCarouselView-outer {
     background: gray;
+    height : 100%;
     .collectionCarouselView-caption {
         margin-left: 10%;
         margin-right: 10%;
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index f462e20b4..3c86bd799 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -12,7 +12,6 @@ import { CollectionSubView } from './CollectionSubView';
 import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons';
 import { Doc } from '../../../new_fields/Doc';
 import { FormattedTextBox } from '../nodes/FormattedTextBox';
-import { ContextMenuProps } from '../ContextMenuItem';
 import { ContextMenu } from '../ContextMenu';
 import { ObjectField } from '../../../new_fields/ObjectField';
 
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 67062ae41..7eb316cf0 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -38,8 +38,8 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
 
     componentDidMount() {
         // is there any reason this needs to exist? -syip.  yes, it handles autoHeight for stacking views (masonry isn't yet supported).
-        this._widthDisposer = reaction(() => this.props.Document[HeightSym]() + this.childDocs.length + (this.props.Document.isExpanded ? 1 : 0),
-            () => this.props.Document._width = 5 + (this.props.Document.isExpanded ? this.childDocs.length * (this.props.Document[HeightSym]()) : 10),
+        this._widthDisposer = reaction(() => this.props.Document[HeightSym]() + this.childDocs.length + (this.props.Document.linearViewIsExpanded ? 1 : 0),
+            () => this.props.Document._width = 5 + (this.props.Document.linearViewIsExpanded ? this.childDocs.length * (this.props.Document[HeightSym]()) : 10),
             { fireImmediately: true }
         );
 
@@ -84,8 +84,8 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
         const guid = Utils.GenerateGuid();
         return <div className="collectionLinearView-outer">
             <div className="collectionLinearView" ref={this.createDashEventsTarget} >
-                <input id={`${guid}`} type="checkbox" checked={BoolCast(this.props.Document.isExpanded)} ref={this.addMenuToggle}
-                    onChange={action((e: any) => this.props.Document.isExpanded = this.addMenuToggle.current!.checked)} />
+                <input id={`${guid}`} type="checkbox" checked={BoolCast(this.props.Document.linearViewIsExpanded)} ref={this.addMenuToggle}
+                    onChange={action((e: any) => this.props.Document.linearViewIsExpanded = this.addMenuToggle.current!.checked)} />
                 <label htmlFor={`${guid}`} style={{ marginTop: "auto", marginBottom: "auto", background: StrCast(this.props.Document.backgroundColor, "black") === StrCast(this.props.Document.color, "white") ? "black" : StrCast(this.props.Document.backgroundColor, "black") }} title="Close Menu"><p>+</p></label>
 
                 <div className="collectionLinearView-content" style={{ height: this.dimension(), width: NumCast(this.props.Document._width, 25) }}>
@@ -97,7 +97,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                         return <div className={`collectionLinearView-docBtn` + (pair.layout.onClick || pair.layout.onDragStart ? "-scalable" : "")} key={pair.layout[Id]} ref={dref}
                             style={{
                                 width: nested ? pair.layout[WidthSym]() : this.dimension() - deltaSize,
-                                height: nested && pair.layout.isExpanded ? pair.layout[HeightSym]() : this.dimension() - deltaSize,
+                                height: nested && pair.layout.linearViewIsExpanded ? pair.layout[HeightSym]() : this.dimension() - deltaSize,
                             }}  >
                             <DocumentView
                                 Document={pair.layout}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 343be1b58..0963e1ea6 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -159,7 +159,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
             const docDragData = de.complete.docDragData;
             (this.props.Document.dropConverter instanceof ScriptField) &&
                 this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this 
-            if (docDragData && !docDragData.applyAsTemplate) {
+            if (docDragData) {
                 if (de.altKey && docDragData.draggedDocuments.length) {
                     this.childDocs.map(doc => {
                         doc.layout_fromParent = docDragData.draggedDocuments[0];
@@ -253,7 +253,8 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                             }
                         });
                     } else {
-                        const htmlDoc = Docs.Create.HtmlDocument(html, { ...options, title: "-web page-", _width: 300, _height: 300, documentText: text });
+                        const htmlDoc = Docs.Create.HtmlDocument(html, { ...options, title: "-web page-", _width: 300, _height: 300 });
+                        Doc.GetProto(htmlDoc)["data-text"] = text;
                         this.props.addDocument(htmlDoc);
                     }
                     return;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index e91c3cc49..a160dcc62 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -61,7 +61,7 @@ export interface TreeViewProps {
     parentKey: string;
     active: (outsideReaction?: boolean) => boolean;
     treeViewHideHeaderFields: () => boolean;
-    preventTreeViewOpen: boolean;
+    treeViewPreventOpen: boolean;
     renderedIds: string[];
     onCheckedClick?: ScriptField;
 }
@@ -84,7 +84,7 @@ library.add(faPlus, faMinus);
  * 
  * special fields:
  * treeViewOpen : flag denoting whether the documents sub-tree (contents) is visible or hidden
- * preventTreeViewOpen : ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document)
+ * treeViewPreventOpen : ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document)
  * treeViewExpandedView : name of field whose contents are being displayed as the document's subtree
  */
 class TreeView extends React.Component<TreeViewProps> {
@@ -96,8 +96,8 @@ class TreeView extends React.Component<TreeViewProps> {
 
     get defaultExpandedView() { return this.childDocs ? this.fieldKey : StrCast(this.props.document.defaultExpandedView, "fields"); }
     @observable _overrideTreeViewOpen = false; // override of the treeViewOpen field allowing the display state to be independent of the document's state
-    set treeViewOpen(c: boolean) { if (this.props.preventTreeViewOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = this._overrideTreeViewOpen = c; }
-    @computed get treeViewOpen() { return (!this.props.preventTreeViewOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; }
+    set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = this._overrideTreeViewOpen = c; }
+    @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; }
     @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); }
     @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
     @computed get dataDoc() { return this.templateDataDoc ? this.templateDataDoc : this.props.document; }
@@ -179,8 +179,7 @@ class TreeView extends React.Component<TreeViewProps> {
         SetValue={undoBatch((value: string) => Doc.SetInPlace(this.props.document, key, value, false) || true)}
         OnFillDown={undoBatch((value: string) => {
             Doc.SetInPlace(this.props.document, key, value, false);
-            const layoutDoc = this.props.document.layout_custom instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.document.layout_custom)) : undefined;
-            const doc = layoutDoc || Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
+            const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
             EditableView.loadId = doc[Id];
             return this.props.addDocument(doc);
         })}
@@ -291,7 +290,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] :
                     DocListCast(contents), this.props.treeViewId, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
                     this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active,
-                    this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.preventTreeViewOpen,
+                    this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
                     [...this.props.renderedIds, doc[Id]], this.props.libraryPath, this.props.onCheckedClick);
             } else {
                 contentElement = <EditableView
@@ -334,7 +333,7 @@ class TreeView extends React.Component<TreeViewProps> {
                     TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document),
                         this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
                         this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
-                        this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.preventTreeViewOpen,
+                        this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
                         [...this.props.renderedIds, this.props.document[Id]], this.props.libraryPath, this.props.onCheckedClick)}
             </ul >;
         } else if (this.treeViewExpandedView === "fields") {
@@ -464,7 +463,7 @@ class TreeView extends React.Component<TreeViewProps> {
         ChromeHeight: undefined | (() => number),
         renderDepth: number,
         treeViewHideHeaderFields: () => boolean,
-        preventTreeViewOpen: boolean,
+        treeViewPreventOpen: boolean,
         renderedIds: string[],
         libraryPath: Doc[] | undefined,
         onCheckedClick: ScriptField | undefined
@@ -574,7 +573,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 parentKey={key}
                 active={active}
                 treeViewHideHeaderFields={treeViewHideHeaderFields}
-                preventTreeViewOpen={preventTreeViewOpen}
+                treeViewPreventOpen={treeViewPreventOpen}
                 renderedIds={renderedIds} />;
         });
     }
@@ -601,8 +600,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
 
     @action
     remove = (document: Document): boolean => {
-        const targetDataDoc = this.props.Document && !this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document[DataSym] as Doc);
-        const children = Cast(targetDataDoc[this.props.fieldKey], listSpec(Doc), []);
+        const children = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []);
         if (children.indexOf(document) !== -1) {
             children.splice(children.indexOf(document), 1);
             return true;
@@ -611,10 +609,8 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     }
     @action
     addDoc = (doc: Document, relativeTo: Opt<Doc>, before?: boolean): boolean => {
-        const doAddDoc = () => {
-            const targetDataDoc = this.props.Document && !this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document[DataSym] as Doc);
-            Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc, relativeTo, before, false, false, false);
-        };
+        const doAddDoc = () =>
+            Doc.AddDocToList(this.props.Document[DataSym], this.props.fieldKey, doc, relativeTo, before, false, false, false);
         if (this.props.Document.resolvedDataDoc instanceof Promise) {
             this.props.Document.resolvedDataDoc.then(resolved => doAddDoc());
         } else {
@@ -637,7 +633,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
             ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
         } else {
             const layoutItems: ContextMenuProps[] = [];
-            layoutItems.push({ description: (this.props.Document.preventTreeViewOpen ? "Persist" : "Abandon") + "Treeview State", event: () => this.props.Document.preventTreeViewOpen = !this.props.Document.preventTreeViewOpen, icon: "paint-brush" });
+            layoutItems.push({ description: (this.props.Document.treeViewPreventOpen ? "Persist" : "Abandon") + "Treeview State", event: () => this.props.Document.treeViewPreventOpen = !this.props.Document.treeViewPreventOpen, icon: "paint-brush" });
             layoutItems.push({ description: (this.props.Document.treeViewHideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.treeViewHideHeaderFields = !this.props.Document.treeViewHideHeaderFields, icon: "paint-brush" });
             layoutItems.push({ description: (this.props.Document.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.props.Document.treeViewHideTitle = !this.props.Document.treeViewHideTitle, icon: "paint-brush" });
             ContextMenu.Instance.addItem({ description: "Treeview Options ...", subitems: layoutItems, icon: "eye" });
@@ -733,8 +729,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                     SetValue={undoBatch((value: string) => Doc.SetInPlace(this.dataDoc, "title", value, false) || true)}
                     OnFillDown={undoBatch((value: string) => {
                         Doc.SetInPlace(this.dataDoc, "title", value, false);
-                        const layoutDoc = this.props.Document.layout_custom instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.Document.layout_custom)) : undefined;
-                        const doc = layoutDoc || Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
+                        const doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, _width: 100, _height: 25, templates: new List<string>([Templates.Title.Layout]) });
                         EditableView.loadId = doc[Id];
                         this.addDoc(doc, this.childDocs.length ? this.childDocs[0] : undefined, true);
                     })} />)}
@@ -744,7 +739,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                         TreeView.GetChildElements(this.childDocs, this.props.Document, this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove,
                             moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
                             this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => BoolCast(this.props.Document.treeViewHideHeaderFields),
-                            BoolCast(this.props.Document.preventTreeViewOpen), [], this.props.LibraryPath, ScriptCast(this.props.Document.onCheckedClick))
+                            BoolCast(this.props.Document.treeViewPreventOpen), [], this.props.LibraryPath, ScriptCast(this.props.Document.onCheckedClick))
                     }
                 </ul>
             </div >
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ad39b69d8..39ce4d6e8 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -133,7 +133,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
 
     @action.bound
     addDocument(doc: Doc): boolean {
-        const targetDataDoc = this.props.Document.resolvedDataDoc && !this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document[DataSym]);
+        const targetDataDoc = this.props.Document[DataSym];
         targetDataDoc[this.props.fieldKey] = new List<Doc>([...DocListCast(targetDataDoc[this.props.fieldKey]), doc]);  // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there
         // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc);
         targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
@@ -145,8 +145,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
     removeDocument(doc: Doc): boolean {
         const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView);
         docView && SelectionManager.DeselectDoc(docView);
-        const targetDataDoc = this.props.Document.resolvedDataDoc && !this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document[DataSym]);
-        const value = Cast(targetDataDoc[this.props.fieldKey], listSpec(Doc), []);
+        const value = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []);
         let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1);
         index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1);
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 7f1817a15..e1854fc2d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1074,7 +1074,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         // this.Document.fitH = this.contentBounds && (this.contentBounds.b - this.contentBounds.y);
         // if isAnnotationOverlay is set, then children will be stored in the extension document for the fieldKey.
         // otherwise, they are stored in fieldKey.  All annotations to this document are stored in the extension document
-        // let lodarea = this.Document[WidthSym]() * this.Document[HeightSym]() / this.props.ScreenToLocalTransform().Scale / this.props.ScreenToLocalTransform().Scale;
         return <div className={"collectionfreeformview-container"}
             ref={this.createDashEventsTarget}
             onWheel={this.onPointerWheel}//pointerEvents: SelectionManager.GetIsDragging() ? "all" : undefined,
@@ -1086,7 +1085,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                 width: this.contentScaling ? `${100 / this.contentScaling}%` : "",
                 height: this.contentScaling ? `${100 / this.contentScaling}%` : this.isAnnotationOverlay ? (this.props.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight()
             }}>
-            {!this.Document._LODdisable && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ? // && this.props.CollectionView && lodarea < NumCast(this.Document.LODarea, 100000) ?
+            {!this.Document._LODdisable && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ?
                 this.placeholder : this.marqueeView}
             <CollectionFreeFormOverlayView elements={this.elementFunc} />
         </div>;
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 671f5b96e..5c449026e 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -1,19 +1,17 @@
 import React = require("react");
-import { action, computed } from "mobx";
+import { computed } from "mobx";
 import { observer } from "mobx-react";
 import "react-table/react-table.css";
 import { Doc, Opt } from "../../../new_fields/Doc";
-import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
+import { ScriptField } from "../../../new_fields/ScriptField";
 import { NumCast, StrCast } from "../../../new_fields/Types";
+import { TraceMobx } from "../../../new_fields/util";
 import { emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
-import { DragManager } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
-import { undoBatch } from "../../util/UndoManager";
+import { CollectionView } from "../collections/CollectionView";
 import '../DocumentDecorations.scss';
 import { DocumentView } from "../nodes/DocumentView";
 import "./ContentFittingDocumentView.scss";
-import { CollectionView } from "../collections/CollectionView";
-import { TraceMobx } from "../../../new_fields/util";
 
 interface ContentFittingDocumentViewProps {
     Document?: Doc;
@@ -55,20 +53,6 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     }
     private contentScaling = () => this.scaling;
 
-    @undoBatch
-    @action
-    drop = (e: Event, de: DragManager.DropEvent) => {
-        const docDragData = de.complete.docDragData;
-        if (docDragData) {
-            this.props.childDocs && this.props.childDocs.map(otherdoc => {
-                const target = Doc.GetProto(otherdoc);
-                target.layout = ComputedField.MakeFunction("this.image_data[0]");
-                target.layout_custom = Doc.MakeDelegate(docDragData.draggedDocuments[0]);
-            });
-            e.stopPropagation();
-        }
-        return true;
-    }
     private PanelWidth = () => this.panelWidth;
     private PanelHeight = () => this.panelHeight;;
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 48df1ea33..e9b4f9f7f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -92,7 +92,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     private _downY: number = 0;
     private _lastTap: number = 0;
     private _doubleTap = false;
-    private _hitTemplateDrag = false;
     private _mainCont = React.createRef<HTMLDivElement>();
     private _dropDisposer?: DragManager.DragDropDisposer;
     private _gestureEventDisposer?: GestureUtils.GestureEventDisposer;
@@ -196,14 +195,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         !this.props.dontRegisterView && DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1);
     }
 
-    startDragging(x: number, y: number, dropAction: dropActionType, applyAsTemplate?: boolean) {
+    startDragging(x: number, y: number, dropAction: dropActionType) {
         if (this._mainCont.current) {
             const dragData = new DragManager.DocumentDragData([this.props.Document]);
             const [left, top] = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(0, 0);
             dragData.offset = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).transformDirection(x - left, y - top);
             dragData.dropAction = dropAction;
             dragData.moveDocument = this.props.moveDocument;//  this.Document.onDragStart ? undefined : this.props.moveDocument;
-            dragData.applyAsTemplate = applyAsTemplate;
             dragData.dragDivName = this.props.dragDivName;
             this.props.Document.sourceContext = this.props.ContainingCollectionDoc; // bcz: !! shouldn't need this ... use search find the document's context dynamically
             DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.Document.onDragStart });
@@ -257,8 +255,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             let preventDefault = true;
             if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
                 const fullScreenAlias = Doc.MakeAlias(this.props.Document);
-                if (StrCast(fullScreenAlias.layoutKey) !== "layout_custom" && fullScreenAlias.layout_custom !== undefined) {
-                    fullScreenAlias.layoutKey = "layout_custom";
+                if (StrCast(fullScreenAlias.layoutKey) !== "layout_fullScreen" && fullScreenAlias.layout_fullScreen) {
+                    fullScreenAlias.layoutKey = "layout_fullScreen";
                 }
                 this.props.addDocTab(fullScreenAlias, undefined, "inTab");
                 SelectionManager.DeselectAll();
@@ -323,7 +321,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             if (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3) {
                 if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick)) {
                     this.cleanUpInteractions();
-                    this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag);
+                    this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined);
                 }
             }
             e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
@@ -434,14 +432,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         if (!e.nativeEvent.cancelBubble || this.onClickHandler || this.Document.onDragStart) {
             this._downX = e.clientX;
             this._downY = e.clientY;
-            this._hitTemplateDrag = false;
-            // this whole section needs to move somewhere else.  We're trying to initiate a special "template" drag where
-            // this document is the template and we apply it to whatever we drop it on.
-            for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) {
-                if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") {
-                    this._hitTemplateDrag = true;
-                }
-            }
             if ((this.active || this.Document.onDragStart || this.onClickHandler) &&
                 !e.ctrlKey &&
                 (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) &&
@@ -470,7 +460,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
                     document.removeEventListener("pointermove", this.onPointerMove);
                     document.removeEventListener("pointerup", this.onPointerUp);
-                    this.startDragging(this._downX, this._downY, this.props.ContainingCollectionDoc?.childDropAction ? this.props.ContainingCollectionDoc?.childDropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag);
+                    this.startDragging(this._downX, this._downY, this.props.ContainingCollectionDoc?.childDropAction ? this.props.ContainingCollectionDoc?.childDropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined);
                 }
             }
             e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
@@ -556,17 +546,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
-    @undoBatch
-    makeSelBtnClicked = (): void => {
-        if (this.Document.isButton || this.Document.onClick || this.Document.ignoreClick) {
-            this.Document.isButton = false;
-            this.Document.ignoreClick = false;
-            this.Document.onClick = undefined;
-        } else {
-            this.props.Document.isButton = "Selector";
-        }
-    }
-
     @undoBatch
     @action
     drop = async (e: Event, de: DragManager.DropEvent) => {
@@ -578,10 +557,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             DocUtils.MakeLink({ doc: de.complete.annoDragData.annotationDocument }, { doc: this.props.Document, ctx: this.props.ContainingCollectionDoc },
                 `Link from ${StrCast(de.complete.annoDragData.annotationDocument.title)}`);
         }
-        if (de.complete.docDragData && de.complete.docDragData.applyAsTemplate) {
-            Doc.ApplyTemplateTo(de.complete.docDragData.draggedDocuments[0], this.props.Document, "layout_custom", undefined);
-            e.stopPropagation();
-        }
         if (de.complete.linkDragData) {
             e.stopPropagation();
             // const docs = await SearchUtil.Search(`data_l:"${destDoc[Id]}"`, true);
@@ -697,7 +672,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript(`toggleDetail(this, "${this.props.Document.layoutKey}")`), icon: "window-restore" });
         onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
         onClicks.push({ description: this.Document.isButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.makeBtnClicked, icon: "concierge-bell" });
-        onClicks.push({ description: this.props.Document.isButton ? "Remove Select Link Behavior" : "Select Link", event: this.makeSelBtnClicked, icon: "concierge-bell" });
         onClicks.push({ description: "Edit onClick Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", obj.x, obj.y) });
         !existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
 
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 7fbee8881..2fb61f9db 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -250,17 +250,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                     Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(draggedDoc.data.Data, draggedDoc.data.Text);
                     e.stopPropagation();
                 }
-                // apply as template when dragging with Meta
-            } else if (draggedDoc && draggedDoc.type === DocumentType.TEXT && !Doc.AreProtosEqual(draggedDoc, this.props.Document) && de.metaKey) {
-                draggedDoc.isTemplateDoc = true;
-                let newLayout = Doc.Layout(draggedDoc);
-                if (typeof (draggedDoc.layout) === "string") {
-                    newLayout = Doc.MakeDelegate(draggedDoc);
-                    newLayout.layout = StrCast(newLayout.layout).replace(/fieldKey={'[^']*'}/, `fieldKey={'${this.props.fieldKey}'}`);
-                }
-                this.Document.layout_custom = newLayout;
-                this.Document.layoutKey = "layout_custom";
-                e.stopPropagation();
                 // embed document when dragging with a userDropAction or an embedDoc flag set
             } else if (de.complete.docDragData.userDropAction || de.complete.docDragData.embedDoc) {
                 const target = de.complete.docDragData.droppedDocuments[0];
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index c0e102195..364bce7a8 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -92,10 +92,11 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
             } else if (de.altKey || !this.dataDoc[this.props.fieldKey]) {
                 const layoutDoc = de.complete.docDragData?.draggedDocuments[0];
                 const targetField = Doc.LayoutFieldKey(layoutDoc);
-                if (layoutDoc?.[DataSym][targetField] instanceof ImageField) {
-                    this.dataDoc[this.props.fieldKey] = ObjectField.MakeCopy(layoutDoc[DataSym][targetField] as ImageField);
-                    this.dataDoc[this.props.fieldKey + "-nativeWidth"] = NumCast(layoutDoc[DataSym][targetField + "-nativeWidth"]);
-                    this.dataDoc[this.props.fieldKey + "-nativeHeight"] = NumCast(layoutDoc[DataSym][targetField + "-nativeHeight"]);
+                const targetDoc = layoutDoc[DataSym];
+                if (targetDoc[targetField] instanceof ImageField) {
+                    this.dataDoc[this.props.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField);
+                    this.dataDoc[this.props.fieldKey + "-nativeWidth"] = NumCast(targetDoc[targetField + "-nativeWidth"]);
+                    this.dataDoc[this.props.fieldKey + "-nativeHeight"] = NumCast(targeDoc[targetField + "-nativeHeight"]);
                     e.stopPropagation();
                 }
             }
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 2305f2dce..55c0660c0 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -17,7 +17,6 @@ import { intersectRect } from "../Utils";
 import { UndoManager, undoBatch } from "../client/util/UndoManager";
 import { computedFn } from "mobx-utils";
 import { RichTextField } from "./RichTextField";
-import { Script } from "vm";
 
 export namespace Field {
     export function toKeyValueString(doc: Doc, key: string): string {
@@ -112,7 +111,12 @@ export class Doc extends RefField {
             get: getter,
             // getPrototypeOf: (target) => Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter
             has: (target, key) => key in target.__fields,
-            ownKeys: target => Object.keys(target.__allfields),
+            ownKeys: target => {
+                let obj = {} as any;
+                Object.assign(obj, target.___fields);
+                runInAction(() => obj.__LAYOUT__ = target.__LAYOUT__);
+                return Object.keys(obj)
+            },
             getOwnPropertyDescriptor: (target, prop) => {
                 if (prop.toString() === "__LAYOUT__") {
                     return Reflect.getOwnPropertyDescriptor(target, prop);
@@ -140,17 +144,7 @@ export class Doc extends RefField {
     [key: string]: FieldResult;
 
     @serializable(alias("fields", map(autoObject(), { afterDeserialize: afterDocDeserialize })))
-    private get __fields() {
-        return this.___fields;
-    }
-    private get __allfields() {
-        let obj = {} as any;
-        Object.assign(obj, this.___fields);
-        runInAction(() => obj.__LAYOUT__ = this.__LAYOUT__);
-        return obj;
-    }
-
-
+    private get __fields() { return this.___fields; }
     private set __fields(value) {
         this.___fields = value;
         for (const key in value) {
@@ -168,18 +162,19 @@ export class Doc extends RefField {
     private [UpdatingFromServer]: boolean = false;
 
     private [Update] = (diff: any) => {
-        if (this[UpdatingFromServer]) {
-            return;
-        }
-        DocServer.UpdateField(this[Id], diff);
+        !this[UpdatingFromServer] && DocServer.UpdateField(this[Id], diff);
     }
 
     private [Self] = this;
     private [SelfProxy]: any;
     public [WidthSym] = () => NumCast(this[SelfProxy]._width);
     public [HeightSym] = () => NumCast(this[SelfProxy]._height);
-    public get [DataSym]() { return Cast(Doc.Layout(this[SelfProxy]).resolvedDataDoc, Doc, null) || this[SelfProxy]; }
     public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; }
+    public get [DataSym]() {
+        const self = this[SelfProxy];
+        return self.resolvedDataDoc && !self.isTemplateForField ? self :
+            Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self);
+    }
     @computed get __LAYOUT__() {
         const templateLayoutDoc = Cast(Doc.LayoutField(this[SelfProxy]), Doc, null);
         if (templateLayoutDoc) {
@@ -195,12 +190,8 @@ export class Doc extends RefField {
         return undefined;
     }
 
-    [ToScriptString]() {
-        return "invalid";
-    }
-    [ToString]() {
-        return "Doc";
-    }
+    [ToScriptString]() { return "invalid"; }
+    [ToString]() { return "Doc"; }
 
     private [CachedUpdates]: { [key: string]: () => void | Promise<any> } = {};
     public static CurrentUserEmail: string = "";
@@ -287,8 +278,7 @@ export namespace Doc {
 
     export function Get(doc: Doc, key: string, ignoreProto: boolean = false): FieldResult {
         try {
-            const self = doc[Self];
-            return getField(self, key, ignoreProto);
+            return getField(doc[Self], key, ignoreProto);
         } catch  {
             return doc;
         }
@@ -357,13 +347,12 @@ export namespace Doc {
         return r || r2 || r3 || r4;
     }
 
-    // gets the document's prototype or returns the document if it is a prototype
-    export function GetProto(doc: Doc) {
-        return doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc));
-    }
-    export function GetDataDoc(doc: Doc): Doc {
-        const proto = Doc.GetProto(doc);
-        return proto === doc ? proto : Doc.GetDataDoc(proto);
+    // Gets the data document for the document.  Note: this is mis-named -- it does not specifically
+    // return the doc's proto, but rather recursively searches through the proto inheritance chain 
+    // 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 {
+        const proto = doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc));
+        return proto === doc ? proto : Doc.GetProto(proto);
     }
 
     export function allKeys(doc: Doc): string[] {
@@ -443,11 +432,6 @@ export namespace Doc {
         return bounds;
     }
 
-    export function MakeTitled(title: string) {
-        const doc = new Doc();
-        doc.title = title;
-        return doc;
-    }
     export function MakeAlias(doc: Doc, id?: string) {
         const alias = !GetT(doc, "isPrototype", "boolean", true) ? Doc.MakeCopy(doc, undefined, id) : Doc.MakeDelegate(doc, id);
         const layout = Doc.LayoutField(alias);
@@ -488,7 +472,7 @@ export namespace Doc {
         if (templateLayoutDoc.resolvedDataDoc instanceof Promise) {
 
             expandedTemplateLayout = undefined;
-        } else if (templateLayoutDoc.resolvedDataDoc === Doc.GetDataDoc(targetDoc)) {
+        } else if (templateLayoutDoc.resolvedDataDoc === Doc.GetProto(targetDoc)) {
             expandedTemplateLayout = templateLayoutDoc;
         } else if (expandedTemplateLayout === undefined) {
             setTimeout(action(() => {
@@ -497,7 +481,7 @@ export namespace Doc {
                     newLayoutDoc.lockedPosition = true;
                     newLayoutDoc.expandedTemplate = targetDoc;
                     targetDoc[expandedLayoutFieldKey] = newLayoutDoc;
-                    const dataDoc = Doc.GetDataDoc(targetDoc);
+                    const dataDoc = Doc.GetProto(targetDoc);
                     newLayoutDoc.resolvedDataDoc = dataDoc;
                     if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List && Cast(templateLayoutDoc[templateField], listSpec(Doc), []).length) {
                         dataDoc[templateField] = ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"] as List)`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc: templateLayoutDoc });
@@ -660,10 +644,6 @@ export namespace Doc {
         // assign the template field doc a delegate of any extension document that was previously used to render the template field (since extension doc's carry rendering informatino)
         Doc.Layout(templateField)[metadataFieldKey + "_ext"] = Doc.MakeDelegate(templateField[templateFieldLayoutString?.split("'")[1] + "_ext"] as Doc);
 
-        if (templateField.backgroundColor !== templateDoc?.defaultBackgroundColor) {
-            templateField.defaultBackgroundColor = templateField.backgroundColor;
-        }
-
         return true;
     }
 
@@ -716,26 +696,26 @@ export namespace Doc {
     export function SetUserDoc(doc: Doc) { manager._user_doc = doc; }
     export function IsBrushed(doc: Doc) {
         return computedFn(function IsBrushed(doc: Doc) {
-            return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetDataDoc(doc));
+            return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc));
         })(doc);
     }
     // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message)
     export function IsBrushedDegreeUnmemoized(doc: Doc) {
-        return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetDataDoc(doc)) ? 1 : 0;
+        return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? 1 : 0;
     }
     export function IsBrushedDegree(doc: Doc) {
         return computedFn(function IsBrushDegree(doc: Doc) {
-            return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetDataDoc(doc)) ? 1 : 0;
+            return Doc.IsBrushedDegreeUnmemoized(doc);
         })(doc);
     }
     export function BrushDoc(doc: Doc) {
         brushManager.BrushedDoc.set(doc, true);
-        brushManager.BrushedDoc.set(Doc.GetDataDoc(doc), true);
+        brushManager.BrushedDoc.set(Doc.GetProto(doc), true);
         return doc;
     }
     export function UnBrushDoc(doc: Doc) {
         brushManager.BrushedDoc.delete(doc);
-        brushManager.BrushedDoc.delete(Doc.GetDataDoc(doc));
+        brushManager.BrushedDoc.delete(Doc.GetProto(doc));
         return doc;
     }
 
@@ -748,14 +728,14 @@ export namespace Doc {
         document.removeEventListener("pointerdown", linkFollowUnhighlight);
     }
 
-    let dt = 0;
+    let _lastDate = 0;
     export function linkFollowHighlight(destDoc: Doc, dataAndDisplayDocs = true) {
         linkFollowUnhighlight();
         Doc.HighlightDoc(destDoc, dataAndDisplayDocs);
         document.removeEventListener("pointerdown", linkFollowUnhighlight);
         document.addEventListener("pointerdown", linkFollowUnhighlight);
-        const x = dt = Date.now();
-        window.setTimeout(() => dt === x && linkFollowUnhighlight(), 5000);
+        const lastDate = _lastDate = Date.now();
+        window.setTimeout(() => _lastDate === lastDate && linkFollowUnhighlight(), 5000);
     }
 
     export class HighlightBrush {
@@ -763,18 +743,18 @@ export namespace Doc {
     }
     const highlightManager = new HighlightBrush();
     export function IsHighlighted(doc: Doc) {
-        return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetDataDoc(doc));
+        return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetProto(doc));
     }
     export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true) {
         runInAction(() => {
             highlightManager.HighlightedDoc.set(doc, true);
-            dataAndDisplayDocs && highlightManager.HighlightedDoc.set(Doc.GetDataDoc(doc), true);
+            dataAndDisplayDocs && highlightManager.HighlightedDoc.set(Doc.GetProto(doc), true);
         });
     }
     export function UnHighlightDoc(doc: Doc) {
         runInAction(() => {
             highlightManager.HighlightedDoc.set(doc, false);
-            highlightManager.HighlightedDoc.set(Doc.GetDataDoc(doc), false);
+            highlightManager.HighlightedDoc.set(Doc.GetProto(doc), false);
         });
     }
     export function UnhighlightAll() {
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 81f073855..3cc05d3d5 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -4,12 +4,13 @@ import { Doc } from "./Doc";
 import { DateField } from "./DateField";
 
 export const documentSchema = createSchema({
-    layout: "string",           // this is the native layout string for the document.  templates can be added using other fields and setting layoutKey below (see layout_custom as an example)
+    type: "string",             // enumerated type of document -- should be template-specific (ie, start with an '_')
+    layout: "string",           // this is the native layout string for the document.  templates can be added using other fields and setting layoutKey below
     layoutKey: "string",        // holds the field key for the field that actually holds the current lyoat
-    layout_custom: Doc,         // used to hold a custom layout (there's nothing special about this field .. any field could hold a custom layout that can be selected by setting 'layoutKey')
     title: "string",            // document title (can be on either data document or layout)
     dropAction: "string",       // override specifying what should happen when this document is dropped (can be "alias" or "copy")
     childDropAction: "string",  // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy")
+    _autoHeight: "boolean",     // whether the height of the document should be computed automatically based on its contents
     _nativeWidth: "number",     // native width of document which determines how much document contents are scaled when the document's width is set
     _nativeHeight: "number",    // "
     _width: "number",           // width of document in its container's coordinate system
@@ -27,20 +28,18 @@ export const documentSchema = createSchema({
     opacity: "number",          // opacity of document
     creationDate: DateField,    // when the document was created
     links: listSpec(Doc),       // computed (readonly) list of links associated with this document
-    removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped
     onClick: ScriptField,       // script to run when document is clicked (can be overriden by an onClick prop)
     onPointerDown: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop)
     onPointerUp: ScriptField,   // script to run when document is clicked (can be overriden by an onClick prop)
     onDragStart: ScriptField,   // script to run when document is dragged (without being selected).  the script should return the Doc to be dropped.
     dragFactory: Doc,           // the document that serves as the "template" for the onDragStart script.  ie, to drag out copies of the dragFactory document.
+    removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped
     ignoreAspect: "boolean",    // whether aspect ratio should be ignored when laying out or manipulating the document
-    autoHeight: "boolean",      // whether the height of the document should be computed automatically based on its contents
     isTemplateForField: "string",// when specifies a field key, then the containing document is a template that renders the specified field
     isBackground: "boolean",    // whether document is a background element and ignores input events (can only selet with marquee)
-    type: "string",             // enumerated type of document
     treeViewOpen: "boolean",    //  flag denoting whether the documents sub-tree (contents) is visible or hidden
     treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree
-    preventTreeViewOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document)
+    treeViewPreventOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document)
     currentTimecode: "number",  // current play back time of a temporal document (video / audio)
     maximizeLocation: "string", // flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab) 
     lockedPosition: "boolean",  // whether the document can be moved (dragged)
@@ -57,7 +56,6 @@ export const documentSchema = createSchema({
     fitToBox: "boolean",        // whether freeform view contents should be zoomed/panned to fill the area of the document view
     xPadding: "number",         // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set
     yPadding: "number",         // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set
-    LODarea: "number",          // area (width*height) where CollectionFreeFormViews switch from a label to rendering contents
     letterSpacing: "string",
     textTransform: "string"
 });
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 45875d455..32c375bd7 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -139,7 +139,7 @@ export class CurrentUserUtils {
     static setupThumbDoc(userDoc: Doc) {
         if (!userDoc.thumbDoc) {
             userDoc.thumbDoc = Docs.Create.LinearDocument(CurrentUserUtils.setupThumbButtons(userDoc), {
-                _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5, isExpanded: true, backgroundColor: "white"
+                _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white"
             });
         }
         return userDoc.thumbDoc;
@@ -181,12 +181,12 @@ export class CurrentUserUtils {
         });
 
         doc.documents = Docs.Create.TreeDocument([], {
-            title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", preventTreeViewOpen: true, lockedPosition: true, backgroundColor: "#eeeeee"
+            title: "DOCUMENTS", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, backgroundColor: "#eeeeee"
         });
 
         // setup Recently Closed library item
         doc.recentlyClosed = Docs.Create.TreeDocument([], {
-            title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", preventTreeViewOpen: true, lockedPosition: true, backgroundColor: "#eeeeee"
+            title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, backgroundColor: "#eeeeee"
         });
 
         return Docs.Create.ButtonDocument({
@@ -255,7 +255,7 @@ export class CurrentUserUtils {
             { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "sticky-note" });
         doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc, doc.slidesBtn as Doc], {
             title: "expanding buttons", _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0",
-            backgroundColor: "black", preventTreeViewOpen: true, forceActive: true, lockedPosition: true,
+            backgroundColor: "black", treeViewPreventOpen: true, forceActive: true, lockedPosition: true,
 
             dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
         });
-- 
cgit v1.2.3-70-g09d2


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/documents/Documents.ts                  |  2 +-
 src/client/views/DocumentButtonBar.tsx             |  2 +-
 src/client/views/MainView.tsx                      | 27 ++++++++++++-----
 .../views/collections/CollectionCarouselView.tsx   |  1 +
 .../views/collections/CollectionDockingView.tsx    |  3 +-
 .../views/collections/CollectionSchemaCells.tsx    |  3 +-
 .../views/collections/CollectionStackingView.tsx   |  1 +
 .../views/collections/CollectionTreeView.scss      |  9 ++++--
 .../views/collections/CollectionTreeView.tsx       | 16 ++++++----
 src/client/views/collections/CollectionView.tsx    |  3 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 12 ++++----
 .../collections/collectionFreeForm/MarqueeView.tsx |  3 +-
 .../CollectionMulticolumnView.tsx                  |  1 +
 .../CollectionMultirowView.tsx                     |  1 +
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  7 ++---
 .../views/nodes/ContentFittingDocumentView.tsx     |  5 ++--
 src/client/views/nodes/DocumentView.tsx            | 34 +++++-----------------
 src/client/views/nodes/FieldView.tsx               |  6 ++--
 src/client/views/nodes/FormattedTextBox.tsx        |  3 +-
 19 files changed, 72 insertions(+), 67 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index adcdf260d..53671707e 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -168,7 +168,7 @@ export namespace Docs {
         const TemplateMap: TemplateMap = new Map([
             [DocumentType.TEXT, {
                 layout: { view: FormattedTextBox, dataField: data },
-                options: { _height: 150, backgroundColor: "#f1efeb", defaultBackgroundColor: "#f1efeb" }
+                options: { _height: 150 }
             }],
             [DocumentType.HIST, {
                 layout: { view: HistogramBox, dataField: data },
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index ff0d2718c..2201fe710 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -301,7 +301,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
         const view0 = this.view0;
         const templates: Map<Template, boolean> = new Map();
         Array.from(Object.values(Templates.TemplateList)).map(template =>
-            templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.getLayoutPropStr("_show" + template.Name) ? true : false, false as boolean)));
+            templates.set(template, this.props.views.reduce((checked, doc) => checked || doc?.props.Document["_show" + template.Name] ? true : false, false as boolean)));
         return !view0 ? (null) : <div title="Customize layout" className="documentButtonBar-linkFlyout" ref={this._dragRef}>
             <Flyout anchorPoint={anchorPoints.LEFT_TOP}
                 content={<TemplateMenu docViews={this.props.views.filter(v => v).map(v => v as DocumentView)} templates={templates} />}>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 192f3b8fb..ba49a2b53 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -13,7 +13,7 @@ import { Doc, DocListCast, Field, FieldResult, Opt } from '../../new_fields/Doc'
 import { Id } from '../../new_fields/FieldSymbols';
 import { List } from '../../new_fields/List';
 import { listSpec } from '../../new_fields/Schema';
-import { Cast, FieldValue, StrCast } from '../../new_fields/Types';
+import { Cast, FieldValue, StrCast, BoolCast } from '../../new_fields/Types';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
 import { emptyFunction, returnEmptyString, returnFalse, returnOne, returnTrue, Utils, emptyPath } from '../../Utils';
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
@@ -43,6 +43,7 @@ import SettingsManager from '../util/SettingsManager';
 import { TraceMobx } from '../../new_fields/util';
 import { RadialMenu } from './nodes/RadialMenu';
 import RichTextMenu from '../util/RichTextMenu';
+import { DocumentType } from '../documents/DocumentTypes';
 
 @observer
 export class MainView extends React.Component {
@@ -56,8 +57,9 @@ export class MainView extends React.Component {
     @observable private _panelHeight: number = 0;
     @observable private _flyoutTranslate: boolean = true;
     @observable public flyoutWidth: number = 250;
+    private get darkScheme() { return BoolCast(Cast(this.userDoc.activeWorkspace, Doc, null)?.darkScheme); }
 
-    @computed private get userDoc() { return CurrentUserUtils.UserDocument; }
+    @computed private get userDoc() { return Doc.UserDoc(); }
     @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; }
     @computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); }
     @computed public get sidebarButtonsDoc() { return Cast(CurrentUserUtils.UserDocument.sidebarButtons, Doc) as Doc; }
@@ -207,7 +209,6 @@ export class MainView extends React.Component {
             _width: this._panelWidth * .7,
             _height: this._panelHeight,
             title: "Collection " + workspaceCount,
-            backgroundColor: "white"
         };
         const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
         Doc.AddDocToList(Doc.GetProto(CurrentUserUtils.UserDocument.documents as Doc), "data", freeformDoc);
@@ -273,6 +274,16 @@ export class MainView extends React.Component {
     getPHeight = () => this._panelHeight;
     getContentsHeight = () => this._panelHeight - this._buttonBarHeight;
 
+    childBackgroundColor = (doc: Doc) => {
+        if (this.darkScheme) {
+            return doc.type === DocumentType.TEXT ? "#112423" : "black";
+        }
+        return doc.type === DocumentType.TEXT ? "#f1efeb" :
+            doc.type === DocumentType.COL && doc._viewType === CollectionViewType.Tree ? "lightgray" : "white";
+    }
+    sidebarBackgroundColor = (doc: Doc) => {
+        return this.childBackgroundColor(doc);
+    }
     @computed get mainDocView() {
         return <DocumentView Document={this.mainContainer!}
             DataDoc={undefined}
@@ -281,13 +292,13 @@ export class MainView extends React.Component {
             addDocTab={this.addDocTabFunc}
             pinToPres={emptyFunction}
             onClick={undefined}
+            backgroundColor={this.childBackgroundColor}
             removeDocument={undefined}
             ScreenToLocalTransform={Transform.Identity}
             ContentScaling={returnOne}
             PanelWidth={this.getPWidth}
             PanelHeight={this.getPHeight}
             renderDepth={0}
-            backgroundColor={returnEmptyString}
             focus={emptyFunction}
             parentActive={returnTrue}
             whenActiveChanged={emptyFunction}
@@ -366,7 +377,7 @@ export class MainView extends React.Component {
     mainContainerXf = () => new Transform(0, -this._buttonBarHeight, 1);
 
     @computed get flyout() {
-        const sidebarContent = this.userDoc && this.userDoc.sidebarContainer;
+        const sidebarContent = this.userDoc?.sidebarContainer;
         if (!(sidebarContent instanceof Doc)) {
             return (null);
         }
@@ -388,7 +399,7 @@ export class MainView extends React.Component {
                     PanelHeight={this.getPHeight}
                     renderDepth={0}
                     focus={emptyFunction}
-                    backgroundColor={returnEmptyString}
+                    backgroundColor={this.sidebarBackgroundColor}
                     parentActive={returnTrue}
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
@@ -414,7 +425,7 @@ export class MainView extends React.Component {
                     PanelHeight={this.getContentsHeight}
                     renderDepth={0}
                     focus={emptyFunction}
-                    backgroundColor={returnEmptyString}
+                    backgroundColor={this.sidebarBackgroundColor}
                     parentActive={returnTrue}
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
@@ -437,7 +448,7 @@ export class MainView extends React.Component {
     @computed get mainContent() {
         const sidebar = this.userDoc && this.userDoc.sidebarContainer;
         return !this.userDoc || !(sidebar instanceof Doc) ? (null) : (
-            <div className="mainView-mainContent" >
+            <div className="mainView-mainContent" style={{ color: this.darkScheme ? "lightGray" : "black" }} >
                 <div className="mainView-flyoutContainer" onPointerLeave={this.pointerLeaveDragger} style={{ width: this.flyoutWidth }}>
                     <div className="mainView-libraryHandle" onPointerDown={this.onPointerDown} onPointerOver={this.pointerOverDragger}
                         style={{ backgroundColor: `${StrCast(sidebar.backgroundColor, "lightGray")}` }} >
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 3c86bd799..226a1c813 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -52,6 +52,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
             <div>
                 <div className="collectionCarouselView-image">
                     <ContentFittingDocumentView {...this.props}
+                        backgroundColor={this.props.backgroundColor}
                         Document={this.childLayoutPairs[index].layout}
                         DataDocument={this.childLayoutPairs[index].data}
                         PanelHeight={this.panelHeight}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index cb413b3e3..0b7dbea7c 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -599,6 +599,7 @@ interface DockedFrameProps {
     dataDocumentId: FieldId;
     glContainer: any;
     libraryPath: (FieldId[]);
+    backgroundColor?: (doc:Doc) => string| undefined;
     //collectionDockingView: CollectionDockingView
 }
 @observer
@@ -756,7 +757,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             parentActive={returnTrue}
             whenActiveChanged={emptyFunction}
             focus={emptyFunction}
-            backgroundColor={returnEmptyString}
+            backgroundColor={CollectionDockingView.Instance.props.backgroundColor}
             addDocTab={this.addDocTab}
             pinToPres={DockedFrameRenderer.PinDoc}
             ContainingCollectionView={undefined}
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;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 7d1f2c284..055035b3e 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -159,6 +159,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return <ContentFittingDocumentView
             Document={doc}
             DataDocument={dataDoc}
+            backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
             renderDepth={this.props.renderDepth + 1}
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index 2fa6813d7..6ebe81545 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -63,7 +63,9 @@
     font-size: 8pt;
     margin-left: 3px;
     display: none;
-    background: lightgray;
+}
+.collectionTreeView-keyHeader:hover {
+    background: #797777;
 }
 
 .collectionTreeView-subtitle {
@@ -84,9 +86,11 @@
 .treeViewItem-openRight {
     display: none;
     height: 17px;
-    background: gray;
     width: 15px;
 }
+.treeViewItem-openRight:hover {
+    background: #797777;
+}
 
 .treeViewItem-border {
     display: inherit;
@@ -101,7 +105,6 @@
     .treeViewItem-openRight {
         display: inline-block;
         height: 17px;
-        background: #a8a7a7;
         width: 15px;
 
         // display: inline;
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index a160dcc62..e2b3cc425 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -56,6 +56,7 @@ export interface TreeViewProps {
     indentDocument?: () => void;
     outdentDocument?: () => void;
     ScreenToLocalTransform: () => Transform;
+    backgroundColor?: (doc: Doc) => string | undefined;
     outerXf: () => { translateX: number, translateY: number };
     treeViewId: Doc;
     parentKey: string;
@@ -289,7 +290,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 const addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
                 contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] :
                     DocListCast(contents), this.props.treeViewId, doc, undefined, key, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
-                    this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active,
+                    this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active,
                     this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
                     [...this.props.renderedIds, doc[Id]], this.props.libraryPath, this.props.onCheckedClick);
             } else {
@@ -332,7 +333,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 {!docs ? (null) :
                     TreeView.GetChildElements(docs, this.props.treeViewId, Doc.Layout(this.props.document),
                         this.templateDataDoc, expandKey, this.props.containingCollection, this.props.prevSibling, addDoc, remDoc, this.move,
-                        this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
+                        this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform,
                         this.props.outerXf, this.props.active, this.props.panelWidth, this.props.ChromeHeight, this.props.renderDepth, this.props.treeViewHideHeaderFields, this.props.treeViewPreventOpen,
                         [...this.props.renderedIds, this.props.document[Id]], this.props.libraryPath, this.props.onCheckedClick)}
             </ul >;
@@ -348,6 +349,7 @@ class TreeView extends React.Component<TreeViewProps> {
                     DataDocument={this.templateDataDoc}
                     LibraryPath={emptyPath}
                     renderDepth={this.props.renderDepth + 1}
+                    backgroundColor={this.props.backgroundColor}
                     fitToBox={this.boundsOfCollectionDocument !== undefined}
                     PanelWidth={this.docWidth}
                     PanelHeight={this.docHeight}
@@ -384,7 +386,7 @@ class TreeView extends React.Component<TreeViewProps> {
     @computed
     get renderBullet() {
         const checked = this.props.document.type === DocumentType.COL ? undefined : this.props.onCheckedClick ? (this.props.document.treeViewChecked ? this.props.document.treeViewChecked : "unchecked") : undefined;
-        return <div className="bullet" title="view inline" onClick={this.bulletClick} style={{ color: StrCast(this.props.document.color, checked === "unchecked" ? "white" : "black"), opacity: 0.4 }}>
+        return <div className="bullet" title="view inline" onClick={this.bulletClick} style={{ color: StrCast(this.props.document.color, checked === "unchecked" ? "white" : "inherit"), opacity: 0.4 }}>
             {<FontAwesomeIcon icon={checked === "check" ? "check" : (checked === "x" ? "times" : checked === "unchecked" ? "square" : !this.treeViewOpen ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down"))} />}
         </div>;
     }
@@ -415,7 +417,7 @@ class TreeView extends React.Component<TreeViewProps> {
         return <>
             <div className="docContainer" title="click to edit title" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
                 style={{
-                    color: this.props.document.isMinimized ? "red" : "black",
+                    color: this.props.document.isMinimized ? "red" : "inherit",
                     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,
@@ -456,6 +458,7 @@ class TreeView extends React.Component<TreeViewProps> {
         dropAction: dropActionType,
         addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string) => boolean,
         pinToPres: (document: Doc) => void,
+        backgroundColor: undefined | ((document: Doc) => string | undefined),
         screenToLocalXf: () => Transform,
         outerXf: () => { translateX: number, translateY: number },
         active: (outsideReaction?: boolean) => boolean,
@@ -561,6 +564,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 renderDepth={renderDepth}
                 deleteDoc={remove}
                 addDocument={addDocument}
+                backgroundColor={backgroundColor}
                 panelWidth={rowWidth}
                 panelHeight={rowHeight}
                 ChromeHeight={ChromeHeight}
@@ -714,7 +718,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
         const moveDoc = (d: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
         return !this.childDocs ? (null) : (
             <div className="collectionTreeView-dropTarget" id="body"
-                style={{ background: StrCast(this.props.Document.backgroundColor, "lightgray"), paddingTop: `${NumCast(this.props.Document._yMargin, 20)}px` }}
+                style={{ background: this.props.backgroundColor?.(this.props.Document), paddingTop: `${NumCast(this.props.Document._yMargin, 20)}px` }}
                 onContextMenu={this.onContextMenu}
                 onWheel={(e: React.WheelEvent) => this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()}
                 onDrop={this.onTreeDrop}
@@ -737,7 +741,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                 <ul className="no-indent" style={{ width: "max-content" }} >
                     {
                         TreeView.GetChildElements(this.childDocs, this.props.Document, this.props.Document, this.props.DataDoc, this.props.fieldKey, this.props.ContainingCollectionDoc, undefined, addDoc, this.remove,
-                            moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform,
+                            moveDoc, dropAction, this.props.addDocTab, this.props.pinToPres, this.props.backgroundColor, this.props.ScreenToLocalTransform,
                             this.outerXf, this.props.active, this.props.PanelWidth, this.props.ChromeHeight, this.props.renderDepth, () => BoolCast(this.props.Document.treeViewHideHeaderFields),
                             BoolCast(this.props.Document.treeViewPreventOpen), [], this.props.LibraryPath, ScriptCast(this.props.Document.onCheckedClick))
                     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 39ce4d6e8..be971eda6 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -38,6 +38,7 @@ import { CollectionViewBaseChrome } from './CollectionViewChromes';
 import { CollectionTimeView } from './CollectionTimeView';
 import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
 import { List } from '../../../new_fields/List';
+import { SubCollectionViewProps } from './CollectionSubView';
 export const COLLECTION_BORDER_WIDTH = 2;
 const path = require('path');
 library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy);
@@ -177,7 +178,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
     }
 
     private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
-        const props = { ...this.props, ...renderProps, ChromeHeight: this.chromeHeight, CollectionView: this, annotationsKey: "" };
+        const props: SubCollectionViewProps = { ...this.props, ...renderProps, ChromeHeight: this.chromeHeight, CollectionView: this, annotationsKey: "" };
         switch (type) {
             case CollectionViewType.Schema: return (<CollectionSchemaView key="collview" {...props} />);
             case CollectionViewType.Docking: return (<CollectionDockingView key="collview" {...props} />);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index e1854fc2d..969d6b3c8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -10,7 +10,7 @@ import { Id } from "../../../../new_fields/FieldSymbols";
 import { InkTool } from "../../../../new_fields/InkField";
 import { createSchema, listSpec, makeInterface } from "../../../../new_fields/Schema";
 import { ScriptField } from "../../../../new_fields/ScriptField";
-import { Cast, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types";
+import { Cast, NumCast, ScriptCast, BoolCast, StrCast } from "../../../../new_fields/Types";
 import { TraceMobx } from "../../../../new_fields/util";
 import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
 import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
@@ -206,6 +206,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     }
 
     @undoBatch
+    @action
     updateClusters(useClusters: boolean) {
         this.props.Document.useClusters = useClusters;
         this._clusterSets.length = 0;
@@ -243,7 +244,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                 docs.map(doc => this._clusterSets[doc.cluster = NumCast(docFirst.cluster)].push(doc));
             }
             childLayouts.map(child => !this._clusterSets.some((set, i) => Doc.IndexOf(child, set) !== -1 && child.cluster === i) && this.updateCluster(child));
-            childLayouts.map(child => Doc.GetProto(child).clusterStr = child.cluster?.toString());
         }
     }
 
@@ -279,16 +279,16 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     }
 
     getClusterColor = (doc: Doc) => {
-        let clusterColor = "";
+        let clusterColor = this.props.backgroundColor?.(doc);
         const cluster = NumCast(doc.cluster);
         if (this.Document.useClusters) {
             if (this._clusterSets.length <= cluster) {
                 setTimeout(() => this.updateCluster(doc), 0);
             } else {
                 // choose a cluster color from a palette
-                const colors = ["#da42429e", "#31ea318c", "#8c4000", "#4a7ae2c4", "#d809ff", "#ff7601", "#1dffff", "yellow", "#1b8231f2", "#000000ad"];
+                const colors = ["#da42429e", "#31ea318c", "rgba(197, 87, 20, 0.55)", "#4a7ae2c4", "rgba(216, 9, 255, 0.5)", "#ff7601", "#1dffff", "yellow", "rgba(27, 130, 49, 0.55)", "rgba(0, 0, 0, 0.268)"];
                 clusterColor = colors[cluster % colors.length];
-                const set = this._clusterSets[cluster] && this._clusterSets[cluster].filter(s => s.backgroundColor && (s.backgroundColor !== s.defaultBackgroundColor));
+                const set = this._clusterSets[cluster]?.filter(s => s.backgroundColor);
                 // override the cluster color with an explicitly set color on a non-background document.  then override that with an explicitly set color on a background document
                 set && set.filter(s => !s.isBackground).map(s => clusterColor = StrCast(s.backgroundColor));
                 set && set.filter(s => s.isBackground).map(s => clusterColor = StrCast(s.backgroundColor));
@@ -709,6 +709,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     @computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; }
     @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
+    backgroundHalo = () => BoolCast(this.Document.useClusters);
 
     getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps {
         return {
@@ -728,6 +729,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             ContainingCollectionDoc: this.props.Document,
             focus: this.focusDocument,
             backgroundColor: this.getClusterColor,
+            backgroundHalo: this.backgroundHalo,
             parentActive: this.props.active,
             bringToFront: this.bringToFront,
             zoomToScale: this.zoomToScale,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 4b0855635..85cda4ecb 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -308,8 +308,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             y: bounds.top,
             _panX: 0,
             _panY: 0,
-            backgroundColor: this.props.isAnnotationOverlay ? "#00000015" : "white",
-            defaultBackgroundColor: this.props.isAnnotationOverlay ? "#00000015" : "white",
+            backgroundColor: this.props.isAnnotationOverlay ? "#00000015" : undefined,
             _width: bounds.width,
             _height: bounds.height,
             _LODdisable: true,
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 7d8de0db4..db5673573 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -207,6 +207,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             {...this.props}
             Document={layout}
             DataDocument={layout.resolvedDataDoc as Doc}
+            backgroundColor={this.props.backgroundColor}
             CollectionDoc={this.props.Document}
             PanelWidth={width}
             PanelHeight={height}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index ec05443e5..630a178cf 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -208,6 +208,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             {...this.props}
             Document={layout}
             DataDocument={layout.resolvedDataDoc as Doc}
+            backgroundColor={this.props.backgroundColor}
             CollectionDoc={this.props.Document}
             PanelWidth={width}
             PanelHeight={height}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 3c27ac9a1..53d17b580 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -61,15 +61,12 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     }
 
     contentScaling = () => this.nativeWidth > 0 && !this.props.Document.ignoreAspect && !this.props.fitToBox ? this.width / this.nativeWidth : 1;
-    clusterColorFunc = (doc: Doc) => this.clusterColor;
     panelWidth = () => (this.dataProvider?.width || this.props.PanelWidth());
     panelHeight = () => (this.dataProvider?.height || this.props.PanelHeight());
     getTransform = (): Transform => this.props.ScreenToLocalTransform()
         .translate(-this.X, -this.Y)
         .scale(1 / this.contentScaling())
 
-    @computed
-    get clusterColor() { return this.props.backgroundColor(this.props.Document); }
     focusDoc = (doc: Doc) => this.props.focus(doc, false);
     render() {
         TraceMobx();
@@ -78,7 +75,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 boxShadow:
                     this.layoutDoc.opacity === 0 ? undefined :  // if it's not visible, then no shadow
                         this.layoutDoc.z ? `#9c9396  ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` :  // if it's a floating doc, give it a big shadow
-                            this.clusterColor ? (`${this.clusterColor} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) :  // if it's just in a cluster, make the shadown roughly match the cluster border extent
+                            this.props.backgroundHalo?.() ? (`${this.props.backgroundColor?.(this.props.Document)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) :  // if it's just in a cluster, make the shadown roughly match the cluster border extent
                                 this.layoutDoc.isBackground ? undefined :  // if it's a background & has a cluster color, make the shadow spread really big
                                     StrCast(this.layoutDoc.boxShadow, ""),
                 borderRadius: StrCast(Doc.Layout(this.layoutDoc).borderRounding),
@@ -96,7 +93,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 dragDivName={"collectionFreeFormDocumentView-container"}
                 ContentScaling={this.contentScaling}
                 ScreenToLocalTransform={this.getTransform}
-                backgroundColor={this.clusterColorFunc}
+                backgroundColor={this.props.backgroundColor}
                 PanelWidth={this.panelWidth}
                 PanelHeight={this.panelHeight}
             /> : <ContentFittingDocumentView {...this.props}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 5c449026e..387da88f5 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -6,7 +6,7 @@ import { Doc, Opt } from "../../../new_fields/Doc";
 import { ScriptField } from "../../../new_fields/ScriptField";
 import { NumCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from "../../../new_fields/util";
-import { emptyFunction, returnEmptyString, returnOne } from "../../../Utils";
+import { emptyFunction, returnOne } from "../../../Utils";
 import { Transform } from "../../util/Transform";
 import { CollectionView } from "../collections/CollectionView";
 import '../DocumentDecorations.scss';
@@ -27,6 +27,7 @@ interface ContentFittingDocumentViewProps {
     CollectionView?: CollectionView;
     CollectionDoc?: Doc;
     onClick?: ScriptField;
+    backgroundColor?: (doc: Doc) => string | undefined;
     getTransform: () => Transform;
     addDocument?: (document: Doc) => boolean;
     moveDocument?: (document: Doc, target: Doc | undefined, addDoc: ((doc: Doc) => boolean)) => boolean;
@@ -86,6 +87,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         LibraryPath={this.props.LibraryPath}
                         fitToBox={this.props.fitToBox}
                         onClick={this.props.onClick}
+                        backgroundColor={this.props.backgroundColor}
                         addDocument={this.props.addDocument}
                         removeDocument={this.props.removeDocument}
                         moveDocument={this.props.moveDocument}
@@ -101,7 +103,6 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         PanelWidth={this.PanelWidth}
                         PanelHeight={this.PanelHeight}
                         focus={this.props.focus || emptyFunction}
-                        backgroundColor={returnEmptyString}
                         bringToFront={emptyFunction}
                         dontRegisterView={this.props.dontRegisterView}
                         zoomToScale={emptyFunction}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ef065f51d..52928e8cb 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -77,7 +77,8 @@ export interface DocumentViewProps {
     addDocTab: (doc: Doc, dataDoc: Doc | undefined, where: string, libraryPath?: Doc[]) => boolean;
     pinToPres: (document: Doc) => void;
     zoomToScale: (scale: number) => void;
-    backgroundColor: (doc: Doc) => string | undefined;
+    backgroundHalo?: () => boolean;
+    backgroundColor?: (doc: Doc) => string | undefined;
     getScale: () => number;
     animateBetweenIcon?: (maximize: boolean, target: number[]) => void;
     ChromeHeight?: () => number;
@@ -295,12 +296,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             this._downX = touch.clientX;
             this._downY = touch.clientY;
             if (!e.nativeEvent.cancelBubble) {
-                this._hitTemplateDrag = false;
-                for (let element = (e.target as any); element && !this._hitTemplateDrag; element = element.parentElement) {
-                    if (element.className && element.className.toString() === "collectionViewBaseChrome-collapse") {
-                        this._hitTemplateDrag = true;
-                    }
-                }
                 if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation();
                 this.removeMoveListeners();
                 this.addMoveListeners();
@@ -778,14 +773,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         });
     }
 
-    // does Document set a layout prop 
-    setsLayoutProp = (prop: string) => this.props.Document[prop] !== this.props.Document["default" + prop[0].toUpperCase() + prop.slice(1)] && this.props.Document["default" + prop[0].toUpperCase() + prop.slice(1)];
-    // get the a layout prop by first choosing the prop from Document, then falling back to the layout doc otherwise.
-    getLayoutPropStr = (prop: string) => {
-        return StrCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : Cast(this.layoutDoc?.expandedTemplate, Doc, null)?.[prop] || this.layoutDoc[prop]);
-    }
-    getLayoutPropNum = (prop: string) => NumCast(this.setsLayoutProp(prop) ? this.props.Document[prop] : this.layoutDoc[prop]);
-
     isSelected = (outsideReaction?: boolean) => SelectionManager.IsSelected(this, outsideReaction);
     select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
 
@@ -848,9 +835,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     @computed get innards() {
         TraceMobx();
-        const showTitle = StrCast(this.getLayoutPropStr("_showTitle"));
-        const showTitleHover = StrCast(this.getLayoutPropStr("_showTitleHover"));
-        const showCaption = this.getLayoutPropStr("_showCaption");
+        const showTitle = StrCast(this.layoutDoc._showTitle);
+        const showTitleHover = StrCast(this.layoutDoc._showTitleHover);
+        const showCaption = StrCast(this.layoutDoc._showCaption);
         const showTextTitle = showTitle && (StrCast(this.layoutDoc.layout).indexOf("PresBox") !== -1 || StrCast(this.layoutDoc.layout).indexOf("FormattedTextBox") !== -1) ? showTitle : undefined;
         const searchHighlight = (!this.Document.searchFields ? (null) :
             <div className="documentView-searchHighlight">
@@ -921,14 +908,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     render() {
         if (!(this.props.Document instanceof Doc)) return (null);
-        const colorSet = this.setsLayoutProp("backgroundColor");
-        const clusterCol = this.props.ContainingCollectionDoc && this.props.ContainingCollectionDoc.clusterOverridesDefaultBackground;
-        const backgroundColor = (clusterCol && !colorSet) ?
-            this.props.backgroundColor(this.Document) || StrCast(this.layoutDoc.backgroundColor) :
-            StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.Document);
-
+        const backgroundColor = StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor?.(this.Document);
         const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document);
-        const borderRounding = this.getLayoutPropStr("borderRounding");
+        const borderRounding = this.layoutDoc.borderRounding;
         const localScale = fullDegree;
 
         const highlightColors = ["transparent", "maroon", "maroon", "yellow", "magenta", "cyan", "orange"];
@@ -943,7 +925,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 transform: this._animate ? `scale(${this._animate})` : undefined,
                 transition: !this._animate ? StrCast(this.Document.transition) : this._animate < 1 ? "transform 0.5s ease-in" : "transform 0.5s ease-out",
                 pointerEvents: this.ignorePointerEvents ? "none" : "all",
-                color: StrCast(this.Document.color),
+                color: StrCast(this.Document.color, "inherit"),
                 outline: highlighting && !borderRounding ? `${highlightColors[fullDegree]} ${highlightStyles[fullDegree]} ${localScale}px` : "solid 0px",
                 border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined,
                 boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined,
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 8250f41f3..00f00dd52 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -3,14 +3,13 @@ import { computed } from "mobx";
 import { observer } from "mobx-react";
 import { DateField } from "../../../new_fields/DateField";
 import { Doc, FieldResult, Opt } from "../../../new_fields/Doc";
-import { IconField } from "../../../new_fields/IconField";
 import { List } from "../../../new_fields/List";
-import { AudioField, ImageField, VideoField } from "../../../new_fields/URLField";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import { AudioField, VideoField } from "../../../new_fields/URLField";
 import { Transform } from "../../util/Transform";
 import { CollectionView } from "../collections/CollectionView";
 import { AudioBox } from "./AudioBox";
 import { VideoBox } from "./VideoBox";
-import { ScriptField } from "../../../new_fields/ScriptField";
 
 //
 // these properties get assigned through the render() method of the DocumentView when it creates this node.
@@ -34,6 +33,7 @@ export interface FieldViewProps {
     pinToPres: (document: Doc) => void;
     removeDocument?: (document: Doc) => boolean;
     moveDocument?: (document: Doc, targetCollection: Doc | undefined, addDocument: (document: Doc) => boolean) => boolean;
+    backgroundColor?: (document: Doc) => string | undefined;
     ScreenToLocalTransform: () => Transform;
     active: (outsideReaction?: boolean) => boolean;
     whenActiveChanged: (isActive: boolean) => void;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 2fb61f9db..3c64b3974 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -186,7 +186,6 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
             tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 5000 - 1000)));
             this._applyingChange = true;
             if (!this.props.Document._textTemplate || Doc.GetProto(this.props.Document) === this.dataDoc) {
-                this.dataDoc[this.props.fieldKey + "-lastModified"] && (this.dataDoc[this.props.fieldKey + "-backgroundColor"] = "lightGray");
                 this.dataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
                 this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()), state.doc.textBetween(0, state.doc.content.size, "\n\n"));
             }
@@ -1075,7 +1074,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
             <div className={`formattedTextBox-cont`} ref={this._ref}
                 style={{
                     height: this.layoutDoc._autoHeight ? "max-content" : undefined,
-                    background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : undefined,
+                    background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"]),
                     opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1,
                     color: this.props.hideOnLeave ? "white" : "inherit",
                     pointerEvents: interactive ? "none" : "all",
-- 
cgit v1.2.3-70-g09d2


From ba9351bc009b6f78ca9815b481bc5643f8af96e0 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 16 Feb 2020 22:59:36 -0500
Subject: fixed warnings

---
 src/Utils.ts                                       |  4 +-
 src/client/util/RichTextRules.ts                   |  2 +-
 src/client/views/DocumentButtonBar.tsx             |  1 -
 src/client/views/DocumentDecorations.tsx           |  2 +-
 .../views/collections/CollectionDockingView.tsx    |  2 +-
 .../views/collections/CollectionSchemaHeaders.tsx  |  4 +-
 .../views/collections/CollectionViewChromes.tsx    |  2 +-
 .../CollectionFreeFormLayoutEngines.tsx            | 38 ++++++------
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../caption_toggle/DetailedCaptionToggle.tsx       | 72 ----------------------
 .../document_templates/image_card/ImageCard.tsx    | 15 -----
 .../views/nodes/ContentFittingDocumentView.tsx     |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  4 +-
 src/client/views/nodes/PDFBox.tsx                  |  2 +-
 src/client/views/pdf/PDFViewer.tsx                 |  7 +--
 src/new_fields/util.ts                             |  2 +-
 17 files changed, 38 insertions(+), 125 deletions(-)
 delete mode 100644 src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx
 delete mode 100644 src/client/views/document_templates/image_card/ImageCard.tsx

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 6a0b3fad8..9162771aa 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -495,7 +495,7 @@ export function setupMoveUpEvents(
         (target as any)._lastX = e.clientX;
         (target as any)._lastY = e.clientY;
         e.stopPropagation();
-    }
+    };
     const _upEvent = (e: PointerEvent): void => {
         upEvent(e);
         if (Math.abs(e.clientX - (target as any)._downX) < 4 || Math.abs(e.clientY - (target as any)._downY) < 4) {
@@ -503,7 +503,7 @@ export function setupMoveUpEvents(
         }
         document.removeEventListener("pointermove", _moveEvent);
         document.removeEventListener("pointerup", _upEvent);
-    }
+    };
     e.stopPropagation();
     document.removeEventListener("pointermove", _moveEvent);
     document.removeEventListener("pointerup", _upEvent);
diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index de0f46202..a4f1ff22c 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -298,5 +298,5 @@ export class RichTextRules {
                     return null;
                 }),
         ]
-    }
+    };
 }
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index ec1f879c2..5d289c5e5 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -318,7 +318,6 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
         const isText = this.view0.props.Document.data instanceof RichTextField; // bcz: Todo - can't assume layout is using the 'data' field.  need to add fieldKey to DocumentView
         const considerPull = isText && this.considerGoogleDocsPull;
         const considerPush = isText && this.considerGoogleDocsPush;
-        Doc.UserDoc().pr
         return <div className="documentButtonBar">
             <div className="documentButtonBar-button">
                 {this.linkButton}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index cc7388a61..44e8a3a48 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -109,7 +109,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 UndoManager.RunInBatch(() => selectionTitleFieldKey && SelectionManager.SelectedDocuments().forEach(d => {
                     const value = typeof d.props.Document[selectionTitleFieldKey] === "number" ? +this._accumulatedTitle : this._accumulatedTitle;
                     didAnything = didAnything || d.props.Document[selectionTitleFieldKey] !== value;
-                    Doc.SetInPlace(d.props.Document, selectionTitleFieldKey, value, true)
+                    Doc.SetInPlace(d.props.Document, selectionTitleFieldKey, value, true);
                 }), "title blur");
                 if (!didAnything) UndoManager.Undo();
             }
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index bf0333d55..902016365 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -434,7 +434,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                 tab.titleElement[0].onchange = (e: any) => {
                     tab.titleElement[0].size = e.currentTarget.value.length + 1;
                     Doc.SetInPlace(doc, "title", e.currentTarget.value, true);
-                }
+                };
                 tab.titleElement[0].size = StrCast(doc.title).length + 1;
                 tab.titleElement[0].value = doc.title;
                 const gearSpan = document.createElement("span");
diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx
index 92dc8780e..c585506b3 100644
--- a/src/client/views/collections/CollectionSchemaHeaders.tsx
+++ b/src/client/views/collections/CollectionSchemaHeaders.tsx
@@ -5,11 +5,13 @@ import "./CollectionSchemaView.scss";
 import { faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faSortAmountDown, faSortAmountUp, faTimes } from '@fortawesome/free-solid-svg-icons';
 import { library, IconProp } from "@fortawesome/fontawesome-svg-core";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Flyout, anchorPoints } from "../DocumentDecorations";
 import { ColumnType } from "./CollectionSchemaView";
 import { faFile } from "@fortawesome/free-regular-svg-icons";
 import { SchemaHeaderField, PastelSchemaPalette } from "../../../new_fields/SchemaHeaderField";
 import { undoBatch } from "../../util/UndoManager";
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
 
 library.add(faPlus, faFont, faHashtag, faAlignJustify, faCheckSquare, faToggleOn, faFile as any, faSortAmountDown, faSortAmountUp, faTimes);
 
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index a21e78188..0378c818c 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -179,7 +179,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     @action closeViewSpecs = () => {
         this._viewSpecsOpen = false;
         document.removeEventListener("pointerdown", this.closeViewSpecs);
-    };
+    }
 
     @action
     openDatePicker = (e: React.PointerEvent) => {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 671a3e0c4..8132d2f7c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -27,15 +27,15 @@ export interface ViewDefBounds {
 }
 
 export interface PoolData {
-    x?: number,
-    y?: number,
-    z?: number,
-    zIndex?: number,
-    width?: number,
-    height?: number,
-    color?: string,
-    transition?: string,
-    highlight?: boolean,
+    x?: number;
+    y?: number;
+    z?: number;
+    zIndex?: number;
+    width?: number;
+    height?: number;
+    color?: string;
+    transition?: string;
+    highlight?: boolean;
 }
 
 export interface ViewDefResult {
@@ -63,16 +63,16 @@ function toLabel(target: FieldResult<Field>) {
  */
 function getTextWidth(text: string, font: string): number {
     // re-use canvas object for better performance
-    var canvas = (getTextWidth as any).canvas || ((getTextWidth as any).canvas = document.createElement("canvas"));
-    var context = canvas.getContext("2d");
+    const canvas = (getTextWidth as any).canvas || ((getTextWidth as any).canvas = document.createElement("canvas"));
+    const context = canvas.getContext("2d");
     context.font = font;
-    var metrics = context.measureText(text);
+    const metrics = context.measureText(text);
     return metrics.width;
 }
 
-interface pivotColumn {
-    docs: Doc[],
-    filters: string[]
+interface PivotColumn {
+    docs: Doc[];
+    filters: string[];
 }
 
 
@@ -86,7 +86,7 @@ export function computePivotLayout(
     viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
 ) {
     const fieldKey = "data";
-    const pivotColumnGroups = new Map<FieldResult<Field>, pivotColumn>();
+    const pivotColumnGroups = new Map<FieldResult<Field>, PivotColumn>();
 
     const pivotFieldKey = toLabel(pivotDoc._pivotField);
     for (const doc of filterDocs) {
@@ -123,7 +123,7 @@ export function computePivotLayout(
     const desc = `${fontSize}px ${getComputedStyle(document.body).fontFamily}`;
     const textlen = Array.from(pivotColumnGroups.keys()).map(c => getTextWidth(toLabel(c), desc)).reduce((p, c) => Math.max(p, c), 0 as number);
     const max_text = Math.min(Math.ceil(textlen / 120) * 28, panelDim[1] / 2);
-    let maxInColumn = Array.from(pivotColumnGroups.values()).reduce((p, s) => Math.max(p, s.docs.length), 1);
+    const maxInColumn = Array.from(pivotColumnGroups.values()).reduce((p, s) => Math.max(p, s.docs.length), 1);
 
     const colWidth = panelDim[0] / pivotColumnGroups.size;
     const colHeight = panelDim[1] - max_text;
@@ -223,7 +223,7 @@ export function computeTimelineLayout(
     const findStack = (time: number, stack: number[]) => {
         const index = stack.findIndex(val => val === undefined || val < x);
         return index === -1 ? stack.length : index;
-    }
+    };
 
     let minTime = minTimeReq === undefined ? Number.MAX_VALUE : minTimeReq;
     let maxTime = maxTimeReq === undefined ? -Number.MAX_VALUE : maxTimeReq;
@@ -266,7 +266,7 @@ export function computeTimelineLayout(
     }
 
     const pivotAxisWidth = NumCast(pivotDoc.pivotTimeWidth, panelDim[1] / 2.5);
-    let stacking: number[] = [];
+    const stacking: number[] = [];
     let zind = 0;
     sortedKeys.forEach(key => {
         if (curTime !== undefined && curTime > prevKey && curTime <= key) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 427a8d9fe..60410544b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -856,7 +856,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         });
         return rangeFilteredDocs;
     }
-    childLayoutDocFunc = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null) as Doc;
+    childLayoutDocFunc = () => this.props.childLayoutTemplate?.() || Cast(this.props.Document.childLayoutTemplate, Doc, null);
     get doLayoutComputation() {
         const { newPool, computedElementData } = this.doInternalLayoutComputation;
         runInAction(() =>
diff --git a/src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx b/src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx
deleted file mode 100644
index 3aaf4120c..000000000
--- a/src/client/views/document_templates/caption_toggle/DetailedCaptionToggle.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-import * as React from 'react';
-import { FontStyleProperty, ColorProperty } from 'csstype';
-import { observer } from 'mobx-react';
-import { observable, action, runInAction } from 'mobx';
-import { FormattedTextBox } from '../../nodes/FormattedTextBox';
-import { FieldViewProps } from '../../nodes/FieldView';
-
-interface DetailedCaptionDataProps {
-    captionFieldKey?: string;
-    detailsFieldKey?: string;
-}
-
-interface DetailedCaptionStylingProps {
-    sharedFontColor?: ColorProperty;
-    captionFontStyle?: FontStyleProperty;
-    detailsFontStyle?: FontStyleProperty;
-    toggleSize?: number;
-}
-
-@observer
-export default class DetailedCaptionToggle extends React.Component<DetailedCaptionDataProps & DetailedCaptionStylingProps & FieldViewProps> {
-    @observable loaded: boolean = false;
-    @observable detailsExpanded: boolean = false;
-
-    @action toggleDetails = (e: React.MouseEvent<HTMLDivElement>) => {
-        e.preventDefault();
-        e.stopPropagation();
-        this.detailsExpanded = !this.detailsExpanded;
-    }
-
-    componentDidMount() {
-        runInAction(() => this.loaded = true);
-    }
-
-    render() {
-        const size = this.props.toggleSize || 20;
-        return (
-            <div style={{
-                transition: "0.5s opacity ease",
-                opacity: this.loaded ? 1 : 0,
-                bottom: 0,
-                fontSize: 14,
-                width: "100%",
-                position: "absolute"
-            }}>
-                {/* caption */}
-                <div style={{ opacity: this.detailsExpanded ? 0 : 1, transition: "opacity 0.3s ease" }}>
-                    <FormattedTextBox {...this.props} fieldKey={this.props.captionFieldKey || "caption"} />
-                </div>
-                {/* details */}
-                <div style={{ opacity: this.detailsExpanded ? 1 : 0, transition: "opacity 0.3s ease" }}>
-                    <FormattedTextBox {...this.props} fieldKey={this.props.detailsFieldKey || "captiondetails"} />
-                </div>
-                {/* toggle */}
-                <div
-                    style={{
-                        width: size,
-                        height: size,
-                        borderRadius: "50%",
-                        backgroundColor: "red",
-                        zIndex: 3,
-                        cursor: "pointer"
-                    }}
-                    onClick={this.toggleDetails}
-                >
-                    <span style={{ color: "white" }}></span>
-                </div>
-            </div>
-        );
-    }
-
-}
diff --git a/src/client/views/document_templates/image_card/ImageCard.tsx b/src/client/views/document_templates/image_card/ImageCard.tsx
deleted file mode 100644
index 868afc423..000000000
--- a/src/client/views/document_templates/image_card/ImageCard.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import * as React from 'react';
-import { FieldViewProps } from '../../nodes/FieldView';
-import { ImageBox } from '../../nodes/ImageBox';
-
-export default class ImageCard extends React.Component<FieldViewProps> {
-
-    render() {
-        return (
-            <div style={{ padding: 30, borderRadius: 15 }}>
-                <ImageBox {...this.props} />
-            </div>
-        );
-    }
-
-}
\ No newline at end of file
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 387da88f5..73fe4fb5d 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -55,7 +55,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     private contentScaling = () => this.scaling;
 
     private PanelWidth = () => this.panelWidth;
-    private PanelHeight = () => this.panelHeight;;
+    private PanelHeight = () => this.panelHeight;
 
     @computed get panelWidth() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth(); }
     @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight(); }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 330410a92..704da3c74 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -271,7 +271,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             }
             preventDefault && e.preventDefault();
         }
-    };
+    }
 
     buttonClick = async (altKey: boolean, ctrlKey: boolean) => {
         const linkDocs = DocListCast(this.props.Document.links);
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 30be64040..c2f1c9ac7 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -369,7 +369,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
 
     specificContextMenu = (e: React.MouseEvent): void => {
         const funcs: ContextMenuProps[] = [];
-        funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document._showSidebar = !this.props.Document._showSidebar }, icon: "expand-arrows-alt" });
+        funcs.push({ description: "Toggle Sidebar", event: () => { e.stopPropagation(); this.props.Document._showSidebar = !this.props.Document._showSidebar; }, icon: "expand-arrows-alt" });
         funcs.push({ description: "Record Bullet", event: () => { e.stopPropagation(); this.recordBullet(); }, icon: "expand-arrows-alt" });
         ["My Text", "Text from Others", "Todo Items", "Important Items", "Ignore Items", "Disagree Items", "By Recent Minute", "By Recent Hour"].forEach(option =>
             funcs.push({
@@ -1067,7 +1067,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
     }
 
     @computed get sidebarWidthPercent() { return StrCast(this.props.Document.sidebarWidthPercent, "0%"); }
-    sidebarWidth = () => { return Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth(); }
+    sidebarWidth = () => Number(this.sidebarWidthPercent.substring(0, this.sidebarWidthPercent.length - 1)) / 100 * this.props.PanelWidth();
     sidebarScreenToLocal = () => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth()), 0);
     @computed get sidebarColor() { return StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], "transparent")); }
     render() {
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index a2aec699f..a96a26b61 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -259,7 +259,7 @@ export class PDFBox extends DocAnnotatableComponent<FieldViewProps, PdfDocument>
             if (!this._pdfjsRequested) {
                 this._pdfjsRequested = true;
                 const promise = Pdfjs.getDocument(pdfUrl.url.href).promise;
-                promise.then(pdf => { runInAction(() => { this._pdf = pdf; console.log("promise"); }) });
+                promise.then(action(pdf => { this._pdf = pdf; console.log("promise"); }));
 
             }
         }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 4f50be5b0..a9b8c6bbe 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -127,9 +127,8 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
         // change the address to be the file address of the PNG version of each page
         // file address of the pdf
         const { url: { href } } = Cast(this.props.Document[this.props.fieldKey], PdfField)!;
-        this._coverPath = href.startsWith(window.location.origin) ?
-            JSON.parse(await rp.get(Utils.prepend(`/thumbnail${this.props.url.substring("files/pdfs/".length, this.props.url.length - ".pdf".length)}-${(this.Document.curPage || 1)}.png`))) :
-            { width: 100, height: 100, path: "" };
+        const addr = Utils.prepend(`/thumbnail${this.props.url.substring("files/pdfs/".length, this.props.url.length - ".pdf".length)}-${(this.Document.curPage || 1)}.png`);
+        this._coverPath = href.startsWith(window.location.origin) ? JSON.parse(await rp.get(addr)) : { width: 100, height: 100, path: "" };
         runInAction(() => this._showWaiting = this._showCover = true);
         this.props.startupLive && this.setupPdfJsViewer();
         this._searchReactionDisposer = reaction(() => this.Document.searchMatch, search => {
@@ -623,7 +622,7 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
         TraceMobx();
         return <div className="pdfViewer-annotationLayer" style={{ height: NumCast(this.Document.nativeHeight), transform: `scale(${this._zoomed})` }} ref={this._annotationLayer}>
             {this.nonDocAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) =>
-                <Annotation {...this.props} focus={this.props.focus} dataDoc={this.dataDoc!} fieldKey={this.props.fieldKey} anno={anno} key={`${anno[Id]}-annotation`} />)}
+                <Annotation {...this.props} focus={this.props.focus} dataDoc={this.dataDoc} fieldKey={this.props.fieldKey} anno={anno} key={`${anno[Id]}-annotation`} />)}
         </div>;
     }
     overlayTransform = () => this.scrollXf().scale(1 / this._zoomed);
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index ebc0a1272..6d7f6b56e 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -100,7 +100,7 @@ export function makeEditable() {
     _setter = _setterImpl;
 }
 
-let layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox",
+const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox",
     "LODdisable", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"];
 export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean {
     let prop = in_prop;
-- 
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/nodes/ContentFittingDocumentView.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 61e12f2e08ed0c0e47b82456b75c441b7278cdd6 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 19 Mar 2020 15:53:07 -0400
Subject: fixed buttons on screenshotbox.  added 'place' option to dragDrop to
 drop the original document without moving it.   switched to passing
 childDropAction as a prop

---
 src/client/util/DragManager.ts                     |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  3 +-
 .../views/collections/CollectionTreeView.tsx       |  5 +--
 src/client/views/collections/CollectionView.tsx    | 25 ++++++-------
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  3 +-
 .../views/nodes/ContentFittingDocumentView.tsx     |  3 ++
 src/client/views/nodes/DocumentView.tsx            |  6 ++--
 src/client/views/nodes/FieldView.tsx               |  1 +
 src/client/views/nodes/ScreenshotBox.scss          | 41 +++++++++++++---------
 src/client/views/nodes/ScreenshotBox.tsx           |  7 ++--
 .../authentication/models/current_user_utils.ts    |  2 +-
 11 files changed, 58 insertions(+), 40 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index f4461d2f7..63a11c85a 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -18,7 +18,7 @@ import { AudioBox } from "../views/nodes/AudioBox";
 import { DateField } from "../../new_fields/DateField";
 import { DocumentView } from "../views/nodes/DocumentView";
 
-export type dropActionType = "alias" | "copy" | undefined;
+export type dropActionType = "place" | "alias" | "copy" | undefined;
 export function SetupDrag(
     _reference: React.RefObject<HTMLElement>,
     docFunc: () => Doc | Promise<Doc> | undefined,
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a936582c3..719778eb1 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -12,7 +12,7 @@ import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from "../../../new_fields/util";
 import { Utils, setupMoveUpEvents, emptyFunction } from "../../../Utils";
-import { DragManager } from "../../util/DragManager";
+import { DragManager, dropActionType } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import { ContextMenu } from "../ContextMenu";
@@ -176,6 +176,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             LibraryPath={this.props.LibraryPath}
             renderDepth={this.props.renderDepth + 1}
             fitToBox={this.props.fitToBox}
+            dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
             PanelWidth={width}
             PanelHeight={height}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 4757e5a53..f8f8a0943 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -130,7 +130,7 @@ class TreeView extends React.Component<TreeViewProps> {
     }
 
     @undoBatch delete = () => this.props.deleteDoc(this.props.document);
-    @undoBatch openRight = () => this.props.addDocTab(this.props.containingCollection.childDropAction === "alias" ? Doc.MakeAlias(this.props.document) : this.props.document, "onRight", this.props.libraryPath);
+    @undoBatch openRight = () => this.props.addDocTab(this.props.dropAction === "alias" ? Doc.MakeAlias(this.props.document) : 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);
@@ -455,6 +455,7 @@ class TreeView extends React.Component<TreeViewProps> {
                         addDocTab={this.props.addDocTab}
                         pinToPres={emptyFunction}
                         onClick={editTitle}
+                        dropAction={this.props.dropAction}
                         moveDocument={this.props.moveDocument}
                         removeDocument={undefined}
                         ScreenToLocalTransform={this.getTransform}
@@ -761,7 +762,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     }
 
     render() {
-        const dropAction = StrCast(this.props.Document.dropAction) as dropActionType;
+        const dropAction = StrCast(this.props.Document.childDropAction) as dropActionType;
         const addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => this.addDoc(doc, relativeTo, before);
         const moveDoc = (d: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
         const childDocs = this.props.overrideDocuments ? this.props.overrideDocuments : this.childDocs;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index c74b9ad6d..edac59efe 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,18 +1,17 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faEye } from '@fortawesome/free-regular-svg-icons';
 import { faColumns, faCopy, faEllipsisV, faFingerprint, faImage, faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons';
-import { action, IReactionDisposer, observable, reaction, runInAction, computed } from 'mobx';
+import { action, observable } from 'mobx';
 import { observer } from "mobx-react";
 import * as React from 'react';
 import Lightbox from 'react-image-lightbox-with-rotate';
 import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app
 import { DateField } from '../../../new_fields/DateField';
-import { Doc, DocListCast, DataSym } from '../../../new_fields/Doc';
-import { Id } from '../../../new_fields/FieldSymbols';
-import { BoolCast, Cast, StrCast, NumCast } from '../../../new_fields/Types';
+import { DataSym, Doc, DocListCast } from '../../../new_fields/Doc';
+import { List } from '../../../new_fields/List';
+import { BoolCast, Cast, NumCast, StrCast } from '../../../new_fields/Types';
 import { ImageField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
-import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
 import { Utils } from '../../../Utils';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
@@ -22,22 +21,23 @@ import { ContextMenu } from "../ContextMenu";
 import { FieldView, FieldViewProps } from '../nodes/FieldView';
 import { ScriptBox } from '../ScriptBox';
 import { Touchable } from '../Touchable';
+import { CollectionCarouselView } from './CollectionCarouselView';
 import { CollectionDockingView } from "./CollectionDockingView";
 import { AddCustomFreeFormLayout } from './collectionFreeForm/CollectionFreeFormLayoutEngines';
 import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
-import { CollectionCarouselView } from './CollectionCarouselView';
 import { CollectionLinearView } from './CollectionLinearView';
 import { CollectionMulticolumnView } from './collectionMulticolumn/CollectionMulticolumnView';
+import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
 import { CollectionSchemaView } from "./CollectionSchemaView";
 import { CollectionStackingView } from './CollectionStackingView';
 import { CollectionStaffView } from './CollectionStaffView';
+import { SubCollectionViewProps } from './CollectionSubView';
+import { CollectionTimeView } from './CollectionTimeView';
 import { CollectionTreeView } from "./CollectionTreeView";
 import './CollectionView.scss';
 import { CollectionViewBaseChrome } from './CollectionViewChromes';
-import { CollectionTimeView } from './CollectionTimeView';
-import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView';
-import { List } from '../../../new_fields/List';
-import { SubCollectionViewProps } from './CollectionSubView';
+import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
+import { Id } from '../../../new_fields/FieldSymbols';
 export const COLLECTION_BORDER_WIDTH = 2;
 const path = require('path');
 library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy);
@@ -75,7 +75,7 @@ export namespace CollectionViewType {
     ]);
 
     export const valueOf = (value: string) => stringMapping.get(value.toLowerCase());
-    export const stringFor = (value: number) => Array.from(stringMapping.entries()).find(entry => entry[1] === value)[0];
+    export const stringFor = (value: number) => Array.from(stringMapping.entries()).find(entry => entry[1] === value)?.[0];
 }
 
 export interface CollectionRenderProps {
@@ -116,7 +116,8 @@ export class CollectionView extends Touchable<FieldViewProps> {
     @action.bound
     addDocument(doc: Doc): boolean {
         const targetDataDoc = this.props.Document[DataSym];
-        targetDataDoc[this.props.fieldKey] = new List<Doc>([...DocListCast(targetDataDoc[this.props.fieldKey]), doc]);  // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there
+        const docList = DocListCast(targetDataDoc[this.props.fieldKey]);
+        !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, doc]));  // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there
         // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc);
         targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
         Doc.GetProto(doc).lastOpened = new DateField;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index fd679b7b2..da44d0d59 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -20,7 +20,7 @@ import { CognitiveServices } from "../../../cognitive_services/CognitiveServices
 import { DocServer } from "../../../DocServer";
 import { Docs } from "../../../documents/Documents";
 import { DocumentManager } from "../../../util/DocumentManager";
-import { DragManager } from "../../../util/DragManager";
+import { DragManager, dropActionType } from "../../../util/DragManager";
 import { HistoryUtil } from "../../../util/History";
 import { InteractionUtils } from "../../../util/InteractionUtils";
 import { SelectionManager } from "../../../util/SelectionManager";
@@ -832,6 +832,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             Document: childLayout,
             LibraryPath: this.libraryPath,
             layoutKey: undefined,
+            dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
             //onClick: undefined, // this.props.onClick,  // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them
             onClick: this.onChildClickHandler,
             ScreenToLocalTransform: childLayout.z ? this.getTransformOverlay : this.getTransform,
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 36233a7e6..8632f9c9a 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -12,6 +12,7 @@ import { CollectionView } from "../collections/CollectionView";
 import '../DocumentDecorations.scss';
 import { DocumentView } from "../nodes/DocumentView";
 import "./ContentFittingDocumentView.scss";
+import { dropActionType } from "../../util/DragManager";
 
 interface ContentFittingDocumentViewProps {
     Document?: Doc;
@@ -21,6 +22,7 @@ interface ContentFittingDocumentViewProps {
     childDocs?: Doc[];
     renderDepth: number;
     fitToBox?: boolean;
+    dropAction?: dropActionType;
     PanelWidth: () => number;
     PanelHeight: () => number;
     focus?: (doc: Doc) => void;
@@ -86,6 +88,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         LayoutDoc={this.props.LayoutDoc}
                         LibraryPath={this.props.LibraryPath}
                         fitToBox={this.props.fitToBox}
+                        dropAction={this.props.dropAction}
                         onClick={this.props.onClick}
                         backgroundColor={this.props.backgroundColor}
                         addDocument={this.props.addDocument}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index c558a1da7..7480f0db8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -14,7 +14,6 @@ import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { AudioField, ImageField, PdfField, VideoField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
 import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { emptyFunction, returnOne, returnTransparent, returnTrue, Utils, OmitKeys } from "../../../Utils";
 import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
 import { DocServer } from "../../DocServer";
@@ -65,6 +64,7 @@ export interface DocumentViewProps {
     onClick?: ScriptField;
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
+    dropAction?: dropActionType;
     dragDivName?: string;
     addDocument?: (doc: Doc) => boolean;
     removeDocument?: (doc: Doc) => boolean;
@@ -275,7 +275,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     }
 
     onClick = (e: React.MouseEvent | React.PointerEvent) => {
-        if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && CurrentUserUtils.MainDocId !== this.props.Document[Id] &&
+        if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && //CurrentUserUtils.MainDocId !== this.props.Document[Id] &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             e.stopPropagation();
             let preventDefault = true;
@@ -474,7 +474,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
                     document.removeEventListener("pointermove", this.onPointerMove);
                     document.removeEventListener("pointerup", this.onPointerUp);
-                    this.startDragging(this._downX, this._downY, this.props.ContainingCollectionDoc?.childDropAction ? this.props.ContainingCollectionDoc?.childDropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined);
+                    this.startDragging(this._downX, this._downY, this.props.dropAction ? this.props.dropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined);
                 }
             }
             e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document'  however it does mark the event as cancelBubble=true which we test for in the move event handlers
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index d030d1f4d..6619330a1 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -25,6 +25,7 @@ export interface FieldViewProps {
     DataDoc?: Doc;
     LibraryPath: Doc[];
     onClick?: ScriptField;
+    dropAction: dropAction;
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (isCtrlPressed: boolean) => void;
     renderDepth: number;
diff --git a/src/client/views/nodes/ScreenshotBox.scss b/src/client/views/nodes/ScreenshotBox.scss
index 4aaccb472..6cc184948 100644
--- a/src/client/views/nodes/ScreenshotBox.scss
+++ b/src/client/views/nodes/ScreenshotBox.scss
@@ -25,22 +25,31 @@
     pointer-events: all;
 }
 
-.screenshotBox-snapshot{
-    color : white;
-    top :25px;
-    right : 25px;
+.screenshotBox-uiButtons {
+    background:dimgray;
+    border: orange solid 1px;
     position: absolute;
-    background-color:rgba(50, 50, 50, 0.2);
-    transform-origin: left top;
-    pointer-events:all;
-}
+    right: 25;
+    top: 0;
+    width:50;
+    height: 25;
+    .screenshotBox-snapshot{
+        color : white;
+        top :0px;
+        right : 5px;
+        position: absolute;
+        background-color:rgba(50, 50, 50, 0.2);
+        transform-origin: left top;
+        pointer-events:all;
+    }
 
-.screenshotBox-recorder{
-    color : white;
-    top :25px;
-    right : 50px;
-    position: absolute;
-    background-color:rgba(50, 50, 50, 0.2);
-    transform-origin: left top;
-    pointer-events:all;
+    .screenshotBox-recorder{
+        color : white;
+        top :0px;
+        left: 5px;
+        position: absolute;
+        background-color:rgba(50, 50, 50, 0.2);
+        transform-origin: left top;
+        pointer-events:all;
+    }
 }
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index cfa6fa8a3..548066f1c 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -145,13 +145,14 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
     })
 
     private get uIButtons() {
-        return ([
+        return (<div className="screenshotBox-uiButtons">
             <div className="screenshotBox-recorder" key="snap" onPointerDown={this.toggleRecording} >
                 <FontAwesomeIcon icon="file" size="lg" />
             </div>,
             <div className="screenshotBox-snapshot" key="snap" onPointerDown={this.onSnapshot} >
                 <FontAwesomeIcon icon="camera" size="lg" />
-            </div>]);
+            </div>
+        </div>);
     }
 
     onSnapshot = (e: React.PointerEvent) => {
@@ -187,7 +188,7 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
                     {this.contentFunc}
                 </CollectionFreeFormView>
             </div>
-            {this.uIButtons}
+            {this.active() ? this.uIButtons : (null)}
         </div >);
     }
 }
\ No newline at end of file
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index ea7b91b23..31588bf82 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -222,7 +222,7 @@ export class CurrentUserUtils {
             _width: 50, _height: 25, title: "Library", fontSize: 10, dontSelect: true,
             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", dontRegisterChildren: true
+                title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "place", 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/nodes/ContentFittingDocumentView.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


From adabfbea2b034beb310530aef9cc8b206e260b67 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 3 Apr 2020 20:23:15 -0400
Subject: added rootSelected() to make forceActive work better

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/RichTextSchema.tsx                 |  1 +
 src/client/views/DocComponent.tsx                  |  6 +++--
 src/client/views/GestureOverlay.tsx                |  1 +
 src/client/views/MainView.tsx                      |  4 ++++
 src/client/views/OverlayView.tsx                   |  1 +
 src/client/views/Palette.tsx                       | 26 +++++++---------------
 src/client/views/RecommendationsBox.tsx            |  1 +
 src/client/views/SearchDocBox.tsx                  |  3 ++-
 .../views/collections/CollectionDockingView.tsx    |  1 +
 .../views/collections/CollectionLinearView.tsx     |  3 ++-
 .../views/collections/CollectionSchemaView.tsx     |  1 +
 .../views/collections/CollectionStackingView.tsx   |  1 +
 src/client/views/collections/CollectionSubView.tsx |  5 +++++
 .../views/collections/CollectionTreeView.tsx       |  2 ++
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  1 +
 .../collections/collectionFreeForm/MarqueeView.tsx |  1 -
 src/client/views/nodes/AudioBox.tsx                | 12 +++++++---
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  7 +++---
 .../views/nodes/ContentFittingDocumentView.tsx     |  1 +
 src/client/views/nodes/DocumentBox.tsx             |  1 +
 src/client/views/nodes/DocumentContentsView.tsx    |  4 ++--
 src/client/views/nodes/DocumentView.tsx            | 24 +++++++++++++++-----
 src/client/views/nodes/FieldView.tsx               |  1 +
 src/client/views/nodes/FormattedTextBoxComment.tsx |  1 +
 src/client/views/pdf/PDFViewer.tsx                 |  3 +--
 .../views/presentationview/PresElementBox.tsx      |  3 ++-
 src/client/views/search/SearchItem.tsx             |  3 ++-
 src/mobile/MobileInterface.tsx                     |  2 ++
 .../authentication/models/current_user_utils.ts    |  2 +-
 31 files changed, 83 insertions(+), 43 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a69bfae01..0a2269bac 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -435,7 +435,7 @@ export namespace Docs {
         Scripting.addGlobal(Buxton);
 
         const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "childDropAction", "_annotationOn",
-            "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor",
+            "_chromeStatus", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "_showTitle", "_showCaption", "_showTitleHover", "_backgroundColor",
             "_xMargin", "_yMargin", "_xPadding", "_yPadding", "_singleLine", "_scrollTop",
             "_color", "isButton", "isBackground", "removeDropProperties", "treeViewOpen"];
 
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 094cd58f3..4a930177d 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -818,6 +818,7 @@ export class DashDocView {
                     LibraryPath={this._textBox.props.LibraryPath}
                     fitToBox={BoolCast(dashDoc._fitToBox)}
                     addDocument={returnFalse}
+                    rootSelected={this._textBox.props.isSelected}
                     removeDocument={removeDoc}
                     ScreenToLocalTransform={this.getDocTransform}
                     addDocTab={this._textBox.props.addDocTab}
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index f4e830a48..454c245cc 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -29,6 +29,7 @@ interface DocExtendableProps {
     fieldKey: string;
     isSelected: (outsideReaction?: boolean) => boolean;
     renderDepth: number;
+    rootSelected: () => boolean;
 }
 export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCtor: (doc: Doc) => T) {
     class Component extends Touchable<P> {
@@ -36,7 +37,7 @@ export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCt
         @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; }
-        active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);//  && !InkingControl.Instance.selectedTool;  // bcz: inking state shouldn't affect static tools 
+        active = (outsideReaction?: boolean) => !this.props.Document.isBackground && ((this.props.Document.forceActive && this.props.rootSelected()) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);//  && !InkingControl.Instance.selectedTool;  // bcz: inking state shouldn't affect static tools 
     }
     return Component;
 }
@@ -50,6 +51,7 @@ export interface DocAnnotatableProps {
     active: () => boolean;
     whenActiveChanged: (isActive: boolean) => void;
     isSelected: (outsideReaction?: boolean) => boolean;
+    rootSelected: () => boolean;
     renderDepth: number;
 }
 export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schemaCtor: (doc: Doc) => T) {
@@ -86,7 +88,7 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema
 
         whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
         active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) &&
-            (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
+            ((this.props.Document.forceActive && this.props.rootSelected()) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
         annotationsActive = (outsideReaction?: boolean) => (InkingControl.Instance.selectedTool !== InkTool.None ||
             (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
     }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index ea60907f6..26bee9a6f 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -705,6 +705,7 @@ export default class GestureOverlay extends Touchable {
                 LibraryPath={emptyPath}
                 addDocument={undefined}
                 addDocTab={returnFalse}
+                rootSelected={returnTrue}
                 pinToPres={emptyFunction}
                 onClick={undefined}
                 removeDocument={undefined}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8d9be5980..fae520e40 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -309,6 +309,7 @@ export class MainView extends React.Component {
             addDocument={undefined}
             addDocTab={this.addDocTabFunc}
             pinToPres={emptyFunction}
+            rootSelected={returnTrue}
             onClick={undefined}
             backgroundColor={this.defaultBackgroundColors}
             removeDocument={undefined}
@@ -407,6 +408,7 @@ export class MainView extends React.Component {
                     DataDoc={undefined}
                     LibraryPath={emptyPath}
                     addDocument={undefined}
+                    rootSelected={returnTrue}
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
                     removeDocument={undefined}
@@ -435,6 +437,7 @@ export class MainView extends React.Component {
                     addDocument={undefined}
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
+                    rootSelected={returnTrue}
                     removeDocument={returnFalse}
                     onClick={undefined}
                     ScreenToLocalTransform={this.mainContainerXf}
@@ -523,6 +526,7 @@ export class MainView extends React.Component {
                     fieldKey={"data"}
                     dropAction={"alias"}
                     annotationsKey={""}
+                    rootSelected={returnTrue}
                     bringToFront={emptyFunction}
                     select={emptyFunction}
                     active={returnFalse}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 220efd4a8..7587071db 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -174,6 +174,7 @@ export class OverlayView extends React.Component {
                     Document={d}
                     LibraryPath={emptyPath}
                     ChromeHeight={returnZero}
+                    rootSelected={returnTrue}
                     // isSelected={returnFalse}
                     // select={emptyFunction}
                     // layoutKey={"layout"}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index e04f814d1..674b27918 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -1,23 +1,12 @@
+import { IReactionDisposer, observable, reaction } from "mobx";
+import { observer } from "mobx-react";
 import * as React from "react";
-import "./Palette.scss";
-import { PointData } from "../../new_fields/InkField";
 import { Doc } from "../../new_fields/Doc";
-import { Docs } from "../documents/Documents";
-import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
-import { List } from "../../new_fields/List";
-import { DocumentView } from "./nodes/DocumentView";
-import { emptyPath, returnFalse, emptyFunction, returnOne, returnEmptyString, returnTrue } from "../../Utils";
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { NumCast } from "../../new_fields/Types";
+import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue } from "../../Utils";
 import { Transform } from "../util/Transform";
-import { computed, action, IReactionDisposer, reaction, observable } from "mobx";
-import { FieldValue, Cast, NumCast } from "../../new_fields/Types";
-import { observer } from "mobx-react";
-import { DocumentContentsView } from "./nodes/DocumentContentsView";
-import { CollectionStackingView } from "./collections/CollectionStackingView";
-import { CollectionView } from "./collections/CollectionView";
-import { CollectionSubView, SubCollectionViewProps } from "./collections/CollectionSubView";
-import { makeInterface } from "../../new_fields/Schema";
-import { documentSchema } from "../../new_fields/documentSchemas";
+import { DocumentView } from "./nodes/DocumentView";
+import "./Palette.scss";
 
 export interface PaletteProps {
     x: number;
@@ -40,7 +29,7 @@ export default class Palette extends React.Component<PaletteProps> {
     }
 
     componentWillUnmount = () => {
-        this._selectedDisposer && this._selectedDisposer();
+        this._selectedDisposer?.();
     }
 
     render() {
@@ -54,6 +43,7 @@ export default class Palette extends React.Component<PaletteProps> {
                             LibraryPath={emptyPath}
                             addDocument={undefined}
                             addDocTab={returnFalse}
+                            rootSelected={returnTrue}
                             pinToPres={emptyFunction}
                             removeDocument={undefined}
                             onClick={undefined}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index 5ebba0abb..bf8de36b4 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -68,6 +68,7 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
                 addDocument={returnFalse}
                 LibraryPath={emptyPath}
                 removeDocument={returnFalse}
+                rootSelected={returnFalse}
                 ScreenToLocalTransform={Transform.Identity}
                 addDocTab={returnFalse}
                 pinToPres={returnFalse}
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index c57f9e737..e66de39d4 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -410,8 +410,9 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
             <div style={{ pointerEvents: "all" }}>
                 <ContentFittingDocumentView {...this.props}
                     Document={this.content}
+                    rootSelected={returnFalse}
                     getTransform={this.props.ScreenToLocalTransform}>
-                    </ContentFittingDocumentView>
+                </ContentFittingDocumentView>
                 <div
                     style={{
                         position: "absolute",
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 4e1e76f39..4209bd574 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -788,6 +788,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             Document={document}
             DataDoc={resolvedDataDoc}
             bringToFront={emptyFunction}
+            rootSelected={returnTrue}
             addDocument={undefined}
             removeDocument={undefined}
             ContentScaling={this.contentScaling}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 344605412..a6ada75b2 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
 import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc';
 import { makeInterface } from '../../../new_fields/Schema';
 import { BoolCast, NumCast, StrCast, Cast } from '../../../new_fields/Types';
-import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../../Utils';
+import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { Transform } from '../../util/Transform';
 import "./CollectionLinearView.scss";
@@ -110,6 +110,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 moveDocument={this.props.moveDocument}
                                 addDocTab={this.props.addDocTab}
                                 pinToPres={emptyFunction}
+                                rootSelected={this.props.isSelected}
                                 removeDocument={this.props.removeDocument}
                                 onClick={undefined}
                                 ScreenToLocalTransform={this.getTransform(dref)}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 981438513..a1b541f74 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -124,6 +124,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
                 LibraryPath={this.props.LibraryPath}
                 childDocs={this.childDocs}
                 renderDepth={this.props.renderDepth}
+                rootSelected={this.rootSelected}
                 PanelWidth={this.previewWidth}
                 PanelHeight={this.previewHeight}
                 getTransform={this.getPreviewTransform}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 076dd3629..d21e17bbc 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -176,6 +176,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             LibraryPath={this.props.LibraryPath}
             renderDepth={this.props.renderDepth + 1}
             fitToBox={this.props.fitToBox}
+            rootSelected={this.rootSelected}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
             PanelWidth={width}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 70927cf22..d1d6ae3c1 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -34,6 +34,7 @@ export interface CollectionViewProps extends FieldViewProps {
     PanelHeight: () => number;
     VisibleHeight?: () => number;
     setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
+    rootSelected: () => boolean;
     fieldKey: string;
 }
 
@@ -95,6 +96,10 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
         }
 
+        rootSelected = () => {
+            return this.props.isSelected() || (this.props.Document.rootDocument || this.props.Document.forceActive ? this.props.rootSelected() : false);
+        }
+
         // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc.
         // When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through
         // to its children which may be templates.
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 6ee48f11b..fc612c66d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -373,6 +373,7 @@ class TreeView extends React.Component<TreeViewProps> {
                     DataDocument={this.templateDataDoc}
                     LibraryPath={emptyPath}
                     renderDepth={this.props.renderDepth + 1}
+                    rootSelected={returnTrue}
                     backgroundColor={this.props.backgroundColor}
                     fitToBox={this.boundsOfCollectionDocument !== undefined}
                     PanelWidth={this.docWidth}
@@ -454,6 +455,7 @@ class TreeView extends React.Component<TreeViewProps> {
                         LibraryPath={this.props.libraryPath || []}
                         addDocument={undefined}
                         addDocTab={this.props.addDocTab}
+                        rootSelected={returnTrue}
                         pinToPres={emptyFunction}
                         onClick={this.props.onChildClick || editTitle}
                         dropAction={this.props.dropAction}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index df1770ffe..3913ccd88 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -117,7 +117,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
         return viewField;
     }
 
-    active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || BoolCast(this.props.Document.forceActive) || this._isChildActive || this.props.renderDepth === 0;
+    active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.rootSelected() && BoolCast(this.props.Document.forceActive)) || this._isChildActive || this.props.renderDepth === 0;
 
     whenActiveChanged = (isActive: boolean) => { this.props.whenActiveChanged(this._isChildActive = isActive); };
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 2871fe192..a164e1794 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -832,6 +832,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             Document: childLayout,
             LibraryPath: this.libraryPath,
             layoutKey: undefined,
+            rootSelected: this.rootSelected,
             dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
             //onClick: undefined, // this.props.onClick,  // bcz: check this out -- I don't think we want to inherit click handlers, or we at least need a way to ignore them
             onClick: this.onChildClickHandler,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 276a49570..503df10c2 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -5,7 +5,6 @@ import { InkField, InkData } from "../../../../new_fields/InkField";
 import { List } from "../../../../new_fields/List";
 import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField";
 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";
 import { SelectionManager } from "../../../util/SelectionManager";
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 03b2a2297..bd54d64ff 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -7,7 +7,7 @@ import { AudioField, nullAudio } from "../../../new_fields/URLField";
 import { DocExtendableComponent } from "../DocComponent";
 import { makeInterface, createSchema } from "../../../new_fields/Schema";
 import { documentSchema } from "../../../new_fields/documentSchemas";
-import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent } from "../../../Utils";
+import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse } from "../../../Utils";
 import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx";
 import { DateField } from "../../../new_fields/DateField";
 import { SelectionManager } from "../../util/SelectionManager";
@@ -258,9 +258,15 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
                                 return !linkTime ? (null) :
                                     <div className={this.props.PanelHeight() < 32 ? "audiobox-marker-minicontainer" : "audiobox-marker-container"} key={l[Id]} style={{ left: `${linkTime / NumCast(this.dataDoc.duration, 1) * 100}%` }}>
                                         <div className={this.props.PanelHeight() < 32 ? "audioBox-linker-mini" : "audioBox-linker"} key={"linker" + i}>
-                                            <DocumentView {...this.props} Document={l} layoutKey={Doc.LinkEndpoint(l, la2)}
+                                            <DocumentView {...this.props}
+                                                Document={l}
+                                                rootSelected={returnFalse}
+                                                layoutKey={Doc.LinkEndpoint(l, la2)}
                                                 ContainingCollectionDoc={this.props.Document}
-                                                parentActive={returnTrue} bringToFront={emptyFunction} zoomToScale={emptyFunction} getScale={returnOne}
+                                                parentActive={returnTrue}
+                                                bringToFront={emptyFunction}
+                                                zoomToScale={emptyFunction}
+                                                getScale={returnOne}
                                                 backgroundColor={returnTransparent} />
                                         </div>
                                         <div key={i} className="audiobox-marker" onPointerEnter={() => Doc.linkFollowHighlight(la1)}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index eaab4086c..356192797 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -89,14 +89,15 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 pointerEvents: this.props.Document.isBackground ? "none" : undefined
             }} >
 
-            {!this.props.fitToBox ? <DocumentView {...this.props}
+            {!this.props.fitToBox ? 
+            <DocumentView {...this.props}
                 dragDivName={"collectionFreeFormDocumentView-container"}
                 ContentScaling={this.contentScaling}
                 ScreenToLocalTransform={this.getTransform}
                 backgroundColor={this.props.backgroundColor}
                 PanelWidth={this.panelWidth}
-                PanelHeight={this.panelHeight}
-            /> : <ContentFittingDocumentView {...this.props}
+                PanelHeight={this.panelHeight} /> 
+            : <ContentFittingDocumentView {...this.props}
                 CollectionDoc={this.props.ContainingCollectionDoc}
                 DataDocument={this.props.DataDoc}
                 getTransform={this.getTransform}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 9494a4bc4..fdf2a9551 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -40,6 +40,7 @@ interface ContentFittingDocumentViewProps {
     addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     dontRegisterView?: boolean;
+    rootSelected: () => boolean;
 }
 
 @observer
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index debe104d7..47118e758 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -122,6 +122,7 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
             CollectionView={this as any} // bcz: hack!  need to pass a prop that can be used to select the container (ie, 'this') when the up selector in document decorations is clicked.  currently, the up selector allows only a containing collection to be selected
             fitToBox={this.props.fitToBox}
             layoutKey={"layout_" + childTemplateName}
+            rootSelected={this.props.isSelected}
             addDocument={this.props.addDocument}
             moveDocument={this.props.moveDocument}
             removeDocument={this.props.removeDocument}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index fc61487e5..687137adc 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,6 +1,6 @@
 import { computed } from "mobx";
 import { observer } from "mobx-react";
-import { Doc } from "../../../new_fields/Doc";
+import { Doc, Opt } from "../../../new_fields/Doc";
 import { Cast, StrCast } from "../../../new_fields/Types";
 import { OmitKeys, Without } from "../../../Utils";
 import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
@@ -62,7 +62,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
     forceLayout?: string,
     forceFieldKey?: string,
     hideOnLeave?: boolean,
-    makeLink?: () => Opt<Doc>;
+    makeLink?: () => Opt<Doc>,  // function to call when a link is made
 }> {
     @computed get layout(): string {
         TraceMobx();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 1e02ab44e..42f5fb946 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -60,6 +60,7 @@ export interface DocumentViewProps {
     LayoutDoc?: () => Opt<Doc>;
     LibraryPath: Doc[];
     fitToBox?: boolean;
+    rootSelected: () => boolean; // whether the root of a template has been selected
     onClick?: ScriptField;
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
@@ -277,7 +278,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this.dontDecorateSelection = this.props.Document.dontDecorateSelection && (!e.ctrlKey || e.button < 2);
         if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
-            e.stopPropagation();
+            let stopPropagate = true;
             let preventDefault = true;
             this.props.bringToFront(this.props.Document);
             if (this._doubleTap && this.props.renderDepth && !this.onClickHandler?.script) { // disable double-click to show full screen for things that have an on click behavior since clicking them twice can be misinterpreted as a double click
@@ -301,9 +302,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered.
                 UndoManager.RunInBatch(() => this.buttonClick(e.altKey, e.ctrlKey), "on link button follow");
             } else {
-                SelectionManager.SelectDoc(this, e.ctrlKey);
+                if (this.props.Document.isTemplateForField && !(e.ctrlKey || e.button > 0)) {
+                    stopPropagate = false;
+                } else {
+                    SelectionManager.SelectDoc(this, e.ctrlKey);
+                }
                 preventDefault = false;
             }
+            stopPropagate && e.stopPropagation();
             preventDefault && e.preventDefault();
         }
     }
@@ -928,6 +934,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const fallback = Cast(this.props.Document.layoutKey, "string");
         return typeof fallback === "string" ? fallback : "layout";
     }
+    rootSelected = () => {
+        return this.isSelected(false) || (this.props.Document.forceActive && this.props.rootSelected?.() ? true : false);
+    }
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
     @computed get contents() {
         TraceMobx();
@@ -937,6 +946,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             DataDoc={this.props.DataDoc}
             LayoutDoc={this.props.LayoutDoc}
             makeLink={this.makeLink}
+            rootSelected={this.rootSelected}
             fitToBox={this.props.fitToBox}
             LibraryPath={this.props.LibraryPath}
             addDocument={this.props.addDocument}
@@ -985,9 +995,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 {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} Document={d} ContainingCollectionDoc={this.props.Document}
-                            PanelWidth={returnOne} PanelHeight={returnOne} layoutKey={this.linkEndpoint(d)} ContentScaling={returnOne}
-                            backgroundColor={returnTransparent} removeDocument={undoBatch(doc => doc.hidden = true)} />
+                        <DocumentView {...this.props}
+                            Document={d}
+                            ContainingCollectionDoc={this.props.Document}
+                            PanelWidth={returnOne} PanelHeight={returnOne}
+                            layoutKey={this.linkEndpoint(d)} ContentScaling={returnOne}
+                            backgroundColor={returnTransparent}
+                            removeDocument={undoBatch(doc => doc.hidden = true)} />
                     </div>)}
             </div>;
         }
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 0305f43d5..13a1becf7 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -29,6 +29,7 @@ export interface FieldViewProps {
     dropAction: dropActionType;
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (isCtrlPressed: boolean) => void;
+    rootSelected: () => boolean;
     renderDepth: number;
     addDocument?: (document: Doc) => boolean;
     addDocTab: (document: Doc, where: string) => boolean;
diff --git a/src/client/views/nodes/FormattedTextBoxComment.tsx b/src/client/views/nodes/FormattedTextBoxComment.tsx
index 61df188f8..d1a563494 100644
--- a/src/client/views/nodes/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/FormattedTextBoxComment.tsx
@@ -181,6 +181,7 @@ export class FormattedTextBoxComment {
                                     LibraryPath={emptyPath}
                                     fitToBox={true}
                                     moveDocument={returnFalse}
+                                    rootSelected={returnFalse}
                                     getTransform={Transform.Identity}
                                     active={returnFalse}
                                     addDocument={returnFalse}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 71495d95f..c032f019d 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -31,8 +31,6 @@ import { InkingControl } from "../InkingControl";
 import { InkTool } from "../../../new_fields/InkField";
 import { TraceMobx } from "../../../new_fields/util";
 import { PdfField } from "../../../new_fields/URLField";
-import { PDFBox } from "../nodes/PDFBox";
-import { FormattedTextBox } from "../nodes/FormattedTextBox";
 import { DocumentView } from "../nodes/DocumentView";
 const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
 const pdfjsLib = require("pdfjs-dist");
@@ -61,6 +59,7 @@ interface IViewerProps {
     PanelHeight: () => number;
     ContentScaling: () => number;
     select: (isCtrlPressed: boolean) => void;
+    rootSelected: () => boolean;
     startupLive: boolean;
     renderDepth: number;
     focus: (doc: Doc) => void;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 758795ed5..7ad3474e8 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -9,7 +9,7 @@ import { documentSchema } from '../../../new_fields/documentSchemas';
 import { Id } from "../../../new_fields/FieldSymbols";
 import { createSchema, makeInterface } from '../../../new_fields/Schema';
 import { Cast, NumCast } from "../../../new_fields/Types";
-import { emptyFunction, emptyPath, returnFalse } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, returnTrue } from "../../../Utils";
 import { Transform } from "../../util/Transform";
 import { CollectionViewType } from '../collections/CollectionView';
 import { DocExtendableComponent } from '../DocComponent';
@@ -175,6 +175,7 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
                     DataDocument={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
                     LibraryPath={emptyPath}
                     fitToBox={true}
+                    rootSelected={returnTrue}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
                     addDocTab={returnFalse}
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 63cef5101..0d77026ad 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -7,7 +7,7 @@ import { observer } from "mobx-react";
 import { Doc } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { emptyFunction, emptyPath, returnFalse, Utils } from "../../../Utils";
+import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue } from "../../../Utils";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { DocumentManager } from "../../util/DocumentManager";
 import { DragManager, SetupDrag } from "../../util/DragManager";
@@ -158,6 +158,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
                 <ContentFittingDocumentView
                     Document={this.props.doc}
                     LibraryPath={emptyPath}
+                    rootSelected={returnFalse}
                     fitToBox={StrCast(this.props.doc.type).indexOf(DocumentType.COL) !== -1}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 1d2d57b96..98a6d384e 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -124,6 +124,7 @@ export default class MobileInterface extends React.Component {
                 addDocument={returnFalse}
                 addDocTab={returnFalse}
                 pinToPres={emptyFunction}
+                rootSelected={returnFalse}
                 removeDocument={undefined}
                 onClick={undefined}
                 ScreenToLocalTransform={Transform.Identity}
@@ -285,6 +286,7 @@ export default class MobileInterface extends React.Component {
                         addDocument={returnFalse}
                         addDocTab={returnFalse}
                         pinToPres={emptyFunction}
+                        rootSelected={returnFalse}
                         removeDocument={undefined}
                         onClick={undefined}
                         ScreenToLocalTransform={Transform.Identity}
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 9a90ce17f..7fe623f18 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -213,7 +213,7 @@ export class CurrentUserUtils {
             _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, dontDecorateSelection: true,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
             sourcePanel: Docs.Create.StackingDocument([dragCreators, color], {
-                _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack"
+                _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true
             }),
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
         });
-- 
cgit v1.2.3-70-g09d2


From 5338dfd24d0f6a65bb3131332746c1d2c82ef7f2 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 4 Apr 2020 15:23:42 -0400
Subject: fix to presentationView opacity. removed getScale and zoomToScale
 props which weren't being used.

---
 src/client/util/DocumentManager.ts                 | 17 --------
 src/client/util/RichTextSchema.tsx                 |  2 -
 src/client/views/GestureOverlay.tsx                |  2 -
 src/client/views/MainView.tsx                      | 12 +-----
 src/client/views/OverlayView.tsx                   |  4 +-
 src/client/views/Palette.tsx                       |  5 +--
 src/client/views/RecommendationsBox.tsx            |  2 -
 .../views/collections/CollectionDockingView.tsx    |  4 +-
 .../views/collections/CollectionLinearView.tsx     |  5 +--
 .../views/collections/CollectionTreeView.tsx       |  2 -
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  8 ----
 src/client/views/nodes/AudioBox.tsx                |  2 -
 .../views/nodes/ContentFittingDocumentView.tsx     |  2 -
 src/client/views/nodes/DocumentView.tsx            |  4 --
 src/client/views/nodes/PresBox.tsx                 | 50 +++++-----------------
 src/mobile/MobileInterface.tsx                     | 10 +----
 16 files changed, 19 insertions(+), 112 deletions(-)

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

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index e0ffaf7e0..63d864db5 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -219,22 +219,5 @@ export class DocumentManager {
             DocumentManager.Instance.jumpToDocument(link, zoom, (doc: Doc) => focus(doc, "onRight"), undefined, undefined);
         }
     }
-
-    @action
-    zoomIntoScale = (docDelegate: Doc, scale: number) => {
-        const docView = DocumentManager.Instance.getDocumentView(Doc.GetProto(docDelegate));
-        docView?.props.zoomToScale(scale);
-    }
-
-    getScaleOfDocView = (docDelegate: Doc) => {
-        const doc = Doc.GetProto(docDelegate);
-
-        const docView = DocumentManager.Instance.getDocumentView(doc);
-        if (docView) {
-            return docView.props.getScale();
-        } else {
-            return 1;
-        }
-    }
 }
 Scripting.addGlobal(function focus(doc: any) { DocumentManager.Instance.getDocumentViews(Doc.GetProto(doc)).map(view => view.props.focus(doc, true)); });
\ No newline at end of file
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 4a930177d..d4568b17f 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -831,8 +831,6 @@ export class DashDocView {
                     parentActive={returnFalse}
                     whenActiveChanged={returnFalse}
                     bringToFront={emptyFunction}
-                    zoomToScale={emptyFunction}
-                    getScale={returnOne}
                     dontRegisterView={false}
                     ContainingCollectionView={this._textBox.props.ContainingCollectionView}
                     ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 26bee9a6f..68f1d13fb 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -721,8 +721,6 @@ export default class GestureOverlay extends Touchable {
                 bringToFront={emptyFunction}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined}
-                zoomToScale={emptyFunction}
-                getScale={returnOne}
             />;
     }
 
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 558bc1a4a..420cc95ec 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -316,8 +316,6 @@ export class MainView extends React.Component {
             bringToFront={emptyFunction}
             ContainingCollectionView={undefined}
             ContainingCollectionDoc={undefined}
-            zoomToScale={emptyFunction}
-            getScale={returnOne}
         />;
     }
     @computed get dockingContent() {
@@ -416,10 +414,7 @@ export class MainView extends React.Component {
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
-                    zoomToScale={emptyFunction}
-                    getScale={returnOne}>
-                </DocumentView>
+                    ContainingCollectionDoc={undefined} />
             </div>
             <div className="mainView-contentArea" style={{ position: "relative", height: `calc(100% - ${this._buttonBarHeight}px)`, width: "100%", overflow: "visible" }}>
                 <DocumentView
@@ -443,10 +438,7 @@ export class MainView extends React.Component {
                     whenActiveChanged={emptyFunction}
                     bringToFront={emptyFunction}
                     ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
-                    zoomToScale={emptyFunction}
-                    getScale={returnOne}>
-                </DocumentView>
+                    ContainingCollectionDoc={undefined} />
                 <button className="mainView-settings" key="settings" onClick={() => SettingsManager.Instance.open()}>
                     Settings
                 </button>
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 7587071db..7cfae0bbb 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -193,9 +193,7 @@ export class OverlayView extends React.Component {
                     addDocTab={returnFalse}
                     pinToPres={emptyFunction}
                     ContainingCollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
-                    zoomToScale={emptyFunction}
-                    getScale={returnOne} />
+                    ContainingCollectionDoc={undefined}/>
             </div>;
         });
     }
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 674b27918..d088d5bba 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -58,10 +58,7 @@ export default class Palette extends React.Component<PaletteProps> {
                             whenActiveChanged={emptyFunction}
                             bringToFront={emptyFunction}
                             ContainingCollectionView={undefined}
-                            ContainingCollectionDoc={undefined}
-                            zoomToScale={emptyFunction}
-                            getScale={returnOne}>
-                        </DocumentView>
+                            ContainingCollectionDoc={undefined} />
                         <div className="palette-cover" style={{ transform: `translate(${Math.max(0, this._selectedIndex) * 50.75 + 23}px, 0px)` }}></div>
                     </div>
                 </div>
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index bf8de36b4..ddeda28ac 100644
--- a/src/client/views/RecommendationsBox.tsx
+++ b/src/client/views/RecommendationsBox.tsx
@@ -80,8 +80,6 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
                 parentActive={returnFalse}
                 whenActiveChanged={returnFalse}
                 bringToFront={emptyFunction}
-                zoomToScale={emptyFunction}
-                getScale={returnOne}
                 ContainingCollectionView={undefined}
                 ContainingCollectionDoc={undefined}
                 ContentScaling={scale}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 4209bd574..11eecf771 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -803,9 +803,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             addDocTab={this.addDocTab}
             pinToPres={DockedFrameRenderer.PinDoc}
             ContainingCollectionView={undefined}
-            ContainingCollectionDoc={undefined}
-            zoomToScale={emptyFunction}
-            getScale={returnOne} />;
+            ContainingCollectionDoc={undefined} />;
     }
 
     render() {
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 728b3066d..3bd50ad52 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -123,10 +123,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 whenActiveChanged={emptyFunction}
                                 bringToFront={emptyFunction}
                                 ContainingCollectionView={undefined}
-                                ContainingCollectionDoc={undefined}
-                                zoomToScale={emptyFunction}
-                                getScale={returnOne}>
-                            </DocumentView>
+                                ContainingCollectionDoc={undefined}/>
                         </div>;
                     })}
                 </div>
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index fc612c66d..77dd9a162 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -473,8 +473,6 @@ class TreeView extends React.Component<TreeViewProps> {
                         dontRegisterView={BoolCast(this.props.treeViewId.dontRegisterChildren)}
                         ContainingCollectionView={undefined}
                         ContainingCollectionDoc={undefined}
-                        zoomToScale={emptyFunction}
-                        getScale={returnOne}
                     />}
             </div >
             {this.props.treeViewHideHeaderFields() ? (null) : headerElements}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a164e1794..376d217bb 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -815,12 +815,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         this.Document.scale = scale * Math.min(this.props.PanelWidth() / NumCast(doc._width), this.props.PanelHeight() / NumCast(doc._height));
     }
 
-    zoomToScale = (scale: number) => {
-        this.Document.scale = scale;
-    }
-
-    getScale = () => this.Document.scale || 1;
-
     @computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; }
     @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
     backgroundHalo = () => BoolCast(this.Document.useClusters);
@@ -848,8 +842,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             backgroundHalo: this.backgroundHalo,
             parentActive: this.props.active,
             bringToFront: this.bringToFront,
-            zoomToScale: this.zoomToScale,
-            getScale: this.getScale
         };
     }
 
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index bd54d64ff..627a71d67 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -265,8 +265,6 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
                                                 ContainingCollectionDoc={this.props.Document}
                                                 parentActive={returnTrue}
                                                 bringToFront={emptyFunction}
-                                                zoomToScale={emptyFunction}
-                                                getScale={returnOne}
                                                 backgroundColor={returnTransparent} />
                                         </div>
                                         <div key={i} className="audiobox-marker" onPointerEnter={() => Doc.linkFollowHighlight(la1)}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index fdf2a9551..9ab6826a3 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -111,8 +111,6 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         focus={this.props.focus || emptyFunction}
                         bringToFront={emptyFunction}
                         dontRegisterView={this.props.dontRegisterView}
-                        zoomToScale={emptyFunction}
-                        getScale={returnOne}
                     />
                 </div>)}
         </div>);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d12530142..11bf5a6a7 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -80,10 +80,8 @@ export interface DocumentViewProps {
     bringToFront: (doc: Doc, sendToBack?: boolean) => void;
     addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
     pinToPres: (document: Doc) => void;
-    zoomToScale: (scale: number) => void;
     backgroundHalo?: () => boolean;
     backgroundColor?: (doc: Doc) => string | undefined;
-    getScale: () => number;
     ChromeHeight?: () => number;
     dontRegisterView?: boolean;
     layoutKey?: string;
@@ -959,9 +957,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             bringToFront={this.props.bringToFront}
             addDocTab={this.props.addDocTab}
             pinToPres={this.props.pinToPres}
-            zoomToScale={this.props.zoomToScale}
             backgroundColor={this.props.backgroundColor}
-            getScale={this.props.getScale}
             ContentScaling={this.childScaling}
             ChromeHeight={this.chromeHeight}
             isSelected={this.isSelected}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index a39c337ca..73d09b4e1 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -49,14 +49,15 @@ export class PresBox extends React.Component<FieldViewProps> {
         this.updateCurrentPresentation();
         if (this.childDocs[this.currentIndex + 1] !== undefined) {
             let nextSelected = this.currentIndex + 1;
+            this.gotoDocument(nextSelected, this.currentIndex);
 
-            for (; nextSelected < this.childDocs.length - 1; nextSelected++) {
-                if (!this.childDocs[nextSelected + 1].groupButton) {
+            for (nextSelected = nextSelected + 1; nextSelected < this.childDocs.length; nextSelected++) {
+                if (!this.childDocs[nextSelected].groupButton) {
                     break;
+                } else {
+                    this.gotoDocument(nextSelected, this.currentIndex);
                 }
             }
-
-            this.gotoDocument(nextSelected, this.currentIndex);
         }
     }
     back = () => {
@@ -72,13 +73,6 @@ export class PresBox extends React.Component<FieldViewProps> {
             }
             prevSelected = Math.max(0, prevSelected - 1);
 
-            if (this.currentIndex > 0 && didZoom) {
-                const prevScale = NumCast(this.childDocs[prevSelected].viewScale);
-                const curScale = DocumentManager.Instance.getScaleOfDocView(docAtCurrent);
-                if (prevScale && prevScale !== curScale) {
-                    DocumentManager.Instance.zoomIntoScale(docAtCurrent, prevScale);
-                }
-            }
             this.gotoDocument(prevSelected, this.currentIndex);
         }
     }
@@ -171,31 +165,15 @@ export class PresBox extends React.Component<FieldViewProps> {
             if (curDoc.navButton && target) {
                 DocumentManager.Instance.jumpToDocument(target, false, undefined, srcContext);
             } else if (curDoc.zoomButton && target) {
-                const curScale = DocumentManager.Instance.getScaleOfDocView(fromDoc);
                 //awaiting jump so that new scale can be found, since jumping is async
                 await DocumentManager.Instance.jumpToDocument(target, true, undefined, srcContext);
-                curDoc.viewScale = DocumentManager.Instance.getScaleOfDocView(target);
-
-                //saving the scale user was on before zooming in
-                if (curScale !== 1) {
-                    fromDoc.viewScale = curScale;
-                }
-
             }
             return;
         }
-        const curScale = DocumentManager.Instance.getScaleOfDocView(fromDoc);
 
         //awaiting jump so that new scale can be found, since jumping is async
         const presTargetDoc = await docToJump.presentationTargetDoc as Doc;
         await DocumentManager.Instance.jumpToDocument(presTargetDoc, willZoom, undefined, srcContext);
-        const newScale = DocumentManager.Instance.getScaleOfDocView(await curDoc.presentationTargetDoc as Doc);
-        curDoc.viewScale = newScale;
-        //saving the scale that user was on
-        if (curScale !== 1) {
-            fromDoc.viewScale = curScale;
-        }
-
     }
 
 
@@ -246,10 +224,9 @@ export class PresBox extends React.Component<FieldViewProps> {
     //stops the presentaton.
     resetPresentation = () => {
         this.updateCurrentPresentation();
-        this.childDocs.forEach(doc => doc.opacity = doc.viewScale = 1);
+        this.childDocs.forEach(doc => (doc.presentationTargetDoc as Doc).opacity = 1);
         this.props.Document._itemIndex = 0;
         this.props.Document.presStatus = false;
-        this.childDocs.length && DocumentManager.Instance.zoomIntoScale(this.childDocs[0], 1);
     }
 
     //The function that starts the presentation, also checking if actions should be applied
@@ -258,13 +235,13 @@ export class PresBox extends React.Component<FieldViewProps> {
         this.updateCurrentPresentation();
         this.childDocs.map(doc => {
             if (doc.hideTillShownButton && this.childDocs.indexOf(doc) > startIndex) {
-                doc.opacity = 0;
+                (doc.presentationTargetDoc as Doc).opacity = 0;
             }
             if (doc.hideAfterButton && this.childDocs.indexOf(doc) < startIndex) {
-                doc.opacity = 0;
+                (doc.presentationTargetDoc as Doc).opacity = 0;
             }
             if (doc.fadeButton && this.childDocs.indexOf(doc) < startIndex) {
-                doc.opacity = 0.5;
+                (doc.presentationTargetDoc as Doc).opacity = 0.5;
             }
         });
     }
@@ -284,16 +261,11 @@ export class PresBox extends React.Component<FieldViewProps> {
         }
     }));
 
-    /**
-     * Initially every document starts with a viewScale 1, which means
-     * that they will be displayed in a canvas with scale 1.
-     */
-    initializeScaleViews = (docList: Doc[], viewtype: number) => {
+    initializeViewAliases = (docList: Doc[], viewtype: number) => {
         const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 46;
         docList.forEach(doc => {
             doc.presBox = this.props.Document; // give contained documents a reference to the presentation
             doc.collapsedHeight = hgt;  //  set the collpased height for documents based on the type of view (Tree or Stack) they will be displaye din
-            !NumCast(doc.viewScale) && (doc.viewScale = 1);
         });
     }
 
@@ -319,7 +291,7 @@ export class PresBox extends React.Component<FieldViewProps> {
     childLayoutTemplate = () => this.props.Document._viewType === CollectionViewType.Stacking ? Cast(Doc.UserDoc().presentationTemplate, Doc, null) : undefined;
     render() {
         const mode = NumCast(this.props.Document._viewType, CollectionViewType.Invalid);
-        this.initializeScaleViews(this.childDocs, mode);
+        this.initializeViewAliases(this.childDocs, mode);
         return <div className="presBox-cont" style={{ minWidth: this.props.Document.inOverlay ? 240 : undefined, pointerEvents: this.active() || this.props.Document.inOverlay ? "all" : "none" }} >
             <div className="presBox-buttons" style={{ display: this.props.Document._chromeStatus === "disabled" ? "none" : undefined }}>
                 <select className="collectionViewBaseChrome-viewPicker"
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 98a6d384e..ed6b74ca8 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -138,10 +138,7 @@ export default class MobileInterface extends React.Component {
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
                 ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
-                zoomToScale={emptyFunction}
-                getScale={returnOne}>
-            </DocumentView>;
+                ContainingCollectionDoc={undefined} />
         }
         return "hello";
     }
@@ -300,10 +297,7 @@ export default class MobileInterface extends React.Component {
                         whenActiveChanged={emptyFunction}
                         bringToFront={emptyFunction}
                         ContainingCollectionView={undefined}
-                        ContainingCollectionDoc={undefined}
-                        zoomToScale={emptyFunction}
-                        getScale={returnOne}>
-                    </DocumentView>
+                        ContainingCollectionDoc={undefined} />
                 </div>
             );
         }
-- 
cgit v1.2.3-70-g09d2


From 48478855cc28aa423b2d1e482bd181c8c5066da6 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 5 Apr 2020 15:13:25 -0400
Subject: adding nativeWidth as props stuff

---
 src/client/util/RichTextSchema.tsx                 |  4 +-
 src/client/views/GestureOverlay.tsx                | 13 ++++---
 src/client/views/MainView.tsx                      | 10 ++++-
 src/client/views/OverlayView.tsx                   |  2 +
 src/client/views/Palette.tsx                       |  4 +-
 src/client/views/RecommendationsBox.tsx            |  4 +-
 src/client/views/TemplateMenu.tsx                  |  6 ++-
 .../views/collections/CollectionDockingView.tsx    |  4 +-
 .../views/collections/CollectionLinearView.tsx     |  6 ++-
 .../views/collections/CollectionSchemaCells.tsx    |  2 +
 .../views/collections/CollectionStackingView.tsx   | 32 +++++++++------
 src/client/views/collections/CollectionSubView.tsx |  8 ++--
 .../views/collections/CollectionTimeView.tsx       |  5 +--
 .../views/collections/CollectionTreeView.tsx       |  2 +
 src/client/views/collections/CollectionView.tsx    |  4 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  5 ++-
 src/client/views/nodes/AudioBox.tsx                |  4 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 45 +++++++++++++---------
 .../views/nodes/ContentFittingDocumentView.tsx     | 25 +++++++-----
 src/client/views/nodes/DocumentView.tsx            | 14 +++++--
 src/client/views/nodes/FieldView.tsx               |  2 +
 src/client/views/nodes/FormattedTextBox.tsx        |  4 +-
 src/client/views/nodes/ImageBox.tsx                |  4 +-
 src/client/views/nodes/KeyValuePair.tsx            |  6 ++-
 src/client/views/nodes/LinkBox.tsx                 |  2 +
 src/client/views/nodes/ScreenshotBox.tsx           |  4 +-
 src/client/views/nodes/VideoBox.tsx                |  4 +-
 src/client/views/nodes/WebBox.tsx                  |  4 +-
 src/client/views/pdf/PDFViewer.tsx                 |  4 +-
 src/mobile/MobileInterface.tsx                     | 14 +++++--
 src/new_fields/documentSchemas.ts                  |  2 +-
 src/new_fields/util.ts                             |  2 +-
 32 files changed, 170 insertions(+), 81 deletions(-)

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

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index d4568b17f..de2707d36 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -16,7 +16,7 @@ import { listSpec } from "../../new_fields/Schema";
 import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
 import { ComputedField } from "../../new_fields/ScriptField";
 import { BoolCast, Cast, NumCast, StrCast } from "../../new_fields/Types";
-import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils } from "../../Utils";
+import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils, returnZero } from "../../Utils";
 import { DocServer } from "../DocServer";
 import { Docs } from "../documents/Documents";
 import { CollectionViewType } from "../views/collections/CollectionView";
@@ -824,6 +824,8 @@ export class DashDocView {
                     addDocTab={this._textBox.props.addDocTab}
                     pinToPres={returnFalse}
                     renderDepth={self._textBox.props.renderDepth + 1}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     PanelWidth={finalLayout[WidthSym]}
                     PanelHeight={finalLayout[HeightSym]}
                     focus={this.outerFocus}
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 68f1d13fb..110b61efe 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -15,7 +15,7 @@ import { Scripting } from "../util/Scripting";
 import { FieldValue, Cast, NumCast, BoolCast } from "../../new_fields/Types";
 import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
 import HorizontalPalette from "./Palette";
-import { Utils, emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue, numberRange } from "../../Utils";
+import { Utils, emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue, numberRange, returnZero } from "../../Utils";
 import { DocumentView } from "./nodes/DocumentView";
 import { Transform } from "../util/Transform";
 import { DocumentContentsView } from "./nodes/DocumentContentsView";
@@ -695,7 +695,8 @@ export default class GestureOverlay extends Touchable {
             </svg>]
         ];
     }
-
+    screenToLocalTransform = () => new Transform(-(this._thumbX ?? 0), -(this._thumbY ?? 0) + this.height, 1);
+    return300 = () => 300;
     @action
     public openFloatingDoc = (doc: Doc) => {
         this._clipboardDoc =
@@ -709,10 +710,12 @@ export default class GestureOverlay extends Touchable {
                 pinToPres={emptyFunction}
                 onClick={undefined}
                 removeDocument={undefined}
-                ScreenToLocalTransform={() => new Transform(-(this._thumbX ?? 0), -(this._thumbY ?? 0) + this.height, 1)}
+                ScreenToLocalTransform={this.screenToLocalTransform}
                 ContentScaling={returnOne}
-                PanelWidth={() => 300}
-                PanelHeight={() => 300}
+                PanelWidth={this.return300}
+                PanelHeight={this.return300}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 renderDepth={0}
                 backgroundColor={returnEmptyString}
                 focus={emptyFunction}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 420cc95ec..bef92f0fd 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -13,7 +13,7 @@ import { listSpec } from '../../new_fields/Schema';
 import { BoolCast, Cast, FieldValue, StrCast } from '../../new_fields/Types';
 import { TraceMobx } from '../../new_fields/util';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
-import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, Utils } from '../../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils } from '../../Utils';
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs, DocumentOptions } from '../documents/Documents';
@@ -307,6 +307,8 @@ export class MainView extends React.Component {
             removeDocument={undefined}
             ScreenToLocalTransform={Transform.Identity}
             ContentScaling={returnOne}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
             PanelWidth={this.getPWidth}
             PanelHeight={this.getPHeight}
             renderDepth={0}
@@ -405,6 +407,8 @@ export class MainView extends React.Component {
                     onClick={undefined}
                     ScreenToLocalTransform={Transform.Identity}
                     ContentScaling={returnOne}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     PanelWidth={this.flyoutWidthFunc}
                     PanelHeight={this.getPHeight}
                     renderDepth={0}
@@ -424,6 +428,8 @@ export class MainView extends React.Component {
                     addDocument={undefined}
                     addDocTab={this.addDocTabFunc}
                     pinToPres={emptyFunction}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     rootSelected={returnTrue}
                     removeDocument={returnFalse}
                     onClick={undefined}
@@ -524,6 +530,8 @@ export class MainView extends React.Component {
                     onClick={undefined}
                     ScreenToLocalTransform={this.buttonBarXf}
                     ContentScaling={returnOne}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     PanelWidth={this.flyoutWidthFunc}
                     PanelHeight={this.getContentsHeight}
                     renderDepth={0}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 7cfae0bbb..4000cade5 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -182,6 +182,8 @@ export class OverlayView extends React.Component {
                     addDocument={undefined}
                     removeDocument={undefined}
                     ContentScaling={returnOne}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     PanelWidth={returnOne}
                     PanelHeight={returnOne}
                     ScreenToLocalTransform={Transform.Identity}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index d088d5bba..63744cb50 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
 import * as React from "react";
 import { Doc } from "../../new_fields/Doc";
 import { NumCast } from "../../new_fields/Types";
-import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue } from "../../Utils";
+import { emptyFunction, emptyPath, returnEmptyString, returnZero, returnFalse, returnOne, returnTrue } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { DocumentView } from "./nodes/DocumentView";
 import "./Palette.scss";
@@ -49,6 +49,8 @@ export default class Palette extends React.Component<PaletteProps> {
                             onClick={undefined}
                             ScreenToLocalTransform={Transform.Identity}
                             ContentScaling={returnOne}
+                            NativeHeight={returnZero}
+                            NativeWidth={returnZero}
                             PanelWidth={() => window.screen.width}
                             PanelHeight={() => window.screen.height}
                             renderDepth={0}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
index ddeda28ac..e66fd3eb4 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, emptyPath } from "../../Utils";
+import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath, returnZero } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { ObjectField } from "../../new_fields/ObjectField";
 import { DocumentView } from "./nodes/DocumentView";
@@ -73,6 +73,8 @@ export class RecommendationsBox extends React.Component<FieldViewProps> {
                 addDocTab={returnFalse}
                 pinToPres={returnFalse}
                 renderDepth={1}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 PanelWidth={returnXDimension}
                 PanelHeight={returnYDimension}
                 focus={emptyFunction}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index f2fb26679..c72f3681a 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -10,7 +10,7 @@ import { Doc, DocListCast } from "../../new_fields/Doc";
 import { Docs, } from "../documents/Documents";
 import { StrCast, Cast } from "../../new_fields/Types";
 import { CollectionTreeView } from "./collections/CollectionTreeView";
-import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath } from "../../Utils";
+import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath, returnZero } from "../../Utils";
 import { Transform } from "../util/Transform";
 import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
 import { Scripting } from "../util/Scripting";
@@ -149,6 +149,8 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                     select={emptyFunction}
                     renderDepth={1}
                     addDocTab={returnFalse}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     PanelWidth={this.return100}
                     PanelHeight={this.return100}
                     treeViewHideHeaderFields={true}
@@ -161,7 +163,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
             );
         }
         return <ul className="template-list" style={{ display: "block" }}>
-            <input placeholder="+ layout" ref={this._customRef} onKeyPress={this.onCustomKeypress}/>
+            <input placeholder="+ layout" ref={this._customRef} onKeyPress={this.onCustomKeypress} />
             {templateMenu}
         </ul>;
     }
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 11eecf771..28aaf0c57 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -15,7 +15,7 @@ import { FieldId } from "../../../new_fields/RefField";
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from '../../../new_fields/util';
 import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
-import { emptyFunction, returnOne, returnTrue, Utils } from "../../../Utils";
+import { emptyFunction, returnOne, returnTrue, Utils, returnZero } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { Docs } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
@@ -794,6 +794,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
             ContentScaling={this.contentScaling}
             PanelWidth={this.panelWidth}
             PanelHeight={this.panelHeight}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
             ScreenToLocalTransform={this.ScreenToLocalTransform}
             renderDepth={0}
             parentActive={returnTrue}
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 3bd50ad52..cb0206260 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -4,7 +4,7 @@ import * as React from 'react';
 import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc';
 import { makeInterface } from '../../../new_fields/Schema';
 import { BoolCast, NumCast, StrCast, Cast, ScriptCast } from '../../../new_fields/Types';
-import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse } from '../../../Utils';
+import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse, returnZero } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { Transform } from '../../util/Transform';
 import "./CollectionLinearView.scss";
@@ -114,6 +114,8 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 onClick={undefined}
                                 ScreenToLocalTransform={this.getTransform(dref)}
                                 ContentScaling={returnOne}
+                                NativeHeight={returnZero}
+                                NativeWidth={returnZero}
                                 PanelWidth={nested ? pair.layout[WidthSym] : () => this.dimension()}// ugh - need to get rid of this inline function to avoid recomputing
                                 PanelHeight={nested ? pair.layout[HeightSym] : () => this.dimension()}
                                 renderDepth={this.props.renderDepth + 1}
@@ -123,7 +125,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                                 whenActiveChanged={emptyFunction}
                                 bringToFront={emptyFunction}
                                 ContainingCollectionView={undefined}
-                                ContainingCollectionDoc={undefined}/>
+                                ContainingCollectionDoc={undefined} />
                         </div>;
                     })}
                 </div>
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index 7b16ff546..ae71c54f7 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -172,6 +172,8 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             whenActiveChanged: emptyFunction,
             PanelHeight: returnZero,
             PanelWidth: returnZero,
+            NativeHeight: returnZero,
+            NativeWidth: returnZero,
             addDocTab: this.props.addDocTab,
             pinToPres: this.props.pinToPres,
             ContentScaling: returnOne
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d21e17bbc..8ceeb66f1 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -11,7 +11,7 @@ import { listSpec } from "../../../new_fields/Schema";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from "../../../new_fields/util";
-import { Utils, setupMoveUpEvents, emptyFunction } from "../../../Utils";
+import { Utils, setupMoveUpEvents, emptyFunction, returnZero, returnOne } from "../../../Utils";
 import { DragManager, dropActionType } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
@@ -24,7 +24,7 @@ import "./CollectionStackingView.scss";
 import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionViewType } from "./CollectionView";
-import { Docs } from "../../documents/Documents";
+import { DocumentView } from "../nodes/DocumentView";
 
 @observer
 export class CollectionStackingView extends CollectionSubView(doc => doc) {
@@ -53,6 +53,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; }
 
     children(docs: Doc[], columns?: number) {
+        TraceMobx();
         this._docXfs.length = 0;
         return docs.map((d, i) => {
             const height = () => this.getDocHeight(d);
@@ -115,7 +116,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     componentDidMount() {
         super.componentDidMount();
         this._heightDisposer = reaction(() => {
-            if (this.props.Document._autoHeight) {
+            if (this.props.Document._autoHeight && !this.props.NativeHeight()) {
                 const sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
                 if (this.isStackingView) {
                     const res = this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => {
@@ -168,12 +169,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
         const layoutDoc = Doc.Layout(doc, this.props.childLayoutTemplate?.());
         const height = () => this.getDocHeight(doc);
-        return <ContentFittingDocumentView
+        return <DocumentView
             Document={doc}
-            DataDocument={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
+            DataDoc={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
             backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
+            FreezeDimensions={this.props.freezeDimensions}
             renderDepth={this.props.renderDepth + 1}
             fitToBox={this.props.fitToBox}
             rootSelected={this.rootSelected}
@@ -181,18 +183,22 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
             PanelWidth={width}
             PanelHeight={height}
-            getTransform={dxf}
+            ScreenToLocalTransform={dxf}
             focus={this.props.focus}
-            CollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document}
-            CollectionView={this.props.CollectionView}
+            ContainingCollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document}
+            ContainingCollectionView={this.props.CollectionView}
             addDocument={this.props.addDocument}
             moveDocument={this.props.moveDocument}
             removeDocument={this.props.removeDocument}
-            active={this.props.active}
+            parentActive={this.props.active}
+            bringToFront={emptyFunction}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
+            ContentScaling={returnOne}
             whenActiveChanged={this.props.whenActiveChanged}
             addDocTab={this.props.addDocTab}
             pinToPres={this.props.pinToPres}>
-        </ContentFittingDocumentView>;
+        </DocumentView>;
     }
 
     getDocWidth(d?: Doc) {
@@ -387,7 +393,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return sections.map(section => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1]));
     }
 
-    @computed get scaling() { return !this.props.Document._nativeWidth ? 1 : this.props.PanelHeight() / NumCast(this.props.Document._nativeHeight); }
+
+    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth) || this.props.NativeWidth() || 0; }
+    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight) || this.props.NativeHeight() || 0; }
+
+    @computed get scaling() { return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; }
 
     render() {
         TraceMobx();
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d1d6ae3c1..32449de5e 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -36,12 +36,15 @@ export interface CollectionViewProps extends FieldViewProps {
     setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
     rootSelected: () => boolean;
     fieldKey: string;
+    NativeWidth: () => number;
+    NativeHeight: () => number;
 }
 
 export interface SubCollectionViewProps extends CollectionViewProps {
     CollectionView: Opt<CollectionView>;
     children?: never | (() => JSX.Element[]) | React.ReactNode;
-    overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explict list (see LinkBox)
+    freezeDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height
+    overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
     ignoreFields?: string[]; // used in TreeView to ignore specified fields (see LinkBox)
     isAnnotationOverlay?: boolean;
     annotationsKey: string;
@@ -213,9 +216,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this 
             if (docDragData) {
                 let added = false;
-                if (this.props.Document._freezeOnDrop) {
-                    de.complete.docDragData?.droppedDocuments.forEach(drop => Doc.freezeNativeDimensions(drop, drop[WidthSym](), drop[HeightSym]()));
-                }
                 if (docDragData.dropAction || docDragData.userDropAction) {
                     added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
                 } else if (docDragData.moveDocument) {
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 4f77e8b0e..d9a10cdc8 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -5,7 +5,7 @@ import { List } from "../../../new_fields/List";
 import { ObjectField } from "../../../new_fields/ObjectField";
 import { RichTextField } from "../../../new_fields/RichTextField";
 import { ComputedField, ScriptField } from "../../../new_fields/ScriptField";
-import { NumCast, StrCast } from "../../../new_fields/Types";
+import { NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
 import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils";
 import { Scripting } from "../../util/Scripting";
 import { ContextMenu } from "../ContextMenu";
@@ -29,7 +29,6 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
         this.props.Document.onChildClick = undefined;
     }
     componentDidMount() {
-        this.props.Document._freezeOnDrop = true;
         const childDetailed = this.props.Document.childDetailed; // bcz: needs to be here to make sure the childDetailed layout template has been loaded when the first item is clicked;
         const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailView'); alias.layoutKey='layout_detailedView'; alias.dropAction='alias'; alias.removeDropProperties=new List<string>(['dropAction']); useRightSplit(alias, shiftKey); ";
         this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "string", containingCollection: Doc.name, shiftKey: "boolean" });
@@ -73,7 +72,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
 
     @computed get contents() {
         return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%" }}>
-            <CollectionFreeFormView  {...this.props} layoutEngine={this.layoutEngine} />
+            <CollectionFreeFormView {...this.props} freezeDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
         </div>;
     }
 
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 77dd9a162..10da50e35 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -465,6 +465,8 @@ class TreeView extends React.Component<TreeViewProps> {
                         ContentScaling={returnOne}
                         PanelWidth={returnZero}
                         PanelHeight={returnZero}
+                        NativeHeight={returnZero}
+                        NativeWidth={returnZero}
                         renderDepth={1}
                         focus={emptyFunction}
                         parentActive={returnTrue}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index a727da267..5d08a2bd8 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -13,7 +13,7 @@ import { List } from '../../../new_fields/List';
 import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../new_fields/Types';
 import { ImageField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
-import { Utils, setupMoveUpEvents, returnFalse } from '../../../Utils';
+import { Utils, setupMoveUpEvents, returnFalse, returnZero } from '../../../Utils';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
 import { ImageUtils } from '../../util/Import & Export/ImageUtils';
@@ -424,6 +424,8 @@ export class CollectionView extends Touchable<FieldViewProps> {
                     <CollectionTreeView {...this.props}
                         CollectionView={this}
                         treeViewHideTitle={true}
+                        NativeHeight={returnZero}
+                        NativeWidth={returnZero}
                         treeViewHideHeaderFields={true}
                         onCheckedClick={this.scriptField!}
                         ignoreFields={this.treeIgnoreFields}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d4e44b9a9..f22f1a304 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -89,8 +89,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     @computed get fitToContent() { return (this.props.fitToBox || this.Document._fitToBox) && !this.isAnnotationOverlay; }
     @computed get parentScaling() { return this.props.ContentScaling && this.fitToContent && !this.isAnnotationOverlay ? this.props.ContentScaling() : 1; }
     @computed get contentBounds() { return aggregateBounds(this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc.xPadding, 10), NumCast(this.layoutDoc.yPadding, 10)); }
-    @computed get nativeWidth() { return this.Document._fitToContent ? 0 : NumCast(this.Document._nativeWidth); }
-    @computed get nativeHeight() { return this.fitToContent ? 0 : NumCast(this.Document._nativeHeight); }
+    @computed get nativeWidth() { return this.Document._fitToContent ? 0 : NumCast(this.Document._nativeWidth, this.props.NativeWidth()); }
+    @computed get nativeHeight() { return this.fitToContent ? 0 : NumCast(this.Document._nativeHeight, this.props.NativeHeight()); }
     private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; }
     private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
     private easing = () => this.props.Document.panTransformType === "Ease";
@@ -825,6 +825,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             DataDoc: childData,
             Document: childLayout,
             LibraryPath: this.libraryPath,
+            FreezeDimensions: this.props.freezeDimensions,
             layoutKey: undefined,
             rootSelected: this.rootSelected,
             dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index be0e1aec4..ff9630273 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -7,7 +7,7 @@ import { AudioField, nullAudio } from "../../../new_fields/URLField";
 import { DocExtendableComponent } from "../DocComponent";
 import { makeInterface, createSchema } from "../../../new_fields/Schema";
 import { documentSchema } from "../../../new_fields/documentSchemas";
-import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse } from "../../../Utils";
+import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero } from "../../../Utils";
 import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx";
 import { DateField } from "../../../new_fields/DateField";
 import { SelectionManager } from "../../util/SelectionManager";
@@ -261,6 +261,8 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
                                         <div className={this.props.PanelHeight() < 32 ? "audioBox-linker-mini" : "audioBox-linker"} key={"linker" + i}>
                                             <DocumentView {...this.props}
                                                 Document={l}
+                                                NativeHeight={returnZero}
+                                                NativeWidth={returnZero}
                                                 rootSelected={returnFalse}
                                                 layoutKey={Doc.LinkEndpoint(l, la2)}
                                                 ContainingCollectionDoc={this.props.Document}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 356192797..8a4842427 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -41,10 +41,11 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         const hgt = this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.dataProvider && this.dataProvider ? this.dataProvider.height : this.layoutDoc[HeightSym]();
         return (hgt === undefined && this.nativeWidth && this.nativeHeight) ? this.width * this.nativeHeight / this.nativeWidth : hgt;
     }
+    @computed get freezeDimensions() { return this.props.FreezeDimensions || this.layoutDoc._freezeChildDimensions; }
     @computed get dataProvider() { return this.props.dataProvider && this.props.dataProvider(this.props.Document) ? this.props.dataProvider(this.props.Document) : undefined; }
-    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth); }
-    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight); }
-
+    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
+    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
+   
     @computed get renderScriptDim() {
         if (this.Document.renderScript) {
             const someView = Cast(this.props.Document.someView, Doc);
@@ -68,6 +69,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         .scale(1 / this.contentScaling())
 
     focusDoc = (doc: Doc) => this.props.focus(doc, false);
+    NativeWidth = () => this.nativeWidth;
+    NativeHeight = () => this.nativeHeight;
     render() {
         TraceMobx();
         return <div className="collectionFreeFormDocumentView-container"
@@ -89,22 +92,26 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 pointerEvents: this.props.Document.isBackground ? "none" : undefined
             }} >
 
-            {!this.props.fitToBox ? 
-            <DocumentView {...this.props}
-                dragDivName={"collectionFreeFormDocumentView-container"}
-                ContentScaling={this.contentScaling}
-                ScreenToLocalTransform={this.getTransform}
-                backgroundColor={this.props.backgroundColor}
-                PanelWidth={this.panelWidth}
-                PanelHeight={this.panelHeight} /> 
-            : <ContentFittingDocumentView {...this.props}
-                CollectionDoc={this.props.ContainingCollectionDoc}
-                DataDocument={this.props.DataDoc}
-                getTransform={this.getTransform}
-                active={returnFalse}
-                focus={this.focusDoc}
-                PanelWidth={this.panelWidth}
-                PanelHeight={this.panelHeight}
+            {!this.props.fitToBox ?
+                <DocumentView {...this.props}
+                    dragDivName={"collectionFreeFormDocumentView-container"}
+                    ContentScaling={this.contentScaling}
+                    ScreenToLocalTransform={this.getTransform}
+                    backgroundColor={this.props.backgroundColor}
+                    NativeHeight={this.NativeHeight}
+                    NativeWidth={this.NativeWidth}
+                    PanelWidth={this.panelWidth}
+                    PanelHeight={this.panelHeight} />
+                : <ContentFittingDocumentView {...this.props}
+                    CollectionDoc={this.props.ContainingCollectionDoc}
+                    DataDocument={this.props.DataDoc}
+                    getTransform={this.getTransform}
+                    NativeHeight={this.NativeHeight}
+                    NativeWidth={this.NativeWidth}
+                    active={returnFalse}
+                    focus={this.focusDoc}
+                    PanelWidth={this.panelWidth}
+                    PanelHeight={this.panelHeight}
                 />}
         </div>;
     }
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 9ab6826a3..09675bf73 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -18,6 +18,9 @@ interface ContentFittingDocumentViewProps {
     Document?: Doc;
     DataDocument?: Doc;
     LayoutDoc?: () => Opt<Doc>;
+    NativeWidth?: () => number;
+    NativeHeight?: () => number;
+    FreezeDimensions?: boolean;
     LibraryPath: Doc[];
     childDocs?: Doc[];
     renderDepth: number;
@@ -47,12 +50,12 @@ interface ContentFittingDocumentViewProps {
 export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
     public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
     private get layoutDoc() { return this.props.Document && (this.props.LayoutDoc?.() || Doc.Layout(this.props.Document)); }
-    private get nativeWidth() { return NumCast(this.layoutDoc?._nativeWidth, this.props.PanelWidth()); }
-    private get nativeHeight() { return NumCast(this.layoutDoc?._nativeHeight, this.props.PanelHeight()); }
+    private nativeWidth = () => NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || this.props.PanelWidth());
+    private nativeHeight = () => NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || this.props.PanelHeight());
     @computed get scaling() {
-        const wscale = this.props.PanelWidth() / (this.nativeWidth || this.props.PanelWidth() || 1);
-        if (wscale * this.nativeHeight > this.props.PanelHeight()) {
-            return (this.props.PanelHeight() / (this.nativeHeight || this.props.PanelHeight() || 1)) || 1;
+        const wscale = this.props.PanelWidth() / (this.nativeWidth() || this.props.PanelWidth() || 1);
+        if (wscale * this.nativeHeight() > this.props.PanelHeight()) {
+            return (this.props.PanelHeight() / (this.nativeHeight() || this.props.PanelHeight() || 1)) || 1;
         }
         return wscale || 1;
     }
@@ -61,12 +64,12 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     private PanelWidth = () => this.panelWidth;
     private PanelHeight = () => this.panelHeight;
 
-    @computed get panelWidth() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth(); }
-    @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight(); }
+    @computed get panelWidth() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeWidth() * this.contentScaling() : this.props.PanelWidth(); }
+    @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); }
 
     private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling());
-    private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; }
-    private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight * this.contentScaling()) / 2 : 0; }
+    private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
+    private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight() * this.contentScaling()) / 2 : 0; }
 
     @computed get borderRounding() { return StrCast(this.props.Document?.borderRounding); }
 
@@ -81,7 +84,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                     style={{
                         transform: `translate(${this.centeringOffset}px, 0px)`,
                         borderRadius: this.borderRounding,
-                        height: Math.abs(this.centeringYOffset) > 0.001 ? `${100 * this.nativeHeight / this.nativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(),
+                        height: Math.abs(this.centeringYOffset) > 0.001 ? `${100 * this.nativeHeight() / this.nativeWidth() * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(),
                         width: Math.abs(this.centeringOffset) > 0.001 ? `${100 * (this.props.PanelWidth() - this.centeringOffset * 2) / this.props.PanelWidth()}%` : this.props.PanelWidth()
                     }}>
                     <DocumentView {...this.props}
@@ -89,6 +92,8 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         DataDoc={this.props.DataDocument}
                         LayoutDoc={this.props.LayoutDoc}
                         LibraryPath={this.props.LibraryPath}
+                        NativeWidth={this.nativeWidth}
+                        NativeHeight={this.nativeHeight}
                         fitToBox={this.props.fitToBox}
                         layoutKey={this.props.layoutKey}
                         dropAction={this.props.dropAction}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index aa3c1b3a2..9c9f2e48e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -3,7 +3,7 @@ import * as fa from '@fortawesome/free-solid-svg-icons';
 import { action, computed, runInAction, trace, observable } from "mobx";
 import { observer } from "mobx-react";
 import * as rp from "request-promise";
-import { Doc, DocListCast, Opt } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc";
 import { Document, PositionDocument } from '../../../new_fields/documentSchemas';
 import { Id } from '../../../new_fields/FieldSymbols';
 import { InkTool } from '../../../new_fields/InkField';
@@ -56,6 +56,9 @@ export type DocFocusFunc = () => boolean;
 export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView>;
     ContainingCollectionDoc: Opt<Doc>;
+    FreezeDimensions?: boolean;
+    NativeWidth: () => number;
+    NativeHeight: () => number;
     Document: Doc;
     DataDoc?: Doc;
     LayoutDoc?: () => Opt<Doc>;
@@ -109,11 +112,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     public get ContentDiv() { return this._mainCont.current; }
     @computed get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
     @computed get topMost() { return this.props.renderDepth === 0; }
-    @computed get nativeWidth() { return this.layoutDoc._nativeWidth || 0; }
-    @computed get nativeHeight() { return this.layoutDoc._nativeHeight || 0; }
+    @computed get freezeDimensions() { return this.props.FreezeDimensions || this.layoutDoc._freezeChildDimensions; }
+    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
+    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
     @computed get onClickHandler() { return this.props.onClick || this.layoutDoc.onClick || this.Document.onClick; }
     @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; }
     @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; }
+    NativeWidth = () => this.nativeWidth;
+    NativeHeight = () => this.nativeHeight;
 
     private _firstX: number = -1;
     private _firstY: number = -1;
@@ -965,6 +971,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         TraceMobx();
         return (<DocumentContentsView ContainingCollectionView={this.props.ContainingCollectionView}
             ContainingCollectionDoc={this.props.ContainingCollectionDoc}
+            NativeHeight={this.NativeHeight}
+            NativeWidth={this.NativeWidth}
             Document={this.props.Document}
             DataDoc={this.props.DataDoc}
             LayoutDoc={this.props.LayoutDoc}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 13a1becf7..dfcb03985 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -45,6 +45,8 @@ export interface FieldViewProps {
     focus: (doc: Doc) => void;
     PanelWidth: () => number;
     PanelHeight: () => number;
+    NativeHeight: () => number;
+    NativeWidth: () => number;
     setVideoBox?: (player: VideoBox) => void;
     ContentScaling: () => number;
     ChromeHeight?: () => number;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 94195fbd6..37770a2e1 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -22,7 +22,7 @@ import { RichTextUtils } from '../../../new_fields/RichTextUtils';
 import { createSchema, makeInterface } from "../../../new_fields/Schema";
 import { Cast, NumCast, StrCast, BoolCast, DateCast } from "../../../new_fields/Types";
 import { TraceMobx } from '../../../new_fields/util';
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, Utils, returnTrue } from '../../../Utils';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, Utils, returnTrue, returnZero } from '../../../Utils';
 import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
 import { DocServer } from "../../DocServer";
 import { Docs, DocUtils } from '../../documents/Documents';
@@ -1216,6 +1216,8 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
                         <CollectionFreeFormView {...this.props}
                             PanelHeight={this.props.PanelHeight}
                             PanelWidth={this.sidebarWidth}
+                            NativeHeight={returnZero}
+                            NativeWidth={returnZero}
                             annotationsKey={this.annotationKey}
                             isAnnotationOverlay={false}
                             focus={this.props.focus}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 00057055f..a4d3f3d79 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -14,7 +14,7 @@ import { ComputedField } from '../../../new_fields/ScriptField';
 import { Cast, NumCast, StrCast } from '../../../new_fields/Types';
 import { AudioField, ImageField } from '../../../new_fields/URLField';
 import { TraceMobx } from '../../../new_fields/util';
-import { emptyFunction, returnOne, Utils } from '../../../Utils';
+import { emptyFunction, returnOne, Utils, returnZero } from '../../../Utils';
 import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices';
 import { Docs } from '../../documents/Documents';
 import { Networking } from '../../Network';
@@ -445,6 +445,8 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
             <CollectionFreeFormView {...this.props}
                 PanelHeight={this.props.PanelHeight}
                 PanelWidth={this.props.PanelWidth}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 annotationsKey={this.annotationKey}
                 isAnnotationOverlay={true}
                 focus={this.props.focus}
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index ef039c857..6dc4ae578 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -62,13 +62,15 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             rootSelected: returnFalse,
             isSelected: returnFalse,
             select: emptyFunction,
-            dropAction:"alias",
-            bringToFront:emptyFunction,
+            dropAction: "alias",
+            bringToFront: emptyFunction,
             renderDepth: 1,
             active: returnFalse,
             whenActiveChanged: emptyFunction,
             ScreenToLocalTransform: Transform.Identity,
             focus: emptyFunction,
+            NativeHeight: returnZero,
+            NativeWidth: returnZero,
             PanelWidth: this.props.PanelWidth,
             PanelHeight: this.props.PanelHeight,
             addDocTab: returnFalse,
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 0e327e130..542c86049 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -23,6 +23,8 @@ export class LinkBox extends DocExtendableComponent<FieldViewProps, LinkDocument
             <CollectionTreeView {...this.props}
                 ChromeHeight={returnZero}
                 overrideDocuments={[this.dataDoc]}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 ignoreFields={Cast(this.props.Document.linkBoxExcludedKeys, listSpec("string"), null)}
                 annotationsKey={""}
                 CollectionView={undefined}
diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx
index 7c58a5148..58ff4971a 100644
--- a/src/client/views/nodes/ScreenshotBox.tsx
+++ b/src/client/views/nodes/ScreenshotBox.tsx
@@ -10,7 +10,7 @@ import { makeInterface } from "../../../new_fields/Schema";
 import { ScriptField } from "../../../new_fields/ScriptField";
 import { Cast, StrCast } from "../../../new_fields/Types";
 import { VideoField } from "../../../new_fields/URLField";
-import { emptyFunction, returnFalse, returnOne, Utils } from "../../../Utils";
+import { emptyFunction, returnFalse, returnOne, Utils, returnZero } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { ContextMenu } from "../ContextMenu";
@@ -170,6 +170,8 @@ export class ScreenshotBox extends DocAnnotatableComponent<FieldViewProps, Scree
                 <CollectionFreeFormView {...this.props}
                     PanelHeight={this.props.PanelHeight}
                     PanelWidth={this.props.PanelWidth}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     annotationsKey={this.annotationKey}
                     focus={this.props.focus}
                     isSelected={this.props.isSelected}
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 24b66d8f7..d384ad12f 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -11,7 +11,7 @@ import { createSchema, makeInterface } from "../../../new_fields/Schema";
 import { ScriptField } from "../../../new_fields/ScriptField";
 import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
 import { VideoField } from "../../../new_fields/URLField";
-import { Utils, emptyFunction, returnOne } from "../../../Utils";
+import { Utils, emptyFunction, returnOne, returnZero } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
 import { ContextMenu } from "../ContextMenu";
@@ -352,6 +352,8 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum
                 <CollectionFreeFormView {...this.props}
                     PanelHeight={this.props.PanelHeight}
                     PanelWidth={this.props.PanelWidth}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
                     annotationsKey={this.annotationKey}
                     focus={this.props.focus}
                     isSelected={this.props.isSelected}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 838fbefb1..ea5d601ec 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -9,7 +9,7 @@ import { InkTool } from "../../../new_fields/InkField";
 import { makeInterface } from "../../../new_fields/Schema";
 import { Cast, NumCast } from "../../../new_fields/Types";
 import { WebField } from "../../../new_fields/URLField";
-import { Utils, returnOne, emptyFunction } from "../../../Utils";
+import { Utils, returnOne, emptyFunction, returnZero } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import { ImageUtils } from "../../util/Import & Export/ImageUtils";
@@ -335,6 +335,8 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
                 PanelHeight={this.props.PanelHeight}
                 PanelWidth={this.props.PanelWidth}
                 annotationsKey={this.annotationKey}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 focus={this.props.focus}
                 isSelected={this.props.isSelected}
                 isAnnotationOverlay={true}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 25ceb6218..36e687f71 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -9,7 +9,7 @@ import { List } from "../../../new_fields/List";
 import { makeInterface, createSchema } from "../../../new_fields/Schema";
 import { ScriptField, ComputedField } from "../../../new_fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { smoothScroll, Utils, emptyFunction, returnOne, intersectRect, addStyleSheet, addStyleSheetRule, clearStyleSheetRules } from "../../../Utils";
+import { smoothScroll, Utils, emptyFunction, returnOne, intersectRect, addStyleSheet, addStyleSheetRule, clearStyleSheetRules, returnZero } from "../../../Utils";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import { CompiledScript, CompileScript } from "../../util/Scripting";
@@ -648,6 +648,8 @@ export class PDFViewer extends DocAnnotatableComponent<IViewerProps, PdfDocument
                 setPreviewCursor={this.setPreviewCursor}
                 PanelHeight={this.panelWidth}
                 PanelWidth={this.panelHeight}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 dropAction={"alias"}
                 VisibleHeight={this.visibleHeight}
                 focus={this.props.focus}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 5f766c121..c87ac719c 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -7,7 +7,7 @@ import { Doc, DocListCast } from '../new_fields/Doc';
 import { Docs } from '../client/documents/Documents';
 import { CollectionView } from '../client/views/collections/CollectionView';
 import { DocumentView } from '../client/views/nodes/DocumentView';
-import { emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue } from '../Utils';
+import { emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue, returnZero } from '../Utils';
 import { Transform } from '../client/util/Transform';
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faPenNib, faHighlighter, faEraser, faMousePointer, faBreadSlice, faTrash, faCheck, faLongArrowAltLeft } from '@fortawesome/free-solid-svg-icons';
@@ -129,6 +129,8 @@ export default class MobileInterface extends React.Component {
                 onClick={undefined}
                 ScreenToLocalTransform={Transform.Identity}
                 ContentScaling={returnOne}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
                 PanelWidth={() => window.screen.width}
                 PanelHeight={() => window.screen.height}
                 renderDepth={0}
@@ -173,6 +175,8 @@ export default class MobileInterface extends React.Component {
         e.stopPropagation();
     }
 
+    panelHeight = () => window.innerHeight;
+    panelWidth = () => window.innerWidth;
     renderInkingContent = () => {
         console.log("rendering inking content");
         // TODO: support panning and zooming
@@ -201,8 +205,10 @@ export default class MobileInterface extends React.Component {
                         bringToFront={emptyFunction}
                         addDocTab={returnFalse}
                         pinToPres={emptyFunction}
-                        PanelHeight={() => window.innerHeight}
-                        PanelWidth={() => window.innerWidth}
+                        PanelWidth={this.panelWidth}
+                        PanelHeight={this.panelHeight}
+                        NativeHeight={returnZero}
+                        NativeWidth={returnZero}
                         focus={emptyFunction}
                         isSelected={returnFalse}
                         select={emptyFunction}
@@ -289,6 +295,8 @@ export default class MobileInterface extends React.Component {
                         onClick={undefined}
                         ScreenToLocalTransform={Transform.Identity}
                         ContentScaling={returnOne}
+                        NativeHeight={returnZero}
+                        NativeWidth={returnZero}
                         PanelWidth={() => window.screen.width}
                         PanelHeight={() => window.screen.height}
                         renderDepth={0}
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 1a5a471a0..ff02596f7 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -28,7 +28,7 @@ export const documentSchema = createSchema({
     _pivotField: "string",      // specifies which field should be used as the timeline/pivot axis
     _replacedChrome: "string",  // what the default chrome is replaced with. Currently only supports the value of 'replaced' for PresBox's.
     _chromeStatus: "string",    // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed'
-    _freezeOnDrop: "boolean",    // whether a document without native dimensions should have its width/height frozen as native dimensions on drop.  Used by Timeline view to make sure documents are scaled to fit the display thumbnail
+    _freezeChildDimensions: "boolean", // freezes child document dimensions (e.g., used by time/pivot view to make sure all children will be scaled to fit their display rectangle)
     color: "string",            // foreground color of document
     backgroundColor: "string",  // background color of document
     opacity: "number",          // opacity of document
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 8c719ccd8..480a55da0 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");
 }
 
-const tracing = false;
+const tracing = true;
 export function TraceMobx() {
     tracing && trace();
 }
-- 
cgit v1.2.3-70-g09d2


From 881a522e1562f948202fcdb6a5a87485bf778597 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 5 Apr 2020 18:30:46 -0400
Subject: more fixes to NativeWidth/Height & FreezeDimensions props stuff

---
 .../views/collections/CollectionSchemaView.tsx      | 11 +++++++----
 .../views/collections/CollectionStackingView.tsx    |  1 -
 .../collectionFreeForm/CollectionFreeFormView.tsx   |  8 ++++++--
 .../views/nodes/CollectionFreeFormDocumentView.tsx  |  6 +++---
 .../views/nodes/ContentFittingDocumentView.tsx      |  1 -
 src/client/views/nodes/DocumentContentsView.tsx     | 10 ----------
 src/client/views/nodes/DocumentView.tsx             | 21 +++++++++++----------
 src/client/views/nodes/ImageBox.tsx                 |  6 +++---
 8 files changed, 30 insertions(+), 34 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index a1b541f74..df9f65a21 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -28,7 +28,8 @@ import "./CollectionSchemaView.scss";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionView } from "./CollectionView";
 import { ContentFittingDocumentView } from "../nodes/ContentFittingDocumentView";
-import { setupMoveUpEvents, emptyFunction } from "../../../Utils";
+import { setupMoveUpEvents, emptyFunction, returnZero, returnOne } from "../../../Utils";
+import { DocumentView } from "../nodes/DocumentView";
 
 library.add(faCog, faPlus, faSortUp, faSortDown);
 library.add(faTable);
@@ -117,12 +118,14 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     @computed
     get previewPanel() {
-        return <div ref={this.createTarget}>
+        return !this.previewDocument ? (null) : <div ref={this.createTarget} style={{ width: `${this.previewWidth()}px` }}>
             <ContentFittingDocumentView
                 Document={this.previewDocument}
                 DataDocument={undefined}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
+                focus={emptyFunction}
                 LibraryPath={this.props.LibraryPath}
-                childDocs={this.childDocs}
                 renderDepth={this.props.renderDepth}
                 rootSelected={this.rootSelected}
                 PanelWidth={this.previewWidth}
@@ -180,7 +183,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     render() {
         return <div className="collectionSchemaView-container">
-            <div className="collectionSchemaView-tableContainer" onPointerDown={this.onPointerDown} onWheel={e => this.props.active(true) && e.stopPropagation()} onDrop={e => this.onExternalDrop(e, {})} ref={this.createTarget}>
+            <div className="collectionSchemaView-tableContainer" style={{ width: `calc(100% - ${this.previewWidth()}px)` }} onPointerDown={this.onPointerDown} onWheel={e => this.props.active(true) && e.stopPropagation()} onDrop={e => this.onExternalDrop(e, {})} ref={this.createTarget}>
                 {this.schemaTable}
             </div>
             {this.dividerDragger}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index b11baeb7a..8ceeb66f1 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -47,7 +47,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
     @computed get showAddAGroup() { return (this.pivotField && (this.props.Document._chromeStatus !== 'view-mode' && this.props.Document._chromeStatus !== 'disabled')); }
     @computed get columnWidth() {
-        TraceMobx();
         return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin,
             this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250));
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f22f1a304..ceec9dfcc 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -952,11 +952,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         const elements: ViewDefResult[] = computedElementData.slice();
         this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).forEach(pair =>
             elements.push({
-                ele: <CollectionFreeFormDocumentView key={pair.layout[Id]}  {...this.getChildDocumentViewProps(pair.layout, pair.data)}
+                ele: <CollectionFreeFormDocumentView
+                    key={pair.layout[Id]}
+                    {...this.getChildDocumentViewProps(pair.layout, pair.data)}
                     dataProvider={this.childDataProvider}
                     LayoutDoc={this.childLayoutDocFunc}
                     jitterRotation={NumCast(this.props.Document.jitterRotation)}
-                    fitToBox={this.props.fitToBox || this.props.layoutEngine !== undefined} />,
+                    fitToBox={this.props.fitToBox || this.props.layoutEngine !== undefined}
+                    FreezeDimensions={this.props.layoutEngine !== undefined}
+                />,
                 bounds: this.childDataProvider(pair.layout)
             }));
 
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 8a4842427..e4c8bbd7b 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -41,11 +41,11 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         const hgt = this.renderScriptDim ? this.renderScriptDim.height : this.props.height !== undefined ? this.props.height : this.props.dataProvider && this.dataProvider ? this.dataProvider.height : this.layoutDoc[HeightSym]();
         return (hgt === undefined && this.nativeWidth && this.nativeHeight) ? this.width * this.nativeHeight / this.nativeWidth : hgt;
     }
-    @computed get freezeDimensions() { return this.props.FreezeDimensions || this.layoutDoc._freezeChildDimensions; }
+    @computed get freezeDimensions() { return this.props.FreezeDimensions; }
     @computed get dataProvider() { return this.props.dataProvider && this.props.dataProvider(this.props.Document) ? this.props.dataProvider(this.props.Document) : undefined; }
     @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
     @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
-   
+
     @computed get renderScriptDim() {
         if (this.Document.renderScript) {
             const someView = Cast(this.props.Document.someView, Doc);
@@ -61,7 +61,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         return undefined;
     }
 
-    contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox ? this.width / this.nativeWidth : 1;
+    contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox && !this.freezeDimensions ? this.width / this.nativeWidth : 1;
     panelWidth = () => (this.dataProvider?.width || this.props.PanelWidth());
     panelHeight = () => (this.dataProvider?.height || this.props.PanelHeight());
     getTransform = (): Transform => this.props.ScreenToLocalTransform()
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 09675bf73..52e5ed1dd 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -22,7 +22,6 @@ interface ContentFittingDocumentViewProps {
     NativeHeight?: () => number;
     FreezeDimensions?: boolean;
     LibraryPath: Doc[];
-    childDocs?: Doc[];
     renderDepth: number;
     fitToBox?: boolean;
     layoutKey?: string;
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 4b6729fe7..dc71ba280 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -63,16 +63,6 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
     hideOnLeave?: boolean,
     makeLink?: () => Opt<Doc>,  // function to call when a link is made
 }> {
-    constructor(props: any) {
-        super(props);
-        console.log("Consructr" + this.props.Document.title);
-    }
-    componentWillUpdate() {
-        console.log("WillUpdate" + this.props.Document.title);
-    }
-    componentWillReceiveProps() {
-        console.log("Receive" + this.props.Document.title);
-    }
     @computed get layout(): string {
         TraceMobx();
         if (!this.layoutDoc) return "<p>awaiting layout</p>";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index eceda4a18..d800579a1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -112,11 +112,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     public get ContentDiv() { return this._mainCont.current; }
     @computed get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
     @computed get topMost() { return this.props.renderDepth === 0; }
-    @computed get freezeDimensions() { return this.props.FreezeDimensions || this.layoutDoc._freezeChildDimensions; }
-    @computed get nativeWidth() { return this.layoutDoc._nativeWidth || 0; }
-    @computed get nativeHeight() { return this.layoutDoc._nativeHeight || 0; }
-    // @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
-    // @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
+    @computed get freezeDimensions() { return this.props.FreezeDimensions; }
+    @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
+    @computed get nativeHeight() { return NumCast(this.layoutDoc._nativeHeight, this.props.NativeHeight() || (this.freezeDimensions ? this.layoutDoc[HeightSym]() : 0)); }
     @computed get onClickHandler() { return this.props.onClick || this.layoutDoc.onClick || this.Document.onClick; }
     @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; }
     @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; }
@@ -969,12 +967,15 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return this.isSelected(false) || (this.props.Document.forceActive && this.props.rootSelected?.() ? true : false);
     }
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
+    panelWidth = () => this.props.PanelWidth();
+    panelHeight = () => this.props.PanelHeight();
+    screenToLocalTransform = () => this.props.ScreenToLocalTransform();
     @computed get contents() {
         TraceMobx();
         return (<DocumentContentsView ContainingCollectionView={this.props.ContainingCollectionView}
             ContainingCollectionDoc={this.props.ContainingCollectionDoc}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
+            NativeWidth={this.NativeWidth}
+            NativeHeight={this.NativeHeight}
             Document={this.props.Document}
             DataDoc={this.props.DataDoc}
             LayoutDoc={this.props.LayoutDoc}
@@ -985,10 +986,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             addDocument={this.props.addDocument}
             removeDocument={this.props.removeDocument}
             moveDocument={this.props.moveDocument}
-            ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+            ScreenToLocalTransform={this.screenToLocalTransform}
             renderDepth={this.props.renderDepth}
-            PanelWidth={this.props.PanelWidth}
-            PanelHeight={this.props.PanelHeight}
+            PanelWidth={this.panelWidth}
+            PanelHeight={this.panelHeight}
             focus={this.props.focus}
             parentActive={this.props.parentActive}
             whenActiveChanged={this.props.whenActiveChanged}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index a4d3f3d79..052251d94 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -436,9 +436,9 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
         const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging";
         return (<div className={`imageBox${dragging}`} onContextMenu={this.specificContextMenu}
             style={{
-                transform: `scale(${this.props.ContentScaling()})`,
-                width: `${100 / this.props.ContentScaling()}%`,
-                height: `${100 / this.props.ContentScaling()}%`,
+                transform: this.props.PanelWidth() ? undefined : `scale(${this.props.ContentScaling()})`,
+                width: this.props.PanelWidth() ? `${this.props.PanelWidth()}px` : `${100 / this.props.ContentScaling()}%`,
+                height: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`,
                 pointerEvents: this.props.Document.isBackground ? "none" : undefined,
                 borderRadius: `${Number(StrCast(this.layoutDoc.borderRounding).replace("px", "")) / this.props.ContentScaling()}px`
             }} >
-- 
cgit v1.2.3-70-g09d2


From bc23e69a88234c213e444b1aa3c5eb895c35aca9 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 6 Apr 2020 00:23:19 -0400
Subject: many more fixes to nativewidth/height layout changes.

---
 .../views/collections/CollectionSchemaView.tsx     | 51 ++++++++++++----------
 .../views/collections/CollectionStackingView.tsx   | 14 +++---
 src/client/views/collections/CollectionSubView.tsx |  2 +-
 .../views/collections/CollectionTimeView.tsx       |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  7 +--
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 19 +++++---
 .../CollectionMulticolumnView.tsx                  |  5 +++
 .../CollectionMultirowView.tsx                     |  6 ++-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  3 +-
 .../views/nodes/ContentFittingDocumentView.tsx     | 17 ++++----
 src/client/views/nodes/DocumentView.tsx            |  4 +-
 src/client/views/nodes/FormattedTextBox.scss       |  9 ++--
 src/client/views/nodes/ImageBox.tsx                |  4 +-
 src/new_fields/util.ts                             |  2 +-
 14 files changed, 82 insertions(+), 63 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index df9f65a21..e835811c9 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -12,7 +12,7 @@ import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { ComputedField } from "../../../new_fields/ScriptField";
-import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
+import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
 import { Docs, DocumentOptions } from "../../documents/Documents";
 import { Gateway } from "../../northstar/manager/Gateway";
 import { CompileScript, Transformer, ts } from "../../util/Scripting";
@@ -118,29 +118,32 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     @computed
     get previewPanel() {
-        return !this.previewDocument ? (null) : <div ref={this.createTarget} style={{ width: `${this.previewWidth()}px` }}>
-            <ContentFittingDocumentView
-                Document={this.previewDocument}
-                DataDocument={undefined}
-                NativeHeight={returnZero}
-                NativeWidth={returnZero}
-                focus={emptyFunction}
-                LibraryPath={this.props.LibraryPath}
-                renderDepth={this.props.renderDepth}
-                rootSelected={this.rootSelected}
-                PanelWidth={this.previewWidth}
-                PanelHeight={this.previewHeight}
-                getTransform={this.getPreviewTransform}
-                CollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document}
-                CollectionView={this.props.CollectionView}
-                moveDocument={this.props.moveDocument}
-                addDocument={this.props.addDocument}
-                removeDocument={this.props.removeDocument}
-                active={this.props.active}
-                whenActiveChanged={this.props.whenActiveChanged}
-                addDocTab={this.props.addDocTab}
-                pinToPres={this.props.pinToPres}
-            />
+        return <div ref={this.createTarget} style={{ width: `${this.previewWidth()}px` }}>
+            {!this.previewDocument ? (null) :
+                <ContentFittingDocumentView
+                    Document={this.previewDocument}
+                    DataDocument={undefined}
+                    NativeHeight={returnZero}
+                    NativeWidth={returnZero}
+                    fitToBox={true}
+                    FreezeDimensions={true}
+                    focus={emptyFunction}
+                    LibraryPath={this.props.LibraryPath}
+                    renderDepth={this.props.renderDepth}
+                    rootSelected={this.rootSelected}
+                    PanelWidth={this.previewWidth}
+                    PanelHeight={this.previewHeight}
+                    getTransform={this.getPreviewTransform}
+                    CollectionDoc={this.props.CollectionView?.props.Document}
+                    CollectionView={this.props.CollectionView}
+                    moveDocument={this.props.moveDocument}
+                    addDocument={this.props.addDocument}
+                    removeDocument={this.props.removeDocument}
+                    active={this.props.active}
+                    whenActiveChanged={this.props.whenActiveChanged}
+                    addDocTab={this.props.addDocTab}
+                    pinToPres={this.props.pinToPres}
+                />}
         </div>;
     }
 
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 8ceeb66f1..d17b1ee48 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -116,7 +116,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     componentDidMount() {
         super.componentDidMount();
         this._heightDisposer = reaction(() => {
-            if (this.props.Document._autoHeight && !this.props.NativeHeight()) {
+            if (this.props.Document._autoHeight && !this.layoutDoc._nativeHeight) {
                 const sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
                 if (this.isStackingView) {
                     const res = this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => {
@@ -175,17 +175,19 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
-            FreezeDimensions={this.props.freezeDimensions}
+            FreezeDimensions={this.props.freezeChildDimensions}
             renderDepth={this.props.renderDepth + 1}
-            fitToBox={this.props.fitToBox}
+            PanelWidth={width}
+            PanelHeight={height}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
+            fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
             rootSelected={this.rootSelected}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
-            PanelWidth={width}
-            PanelHeight={height}
             ScreenToLocalTransform={dxf}
             focus={this.props.focus}
-            ContainingCollectionDoc={this.props.CollectionView && this.props.CollectionView.props.Document}
+            ContainingCollectionDoc={this.props.CollectionView?.props.Document}
             ContainingCollectionView={this.props.CollectionView}
             addDocument={this.props.addDocument}
             moveDocument={this.props.moveDocument}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 32449de5e..a46bc67a2 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -43,7 +43,7 @@ export interface CollectionViewProps extends FieldViewProps {
 export interface SubCollectionViewProps extends CollectionViewProps {
     CollectionView: Opt<CollectionView>;
     children?: never | (() => JSX.Element[]) | React.ReactNode;
-    freezeDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height
+    freezeChildDimensions?: boolean; // used by TimeView to coerce documents to treat their width height as their native width/height
     overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explicit list (see LinkBox)
     ignoreFields?: string[]; // used in TreeView to ignore specified fields (see LinkBox)
     isAnnotationOverlay?: boolean;
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index d9a10cdc8..4b005ba42 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -72,7 +72,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
 
     @computed get contents() {
         return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%" }}>
-            <CollectionFreeFormView {...this.props} freezeDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
+            <CollectionFreeFormView {...this.props} freezeChildDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
         </div>;
     }
 
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 10da50e35..eff4758cf 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -103,7 +103,7 @@ class TreeView extends React.Component<TreeViewProps> {
     set treeViewOpen(c: boolean) { if (this.props.treeViewPreventOpen) this._overrideTreeViewOpen = c; else this.props.document.treeViewOpen = this._overrideTreeViewOpen = c; }
     @computed get treeViewOpen() { return (!this.props.treeViewPreventOpen && BoolCast(this.props.document.treeViewOpen)) || this._overrideTreeViewOpen; }
     @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.defaultExpandedView); }
-    @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
+    @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.containingCollection.maxEmbedHeight, 200); }
     @computed get dataDoc() { return this.templateDataDoc ? this.templateDataDoc : this.props.document; }
     @computed get fieldKey() {
         const splits = StrCast(Doc.LayoutField(this.props.document)).split("fieldKey={\'");
@@ -280,7 +280,7 @@ class TreeView extends React.Component<TreeViewProps> {
     }
     docWidth = () => {
         const layoutDoc = Doc.Layout(this.props.document);
-        const aspect = NumCast(layoutDoc._nativeHeight) / NumCast(layoutDoc._nativeWidth);
+        const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
         if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.panelWidth() - 20));
         return NumCast(layoutDoc._nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.panelWidth() - 20) : this.props.panelWidth() - 20;
     }
@@ -288,7 +288,7 @@ class TreeView extends React.Component<TreeViewProps> {
         const layoutDoc = Doc.Layout(this.props.document);
         const bounds = this.boundsOfCollectionDocument;
         return Math.min(this.MAX_EMBED_HEIGHT, (() => {
-            const aspect = NumCast(layoutDoc._nativeHeight) / NumCast(layoutDoc._nativeWidth, 1);
+            const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
             if (aspect) return this.docWidth() * aspect;
             if (bounds) return this.docWidth() * (bounds.b - bounds.y) / (bounds.r - bounds.x);
             return layoutDoc._fitWidth ? (!this.props.document.nativeHeight ? NumCast(this.props.containingCollection._height) :
@@ -376,6 +376,7 @@ class TreeView extends React.Component<TreeViewProps> {
                     rootSelected={returnTrue}
                     backgroundColor={this.props.backgroundColor}
                     fitToBox={this.boundsOfCollectionDocument !== undefined}
+                    FreezeDimensions={true}
                     PanelWidth={this.docWidth}
                     PanelHeight={this.docHeight}
                     getTransform={this.docTransform}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ceec9dfcc..22dd2d831 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -15,7 +15,7 @@ import { ScriptField } from "../../../../new_fields/ScriptField";
 import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types";
 import { TraceMobx } from "../../../../new_fields/util";
 import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnOne, Utils } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnOne, Utils, returnZero } from "../../../../Utils";
 import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
 import { DocServer } from "../../../DocServer";
 import { Docs } from "../../../documents/Documents";
@@ -89,7 +89,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     @computed get fitToContent() { return (this.props.fitToBox || this.Document._fitToBox) && !this.isAnnotationOverlay; }
     @computed get parentScaling() { return this.props.ContentScaling && this.fitToContent && !this.isAnnotationOverlay ? this.props.ContentScaling() : 1; }
     @computed get contentBounds() { return aggregateBounds(this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc.xPadding, 10), NumCast(this.layoutDoc.yPadding, 10)); }
-    @computed get nativeWidth() { return this.Document._fitToContent ? 0 : NumCast(this.Document._nativeWidth, this.props.NativeWidth()); }
+    @computed get nativeWidth() { return this.fitToContent ? 0 : NumCast(this.Document._nativeWidth, this.props.NativeWidth()); }
     @computed get nativeHeight() { return this.fitToContent ? 0 : NumCast(this.Document._nativeHeight, this.props.NativeHeight()); }
     private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; }
     private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
@@ -822,10 +822,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps {
         return {
             ...this.props,
+            NativeHeight: returnZero,
+            NativeWidth: returnZero,
+            fitToBox: false,
             DataDoc: childData,
             Document: childLayout,
             LibraryPath: this.libraryPath,
-            FreezeDimensions: this.props.freezeDimensions,
+            FreezeDimensions: this.props.freezeChildDimensions,
             layoutKey: undefined,
             rootSelected: this.rootSelected,
             dropAction: StrCast(this.props.Document.childDropAction) as dropActionType,
@@ -958,8 +961,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     dataProvider={this.childDataProvider}
                     LayoutDoc={this.childLayoutDocFunc}
                     jitterRotation={NumCast(this.props.Document.jitterRotation)}
-                    fitToBox={this.props.fitToBox || this.props.layoutEngine !== undefined}
-                    FreezeDimensions={this.props.layoutEngine !== undefined}
+                    fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)}
+                    FreezeDimensions={BoolCast(this.props.freezeChildDimensions)}
                 />,
                 bounds: this.childDataProvider(pair.layout)
             }));
@@ -1122,8 +1125,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     @computed get contentScaling() {
         if (this.props.annotationsKey) return 0;
-        const hscale = this.nativeHeight ? this.props.PanelHeight() / this.nativeHeight : 1;
-        const wscale = this.nativeWidth ? this.props.PanelWidth() / this.nativeWidth : 1;
+        const nw = NumCast(this.Document._nativeWidth, this.props.NativeWidth());
+        const nh = NumCast(this.Document._nativeHeight, this.props.NativeHeight());
+        const hscale = nh ? this.props.PanelHeight() / nh : 1;
+        const wscale = nw ? this.props.PanelWidth() / nw : 1;
         return wscale < hscale ? wscale : hscale;
     }
     render() {
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index aa8e1fb43..7e511ae34 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -14,6 +14,7 @@ import "./collectionMulticolumnView.scss";
 import ResizeBar from './MulticolumnResizer';
 import WidthLabel from './MulticolumnWidthLabel';
 import { List } from '../../../../new_fields/List';
+import { returnZero } from '../../../../Utils';
 
 type MulticolumnDocument = makeInterface<[typeof documentSchema]>;
 const MulticolumnDocument = makeInterface(documentSchema);
@@ -208,6 +209,10 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
             {...this.props}
             Document={layout}
             DataDocument={layout.resolvedDataDoc as Doc}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
+            fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+            FreezeDimensions={BoolCast(this.props.Document._freezeChildDimensions)}
             backgroundColor={this.props.backgroundColor}
             CollectionDoc={this.props.Document}
             PanelWidth={width}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 5e59f8237..daf1fda6c 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -6,7 +6,7 @@ import * as React from "react";
 import { Doc } from '../../../../new_fields/Doc';
 import { NumCast, StrCast, BoolCast, ScriptCast } from '../../../../new_fields/Types';
 import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView';
-import { Utils } from '../../../../Utils';
+import { Utils, returnZero } from '../../../../Utils';
 import "./collectionMultirowView.scss";
 import { computed, trace, observable, action } from 'mobx';
 import { Transform } from '../../../util/Transform';
@@ -208,6 +208,10 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
             {...this.props}
             Document={layout}
             DataDocument={layout.resolvedDataDoc as Doc}
+            NativeHeight={returnZero}
+            NativeWidth={returnZero}
+            fitToBox={BoolCast(this.props.Document._freezeChildDimensions)}
+            FreezeDimensions={BoolCast(this.props.Document._freezeChildDimensions)}
             backgroundColor={this.props.backgroundColor}
             CollectionDoc={this.props.Document}
             PanelWidth={width}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index e4c8bbd7b..7e9e654cd 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -10,7 +10,6 @@ import { DocumentView, DocumentViewProps } from "./DocumentView";
 import React = require("react");
 import { PositionDocument } from "../../../new_fields/documentSchemas";
 import { TraceMobx } from "../../../new_fields/util";
-import { returnFalse } from "../../../Utils";
 import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
 
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
@@ -108,7 +107,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                     getTransform={this.getTransform}
                     NativeHeight={this.NativeHeight}
                     NativeWidth={this.NativeWidth}
-                    active={returnFalse}
+                    active={this.props.parentActive}
                     focus={this.focusDoc}
                     PanelWidth={this.panelWidth}
                     PanelHeight={this.panelHeight}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 52e5ed1dd..f66ff8020 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -2,7 +2,7 @@ import React = require("react");
 import { computed } from "mobx";
 import { observer } from "mobx-react";
 import "react-table/react-table.css";
-import { Doc, Opt } from "../../../new_fields/Doc";
+import { Doc, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc";
 import { ScriptField } from "../../../new_fields/ScriptField";
 import { NumCast, StrCast } from "../../../new_fields/Types";
 import { TraceMobx } from "../../../new_fields/util";
@@ -15,7 +15,7 @@ import "./ContentFittingDocumentView.scss";
 import { dropActionType } from "../../util/DragManager";
 
 interface ContentFittingDocumentViewProps {
-    Document?: Doc;
+    Document: Doc;
     DataDocument?: Doc;
     LayoutDoc?: () => Opt<Doc>;
     NativeWidth?: () => number;
@@ -48,13 +48,14 @@ interface ContentFittingDocumentViewProps {
 @observer
 export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
     public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
-    private get layoutDoc() { return this.props.Document && (this.props.LayoutDoc?.() || Doc.Layout(this.props.Document)); }
-    private nativeWidth = () => NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || this.props.PanelWidth());
-    private nativeHeight = () => NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || this.props.PanelHeight());
+    private get layoutDoc() { return this.props.LayoutDoc?.() || Doc.Layout(this.props.Document); }
+    @computed get freezeDimensions() { return this.props.FreezeDimensions; }
+    nativeWidth = () => { return NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth())); }
+    nativeHeight = () => { return NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight())); }
     @computed get scaling() {
-        const wscale = this.props.PanelWidth() / (this.nativeWidth() || this.props.PanelWidth() || 1);
+        const wscale = this.props.PanelWidth() / this.nativeWidth();
         if (wscale * this.nativeHeight() > this.props.PanelHeight()) {
-            return (this.props.PanelHeight() / (this.nativeHeight() || this.props.PanelHeight() || 1)) || 1;
+            return (this.props.PanelHeight() / this.nativeHeight()) || 1;
         }
         return wscale || 1;
     }
@@ -67,7 +68,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); }
 
     private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling());
-    private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
+    private get centeringOffset() { return this.nativeWidth() && !this.props.Document._fitWidth ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
     private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight() * this.contentScaling()) / 2 : 0; }
 
     @computed get borderRounding() { return StrCast(this.props.Document?.borderRounding); }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d800579a1..32c5a02e5 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -110,7 +110,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     public get displayName() { return "DocumentView(" + this.props.Document.title + ")"; } // this makes mobx trace() statements more descriptive
     public get ContentDiv() { return this._mainCont.current; }
-    @computed get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
+    get active() { return SelectionManager.IsSelected(this, true) || this.props.parentActive(true); }
     @computed get topMost() { return this.props.renderDepth === 0; }
     @computed get freezeDimensions() { return this.props.FreezeDimensions; }
     @computed get nativeWidth() { return NumCast(this.layoutDoc._nativeWidth, this.props.NativeWidth() || (this.freezeDimensions ? this.layoutDoc[WidthSym]() : 0)); }
@@ -124,8 +124,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     private _firstX: number = -1;
     private _firstY: number = -1;
 
-
-
     handle1PointerHoldStart = (e: Event, me: InteractionUtils.MultiTouchEvent<React.TouchEvent>): any => {
         this.removeMoveListeners();
         this.removeEndListeners();
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 526939438..7d40b3149 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -39,11 +39,6 @@
         position: absolute;
     }
 }
-
-.collectionfreeformview-container {
-    position: relative;
-}
-
 .formattedTextBox-outer {
     position: relative;
     overflow: auto;
@@ -75,6 +70,10 @@
     position: absolute;
     right: 0;
 
+    .collectionfreeformview-container {
+        position: relative;
+    }
+    
     >.formattedTextBox-sidebar-handle {
         right: unset;
         left: -5;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 052251d94..e0b3a6809 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -433,12 +433,14 @@ export class ImageBox extends DocAnnotatableComponent<FieldViewProps, ImageDocum
     contentFunc = () => [this.content];
     render() {
         TraceMobx();
+        const rotation = NumCast(this.dataDoc[this.fieldKey + "-rotation"]);
+        const aspect = (rotation % 180) ? this.Document[HeightSym]() / this.Document[WidthSym]() : 1;
         const dragging = !SelectionManager.GetIsDragging() ? "" : "-dragging";
         return (<div className={`imageBox${dragging}`} onContextMenu={this.specificContextMenu}
             style={{
                 transform: this.props.PanelWidth() ? undefined : `scale(${this.props.ContentScaling()})`,
                 width: this.props.PanelWidth() ? `${this.props.PanelWidth()}px` : `${100 / this.props.ContentScaling()}%`,
-                height: this.props.PanelWidth() ? undefined : `${100 / this.props.ContentScaling()}%`,
+                height: this.props.PanelWidth() ? `${this.props.PanelWidth() * aspect}px` : `${100 / this.props.ContentScaling()}%`,
                 pointerEvents: this.props.Document.isBackground ? "none" : undefined,
                 borderRadius: `${Number(StrCast(this.layoutDoc.borderRounding).replace("px", "")) / this.props.ContentScaling()}px`
             }} >
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 480a55da0..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");
 }
 
-const tracing = true;
+const tracing = false;
 export function TraceMobx() {
     tracing && trace();
 }
-- 
cgit v1.2.3-70-g09d2


From 11f5c3139074db379f64f7a3be98493cf18cbfd3 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 6 Apr 2020 04:07:45 -0400
Subject: everything's working with panelwidth/height etc stuff?? maybe?

---
 .../views/collections/CollectionStackingView.tsx   | 109 +++++++++++++--------
 .../CollectionStackingViewFieldColumn.tsx          |   3 +-
 .../views/collections/CollectionTreeView.tsx       |   5 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   1 +
 .../views/nodes/ContentFittingDocumentView.tsx     |  14 +--
 src/new_fields/util.ts                             |   2 +-
 6 files changed, 82 insertions(+), 52 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d17b1ee48..d9183cdb6 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -24,7 +24,7 @@ import "./CollectionStackingView.scss";
 import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
 import { CollectionSubView } from "./CollectionSubView";
 import { CollectionViewType } from "./CollectionView";
-import { DocumentView } from "../nodes/DocumentView";
+const _global = (window /* browser */ || global /* node */) as any;
 
 @observer
 export class CollectionStackingView extends CollectionSubView(doc => doc) {
@@ -47,6 +47,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
     @computed get showAddAGroup() { return (this.pivotField && (this.props.Document._chromeStatus !== 'view-mode' && this.props.Document._chromeStatus !== 'disabled')); }
     @computed get columnWidth() {
+        TraceMobx();
         return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin,
             this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250));
     }
@@ -113,34 +114,49 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return fields;
     }
 
+    getSimpleDocHeight(d?: Doc) {
+        if (!d) return 0;
+        const layoutDoc = Doc.Layout(d, this.props.childLayoutTemplate?.());
+        const nw = NumCast(layoutDoc._nativeWidth);
+        const nh = NumCast(layoutDoc._nativeHeight);
+        let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
+        if (!layoutDoc._fitWidth && nw && nh) {
+            const aspect = nw && nh ? nh / nw : 1;
+            if (!(this.props.Document.fillColumn)) wid = Math.min(layoutDoc[WidthSym](), wid);
+            return wid * aspect;
+        }
+        return layoutDoc._fitWidth ? wid * NumCast(layoutDoc.scrollHeight, nh) / (nw || 1) : layoutDoc[HeightSym]();
+    }
     componentDidMount() {
         super.componentDidMount();
-        this._heightDisposer = reaction(() => {
-            if (this.props.Document._autoHeight && !this.layoutDoc._nativeHeight) {
-                const sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
-                if (this.isStackingView) {
-                    const res = this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => {
-                        const r1 = Math.max(maxHght,
-                            (this.Sections.size ? 50 : 0) + s.reduce((height, d, i) => {
-                                const val = height + this.getDocHeight(d) + (i === s.length - 1 ? this.yMargin : this.gridGap);
-                                return val;
-                            }, this.yMargin));
-                        return r1;
-                    }, 0);
-                    return res;
-                } else {
-                    const sum = Array.from(this._heightMap.values()).reduce((acc: number, curr: number) => acc += curr, 0);
-                    return this.props.ContentScaling() * (sum + (this.Sections.size ? (this.props.Document.miniHeaders ? 20 : 85) : -15));
-                }
-            }
-            return -1;
-        },
-            (hgt: number) => {
-                const doc = hgt === -1 ? undefined : this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
-                doc && hgt > 0 && (Doc.Layout(doc)._height = hgt);
-            },
-            { fireImmediately: true }
-        );
+        // this._heightDisposer = reaction(() => {
+        //     TraceMobx();
+        //     if (this.props.Document._autoHeight && !this.layoutDoc._nativeHeight) {
+        //         const sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
+        //         if (this.isStackingView) {
+        //             const res = Math.max(...sectionsList.map((s, i) => {
+        //                 const secSize = (this.Sections.size ? 50 : 0) + s.reduce((height, d, i) => {
+        //                     const val = this.getSimpleDocHeight(d) + (i === s.length - 1 ? this.yMargin : this.gridGap);
+        //                     console.log(d.title + " " + val + " => " + (val + height));
+        //                     return height + val;
+        //                 }, this.yMargin);
+        //                 console.log("Sec" + i + " = " + secSize);
+        //                 return secSize;
+        //             }));
+        //             return res * this.props.ContentScaling();
+        //         } else {
+        //             const sum = Array.from(this._heightMap.values()).reduce((acc: number, curr: number) => acc += curr, 0);
+        //             return this.props.ContentScaling() * (sum + (this.Sections.size ? (this.props.Document.miniHeaders ? 20 : 85) : -15));
+        //         }
+        //     }
+        //     return -1;
+        // },
+        //     (hgt: number) => {
+        //         const doc = hgt === -1 ? undefined : this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
+        //         doc && hgt > 0 && (Doc.Layout(doc)._height = hgt);
+        //     },
+        //     { fireImmediately: true }
+        // );
 
         // reset section headers when a new filter is inputted
         this._pivotFieldDisposer = reaction(
@@ -169,9 +185,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
         const layoutDoc = Doc.Layout(doc, this.props.childLayoutTemplate?.());
         const height = () => this.getDocHeight(doc);
-        return <DocumentView
+        return <ContentFittingDocumentView
             Document={doc}
-            DataDoc={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
+            DataDocument={dataDoc || (doc[DataSym] !== doc && doc[DataSym])}
             backgroundColor={this.props.backgroundColor}
             LayoutDoc={this.props.childLayoutTemplate}
             LibraryPath={this.props.LibraryPath}
@@ -185,22 +201,18 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             rootSelected={this.rootSelected}
             dropAction={StrCast(this.props.Document.childDropAction) as dropActionType}
             onClick={layoutDoc.isTemplateDoc ? this.onClickHandler : this.onChildClickHandler}
-            ScreenToLocalTransform={dxf}
+            getTransform={dxf}
             focus={this.props.focus}
-            ContainingCollectionDoc={this.props.CollectionView?.props.Document}
-            ContainingCollectionView={this.props.CollectionView}
+            CollectionDoc={this.props.CollectionView?.props.Document}
+            CollectionView={this.props.CollectionView}
             addDocument={this.props.addDocument}
             moveDocument={this.props.moveDocument}
             removeDocument={this.props.removeDocument}
-            parentActive={this.props.active}
-            bringToFront={emptyFunction}
-            NativeHeight={returnZero}
-            NativeWidth={returnZero}
-            ContentScaling={returnOne}
+            active={this.props.active}
             whenActiveChanged={this.props.whenActiveChanged}
             addDocTab={this.props.addDocTab}
             pinToPres={this.props.pinToPres}>
-        </DocumentView>;
+        </ContentFittingDocumentView>;
     }
 
     getDocWidth(d?: Doc) {
@@ -295,6 +307,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         });
     }
     headings = () => Array.from(this.Sections);
+    refList = new Map<any, number>();
     sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
         const key = this.pivotField;
         let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
@@ -305,6 +318,21 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const cols = () => this.isStackingView ? 1 : Math.max(1, Math.min(this.filteredChildren.length,
             Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
         return <CollectionStackingViewFieldColumn
+            observeHeight={(ref) => {
+                if (ref) {
+                    this.refList.set(ref, 0);
+                    this.observer = new _global.ResizeObserver(action((entries: any) => {
+                        if (this.props.Document.autoHeight && ref) {
+                            const doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
+                            for (const entry of entries) {
+                                this.refList.set(ref, entry.contentRect.height);
+                            }
+                            Doc.Layout(doc)._height = Math.max(...Array.from(this.refList.entries()).map(entry => Number(getComputedStyle(entry[0]).height.replace("px", ""))));
+                        }
+                    }));
+                    this.observer.observe(ref);
+                }
+            }}
             key={heading ? heading.heading : ""}
             cols={cols}
             headings={this.headings}
@@ -323,11 +351,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         const y = this._scroll; // required for document decorations to update when the text box container is scrolled
         const { scale, translateX, translateY } = Utils.GetScreenTransform(dref);
         const outerXf = Utils.GetScreenTransform(this._masonryGridRef!);
-        const scaling = 1 / Math.min(1, this.props.PanelHeight() / this.layoutDoc[HeightSym]());
         const offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
-        const offsetx = (doc[WidthSym]() - doc[WidthSym]() / scaling) / 2;
         const offsety = (this.props.ChromeHeight && this.props.ChromeHeight() < 0 ? this.props.ChromeHeight() : 0);
-        return this.props.ScreenToLocalTransform().translate(offset[0] - offsetx, offset[1] + offsety).scale(scaling);
+        return this.props.ScreenToLocalTransform().translate(offset[0], offset[1] + offsety);
     }
 
     sectionMasonry = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
@@ -401,6 +427,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
 
     @computed get scaling() { return !this.nativeWidth ? 1 : this.props.PanelHeight() / this.nativeHeight; }
 
+    observer: any;
     render() {
         TraceMobx();
         const editableViewProps = {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 0a48c95e4..dcaffe7af 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -39,6 +39,7 @@ interface CSVFieldColumnProps {
     type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined;
     createDropTarget: (ele: HTMLDivElement) => void;
     screenToLocalTransform: () => Transform;
+    observeHeight: (myref: any) => void;
 }
 
 @observer
@@ -358,7 +359,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                 {this.props.parent.Document.hideHeadings ? (null) : headingView}
                 {
                     this.collapsed ? (null) :
-                        <div>
+                        <div ref={ref => ref && this.props.observeHeight(ref)}>
                             <div key={`${heading}-stack`} className={`collectionStackingView-masonry${singleColumn ? "Single" : "Grid"}`}
                                 style={{
                                     padding: singleColumn ? `${columnYMargin}px ${0}px ${style.yMargin}px ${0}px` : `${columnYMargin}px ${0}px`,
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index eff4758cf..7edda5a4f 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -267,8 +267,9 @@ class TreeView extends React.Component<TreeViewProps> {
     docTransform = () => {
         const { scale, translateX, translateY } = Utils.GetScreenTransform(this._dref.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] + (this.props.ChromeHeight && this.props.ChromeHeight() < 0 ? this.props.ChromeHeight() : 0));
+        const offset = this.props.ScreenToLocalTransform().transformDirection((outerXf.translateX - translateX), outerXf.translateY - translateY);
+        const finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]);
+
         return finalXf;
     }
     getTransform = () => {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 22dd2d831..9581ec255 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -99,6 +99,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     private zoomScaling = () => (1 / this.parentScaling) * (this.fitToContent ?
         Math.min(this.props.PanelHeight() / (this.contentBounds.b - this.contentBounds.y), this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x)) :
         this.Document.scale || 1)
+
     private centeringShiftX = () => !this.nativeWidth && !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling : 0;  // shift so pan position is at center of window for non-overlay collections
     private centeringShiftY = () => !this.nativeHeight && !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling : 0;// shift so pan position is at center of window for non-overlay collections
     private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index f66ff8020..642264b85 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -50,8 +50,8 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
     private get layoutDoc() { return this.props.LayoutDoc?.() || Doc.Layout(this.props.Document); }
     @computed get freezeDimensions() { return this.props.FreezeDimensions; }
-    nativeWidth = () => { return NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth())); }
-    nativeHeight = () => { return NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight())); }
+    nativeWidth = () => NumCast(this.layoutDoc?._nativeWidth, this.props.NativeWidth?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[WidthSym]() : this.props.PanelWidth()));
+    nativeHeight = () => NumCast(this.layoutDoc?._nativeHeight, this.props.NativeHeight?.() || (this.freezeDimensions && this.layoutDoc ? this.layoutDoc[HeightSym]() : this.props.PanelHeight()));
     @computed get scaling() {
         const wscale = this.props.PanelWidth() / this.nativeWidth();
         if (wscale * this.nativeHeight() > this.props.PanelHeight()) {
@@ -64,8 +64,8 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
     private PanelWidth = () => this.panelWidth;
     private PanelHeight = () => this.panelHeight;
 
-    @computed get panelWidth() { return this.nativeWidth && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeWidth() * this.contentScaling() : this.props.PanelWidth(); }
-    @computed get panelHeight() { return this.nativeHeight && (!this.props.Document || !this.props.Document._fitWidth) ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); }
+    @computed get panelWidth() { return this.nativeWidth && !this.props.Document._fitWidth ? this.nativeWidth() * this.contentScaling() : this.props.PanelWidth(); }
+    @computed get panelHeight() { return this.nativeHeight && !this.props.Document._fitWidth ? this.nativeHeight() * this.contentScaling() : this.props.PanelHeight(); }
 
     private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling());
     private get centeringOffset() { return this.nativeWidth() && !this.props.Document._fitWidth ? (this.props.PanelWidth() - this.nativeWidth() * this.contentScaling()) / 2 : 0; }
@@ -94,6 +94,9 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         LibraryPath={this.props.LibraryPath}
                         NativeWidth={this.nativeWidth}
                         NativeHeight={this.nativeHeight}
+                        PanelWidth={this.PanelWidth}
+                        PanelHeight={this.PanelHeight}
+                        ContentScaling={this.contentScaling}
                         fitToBox={this.props.fitToBox}
                         layoutKey={this.props.layoutKey}
                         dropAction={this.props.dropAction}
@@ -110,9 +113,6 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
                         parentActive={this.props.active}
                         ScreenToLocalTransform={this.getTransform}
                         renderDepth={this.props.renderDepth}
-                        ContentScaling={this.contentScaling}
-                        PanelWidth={this.PanelWidth}
-                        PanelHeight={this.PanelHeight}
                         focus={this.props.focus || emptyFunction}
                         bringToFront={emptyFunction}
                         dontRegisterView={this.props.dontRegisterView}
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 8c719ccd8..480a55da0 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");
 }
 
-const tracing = false;
+const tracing = true;
 export function TraceMobx() {
     tracing && trace();
 }
-- 
cgit v1.2.3-70-g09d2


From 892174ef482f3d45167a0c2d1c3163e6b9443c66 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 7 Apr 2020 11:52:25 -0400
Subject: got rid of some run-time errors/warnings related to CORS-ifying
 imagebox requests, and avoiding memoizing messages for computedFn's outside
 reactions.

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/SelectionManager.ts                |  8 ++-
 src/client/views/DocComponent.tsx                  |  8 +--
 src/client/views/GestureOverlay.tsx                |  1 -
 src/client/views/TemplateMenu.tsx                  | 66 +++++++++++-----------
 src/client/views/collections/CollectionSubView.tsx |  6 +-
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../views/collections/ParentDocumentSelector.tsx   |  2 -
 .../views/nodes/ContentFittingDocumentView.tsx     |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  6 +-
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 .../views/presentationview/PresElementBox.tsx      |  2 +-
 src/new_fields/Doc.ts                              |  2 +-
 src/new_fields/ScriptField.ts                      |  5 +-
 15 files changed, 57 insertions(+), 59 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index c9d7fac33..cc85e5c6f 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -504,7 +504,7 @@ export namespace Docs {
                 const extension = path.extname(target);
                 target = `${target.substring(0, target.length - extension.length)}_o${extension}`;
             }
-            requestImageSize(target)
+            requestImageSize(Utils.CorsProxy(target))
                 .then((size: any) => {
                     const aspect = size.height / size.width;
                     if (!inst._nativeWidth) {
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 2a6e3bf8a..6c386d684 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -55,11 +55,13 @@ export namespace SelectionManager {
         manager.SelectDoc(docView, ctrlPressed);
     }
 
-
+    // computed functions, such as used in IsSelected generate errors if they're called outside of a
+    // reaction context.  Specifying the context with 'outsideReaction' allows an efficiency feature
+    // to avoid unnecessary mobx invalidations when running inside a reaction.
     export function IsSelected(doc: DocumentView, outsideReaction?: boolean): boolean {
         return outsideReaction ?
-            manager.SelectedDocuments.get(doc) ? true : false :
-            computedFn(function isSelected(doc: DocumentView) {
+            manager.SelectedDocuments.get(doc) ? true : false : // get() accesses a hashtable -- setting anything in the hashtable generates a mobx invalidation for every get()
+            computedFn(function isSelected(doc: DocumentView) {  // wraapping get() in a computedFn only generates mobx() invalidations when the return value of the function for the specific get parameters has changed
                 return manager.SelectedDocuments.get(doc) ? true : false;
             })(doc);
     }
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 9456895d6..21eec66be 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -31,7 +31,7 @@ interface DocExtendableProps {
     fieldKey: string;
     isSelected: (outsideReaction?: boolean) => boolean;
     renderDepth: number;
-    rootSelected: () => boolean;
+    rootSelected: (outsideReaction?: boolean) => boolean;
 }
 export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCtor: (doc: Doc) => T) {
     class Component extends Touchable<P> {
@@ -39,7 +39,7 @@ export function DocExtendableComponent<P extends DocExtendableProps, T>(schemaCt
         @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; }
-        active = (outsideReaction?: boolean) => !this.props.Document.isBackground && ((this.props.Document.forceActive && this.props.rootSelected()) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);//  && !InkingControl.Instance.selectedTool;  // bcz: inking state shouldn't affect static tools 
+        active = (outsideReaction?: boolean) => !this.props.Document.isBackground && ((this.props.Document.forceActive && this.props.rootSelected(outsideReaction)) || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);//  && !InkingControl.Instance.selectedTool;  // bcz: inking state shouldn't affect static tools 
         protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
     }
     return Component;
@@ -54,7 +54,7 @@ export interface DocAnnotatableProps {
     active: () => boolean;
     whenActiveChanged: (isActive: boolean) => void;
     isSelected: (outsideReaction?: boolean) => boolean;
-    rootSelected: () => boolean;
+    rootSelected: (outsideReaction?: boolean) => boolean;
     renderDepth: number;
 }
 export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schemaCtor: (doc: Doc) => T) {
@@ -92,7 +92,7 @@ export function DocAnnotatableComponent<P extends DocAnnotatableProps, T>(schema
 
         whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive));
         active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) &&
-            ((this.props.Document.forceActive && this.props.rootSelected()) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
+            ((this.props.Document.forceActive && this.props.rootSelected(outsideReaction)) || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
         annotationsActive = (outsideReaction?: boolean) => (InkingControl.Instance.selectedTool !== InkTool.None ||
             (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false)
     }
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index f0205133c..69aa8dbaa 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -738,7 +738,6 @@ export default class GestureOverlay extends Touchable {
     }
 
     render() {
-        trace();
         return (
             <div className="gestureOverlay-cont" onPointerDown={this.onPointerDown} onTouchStart={this.onReactTouchStart}>
                 {this.showMobileInkOverlay ? <MobileInkOverlay /> : <></>}
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index c72f3681a..8fb8e7516 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -127,44 +127,42 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
             addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction(`templateIsUsed(this)`));
             this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push(
                 <OtherToggle key={template} name={template} checked={templateName === template} toggle={e => this.toggleLayout(e, template)} />));
-            templateMenu.push(
-                <CollectionTreeView
-                    Document={Doc.UserDoc().templateDocs as Doc}
-                    CollectionView={undefined}
-                    ContainingCollectionDoc={undefined}
-                    ContainingCollectionView={undefined}
-                    rootSelected={returnFalse}
-                    onCheckedClick={this.scriptField!}
-                    onChildClick={this.scriptField!}
-                    LibraryPath={emptyPath}
-                    dropAction={undefined}
-                    active={returnTrue}
-                    ContentScaling={returnOne}
-                    bringToFront={emptyFunction}
-                    focus={emptyFunction}
-                    whenActiveChanged={emptyFunction}
-                    ScreenToLocalTransform={Transform.Identity}
-                    isSelected={returnFalse}
-                    pinToPres={emptyFunction}
-                    select={emptyFunction}
-                    renderDepth={1}
-                    addDocTab={returnFalse}
-                    NativeHeight={returnZero}
-                    NativeWidth={returnZero}
-                    PanelWidth={this.return100}
-                    PanelHeight={this.return100}
-                    treeViewHideHeaderFields={true}
-                    annotationsKey={""}
-                    dontRegisterView={true}
-                    fieldKey={"data"}
-                    moveDocument={(doc: Doc) => false}
-                    removeDocument={(doc: Doc) => false}
-                    addDocument={(doc: Doc) => false} />
-            );
         }
         return <ul className="template-list" style={{ display: "block" }}>
             <input placeholder="+ layout" ref={this._customRef} onKeyPress={this.onCustomKeypress} />
             {templateMenu}
+            <CollectionTreeView
+                Document={Doc.UserDoc().templateDocs as Doc}
+                CollectionView={undefined}
+                ContainingCollectionDoc={undefined}
+                ContainingCollectionView={undefined}
+                rootSelected={returnFalse}
+                onCheckedClick={this.scriptField!}
+                onChildClick={this.scriptField!}
+                LibraryPath={emptyPath}
+                dropAction={undefined}
+                active={returnTrue}
+                ContentScaling={returnOne}
+                bringToFront={emptyFunction}
+                focus={emptyFunction}
+                whenActiveChanged={emptyFunction}
+                ScreenToLocalTransform={Transform.Identity}
+                isSelected={returnFalse}
+                pinToPres={emptyFunction}
+                select={emptyFunction}
+                renderDepth={1}
+                addDocTab={returnFalse}
+                NativeHeight={returnZero}
+                NativeWidth={returnZero}
+                PanelWidth={this.return100}
+                PanelHeight={this.return100}
+                treeViewHideHeaderFields={true}
+                annotationsKey={""}
+                dontRegisterView={true}
+                fieldKey={"data"}
+                moveDocument={(doc: Doc) => false}
+                removeDocument={(doc: Doc) => false}
+                addDocument={(doc: Doc) => false} />
         </ul>;
     }
 }
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a46bc67a2..746b2e174 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -34,7 +34,7 @@ export interface CollectionViewProps extends FieldViewProps {
     PanelHeight: () => number;
     VisibleHeight?: () => number;
     setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
-    rootSelected: () => boolean;
+    rootSelected: (outsideReaction?: boolean) => boolean;
     fieldKey: string;
     NativeWidth: () => number;
     NativeHeight: () => number;
@@ -99,8 +99,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
         }
 
-        rootSelected = () => {
-            return this.props.isSelected() || (this.props.Document.rootDocument || this.props.Document.forceActive ? this.props.rootSelected() : false);
+        rootSelected = (outsideReaction: boolean) => {
+            return this.props.isSelected(outsideReaction) || (this.props.Document.rootDocument || this.props.Document.forceActive ? this.props.rootSelected(outsideReaction) : false);
         }
 
         // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc.
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index d7224fa4b..c7ab66c9f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -122,7 +122,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
         return viewField;
     }
 
-    active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.rootSelected() && BoolCast(this.props.Document.forceActive)) || this._isChildActive || this.props.renderDepth === 0;
+    active = (outsideReaction?: boolean) => this.props.isSelected(outsideReaction) || (this.props.rootSelected(outsideReaction) && BoolCast(this.props.Document.forceActive)) || this._isChildActive || this.props.renderDepth === 0;
 
     whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive);
 
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 35e3a8958..afe269ec3 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -107,7 +107,6 @@ export class DockingViewButtonSelector extends React.Component<{ views: Document
     }
 
     @computed get flyout() {
-        trace();
         return (
             <div className="ParentDocumentSelector-flyout" title=" ">
                 <DocumentButtonBar views={this.props.views} stack={this.props.Stack} />
@@ -116,7 +115,6 @@ export class DockingViewButtonSelector extends React.Component<{ views: Document
     }
 
     render() {
-        trace();
         return <span title="Tap for menu, drag tab as document" onPointerDown={e => { this.props.views[0].select(false); e.stopPropagation(); }} className="buttonSelector">
             <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.flyout} stylesheet={this.customStylesheet}>
                 <FontAwesomeIcon icon={"cog"} size={"sm"} />
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 642264b85..641797cac 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -42,7 +42,7 @@ interface ContentFittingDocumentViewProps {
     addDocTab: (document: Doc, where: string) => boolean;
     pinToPres: (document: Doc) => void;
     dontRegisterView?: boolean;
-    rootSelected: () => boolean;
+    rootSelected: (outsideReaction?: boolean) => boolean;
 }
 
 @observer
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f374b5803..2df5c9bbd 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -64,7 +64,7 @@ export interface DocumentViewProps {
     LayoutDoc?: () => Opt<Doc>;
     LibraryPath: Doc[];
     fitToBox?: boolean;
-    rootSelected: () => boolean; // whether the root of a template has been selected
+    rootSelected: (outsideReaction?: boolean) => boolean; // whether the root of a template has been selected
     onClick?: ScriptField;
     onPointerDown?: ScriptField;
     onPointerUp?: ScriptField;
@@ -964,8 +964,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const fallback = Cast(this.props.Document.layoutKey, "string");
         return typeof fallback === "string" ? fallback : "layout";
     }
-    rootSelected = () => {
-        return this.isSelected(false) || (this.props.Document.forceActive && this.props.rootSelected?.() ? true : false);
+    rootSelected = (outsideReaction: boolean) => {
+        return this.isSelected(outsideReaction) || (this.props.Document.forceActive && this.props.rootSelected?.(outsideReaction) ? true : false);
     }
     childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling());
     panelWidth = () => this.props.PanelWidth();
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index dfcb03985..a3790d38b 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -29,7 +29,7 @@ export interface FieldViewProps {
     dropAction: dropActionType;
     isSelected: (outsideReaction?: boolean) => boolean;
     select: (isCtrlPressed: boolean) => void;
-    rootSelected: () => boolean;
+    rootSelected: (outsideReaction?: boolean) => boolean;
     renderDepth: number;
     addDocument?: (document: Doc) => boolean;
     addDocTab: (document: Doc, where: string) => boolean;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 36e687f71..720f09fe0 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -59,7 +59,7 @@ interface IViewerProps {
     PanelHeight: () => number;
     ContentScaling: () => number;
     select: (isCtrlPressed: boolean) => void;
-    rootSelected: () => boolean;
+    rootSelected: (outsideReaction?: boolean) => boolean;
     startupLive: boolean;
     renderDepth: number;
     focus: (doc: Doc) => void;
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 7ad3474e8..289d3a9a1 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -197,7 +197,7 @@ export class PresElementBox extends DocExtendableComponent<FieldViewProps, PresD
         const treecontainer = this.props.ContainingCollectionDoc?._viewType === CollectionViewType.Tree;
         const className = "presElementBox-item" + (this.currentIndex === this.indexInPres ? " presElementBox-selected" : "");
         const pbi = "presElementBox-interaction";
-        return !this.presElementDoc ? (null) : (
+        return !(this.presElementDoc instanceof Doc) || this.targetDoc instanceof Promise ? (null) : (
             <div className={className} key={this.props.Document[Id] + this.indexInPres}
                 style={{ outlineWidth: Doc.IsBrushed(this.targetDoc) ? `1px` : "0px", }}
                 onClick={e => { this.props.focus(this.presElementDoc); e.stopPropagation(); }}>
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 964b2e316..d381447c5 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -713,7 +713,7 @@ export namespace Doc {
     export function SetUserDoc(doc: Doc) { manager._user_doc = doc; }
     export function IsBrushed(doc: Doc) {
         return computedFn(function IsBrushed(doc: Doc) {
-            return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc));
+            return brushManager.BrushedDoc.has(doc) ||  brushManager.BrushedDoc.has(Doc.GetProto(doc));
         })(doc);
     }
     // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message)
diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts
index 148886848..4a3119aeb 100644
--- a/src/new_fields/ScriptField.ts
+++ b/src/new_fields/ScriptField.ts
@@ -131,7 +131,8 @@ export class ScriptField extends ObjectField {
 export class ComputedField extends ScriptField {
     _lastComputedResult: any;
     //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc
-    value = computedFn((doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.rootDocument, Doc, null) || doc, _last_: this._lastComputedResult }, console.log).result);
+    value = computedFn((doc: Doc) => this._valueOutsideReaction(doc));
+    _valueOutsideReaction = (doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.rootDocument, Doc, null) || doc, _last_: this._lastComputedResult }, console.log).result;
     public static MakeScript(script: string, params: object = {}) {
         const compiled = ScriptField.CompileScript(script, params, false);
         return compiled.compiled ? new ComputedField(compiled) : undefined;
@@ -166,7 +167,7 @@ export namespace ComputedField {
     export function initPlugin() {
         Plugins.addGetterPlugin((doc, _, value) => {
             if (useComputed && value instanceof ComputedField) {
-                return { value: value.value(doc), shouldReturn: true };
+                return { value: value._valueOutsideReaction(doc), shouldReturn: true };
             }
         });
     }
-- 
cgit v1.2.3-70-g09d2

