From dab8f5893ffb8fab05a46695b9d1a690d1171bca Mon Sep 17 00:00:00 2001
From: Stanley Yip <stanley_yip@brown.edu>
Date: Sun, 2 Feb 2020 19:18:23 -0500
Subject: some more stuff

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

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

diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 67062ae41..e613bf411 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -82,13 +82,14 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
 
     render() {
         const guid = Utils.GenerateGuid();
+        const flexDir: any = StrCast(this.Document.flexDirection);
         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)} />
                 <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) }}>
+                <div className="collectionLinearView-content" style={{ height: this.dimension(), width: NumCast(this.props.Document._width, 25), flexDirection: flexDir }}>
                     {this.childLayoutPairs.filter((pair) => this.isCurrent(pair.layout)).map((pair, ind) => {
                         const nested = pair.layout._viewType === CollectionViewType.Linear;
                         const dref = React.createRef<HTMLDivElement>();
-- 
cgit v1.2.3-70-g09d2


From 8b71007c98f3c5f5092d15c6ce91142729bcec22 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 3 Mar 2020 14:02:17 -0500
Subject: fixed dragging from linear view because of screentransform.  added
 [[key=value]] syntax.  added button for seeing enumerated values.    added
 step up button in DocDec for selecting parent collection

---
 src/client/util/RichTextRules.ts                   |  8 ++-
 src/client/util/RichTextSchema.tsx                 | 57 +++++++++++++++-------
 src/client/views/DocumentDecorations.scss          | 11 +++++
 src/client/views/DocumentDecorations.tsx           | 16 +++++-
 .../views/collections/CollectionLinearView.tsx     |  2 +-
 src/new_fields/Doc.ts                              | 34 ++++++-------
 6 files changed, 89 insertions(+), 39 deletions(-)

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

diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts
index 70a1a5154..7ffc2dd9c 100644
--- a/src/client/util/RichTextRules.ts
+++ b/src/client/util/RichTextRules.ts
@@ -81,10 +81,11 @@ export class RichTextRules {
 
             // create a text display of a metadata field on this or another document, or create a hyperlink portal to another document [[ <fieldKey> : <Doc>]]   // [[:Doc]] => hyperlink   [[fieldKey]] => show field   [[fieldKey:Doc]] => show field of doc
             new InputRule(
-                new RegExp(/\[\[([a-zA-Z_#@\? \-0-9]*)(:[a-zA-Z_#@\? \-0-9]+)?\]\]$/),
+                new RegExp(/\[\[([a-zA-Z_#@\? \-0-9]*)(=[a-zA-Z_#@\? \-0-9]*)?(:[a-zA-Z_#@\? \-0-9]+)?\]\]$/),
                 (state, match, start, end) => {
                     const fieldKey = match[1];
-                    const docid = match[2]?.substring(1);
+                    const docid = match[3]?.substring(1);
+                    const value = match[2]?.substring(1);
                     if (!fieldKey) {
                         if (docid) {
                             DocServer.GetRefField(docid).then(docx => {
@@ -97,6 +98,9 @@ export class RichTextRules {
                         }
                         return state.tr;
                     }
+                    if (value !== "") {
+                        this.Document[DataSym][fieldKey] = value;
+                    }
                     const fieldView = state.schema.nodes.dashField.create({ fieldKey, docid });
                     return state.tr.deleteRange(start, end).insert(start, fieldView);
                 }),
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 2ef22b6a0..034f5d55a 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -8,28 +8,25 @@ import { EditorState, NodeSelection, Plugin, TextSelection } from "prosemirror-s
 import { StepMap } from "prosemirror-transform";
 import { EditorView } from "prosemirror-view";
 import * as ReactDOM from 'react-dom';
-import { Doc, Field, HeightSym, WidthSym, DocListCast } from "../../new_fields/Doc";
+import { Doc, DocListCast, Field, HeightSym, WidthSym } from "../../new_fields/Doc";
 import { Id } from "../../new_fields/FieldSymbols";
+import { List } from "../../new_fields/List";
 import { ObjectField } from "../../new_fields/ObjectField";
+import { listSpec } from "../../new_fields/Schema";
+import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
 import { ComputedField } from "../../new_fields/ScriptField";
-import { BoolCast, NumCast, StrCast, Cast } from "../../new_fields/Types";
+import { BoolCast, Cast, NumCast, StrCast } from "../../new_fields/Types";
 import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils } from "../../Utils";
 import { DocServer } from "../DocServer";
+import { Docs } from "../documents/Documents";
+import { CollectionViewType } from "../views/collections/CollectionView";
+import { ContextMenu } from "../views/ContextMenu";
 import { DocumentView } from "../views/nodes/DocumentView";
 import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
 import { DocumentManager } from "./DocumentManager";
 import ParagraphNodeSpec from "./ParagraphNodeSpec";
 import { Transform } from "./Transform";
 import React = require("react");
-import { CollectionSchemaBooleanCell } from "../views/collections/CollectionSchemaCells";
-import { ContextMenu } from "../views/ContextMenu";
-import { ContextMenuProps } from "../views/ContextMenuItem";
-import { Docs } from "../documents/Documents";
-import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
-import { toBlob } from "html-to-image";
-import { listSpec } from "../../new_fields/Schema";
-import { List } from "../../new_fields/List";
-import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField";
 
 const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
     preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
@@ -839,8 +836,8 @@ export class DashDocView {
                 zoomToScale={emptyFunction}
                 getScale={returnOne}
                 dontRegisterView={false}
-                ContainingCollectionView={undefined}
-                ContainingCollectionDoc={undefined}
+                ContainingCollectionView={this._textBox.props.ContainingCollectionView}
+                ContainingCollectionDoc={this._textBox.props.ContainingCollectionDoc}
                 ContentScaling={this.contentScaling}
             />, this._dashSpan);
             if (node.attrs.width !== dashDoc._width + "px" || node.attrs.height !== dashDoc._height + "px") {
@@ -863,6 +860,7 @@ export class DashFieldView {
     _fieldWrapper: HTMLDivElement; // container for label and value
     _labelSpan: HTMLSpanElement; // field label
     _fieldSpan: HTMLDivElement;  // field value
+    _enumerables: HTMLDivElement;  // field value
     _reactionDisposer: IReactionDisposer | undefined;
     _textBoxDoc: Doc;
     @observable _dashDoc: Doc | undefined;
@@ -879,6 +877,19 @@ export class DashFieldView {
         this._fieldWrapper.style.display = "inline-block";
 
         const self = this;
+        this._enumerables = document.createElement("div");
+        this._enumerables.style.width = "10px";
+        this._enumerables.style.height = "10px";
+        this._enumerables.style.position = "relative";
+        this._enumerables.style.display = "none";
+        this._enumerables.style.background = "dimGray";
+
+        this._enumerables.onpointerdown = async (e) => {
+            e.stopPropagation();
+            const collview = await Doc.addEnumerationToTextField(self._textBoxDoc, node.attrs.fieldKey, [Docs.Create.TextDocument(self._fieldSpan.innerText, { title: self._fieldSpan.innerText })]);
+            collview instanceof Doc && tbox.props.addDocTab(collview, "onRight");
+        }
+
         this._fieldSpan = document.createElement("div");
         this._fieldSpan.id = Utils.GenerateGuid();
         this._fieldSpan.contentEditable = "true";
@@ -888,7 +899,10 @@ export class DashFieldView {
         this._fieldSpan.style.backgroundColor = "rgba(155, 155, 155, 0.24)";
         this._fieldSpan.onkeypress = function (e: any) { e.stopPropagation(); };
         this._fieldSpan.onkeyup = function (e: any) { e.stopPropagation(); };
-        this._fieldSpan.onmousedown = function (e: any) { e.stopPropagation(); };
+        this._fieldSpan.onmousedown = function (e: any) {
+            e.stopPropagation();
+            self._enumerables.style.display = "inline-block";
+        };
         this._fieldSpan.oncontextmenu = function (e: any) {
             ContextMenu.Instance.addItem({
                 description: "Show Enumeration Templates", event: () => {
@@ -898,15 +912,17 @@ export class DashFieldView {
             });
         };
         this._fieldSpan.onblur = function (e: any) {
+            self._enumerables.style.display = "none";
             let newText = self._fieldSpan.innerText.startsWith(":=") ? ":=-computed-" : self._fieldSpan.innerText;
+
             // look for a document whose id === the fieldKey being displayed.  If there's a match, then that document
             // holds the different enumerated values for the field in the titles of its collected documents.
             // if there's a partial match from the start of the input text, complete the text --- TODO: make this an auto suggest box and select from a drop down.
-
-            // alternatively, if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key
             DocServer.GetRefField(node.attrs.fieldKey).then(options => {
                 (options instanceof Doc) && DocListCast(options.data).forEach(opt => StrCast(opt.title).startsWith(newText) && (newText = StrCast(opt.title)));
                 self._fieldSpan.innerHTML = self._dashDoc![self._fieldKey] = newText;
+
+                // if the text starts with a ':=' then treat it as an expression by making a computed field from its value storing it in the key
                 if (newText.startsWith(":=") && self._dashDoc && e.data === null && !e.inputType.includes("delete")) {
                     Doc.Layout(tbox.props.Document)[self._fieldKey] = ComputedField.MakeFunction(self._fieldSpan.innerText.substring(2));
                 }
@@ -947,8 +963,12 @@ export class DashFieldView {
         this._labelSpan.title = "click to see related tags";
         this._labelSpan.onpointerdown = function (e: any) {
             e.stopPropagation();
-            if (tbox.props.ContainingCollectionDoc) {
-                const alias = Doc.MakeAlias(tbox.props.ContainingCollectionDoc);
+            let container = tbox.props.ContainingCollectionView;
+            while (container?.props.Document.isTemplateForField || container?.props.Document.isTemplateDoc) {
+                container = container.props.ContainingCollectionView;
+            }
+            if (container) {
+                const alias = Doc.MakeAlias(container.props.Document);
                 alias.viewType = CollectionViewType.Time;
                 let list = Cast(alias.schemaColumns, listSpec(SchemaHeaderField));
                 if (!list) {
@@ -974,6 +994,7 @@ export class DashFieldView {
 
         this._fieldWrapper.appendChild(this._labelSpan);
         this._fieldWrapper.appendChild(this._fieldSpan);
+        this._fieldWrapper.appendChild(this._enumerables);
         (this as any).dom = this._fieldWrapper;
     }
     destroy() {
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 1992c5efa..fdf7c3f42 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -27,6 +27,17 @@ $linkGap : 3px;
         opacity: 1;
     }
 
+    .documentDecorations-selector {
+        pointer-events: auto;
+        height: 15px;
+        width: 15px;
+        left: -20px;
+        top: 20px;
+        display: inline-block;
+        position: absolute;
+        opacity: 0.5;
+    }
+
     .documentDecorations-radius {
         pointer-events: auto;
         background: black;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 4922411e8..c98be0d4a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -8,7 +8,7 @@ import { PositionDocument } from '../../new_fields/documentSchemas';
 import { ScriptField } from '../../new_fields/ScriptField';
 import { Cast, StrCast, NumCast } from "../../new_fields/Types";
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
-import { Utils, setupMoveUpEvents } from "../../Utils";
+import { Utils, setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils";
 import { DocUtils } from "../documents/Documents";
 import { DocumentType } from '../documents/DocumentTypes';
 import { DragManager } from "../util/DragManager";
@@ -244,6 +244,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         SelectionManager.DeselectAll();
     }
 
+    @action
+    onSelectorUp = (e: React.PointerEvent): void => {
+        setupMoveUpEvents(this, e, returnFalse, emptyFunction, action((e) => {
+            const selDoc = SelectionManager.SelectedDocuments()?.[0];
+            if (selDoc) {
+                selDoc.props.ContainingCollectionView?.props.select(false);
+            }
+        }));
+    }
+
     @action
     onRadiusDown = (e: React.PointerEvent): void => {
         setupMoveUpEvents(this, e, this.onRadiusMove, (e) => this._resizeUndo?.end(), (e) => { });
@@ -496,6 +506,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                     onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-bottomRightResizer" className="documentDecorations-resizer"
                     onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
+                {seldoc.props.renderDepth <= 1 || !seldoc.props.ContainingCollectionView ? (null) : <div id="documentDecorations-levelSelector" className="documentDecorations-selector" title="tap to select containing document"
+                    onPointerDown={this.onSelectorUp} onContextMenu={(e) => e.preventDefault()}>
+                    <FontAwesomeIcon className="documentdecorations-times" icon={faArrowAltCircleUp} size="lg" />
+                </div>}
                 <div id="documentDecorations-borderRadius" className="documentDecorations-radius"
                     onPointerDown={this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}></div>
 
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 9384eb381..79ec6d518 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -77,7 +77,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
     getTransform = (ele: React.RefObject<HTMLDivElement>) => () => {
         if (!ele.current) return Transform.Identity();
         const { scale, translateX, translateY } = Utils.GetScreenTransform(ele.current);
-        return new Transform(-translateX, -translateY, 1 / scale);
+        return new Transform(-translateX, -translateY, 1);
     }
 
     render() {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 0f3896055..6d94f050c 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -865,25 +865,25 @@ export namespace Doc {
         return (await DocServer.GetRefField(enumeratedFieldKey)) as Doc;
     }
 
-    export function addEnumerationToTextField(doc: Opt<Doc>, enumeratedFieldKey: string, enumeratedDocs: Doc[]) {
-        DocServer.GetRefField(enumeratedFieldKey).then(optionsCollection => {
-            if (!(optionsCollection instanceof Doc)) {
-                optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey);
-                Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc);
+    export async function addEnumerationToTextField(doc: Opt<Doc>, enumeratedFieldKey: string, enumeratedDocs: Doc[]) {
+        let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey);
+        if (!(optionsCollection instanceof Doc)) {
+            optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey);
+            Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc);
+        }
+        const options = optionsCollection as Doc;
+        doc && (Doc.GetProto(doc).backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options }));
+        doc && (Doc.GetProto(doc).color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options }));
+        enumeratedDocs.map(enumeratedDoc => {
+            const found = DocListCast(options.data).find(d => d.title === enumeratedDoc.title);
+            if (found) {
+                found._backgroundColor = enumeratedDoc._backgroundColor || found._backgroundColor;
+                found._color = enumeratedDoc._color || found._color;
+            } else {
+                Doc.AddDocToList(options, "data", enumeratedDoc);
             }
-            const options = optionsCollection as Doc;
-            doc && (Doc.GetProto(doc).backgroundColor = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey})?._backgroundColor || "white"`, undefined, { options }));
-            doc && (Doc.GetProto(doc).color = ComputedField.MakeFunction(`options.data.find(doc => doc.title === (this.expandedTemplate||this).${enumeratedFieldKey}).color || "black"`, undefined, { options }));
-            enumeratedDocs.map(enumeratedDoc => {
-                const found = DocListCast(options.data).find(d => d.title === enumeratedDoc.title);
-                if (found) {
-                    found._backgroundColor = enumeratedDoc._backgroundColor || found._backgroundColor;
-                    found._color = enumeratedDoc._color || found._color;
-                } else {
-                    Doc.AddDocToList(options, "data", enumeratedDoc);
-                }
-            });
         });
+        return optionsCollection;
     }
 }
 
-- 
cgit v1.2.3-70-g09d2


From 786572f3cd674459f55b7f66e8eb257026f373ef Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 23 Mar 2020 21:24:50 -0400
Subject: fixed RichTextMenu to not obscure selection. fixed templateMenu to
 display a TreeView document of options.  fixed resize in docDecorations for
 dragging corners other than bottom-right.

---
 src/client/util/DropConverter.ts                   |  2 +-
 src/client/views/DocumentButtonBar.tsx             |  4 +-
 src/client/views/DocumentDecorations.scss          |  3 +
 src/client/views/DocumentDecorations.tsx           |  6 +-
 src/client/views/TemplateMenu.tsx                  | 94 ++++++++++++++++++----
 .../views/collections/CollectionDockingView.tsx    | 27 +++++--
 .../views/collections/CollectionLinearView.tsx     | 20 ++---
 .../views/collections/CollectionTreeView.scss      |  1 +
 .../views/collections/CollectionTreeView.tsx       |  7 +-
 .../views/collections/ParentDocumentSelector.tsx   | 22 ++---
 .../collections/collectionFreeForm/MarqueeView.tsx | 12 ++-
 src/client/views/nodes/DocumentView.tsx            | 15 ++--
 src/client/views/nodes/FormattedTextBox.tsx        | 25 ++++--
 src/client/views/search/SearchItem.tsx             |  2 +-
 src/new_fields/Doc.ts                              |  2 -
 src/new_fields/ScriptField.ts                      |  4 +-
 src/new_fields/util.ts                             |  1 -
 .../authentication/models/current_user_utils.ts    | 16 +++-
 18 files changed, 189 insertions(+), 74 deletions(-)

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

diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index 861cde5de..a6a43d06a 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -49,7 +49,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
                 (layoutDoc.layout instanceof Doc) && !data.userDropAction;
             }
             layoutDoc.isTemplateDoc = true;
-            dbox = Docs.Create.FontIconDocument({ _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, backgroundColor: StrCast(doc.backgroundColor), title: "Custom", icon: layoutDoc.isTemplateDoc ? "font" : "bolt" });
+            dbox = Docs.Create.FontIconDocument({ _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, backgroundColor: StrCast(doc.backgroundColor), title: StrCast(layoutDoc.title), icon: layoutDoc.isTemplateDoc ? "font" : "bolt" });
             dbox.dragFactory = layoutDoc;
             dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined;
             dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)');
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 23875fa33..8a33232b4 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -108,7 +108,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
         this._pullColorAnimating = false;
     });
 
-    get view0() { return this.props.views && this.props.views.length ? this.props.views[0] : undefined; }
+    get view0() { return this.props.views?.[0]; }
 
     @action
     onLinkButtonMoved = (e: PointerEvent): void => {
@@ -250,7 +250,7 @@ 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, where) => {
+        return !this.view0 ? (null) : <ParentDocSelector 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");
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 8d6002f8f..353520026 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -80,6 +80,7 @@ $linkGap : 3px;
     #documentDecorations-topLeftResizer,
     #documentDecorations-bottomRightResizer {
         cursor: nwse-resize;
+        background: dimGray;
     }
 
     #documentDecorations-bottomRightResizer {
@@ -89,6 +90,7 @@ $linkGap : 3px;
     #documentDecorations-topRightResizer,
     #documentDecorations-bottomLeftResizer {
         cursor: nesw-resize;
+        background: dimGray;
     }
 
     #documentDecorations-topResizer,
@@ -158,6 +160,7 @@ $linkGap : 3px;
     padding-top: 5px;
     width: $MINIMIZED_ICON_SIZE;
     height: $MINIMIZED_ICON_SIZE;
+    max-height: 20px;
 }
 
 .documentDecorations-background {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index c4abc935f..ff72592d8 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -266,7 +266,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         let dist = Math.sqrt((e.clientX - down[0]) * (e.clientX - down[0]) + (e.clientY - down[1]) * (e.clientY - down[1]));
         dist = dist < 3 ? 0 : dist;
         SelectionManager.SelectedDocuments().map(dv => dv.props.Document).map(doc => doc.layout instanceof Doc ? doc.layout : doc.isTemplateForField ? doc : Doc.GetProto(doc)).
-            map(d => d.borderRounding = `${Math.max(0, dist)}px`);
+            map(d => d.borderRounding = `${Math.max(0, dist)}%`);
         return false;
     }
 
@@ -330,6 +330,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 const width = (layoutDoc._width || 0);
                 const height = (layoutDoc._height || (nheight / nwidth * width));
                 const scale = element.props.ScreenToLocalTransform().Scale * element.props.ContentScaling();
+                if (nwidth && nheight) {
+                    if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth;
+                    else dW = dH * nwidth / nheight;
+                }
                 const actualdW = Math.max(width + (dW * scale), 20);
                 const actualdH = Math.max(height + (dH * scale), 20);
                 doc.x = (doc.x || 0) + dX * (actualdW - width);
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 5029b4074..cf6ce2c6f 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -1,4 +1,4 @@
-import { action, observable, runInAction, ObservableSet } from "mobx";
+import { action, observable, runInAction, ObservableSet, trace, computed } from "mobx";
 import { observer } from "mobx-react";
 import { SelectionManager } from "../util/SelectionManager";
 import { undoBatch } from "../util/UndoManager";
@@ -7,8 +7,13 @@ import { DocumentView } from "./nodes/DocumentView";
 import { Template } from "./Templates";
 import React = require("react");
 import { Doc, DocListCast } from "../../new_fields/Doc";
+import { Docs, } from "../documents/Documents";
 import { StrCast, Cast } from "../../new_fields/Types";
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { CollectionTreeView } from "./collections/CollectionTreeView";
+import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath } from "../../Utils";
+import { Transform } from "../util/Transform";
+import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
+import { Scripting } from "../util/Scripting";
 
 @observer
 class TemplateToggle extends React.Component<{ template: Template, checked: boolean, toggle: (event: React.ChangeEvent<HTMLInputElement>, template: Template) => void }> {
@@ -50,7 +55,10 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
     @observable private _hidden: boolean = true;
 
     toggleLayout = (e: React.ChangeEvent<HTMLInputElement>, layout: string): void => {
-        this.props.docViews.map(dv => dv.switchViews(e.target.checked, layout));//.setCustomView(e.target.checked, layout));
+        this.props.docViews.map(dv => dv.switchViews(e.target.checked, layout));
+    }
+    toggleDefault = (e: React.ChangeEvent<HTMLInputElement>): void => {
+        this.props.docViews.map(dv => dv.switchViews(false, "layout"));
     }
 
     toggleFloat = (e: React.ChangeEvent<HTMLInputElement>): void => {
@@ -94,27 +102,81 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
         Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document))).
             filter(key => key.startsWith("layout_")).
             map(key => runInAction(() => this._addedKeys.add(key.replace("layout_", ""))));
-        DocListCast(Cast(CurrentUserUtils.UserDocument.expandingButtons, Doc, null)?.data)?.map(btnDoc => {
-            if (StrCast(Cast(btnDoc?.dragFactory, Doc, null)?.title)) {
-                runInAction(() => this._addedKeys.add(StrCast(Cast(btnDoc?.dragFactory, Doc, null)?.title)));
-            }
-        });
     }
 
+    return100 = () => 100;
+    @computed get scriptField() {
+        return ScriptField.MakeScript("switchView(firstDoc, this)", { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name, firstDoc: Doc.name },
+            { firstDoc: this.props.docViews[0].props.Document });
+    }
     render() {
-        const layout = Doc.Layout(this.props.docViews[0].Document);
+        const firstDoc = this.props.docViews[0].props.Document;
+        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 layout = Doc.Layout(firstDoc);
         const templateMenu: Array<JSX.Element> = [];
         this.props.templates.forEach((checked, template) =>
             templateMenu.push(<TemplateToggle key={template.Name} template={template} checked={checked} toggle={this.toggleTemplate} />));
-        templateMenu.push(<OtherToggle key={"audio"} name={"Audio"} checked={this.props.docViews[0].Document._showAudio ? true : false} toggle={this.toggleAudio} />);
-        templateMenu.push(<OtherToggle key={"float"} name={"Float"} checked={this.props.docViews[0].Document.z ? true : false} toggle={this.toggleFloat} />);
+        templateMenu.push(<OtherToggle key={"audio"} name={"Audio"} checked={firstDoc._showAudio ? true : false} toggle={this.toggleAudio} />);
+        templateMenu.push(<OtherToggle key={"float"} name={"Float"} checked={firstDoc.z ? true : false} toggle={this.toggleFloat} />);
         templateMenu.push(<OtherToggle key={"chrome"} name={"Chrome"} checked={layout._chromeStatus !== "disabled"} toggle={this.toggleChrome} />);
-        this._addedKeys && Array.from(this._addedKeys).map(layout =>
-            templateMenu.push(<OtherToggle key={layout} name={layout} checked={StrCast(this.props.docViews[0].Document.layoutKey, "layout") === "layout_" + layout} toggle={e => this.toggleLayout(e, layout)} />)
-        );
+        templateMenu.push(<OtherToggle key={"default"} name={"Default"} checked={templateName === "layout"} toggle={this.toggleDefault} />);
+        if (noteTypesDoc) {
+            addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction("templateIsUsed(this, firstDoc)", { firstDoc: "string" }, { firstDoc: StrCast(firstDoc.title) }));
+            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}
+                    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}
+                    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" }}>
-            {templateMenu}
             <input placeholder="+ layout" ref={this._customRef} onKeyPress={this.onCustomKeypress}></input>
+            {templateMenu}
         </ul>;
     }
-}
\ No newline at end of file
+}
+
+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)
+});
+
+Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitlte: string) {
+    const firstDoc = SelectionManager.SelectedDocuments()[0].props.Document;
+    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
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 00e22d6fb..1fb78f625 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -2,7 +2,7 @@ import { library } from '@fortawesome/fontawesome-svg-core';
 import { faFile } from '@fortawesome/free-solid-svg-icons';
 import 'golden-layout/src/css/goldenlayout-base.css';
 import 'golden-layout/src/css/goldenlayout-dark-theme.css';
-import { action, computed, Lambda, observable, reaction, runInAction } from "mobx";
+import { action, computed, Lambda, observable, reaction, runInAction, trace } from "mobx";
 import { observer } from "mobx-react";
 import * as ReactDOM from 'react-dom';
 import Measure from "react-measure";
@@ -20,7 +20,7 @@ import { DocServer } from "../../DocServer";
 import { Docs } from '../../documents/Documents';
 import { DocumentType } from '../../documents/DocumentTypes';
 import { DocumentManager } from '../../util/DocumentManager';
-import { DragManager } from "../../util/DragManager";
+import { DragManager, dropActionType } from "../../util/DragManager";
 import { Scripting } from '../../util/Scripting';
 import { SelectionManager } from '../../util/SelectionManager';
 import { Transform } from '../../util/Transform';
@@ -504,15 +504,25 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                     }
                     tab.setActive(true);
                 };
-                ReactDOM.render(<span title="Drag as document"
-                    className="collectionDockingView-dragAsDocument"
-                    onPointerDown={e => {
+                const onDown = (e: React.PointerEvent) => {
+                    if (!(e.nativeEvent as any).defaultPrevented) {
                         e.preventDefault();
                         e.stopPropagation();
                         const dragData = new DragManager.DocumentDragData([doc]);
-                        dragData.dropAction = doc.dropAction === "alias" ? "alias" : doc.dropAction === "copy" ? "copy" : undefined;
+                        dragData.dropAction = doc.dropAction as dropActionType;
                         DragManager.StartDocumentDrag([gearSpan], dragData, e.clientX, e.clientY);
-                    }}><DockingViewButtonSelector Document={doc} Stack={stack} /></span>, gearSpan);
+                    }
+                }
+                let rendered = false;
+                tab.buttonDisposer = reaction(() => ((view: Opt<DocumentView>) => view ? [view] : [])(DocumentManager.Instance.getDocumentView(doc)),
+                    (views) => {
+                        !rendered && ReactDOM.render(<span title="Drag as document" className="collectionDockingView-dragAsDocument" onPointerDown={onDown} >
+                            <DockingViewButtonSelector views={views} Stack={stack} />
+                        </span>,
+                            gearSpan);
+                        rendered = true;
+                    });
+
                 tab.reactComponents = [gearSpan];
                 tab.element.append(gearSpan);
                 tab.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => {
@@ -526,7 +536,8 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
         }
         tab.closeElement.off('click') //unbind the current click handler
             .click(async function () {
-                tab.reactionDisposer && tab.reactionDisposer();
+                tab.reactionDisposer?.();
+                tab.buttonDisposer?.();
                 const doc = await DocServer.GetRefField(tab.contentItem.config.props.documentId);
                 if (doc instanceof Doc) {
                     const theDoc = doc;
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 79ec6d518..344605412 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -31,7 +31,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
         this._dropDisposer && this._dropDisposer();
         this._widthDisposer && this._widthDisposer();
         this._selectedDisposer && this._selectedDisposer();
-        this.childLayoutPairs.filter((pair) => this.isCurrent(pair.layout)).map((pair, ind) => {
+        this.childLayoutPairs.map((pair, ind) => {
             Cast(pair.layout.proto?.onPointerUp, ScriptField)?.script.run({ this: pair.layout.proto }, console.log);
         });
     }
@@ -48,7 +48,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
             (i) => runInAction(() => {
                 this._selectedIndex = i;
                 let selected: any = undefined;
-                this.childLayoutPairs.filter((pair) => this.isCurrent(pair.layout)).map(async (pair, ind) => {
+                this.childLayoutPairs.map(async (pair, ind) => {
                     const isSelected = this._selectedIndex === ind;
                     if (isSelected) {
                         selected = pair;
@@ -71,8 +71,6 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
         }
     }
 
-    public isCurrent(doc: Doc) { return (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); }
-
     dimension = () => NumCast(this.props.Document._height); // 2 * the padding
     getTransform = (ele: React.RefObject<HTMLDivElement>) => () => {
         if (!ele.current) return Transform.Identity();
@@ -87,17 +85,21 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
             <div className="collectionLinearView" ref={this.createDashEventsTarget} >
                 <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>
+                <label htmlFor={`${guid}`} title="Close Menu" 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") }} >
+                    <p>+</p>
+                </label>
 
-                <div className="collectionLinearView-content" style={{ height: this.dimension(), width: NumCast(this.props.Document._width, 25), flexDirection: flexDir }}>
-                    {this.childLayoutPairs.filter((pair) => this.isCurrent(pair.layout)).map((pair, ind) => {
+                <div className="collectionLinearView-content" style={{ height: this.dimension(), flexDirection: flexDir }}>
+                    {this.childLayoutPairs.map((pair, ind) => {
                         const nested = pair.layout._viewType === CollectionViewType.Linear;
                         const dref = React.createRef<HTMLDivElement>();
                         const nativeWidth = NumCast(pair.layout._nativeWidth, this.dimension());
                         const deltaSize = nativeWidth * .15 / 2;
-                        return <div className={`collectionLinearView-docBtn` + (pair.layout.onClick || pair.layout.onDragStart ? "-scalable" : "")} key={pair.layout[Id]} ref={dref}
+                        const scalable = pair.layout.onClick || pair.layout.onDragStart;
+                        return <div className={`collectionLinearView-docBtn` + (scalable ? "-scalable" : "")} key={pair.layout[Id]} ref={dref}
                             style={{
-                                width: nested ? pair.layout[WidthSym]() : this.dimension() - deltaSize,
+                                width: scalable ? (nested ? pair.layout[WidthSym]() : this.dimension() - deltaSize) : undefined,
                                 height: nested && pair.layout.linearViewIsExpanded ? pair.layout[HeightSym]() : this.dimension() - deltaSize,
                             }}  >
                             <DocumentView
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index fd4a963c3..5efd97a6b 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -22,6 +22,7 @@
     ul {
         list-style: none;
         padding-left: 20px;
+        margin-bottom: 1px;// otherwise vertical scrollbars may pop up for no apparent reason....
     }
 
 
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 8af4b6dfd..53df7f041 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -778,7 +778,12 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as
         const childDocs = this.props.overrideDocuments ? this.props.overrideDocuments : this.childDocs;
         return !childDocs ? (null) : (
             <div className="collectionTreeView-dropTarget" id="body"
-                style={{ background: this.props.backgroundColor?.(this.props.Document), paddingTop: `${NumCast(this.props.Document._yMargin, 20)}px` }}
+                style={{
+                    background: this.props.backgroundColor?.(this.props.Document),
+                    paddingLeft: `${NumCast(this.props.Document._xPadding, 10)}px`,
+                    paddingRight: `${NumCast(this.props.Document._xPadding, 10)}px`,
+                    paddingTop: `${NumCast(this.props.Document._yPadding, 20)}px`
+                }}
                 onContextMenu={this.onContextMenu}
                 onWheel={(e: React.WheelEvent) => this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()}
                 onDrop={this.onTreeDrop}
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 43ba5c614..35e3a8958 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -2,7 +2,7 @@ import * as React from "react";
 import './ParentDocumentSelector.scss';
 import { Doc } from "../../../new_fields/Doc";
 import { observer } from "mobx-react";
-import { observable, action, runInAction } from "mobx";
+import { observable, action, runInAction, trace, computed } from "mobx";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { SearchUtil } from "../../util/SearchUtil";
 import { CollectionDockingView } from "./CollectionDockingView";
@@ -14,6 +14,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { faCog, faChevronCircleUp } from "@fortawesome/free-solid-svg-icons";
 import { library } from "@fortawesome/fontawesome-svg-core";
 import { DocumentView } from "../nodes/DocumentView";
+import { SelectionManager } from "../../util/SelectionManager";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -22,7 +23,6 @@ library.add(faCog);
 
 type SelectorProps = {
     Document: Doc,
-    Views: DocumentView[],
     Stack?: any,
     addDocTab(doc: Doc, location: string): void
 };
@@ -93,7 +93,7 @@ export class ParentDocSelector extends React.Component<SelectorProps> {
 }
 
 @observer
-export class DockingViewButtonSelector extends React.Component<{ Document: Doc, Stack: any }> {
+export class DockingViewButtonSelector extends React.Component<{ views: DocumentView[], Stack: any }> {
     @observable hover = false;
 
     customStylesheet(styles: any) {
@@ -106,15 +106,19 @@ export class DockingViewButtonSelector extends React.Component<{ Document: Doc,
         };
     }
 
-    render() {
-        const view = DocumentManager.Instance.getDocumentView(this.props.Document);
-        const flyout = (
+    @computed get flyout() {
+        trace();
+        return (
             <div className="ParentDocumentSelector-flyout" title=" ">
-                <DocumentButtonBar views={[view]} stack={this.props.Stack} />
+                <DocumentButtonBar views={this.props.views} stack={this.props.Stack} />
             </div>
         );
-        return <span title="Tap for menu, drag tab as document" onPointerDown={e => !this.props.Stack && e.stopPropagation()} className="buttonSelector">
-            <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout} stylesheet={this.customStylesheet}>
+    }
+
+    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"} />
             </Flyout>
         </span>;
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 4bf3329eb..17bba9568 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -107,8 +107,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
             });
         } else if (!e.ctrlKey) {
             FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout ? e.key : "";
-            this.props.addLiveTextDocument(
-                Docs.Create.TextDocument("", { _width: NumCast((FormattedTextBox.DefaultLayout as Doc)?._width) || 200, _height: 100, layout: FormattedTextBox.DefaultLayout, x: x, y: y, _autoHeight: true, title: "-typed text-" }));
+            let 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);
+                tbox.layoutKey = "layout_"+StrCast(template.title);
+                tbox[StrCast(tbox.layoutKey)] = template;
+            }
+            this.props.addLiveTextDocument(tbox);
         }
         e.stopPropagation();
     }
@@ -334,7 +340,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                 this.props.removeDocument(d);
                 d.x = NumCast(d.x) - bounds.left - bounds.width / 2;
                 d.y = NumCast(d.y) - bounds.top - bounds.height / 2;
-                d.displayTimecode = undefined;
+                d.displayTimecode = undefined;  // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
                 return d;
             });
         }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 874d075e6..9a7568518 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -516,7 +516,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     static makeCustomViewClicked = (doc: Doc, dataDoc: Opt<Doc>, creator: (documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc, name: string = "custom", docLayoutTemplate?: Doc) => {
         const batch = UndoManager.StartBatch("CustomViewClicked");
         const customName = "layout_" + name;
-        if (!StrCast(doc.title).endsWith(name)) doc.title = doc.title + "_" + name;
         if (doc[customName] === undefined) {
             const _width = NumCast(doc._width);
             const _height = NumCast(doc._height);
@@ -634,13 +633,15 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             // } else 
             if (custom) {
                 DocumentView.makeNativeViewClicked(this.props.Document);
+                const userDoc = Doc.UserDoc();
 
-                const imgView = Cast(Doc.UserDoc().iconView, Doc, null);
-                const iconImgView = Cast(Doc.UserDoc().iconImageView, Doc, null);
-                const iconColView = Cast(Doc.UserDoc().iconColView, Doc, null);
+                const imgView = Cast(userDoc.iconView, Doc, null);
+                const iconImgView = Cast(userDoc.iconImageView, Doc, null);
+                const iconColView = Cast(userDoc.iconColView, Doc, null);
                 const iconViews = [imgView, iconImgView, iconColView];
-                const expandingButtons = DocListCast(Cast(Doc.UserDoc().expandingButtons, Doc, null)?.data);
-                const allTemplates = iconViews.concat(expandingButtons);
+                const templateButtons = DocListCast(Cast(userDoc.templateButtons, Doc, null)?.data);
+                const noteTypes = DocListCast(Cast(userDoc.noteTypes, Doc, null)?.data);
+                const allTemplates = iconViews.concat(templateButtons).concat(noteTypes);
                 let foundLayout: Opt<Doc>;
                 allTemplates.map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => {
                     if (StrCast(tempDoc.title) === this.props.Document.type + "_" + layout) {
@@ -1028,7 +1029,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             </div>);
         const captionView = (!showCaption ? (null) :
             <div className="documentView-captionWrapper">
-                <FormattedTextBox {...this.props} onClick={this.onClickHandler}
+                <FormattedTextBox {...this.props} onClick={this.onClickHandler} dropAction="alias"
                     DataDoc={this._dataDoc} active={returnTrue} Document={this._layoutDoc || this.props.Document}
                     isSelected={this.isSelected} focus={emptyFunction} select={this.select}
                     hideOnLeave={true} fieldKey={showCaption}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 1fa603cbd..e7c9e5e6b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -47,6 +47,7 @@ import "./FormattedTextBox.scss";
 import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment';
 import React = require("react");
 import { PrefetchProxy } from '../../../new_fields/Proxy';
+import { makeTemplate } from '../../util/DropConverter';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight, faUpload);
@@ -249,7 +250,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
     }
     protected createDropTarget = (ele: HTMLDivElement) => {
         this.ProseRef = ele;
-        this.dropDisposer && this.dropDisposer();
+        this.dropDisposer?.();
         ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
     }
 
@@ -386,9 +387,14 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
     }
     specificContextMenu = (e: React.MouseEvent): void => {
         const funcs: ContextMenuProps[] = [];
-        this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document.proto as Doc), icon: "eye" });
+        this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" });
         funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" });
-        !this.props.Document.expandedTemplate && funcs.push({ description: "Make Template", event: () => { this.props.Document.isTemplateDoc = true; Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document); }, icon: "eye" });
+        !this.props.Document.expandedTemplate && funcs.push({
+            description: "Make Template", event: () => {
+                this.props.Document.isTemplateDoc = makeTemplate(this.props.Document, true);
+                Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document);
+            }, icon: "eye"
+        });
         funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" });
         funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" });
         funcs.push({ description: "Toggle Audio", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" });
@@ -901,6 +907,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
         if (e.buttons === 1 && this.props.isSelected(true) && !e.altKey) {
             e.stopPropagation();
         }
+        this._downX = this._downY = Number.NaN;
     }
 
     @action
@@ -914,12 +921,16 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
         prosediv && (prosediv.keeplocation = undefined);
         const pos = this._editorView?.state.selection.$from.pos || 1;
         keeplocation && setTimeout(() => this._editorView?.dispatch(this._editorView?.state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos))));
+        const coords = !Number.isNaN(this._downX) ? { left: this._downX, top: this._downY, bottom: this._downY, right: this._downX } : this._editorView?.coordsAtPos(pos);
 
         // jump rich text menu to this textbox
-        const { current } = this._ref;
-        if (current && this.props.Document._chromeStatus !== "disabled") {
-            const x = Math.min(Math.max(current.getBoundingClientRect().left, 0), window.innerWidth - RichTextMenu.Instance.width);
-            const y = this._ref.current!.getBoundingClientRect().top - RichTextMenu.Instance.height - 50;
+        const bounds = this._ref.current?.getBoundingClientRect();
+        if (bounds && this.props.Document._chromeStatus !== "disabled") {
+            const x = Math.min(Math.max(bounds.left, 0), window.innerWidth - RichTextMenu.Instance.width);
+            let y = Math.min(Math.max(0, bounds.top - RichTextMenu.Instance.height - 50), window.innerHeight - RichTextMenu.Instance.height);
+            if (coords && coords.left > x && coords.left < x + RichTextMenu.Instance.width && coords.top > y && coords.top < y + RichTextMenu.Instance.height + 50) {
+                y = Math.min(bounds.bottom, window.innerHeight - RichTextMenu.Instance.height);
+            }
             RichTextMenu.Instance.jumpTo(x, y);
         }
     }
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 2cbb24da7..63cef5101 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -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, where) => CollectionDockingView.AddRightSplit(doc)} />;
+        return <ParentDocSelector 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 50adf0392..322b57272 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -795,8 +795,6 @@ export namespace Doc {
         const prevLayout = StrCast(doc.layoutKey).split("_")[1];
         const deiconify = prevLayout === "icon" && StrCast(doc.deiconifyLayout) ? "layout_" + StrCast(doc.deiconifyLayout) : "";
         prevLayout === "icon" && (doc.deiconifyLayout = undefined);
-        if (StrCast(doc.title).endsWith("_" + prevLayout) && deiconify) doc.title = StrCast(doc.title).replace("_" + prevLayout, deiconify);
-        else doc.title = undefined;
         doc.layoutKey = deiconify || "layout";
     }
     export function setDocFilterRange(target: Doc, key: string, range?: number[]) {
diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts
index 9288fea9e..606f55b7c 100644
--- a/src/new_fields/ScriptField.ts
+++ b/src/new_fields/ScriptField.ts
@@ -119,8 +119,8 @@ export class ScriptField extends ObjectField {
         return compiled.compiled ? new ScriptField(compiled) : undefined;
     }
 
-    public static MakeScript(script: string, params: object = {}) {
-        const compiled = ScriptField.CompileScript(script, params, false);
+    public static MakeScript(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) {
+        const compiled = ScriptField.CompileScript(script, params, false, capturedVariables);
         return compiled.compiled ? new ScriptField(compiled) : undefined;
     }
 }
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 6d7f6b56e..3ab1b299b 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -7,7 +7,6 @@ import { ObjectField } from "./ObjectField";
 import { action, trace } from "mobx";
 import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols";
 import { DocServer } from "../client/DocServer";
-import { props } from "bluebird";
 
 function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 31588bf82..9c39ce7de 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -53,7 +53,7 @@ export class CurrentUserUtils {
         ];
         doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" });
         Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues);
-        doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Types", _height: 75 }));
+        doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Layouts", _height: 75 }));
     }
 
     // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
@@ -292,12 +292,20 @@ 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.descriptionBtn = Docs.Create.FontIconDocument(
             { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "description view", icon: "sticky-note" });
-        doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc, doc.slidesBtn as Doc, doc.descriptionBtn as Doc,
-        ...DocListCast(Cast(doc.noteTypes, Doc, null))], {
+        doc.templateButtons = Docs.Create.LinearDocument([doc.slidesBtn as Doc, doc.descriptionBtn as Doc], {
+            title: "template buttons", _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", dontSelect: true,
+            backgroundColor: "black", treeViewPreventOpen: true, forceActive: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true,
+            dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
+        });
+        doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc, doc.templateButtons as Doc], {
             title: "expanding buttons", _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0",
-            backgroundColor: "black", treeViewPreventOpen: true, forceActive: true, lockedPosition: true,
+            backgroundColor: "black", treeViewPreventOpen: true, forceActive: true, lockedPosition: true, linearViewIsExpanded: true,
             dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
         });
+        doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc], {
+            title: "template layouts", _xPadding: 0, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)",
+                { dragData: DragManager.DocumentDragData.name })
+        }));
     }
 
     // sets up the default set of documents to be shown in the Overlay layer
-- 
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/collections/CollectionLinearView.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 50552174123eb5622821de5f848e6e70c7346214 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 3 Apr 2020 23:45:34 -0400
Subject: fixed a bunch of warnings

---
 src/client/documents/Documents.ts                  |  7 ++--
 src/client/util/SelectionManager.ts                |  6 +---
 src/client/views/DocumentDecorations.tsx           |  1 -
 src/client/views/MainView.tsx                      | 40 +++++++++------------
 src/client/views/SearchDocBox.tsx                  | 15 ++++----
 src/client/views/TemplateMenu.tsx                  |  1 +
 .../views/collections/CollectionLinearView.scss    |  2 ++
 .../views/collections/CollectionLinearView.tsx     | 27 +++++++-------
 .../views/collections/CollectionSchemaCells.tsx    |  1 +
 src/client/views/nodes/DocumentBox.tsx             |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  4 +--
 src/client/views/nodes/FormattedTextBox.tsx        |  2 +-
 src/client/views/nodes/KeyValuePair.tsx            |  1 +
 src/client/views/pdf/PDFMenu.tsx                   |  2 +-
 src/client/views/search/SearchBox.tsx              | 38 ++++++++------------
 src/new_fields/documentSchemas.ts                  |  1 -
 .../authentication/models/current_user_utils.ts    | 42 +++++++++++++---------
 17 files changed, 90 insertions(+), 102 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 1a2969cf5..514200d95 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -118,7 +118,6 @@ export interface DocumentOptions {
     lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed
     opacity?: number;
     defaultBackgroundColor?: string;
-    dontDecorateSelection?: boolean; // whether document decorations should be displayed when the document is selected
     isBackground?: boolean;
     isButton?: boolean;
     columnWidth?: number;
@@ -164,9 +163,9 @@ export interface DocumentOptions {
     flexDirection?: "unset" | "row" | "column" | "row-reverse" | "column-reverse";
     selectedIndex?: number;
     syntaxColor?: string; // can be applied to text for syntax highlighting all matches in the text
-    searchText?: string, //for searchbox
-    searchQuery?: string, // for queryBox
-    filterQuery?: string,
+    searchText?: string; //for searchbox
+    searchQuery?: string; // for queryBox
+    filterQuery?: string;
     linearViewIsExpanded?: boolean; // is linear view expanded
 }
 
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 7221fbbf9..2a6e3bf8a 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -33,7 +33,6 @@ export namespace SelectionManager {
         @action
         DeselectDoc(docView: DocumentView): void {
             if (manager.SelectedDocuments.get(docView)) {
-                docView.dontDecorateSelection = false;
                 manager.SelectedDocuments.delete(docView);
                 docView.props.whenActiveChanged(false);
                 Doc.UserDoc().SelectedDocs = new List(SelectionManager.SelectedDocuments().map(dv => dv.props.Document));
@@ -41,10 +40,7 @@ export namespace SelectionManager {
         }
         @action
         DeselectAll(): void {
-            Array.from(manager.SelectedDocuments.keys()).map(dv => {
-                dv.dontDecorateSelection = false;
-                dv.props.whenActiveChanged(false);
-            });
+            Array.from(manager.SelectedDocuments.keys()).map(dv => dv.props.whenActiveChanged(false));
             manager.SelectedDocuments.clear();
             Doc.UserDoc().SelectedDocs = new List<Doc>([]);
         }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index c35263237..e313b117f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -69,7 +69,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     get Bounds(): { x: number, y: number, b: number, r: number } {
         return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
             if (documentView.props.renderDepth === 0 ||
-                documentView.dontDecorateSelection ||
                 Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) {
                 return bounds;
             }
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index fae520e40..558bc1a4a 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,54 +1,46 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import {
-    faFileAlt, faStickyNote, faArrowDown, faBullseye, faFilter, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight,
-    faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faFileAudio, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter, faMicrophone, faCompressArrowsAlt, faPhone, faStamp, faClipboard, faVideo,
-} from '@fortawesome/free-solid-svg-icons';
+import { faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import "normalize.css";
 import * as React from 'react';
 import Measure from 'react-measure';
-import { Doc, DocListCast, Field, FieldResult, Opt } from '../../new_fields/Doc';
+import { Doc, DocListCast, Field, 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, BoolCast } from '../../new_fields/Types';
+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, returnEmptyString, returnFalse, returnOne, returnTrue, Utils, emptyPath } from '../../Utils';
+import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, Utils } from '../../Utils';
 import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager';
 import { DocServer } from '../DocServer';
 import { Docs, DocumentOptions } from '../documents/Documents';
+import { DocumentType } from '../documents/DocumentTypes';
 import { HistoryUtil } from '../util/History';
+import RichTextMenu from '../util/RichTextMenu';
+import { Scripting } from '../util/Scripting';
+import SettingsManager from '../util/SettingsManager';
 import SharingManager from '../util/SharingManager';
 import { Transform } from '../util/Transform';
-import { CollectionLinearView } from './collections/CollectionLinearView';
-import { CollectionViewType, CollectionView } from './collections/CollectionView';
 import { CollectionDockingView } from './collections/CollectionDockingView';
+import MarqueeOptionsMenu from './collections/collectionFreeForm/MarqueeOptionsMenu';
+import { CollectionLinearView } from './collections/CollectionLinearView';
+import { CollectionView, CollectionViewType } from './collections/CollectionView';
 import { ContextMenu } from './ContextMenu';
 import { DictationOverlay } from './DictationOverlay';
 import { DocumentDecorations } from './DocumentDecorations';
+import GestureOverlay from './GestureOverlay';
 import KeyManager from './GlobalKeyHandler';
 import "./MainView.scss";
 import { MainViewNotifs } from './MainViewNotifs';
+import { AudioBox } from './nodes/AudioBox';
 import { DocumentView } from './nodes/DocumentView';
+import { RadialMenu } from './nodes/RadialMenu';
+import { OverlayView } from './OverlayView';
 import PDFMenu from './pdf/PDFMenu';
 import { PreviewCursor } from './PreviewCursor';
-import { FilterBox } from './search/FilterBox';
-import { SchemaHeaderField, RandomPastel } from '../../new_fields/SchemaHeaderField';
-//import { DocumentManager } from '../util/DocumentManager';
-import { RecommendationsBox } from './RecommendationsBox';
-import { PresBox } from './nodes/PresBox';
-import { OverlayView } from './OverlayView';
-import MarqueeOptionsMenu from './collections/collectionFreeForm/MarqueeOptionsMenu';
-import GestureOverlay from './GestureOverlay';
-import { Scripting } from '../util/Scripting';
-import { AudioBox } from './nodes/AudioBox';
-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 {
diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx
index cd9666af8..4790a2ad7 100644
--- a/src/client/views/SearchDocBox.tsx
+++ b/src/client/views/SearchDocBox.tsx
@@ -81,8 +81,8 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
     updateKey = async (newKey: string) => {
         this.query = newKey;
         if (newKey.length > 1) {
-            let newdocs = await this.getAllResults(this.query);
-            let things = newdocs.docs
+            const newdocs = await this.getAllResults(this.query);
+            const things = newdocs.docs;
             console.log(things);
             console.log(this.content);
             runInAction(() => {
@@ -152,10 +152,9 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
     enter = async (e: React.KeyboardEvent) => {
         console.log(e.key);
         if (e.key === "Enter") {
-            let newdocs = await this.getAllResults(this.query)
-            let things = newdocs.docs
-            console.log(things);
-            this.content = Docs.Create.TreeDocument(things, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` });
+            const newdocs = await this.getAllResults(this.query);
+            console.log(newdocs.docs);
+            this.content = Docs.Create.TreeDocument(newdocs.docs, { _width: 200, _height: 400, _chromeStatus: "disabled", title: `Search Docs: "Results"` });
 
         }
     }
@@ -290,7 +289,7 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
             }
         }
         //return Docs.Create.TreeDocument(docs, { _width: 200, _height: 400, backgroundColor: "grey", title: `Search Docs: "${this._searchString}"` });
-        return Docs.Create.QueryDocument(docs, { _width: 200, _height: 400, searchText: this._searchString, title: `Query Docs: "${this._searchString}"` });
+        return Docs.Create.QueryDocument({ _width: 200, _height: 400, searchText: this._searchString, title: `Query Docs: "${this._searchString}"` });
     }
 
     @action.bound
@@ -416,7 +415,7 @@ export class SearchDocBox extends React.Component<FieldViewProps> {
                         top: 0,
                     }}
                     title={"Add Metadata"}
-                    onClick={action(() => { this.editingMetadata = !this.editingMetadata })}
+                    onClick={action(() => this.editingMetadata = !this.editingMetadata)}
                 />
                 <div className="editableclass" onKeyPress={this.enter} style={{ opacity: isEditing ? 1 : 0, pointerEvents: isEditing ? "auto" : "none", transition: "0.4s opacity ease", position: "absolute", top: 0, left: 0, height: 20, width: "-webkit-fill-available" }}>
                     <EditableView
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index e61f90db8..3fb330840 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -133,6 +133,7 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
                     CollectionView={undefined}
                     ContainingCollectionDoc={undefined}
                     ContainingCollectionView={undefined}
+                    rootSelected={returnFalse}
                     onCheckedClick={this.scriptField!}
                     onChildClick={this.scriptField!}
                     LibraryPath={emptyPath}
diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss
index eae9e0220..123a27deb 100644
--- a/src/client/views/collections/CollectionLinearView.scss
+++ b/src/client/views/collections/CollectionLinearView.scss
@@ -8,6 +8,8 @@
         display:flex;
         height: 100%;
         >label {
+            margin-top: "auto";
+            margin-bottom: "auto";
             background: $dark-color;
             color: $light-color;
             display: inline-block;
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index a6ada75b2..728b3066d 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -3,7 +3,7 @@ import { observer } from 'mobx-react';
 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 { BoolCast, NumCast, StrCast, Cast, ScriptCast } from '../../../new_fields/Types';
 import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse } from '../../../Utils';
 import { DragManager } from '../../util/DragManager';
 import { Transform } from '../../util/Transform';
@@ -13,7 +13,6 @@ import { CollectionSubView } from './CollectionSubView';
 import { DocumentView } from '../nodes/DocumentView';
 import { documentSchema } from '../../../new_fields/documentSchemas';
 import { Id } from '../../../new_fields/FieldSymbols';
-import { ScriptField } from '../../../new_fields/ScriptField';
 
 
 type LinearDocument = makeInterface<[typeof documentSchema,]>;
@@ -28,12 +27,10 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
     private _selectedDisposer?: IReactionDisposer;
 
     componentWillUnmount() {
-        this._dropDisposer && this._dropDisposer();
-        this._widthDisposer && this._widthDisposer();
-        this._selectedDisposer && this._selectedDisposer();
-        this.childLayoutPairs.map((pair, ind) => {
-            Cast(pair.layout.proto?.onPointerUp, ScriptField)?.script.run({ this: pair.layout.proto }, console.log);
-        });
+        this._dropDisposer?.();
+        this._widthDisposer?.();
+        this._selectedDisposer?.();
+        this.childLayoutPairs.map((pair, ind) => ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log));
     }
 
     componentDidMount() {
@@ -54,11 +51,11 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
                         selected = pair;
                     }
                     else {
-                        Cast(pair.layout.proto?.onPointerUp, ScriptField)?.script.run({ this: pair.layout.proto }, console.log);
+                        ScriptCast(pair.layout.proto?.onPointerUp)?.script.run({ this: pair.layout.proto }, console.log);
                     }
                 });
                 if (selected && selected.layout) {
-                    Cast(selected.layout.proto?.onPointerDown, ScriptField)?.script.run({ this: selected.layout.proto }, console.log);
+                    ScriptCast(selected.layout.proto?.onPointerDown)?.script.run({ this: selected.layout.proto }, console.log);
                 }
             }),
             { fireImmediately: true }
@@ -81,14 +78,16 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
     render() {
         const guid = Utils.GenerateGuid();
         const flexDir: any = StrCast(this.Document.flexDirection);
+        const backgroundColor = StrCast(this.props.Document.backgroundColor, "black");
+        const color = StrCast(this.props.Document.color, "white");
         return <div className="collectionLinearView-outer">
             <div className="collectionLinearView" ref={this.createDashEventsTarget} >
-                <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}`} title="Close Menu" 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") }} >
+                <label htmlFor={`${guid}`} title="Close Menu" style={{ background: backgroundColor === color ? "black" : backgroundColor }}
+                    onPointerDown={e => e.stopPropagation()} >
                     <p>+</p>
                 </label>
+                <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)} />
 
                 <div className="collectionLinearView-content" style={{ height: this.dimension(), flexDirection: flexDir }}>
                     {this.childLayoutPairs.map((pair, ind) => {
diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx
index f124fe21b..7b16ff546 100644
--- a/src/client/views/collections/CollectionSchemaCells.tsx
+++ b/src/client/views/collections/CollectionSchemaCells.tsx
@@ -159,6 +159,7 @@ export class CollectionSchemaCell extends React.Component<CellProps> {
             LibraryPath: [],
             dropAction: "alias",
             bringToFront: emptyFunction,
+            rootSelected: returnFalse,
             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/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
index 47118e758..0e2685d41 100644
--- a/src/client/views/nodes/DocumentBox.tsx
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -112,7 +112,7 @@ export class DocumentBox extends DocAnnotatableComponent<FieldViewProps, DocBoxS
         if (containedDoc && childTemplateName && !containedDoc["layout_" + childTemplateName]) {
             setTimeout(() => {
                 DocumentView.createCustomView(containedDoc, Docs.Create.StackingDocument, childTemplateName);
-                Doc.expandTemplateLayout(Cast(containedDoc["layout_" + childTemplateName], Doc, null)!, containedDoc, undefined);
+                Doc.expandTemplateLayout(Cast(containedDoc["layout_" + childTemplateName], Doc, null), containedDoc, undefined);
             }, 0);
         }
         const contents = !(containedDoc instanceof Doc) ? (null) : <ContentFittingDocumentView
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 42f5fb946..9cccc9765 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -273,9 +273,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         }
     }
 
-    dontDecorateSelection: any = false;
     onClick = (e: React.MouseEvent | React.PointerEvent) => {
-        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)) {
             let stopPropagate = true;
@@ -295,7 +293,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     this: this.props.Document,
                     self: Cast(this.props.Document.rootDocument, Doc, null) || this.props.Document,
                     containingCollection: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey
-                }, console.log) && !this.props.Document.dontDecorateSelection && !this.props.Document.isButton && this.select(false), "on click");
+                }, console.log) && !this.props.Document.isButton && this.select(false), "on click");
             } else if (this.Document.type === DocumentType.BUTTON) {
                 UndoManager.RunInBatch(() => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY), "on button click");
             } else if (this.Document.isButton) {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 241345f3e..94195fbd6 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -292,7 +292,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
         const linkDoc = data.linkDocument!;
         const anchor1Title = linkDoc.anchor1 instanceof Doc ? StrCast(linkDoc.anchor1.title) : "-untitled-";
         const anchor1Id = linkDoc.anchor1 instanceof Doc ? linkDoc.anchor1[Id] : "";
-        this.makeLinkToSelection(linkDoc[Id], anchor1Title, "onRight", anchor1Id)
+        this.makeLinkToSelection(linkDoc[Id], anchor1Title, "onRight", anchor1Id);
     }
 
     getNodeEndpoints(context: Node, node: Node): { from: number, to: number } | null {
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 3d59ea61a..ef039c857 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -59,6 +59,7 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
             ContainingCollectionView: undefined,
             ContainingCollectionDoc: undefined,
             fieldKey: this.props.keyName,
+            rootSelected: returnFalse,
             isSelected: returnFalse,
             select: emptyFunction,
             dropAction:"alias",
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 5913c5a82..2a6eff7ff 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -64,7 +64,7 @@ export default class PDFMenu extends AntimodeMenu {
     togglePin = action((e: React.MouseEvent) => {
         this.Pinned = !this.Pinned;
         !this.Pinned && (this.Highlighting = false);
-    })
+    });
 
     @action
     highlightClicked = (e: React.MouseEvent) => {
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 49b6b18ca..a5b24addc 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -89,9 +89,7 @@ export class SearchBox extends React.Component<SearchProps> {
 
 
     @action
-    getViews = async (doc: Doc) => {
-        return await SearchUtil.GetViewsOfDocument(doc);
-    }
+    getViews = (doc: Doc) => SearchUtil.GetViewsOfDocument(doc);
 
     @action.bound
     onChange(e: React.ChangeEvent<HTMLInputElement>) {
@@ -130,23 +128,18 @@ export class SearchBox extends React.Component<SearchProps> {
         }
     }
 
-    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB, DocumentType.TEMPLATE];
+    public _allIcons: string[] = [DocumentType.AUDIO, DocumentType.COL, DocumentType.IMG, DocumentType.LINK, DocumentType.PDF, DocumentType.TEXT, DocumentType.VID, DocumentType.WEB];
     //if true, any keywords can be used. if false, all keywords are required.
     //this also serves as an indicator if the word status filter is applied
     @observable private _filterOpen: boolean = false;
     //if icons = all icons, then no icon filter is applied
     @observable private _icons: string[] = this._allIcons;
     //if all of these are true, no key filter is applied
-    @observable private _anyKeywordStatus: boolean = true;
-    @observable private _allKeywordStatus: boolean = true;
     @observable private _titleFieldStatus: boolean = true;
     @observable private _authorFieldStatus: boolean = true;
-    @observable private _dataFieldStatus: boolean = true;
     //this also serves as an indicator if the collection status filter is applied
     @observable public _deletedDocsStatus: boolean = false;
     @observable private _collectionStatus = false;
-    @observable private _collectionSelfStatus = true;
-    @observable private _collectionParentStatus = true;
 
 
     getFinalQuery(query: string): string {
@@ -187,7 +180,7 @@ export class SearchBox extends React.Component<SearchProps> {
 
     @action
     filterDocsByType(docs: Doc[]) {
-        if (this._icons.length === 9) {
+        if (this._icons.length === this._allIcons.length) {
             return docs;
         }
         const finalDocs: Doc[] = [];
@@ -218,7 +211,7 @@ export class SearchBox extends React.Component<SearchProps> {
     }
 
     get filterTypes() {
-        return this._icons.length === 9 ? undefined : this._icons;
+        return this._icons.length === this._allIcons.length ? undefined : this._icons;
     }
 
     @action.bound
@@ -296,7 +289,7 @@ export class SearchBox extends React.Component<SearchProps> {
 
     @action
     submitSearch = async () => {
-        let query = this._searchString;
+        const query = this._searchString;
         this.getFinalQuery(query);
         this._results = [];
         this._resultsSet.clear();
@@ -526,10 +519,10 @@ export class SearchBox extends React.Component<SearchProps> {
     handleNodeChange = () => {
         this._nodeStatus = !this._nodeStatus;
         if (this._nodeStatus) {
-            this.expandSection(`node${this.props.id}`)
+            this.expandSection(`node${this.props.id}`);
         }
         else {
-            this.collapseSection(`node${this.props.id}`)
+            this.collapseSection(`node${this.props.id}`);
         }
     }
 
@@ -565,13 +558,13 @@ export class SearchBox extends React.Component<SearchProps> {
 
 
     collapseSection(thing: string) {
-        let id = this.props.id;
-        let element = document.getElementById(thing)!;
+        const id = this.props.id;
+        const element = document.getElementById(thing)!;
         // get the height of the element's inner content, regardless of its actual size
-        var sectionHeight = element.scrollHeight;
+        const sectionHeight = element.scrollHeight;
 
         // temporarily disable all css transitions
-        var elementTransition = element.style.transition;
+        const elementTransition = element.style.transition;
         element.style.transition = '';
 
         // on the next frame (as soon as the previous style change has taken effect),
@@ -585,7 +578,7 @@ export class SearchBox extends React.Component<SearchProps> {
             // have the element transition to height: 0
             requestAnimationFrame(function () {
                 element.style.height = 0 + 'px';
-                thing == `filterhead${id}` ? document.getElementById(`filterhead${id}`)!.style.padding = "0" : null;
+                thing ===`filterhead${id}` ? document.getElementById(`filterhead${id}`)!.style.padding = "0" : null;
             });
         });
 
@@ -595,12 +588,11 @@ export class SearchBox extends React.Component<SearchProps> {
 
     expandSection(thing: string) {
         console.log("expand");
-        let element = document.getElementById(thing)!;
+        const element = document.getElementById(thing)!;
         // get the height of the element's inner content, regardless of its actual size
-        var sectionHeight = element.scrollHeight;
+        const sectionHeight = element.scrollHeight;
 
         // have the element transition to the height of its inner content
-        let temp = element.style.height;
         element.style.height = sectionHeight + 'px';
 
         // when the next css transition finishes (which should be the one we just triggered)
@@ -620,7 +612,7 @@ export class SearchBox extends React.Component<SearchProps> {
     }
 
     autoset(thing: string) {
-        let element = document.getElementById(thing)!;
+        const element = document.getElementById(thing)!;
         console.log("autoset");
         element.removeEventListener('transitionend', function (e) { });
 
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 4bf871d97..3ac46362a 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -42,7 +42,6 @@ export const documentSchema = createSchema({
     removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped
     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)
-    dontDecorateSelection: "boolean",      // whether document should be selected when clicked (usually set to false for buttons)
     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
     treeViewPreventOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document)
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index eeb19b034..da33e3050 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -97,11 +97,15 @@ export class CurrentUserUtils {
             _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100,
             icon: data.icon,
             title: data.title,
+            isButton: true,
             ignoreClick: data.ignoreClick,
             dropAction: data.click ? "copy" : undefined,
-            onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
-            ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen, dontDecorateSelection: true,
-            backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]), dragFactory: data.dragFactory,
+            onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined,
+            onClick: data.click ? ScriptField.MakeScript(data.click) : undefined,
+            ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined,
+            activePen: data.activePen,
+            backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]),
+            dragFactory: data.dragFactory,
         }));
     }
 
@@ -166,9 +170,12 @@ export class CurrentUserUtils {
     static setupThumbDoc(userDoc: Doc) {
         if (!userDoc.thumbDoc) {
             const thumbDoc = Docs.Create.LinearDocument(CurrentUserUtils.setupThumbButtons(userDoc), {
-                _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white"
+                _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons",
+                _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white"
+            });
+            thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], {
+                _width: 300, _height: 25, _autoHeight: true, _chromeStatus: "disabled", linearViewIsExpanded: true, flexDirection: "column"
             });
-            thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], { _width: 300, _height: 25, _autoHeight: true, _chromeStatus: "disabled", linearViewIsExpanded: true, flexDirection: "column" });
             userDoc.thumbDoc = thumbDoc;
         }
         return Cast(userDoc.thumbDoc, Doc);
@@ -210,11 +217,12 @@ export class CurrentUserUtils {
         });
 
         return Docs.Create.ButtonDocument({
-            _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer, dontDecorateSelection: true,
+            _width: 35, _height: 25, title: "Tools", fontSize: 10, targetContainer: sidebarContainer,
             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", forceActive: true
             }),
+            isButton: true,
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
         });
     }
@@ -236,11 +244,12 @@ export class CurrentUserUtils {
         });
 
         return Docs.Create.ButtonDocument({
-            _width: 50, _height: 25, title: "Library", fontSize: 10, dontDecorateSelection: true,
+            _width: 50, _height: 25, title: "Library", fontSize: 10,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
             sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, Docs.Prototypes.MainLinkDocument(), doc, doc.recentlyClosed as Doc], {
                 title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "place", lockedPosition: true, boxShadow: "0 0", dontRegisterChildren: true
             }),
+            isButton: true,
             targetContainer: sidebarContainer,
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;")
         });
@@ -249,11 +258,12 @@ export class CurrentUserUtils {
     // setup the Search button which will display the search panel.  
     static setupSearchPanel(sidebarContainer: Doc) {
         return Docs.Create.ButtonDocument({
-            _width: 50, _height: 25, title: "Search", fontSize: 10, dontDecorateSelection: true,
+            _width: 50, _height: 25, title: "Search", fontSize: 10,
             letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)",
             sourcePanel: Docs.Create.QueryDocument({ title: "search stack", }),
             targetContainer: sidebarContainer,
             lockedPosition: true,
+            isButton: true,
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel")
         });
     }
@@ -280,26 +290,26 @@ export class CurrentUserUtils {
     static setupExpandingButtons(doc: Doc) {
         const queryTemplate = Docs.Create.MulticolumnDocument(
             [
-                Docs.Create.QueryDocument({ title: "query", _height: 200, forceActive: true  }),
+                Docs.Create.QueryDocument({ title: "query", _height: 200, forceActive: true }),
                 Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true, forceActive: true })
             ],
             { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
         queryTemplate.isTemplateDoc = makeTemplate(queryTemplate);
         const slideTemplate = Docs.Create.MultirowDocument(
             [
-                Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, forceActive: true  }),
-                Docs.Create.TextDocument("", { title: "text", _height: 100, forceActive: true})
+                Docs.Create.MulticolumnDocument([], { title: "data", _height: 200, forceActive: true }),
+                Docs.Create.TextDocument("", { title: "text", _height: 100, forceActive: true })
             ],
-            { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true});
+            { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, _autoHeight: false, forceActive: true, hideFilterView: true });
         slideTemplate.isTemplateDoc = makeTemplate(slideTemplate);
         const descriptionTemplate = Docs.Create.TextDocument("", { title: "text", _height: 100, _showTitle: "title" });
         Doc.GetProto(descriptionTemplate).layout = FormattedTextBox.LayoutString("description");
         descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView");
 
-        const ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ ...opts, dontDecorateSelection: true, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 })) as any as Doc;
+        const ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ ...opts, isButton: true, dropAction: "alias", removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 })) as any as Doc;
         const blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, {
             ...opts,
-            _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", dontDecorateSelection: true, forceActive: true,
+            _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", isButton: true, forceActive: true,
             dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }),
             backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true
         })) as any as Doc;
@@ -309,8 +319,8 @@ export class CurrentUserUtils {
         doc.slidesBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "sticky-note" });
         doc.descriptionBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "description view", icon: "sticky-note" });
         doc.queryBtn = ficon({ onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: queryTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "query view", icon: "sticky-note" });
-        doc.templateButtons = blist({ title: "template buttons" }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]);
-        doc.expandingButtons = blist({ title: "expanding buttons" }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.templateButtons as Doc]);
+        doc.templateButtons = blist({ title: "template buttons", ignoreClick: true }, [doc.slidesBtn as Doc, doc.descriptionBtn as Doc, doc.queryBtn as Doc]);
+        doc.expandingButtons = blist({ title: "expanding buttons", ignoreClick: true }, [doc.undoBtn as Doc, doc.redoBtn as Doc, doc.templateButtons as Doc]);
         doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc], {
             title: "template layouts", _xPadding: 0,
             dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
-- 
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/collections/CollectionLinearView.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/collections/CollectionLinearView.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

