From 98d6476cc1d18617399b28fa670848f97160ffa1 Mon Sep 17 00:00:00 2001
From: monikahedman <monika_hedman@brown.edu>
Date: Wed, 17 Jul 2019 17:59:45 -0400
Subject: smol changes

---
 src/client/views/DocumentDecorations.tsx | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index fb5104915..d8a4bd071 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,5 +1,5 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faLink, faTag } from '@fortawesome/free-solid-svg-icons';
+import { faLink, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
@@ -34,6 +34,7 @@ export const Flyout = higflyout.default;
 
 library.add(faLink);
 library.add(faTag);
+library.add(faTimes);
 
 @observer
 export class DocumentDecorations extends React.Component<{}, { value: string }> {
@@ -726,7 +727,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 {this._edtingTitle ?
                     <input ref={this.keyinput} className="title" type="text" name="dynbox" value={this._title} onBlur={this.titleBlur} onChange={this.titleChanged} onKeyPress={this.titleEntered} /> :
                     <div className="title" onPointerDown={this.onTitleDown} ><span>{`${this.selectionTitle}`}</span></div>}
-                <div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>X</div>
+                <div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>
+                    <FontAwesomeIcon className="documentdecorations-icon" icon={faTimes} size="lg" />
+                </div>
                 <div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-topResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-topRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
-- 
cgit v1.2.3-70-g09d2


From f3c02a5df4c589846d47f0c435456f4c83b58484 Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Thu, 18 Jul 2019 14:09:43 -0400
Subject: hi

---
 src/client/views/DocumentDecorations.scss |  5 ++++
 src/client/views/DocumentDecorations.tsx  |  2 +-
 src/client/views/Main.scss                | 38 ++++++++++++++++++-------------
 3 files changed, 28 insertions(+), 17 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 537444a93..3627edaae 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -223,6 +223,11 @@ $linkGap : 3px;
     margin-top: 3px;
 }
 
+.documentdecorations-times {
+    margin-top: 3px;
+    padding-right: 3px;
+}
+
 .templating-button,
 .docDecs-tagButton {
     width: 20px;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index d8a4bd071..3be5146f6 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -728,7 +728,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                     <input ref={this.keyinput} className="title" type="text" name="dynbox" value={this._title} onBlur={this.titleBlur} onChange={this.titleChanged} onKeyPress={this.titleEntered} /> :
                     <div className="title" onPointerDown={this.onTitleDown} ><span>{`${this.selectionTitle}`}</span></div>}
                 <div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>
-                    <FontAwesomeIcon className="documentdecorations-icon" icon={faTimes} size="lg" />
+                    <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
                 </div>
                 <div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-topResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index a16123476..eed2ae4fa 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -24,7 +24,7 @@ div {
 
 .jsx-parser {
     width: 100%;
-    height:100%;
+    height: 100%;
     pointer-events: none;
     border-radius: inherit;
 }
@@ -119,6 +119,7 @@ button:hover {
         margin-bottom: 10px;
     }
 }
+
 .toolbar-color-picker {
     background-color: $light-color;
     border-radius: 5px;
@@ -128,6 +129,7 @@ button:hover {
     left: -3px;
     box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
 }
+
 .toolbar-color-button {
     border-radius: 11px;
     width: 22px;
@@ -146,7 +148,7 @@ button:hover {
     bottom: 22px;
     left: 250px;
 
-    > label {
+    >label {
         background: $dark-color;
         color: $light-color;
         display: inline-block;
@@ -168,15 +170,15 @@ button:hover {
         transform: scale(1.15);
     }
 
-    > input {
+    >input {
         display: none;
     }
 
-    > input:not(:checked)~#add-options-content {
+    >input:not(:checked)~#add-options-content {
         display: none;
     }
 
-    > input:checked~label {
+    >input:checked~label {
         transform: rotate(45deg);
         transition: transform 0.5s;
         cursor: pointer;
@@ -221,7 +223,7 @@ ul#add-options-list {
     list-style: none;
     padding: 5 0 0 0;
 
-    > li {
+    >li {
         display: inline-block;
         padding: 0;
     }
@@ -231,7 +233,7 @@ ul#add-options-list {
     height: 100%;
     position: absolute;
     display: flex;
-    flex-direction:column;
+    flex-direction: column;
 }
 
 .mainView-libraryHandle {
@@ -243,21 +245,25 @@ ul#add-options-list {
     position: absolute;
     z-index: 1;
 }
+
 .svg-inline--fa {
     vertical-align: unset;
 }
+
 .mainView-workspace {
-    height:200px;
-    position:relative;
-    display:flex;
+    height: 200px;
+    position: relative;
+    display: flex;
 }
+
 .mainView-library {
-    height:75%;
-    position:relative;
-    display:flex;
+    height: 75%;
+    position: relative;
+    display: flex;
 }
+
 .mainView-recentlyClosed {
-    height:25%;
-    position:relative;
-    display:flex;
+    height: 25%;
+    position: relative;
+    display: flex;
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From e0709211b80f5e69384318ebe007c877cd6dbfd5 Mon Sep 17 00:00:00 2001
From: Eleanor Eng <eleanor_eng@brown.edu>
Date: Fri, 19 Jul 2019 11:38:10 -0400
Subject: mac resize fix

---
 src/client/views/DocumentDecorations.tsx | 7 +++++++
 1 file changed, 7 insertions(+)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 3be5146f6..bf880b9c3 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -63,6 +63,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     @observable private _opacity = 1;
     @observable private _removeIcon = false;
     @observable public Interacting = false;
+    @observable private _isMoving = false;
 
     constructor(props: Readonly<{}>) {
         super(props);
@@ -337,9 +338,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             document.addEventListener("pointermove", this.onRadiusMove);
             document.addEventListener("pointerup", this.onRadiusUp);
         }
+        if (!this._isMoving) {
+            let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1]));
+            SelectionManager.SelectedDocuments().map(dv => dv.props.Document.borderRounding = Doc.GetProto(dv.props.Document).borderRounding = `${Math.min(100, dist)}%`);
+        }
     }
 
     onRadiusMove = (e: PointerEvent): void => {
+        this._isMoving = true;
         let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1]));
         SelectionManager.SelectedDocuments().map(dv => dv.props.Document.borderRounding = Doc.GetProto(dv.props.Document).borderRounding = `${Math.min(100, dist)}%`);
         e.stopPropagation();
@@ -351,6 +357,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         e.preventDefault();
         this._isPointerDown = false;
         this._resizeUndo && this._resizeUndo.end();
+        this._isMoving = false;
         document.removeEventListener("pointermove", this.onRadiusMove);
         document.removeEventListener("pointerup", this.onRadiusUp);
     }
-- 
cgit v1.2.3-70-g09d2


From 87b4d7ab7a28a01335dd081fc85c010a22aae5d1 Mon Sep 17 00:00:00 2001
From: Eleanor Eng <eleanor_eng@brown.edu>
Date: Fri, 19 Jul 2019 11:42:25 -0400
Subject: it's just 0

---
 src/client/views/DocumentDecorations.tsx | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index bf880b9c3..60dcf06cd 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -339,8 +339,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             document.addEventListener("pointerup", this.onRadiusUp);
         }
         if (!this._isMoving) {
-            let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1]));
-            SelectionManager.SelectedDocuments().map(dv => dv.props.Document.borderRounding = Doc.GetProto(dv.props.Document).borderRounding = `${Math.min(100, dist)}%`);
+            SelectionManager.SelectedDocuments().map(dv => dv.props.Document.borderRounding = Doc.GetProto(dv.props.Document).borderRounding = `${Math.min(100, 0)}%`);
         }
     }
 
-- 
cgit v1.2.3-70-g09d2


From 0191d5dfb07b6e50e5bda4523b79ff9769159541 Mon Sep 17 00:00:00 2001
From: monikahedman <monika_hedman@brown.edu>
Date: Fri, 19 Jul 2019 16:33:19 -0400
Subject: changed min

---
 src/client/views/DocumentDecorations.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 60dcf06cd..8e63ea4c3 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -339,7 +339,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             document.addEventListener("pointerup", this.onRadiusUp);
         }
         if (!this._isMoving) {
-            SelectionManager.SelectedDocuments().map(dv => dv.props.Document.borderRounding = Doc.GetProto(dv.props.Document).borderRounding = `${Math.min(100, 0)}%`);
+            SelectionManager.SelectedDocuments().map(dv => dv.props.Document.borderRounding = Doc.GetProto(dv.props.Document).borderRounding = `0%`);
         }
     }
 
-- 
cgit v1.2.3-70-g09d2


From d4accdd22cabdd78fc7bd76dd7ce3cb59e4b102f Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 1 Aug 2019 00:31:50 -0400
Subject: more treeview cleanup and fixes.

---
 src/client/util/SelectionManager.ts                |   1 +
 src/client/views/DocumentDecorations.tsx           |   4 +-
 .../views/collections/CollectionTreeView.tsx       | 340 +++++++++------------
 .../authentication/models/current_user_utils.ts    |   2 +-
 4 files changed, 145 insertions(+), 202 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 9efef888d..ee623d082 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -4,6 +4,7 @@ import { DocumentView } from "../views/nodes/DocumentView";
 import { FormattedTextBox } from "../views/nodes/FormattedTextBox";
 import { NumCast, StrCast } from "../../new_fields/Types";
 import { InkingControl } from "../views/InkingControl";
+import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
 
 export namespace SelectionManager {
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 40f2c3da9..eccfc7c30 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -29,6 +29,7 @@ import { LinkManager } from '../util/LinkManager';
 import { ObjectField } from '../../new_fields/ObjectField';
 import { MetadataEntryMenu } from './MetadataEntryMenu';
 import { ImageBox } from './nodes/ImageBox';
+import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -144,7 +145,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     @computed
     get Bounds(): { x: number, y: number, b: number, r: number } {
         return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
-            if (documentView.props.renderDepth === 0) {
+            if (documentView.props.renderDepth === 0 ||
+                Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) {
                 return bounds;
             }
             let transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index fa75c680a..7f5d78313 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -25,7 +25,6 @@ import { CollectionSchemaPreview } from './CollectionSchemaView';
 import { CollectionSubView } from "./CollectionSubView";
 import "./CollectionTreeView.scss";
 import React = require("react");
-import { LinkManager } from '../../util/LinkManager';
 import { ComputedField } from '../../../new_fields/ScriptField';
 import { KeyValueBox } from '../nodes/KeyValueBox';
 
@@ -67,22 +66,24 @@ library.add(faPlus, faMinus);
  * Component that takes in a document prop and a boolean whether it's collapsed or not.
  */
 class TreeView extends React.Component<TreeViewProps> {
+    static loadId = "";
     private _header?: React.RefObject<HTMLDivElement> = React.createRef();
     private _treedropDisposer?: DragManager.DragDropDisposer;
     private _dref = React.createRef<HTMLDivElement>();
-    @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, this.fieldKey); }
-    @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
     @observable _collapsed: boolean = true;
-
+    @computed get treeViewExpandedView() { return StrCast(this.props.document.treeViewExpandedView, "fields"); }
+    @computed get MAX_EMBED_HEIGHT() { return NumCast(this.props.document.maxEmbedHeight, 300); }
+    @computed get dataDoc() { return this.resolvedDataDoc ? this.resolvedDataDoc : this.props.document; }
     @computed get fieldKey() {
-        let layout = StrCast(this.props.document.layout);
-        if (layout.indexOf("fieldKey={\"") !== -1) {
-            return layout.split("fieldKey={\"")[1].split("\"")[0];
-        }
-        return "data";
+        let splits = StrCast(this.props.document.layout).split("fieldKey={\"");
+        return splits.length > 1 ? splits[1].split("\"")[0] : "data";
+    }
+    @computed get childDocs() {
+        let layout = this.props.document.layout as Doc;
+        return (this.props.dataDoc ? Cast(this.props.dataDoc[this.fieldKey], listSpec(Doc)) : undefined) ||
+            (layout ? Cast(layout[this.fieldKey], listSpec(Doc)) : undefined) ||
+            Cast(this.props.document[this.fieldKey], listSpec(Doc));
     }
-
-    @computed get dataDoc() { return this.resolvedDataDoc ? this.resolvedDataDoc : this.props.document; }
     @computed get resolvedDataDoc() {
         if (this.props.dataDoc === undefined && this.props.document.layout instanceof Doc) {
             // if there is no dataDoc (ie, we're not rendering a template layout), but this document
@@ -92,16 +93,30 @@ class TreeView extends React.Component<TreeViewProps> {
         }
         return this.props.dataDoc;
     }
+    @computed get boundsOfCollectionDocument() {
+        return StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1 ? undefined :
+            Doc.ComputeContentBounds(DocListCast(this.props.document.data));
+    }
 
-    protected createTreeDropTarget = (ele: HTMLDivElement) => {
-        this._treedropDisposer && this._treedropDisposer();
-        if (ele) {
-            this._treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } });
+    @undoBatch delete = () => this.props.deleteDoc(this.dataDoc);
+    @undoBatch openRight = () => this.props.addDocTab(this.props.document, undefined, "onRight");
+    @undoBatch indent = () => this.props.addDocument(this.props.document) && this.delete();
+    @undoBatch move = (doc: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => {
+        return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc);
+    }
+    @undoBatch @action remove = (document: Document, key: string): boolean => {
+        let children = Cast(this.dataDoc[key], listSpec(Doc), []);
+        if (children.indexOf(document) !== -1) {
+            children.splice(children.indexOf(document), 1);
+            return true;
         }
+        return false;
     }
 
-    @undoBatch delete = () => this.props.deleteDoc(this.dataDoc);
-    @undoBatch openRight = async () => this.props.addDocTab(this.props.document, undefined, "onRight");
+    protected createTreeDropTarget = (ele: HTMLDivElement) => {
+        this._treedropDisposer && this._treedropDisposer();
+        ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.treeDrop.bind(this) } }));
+    }
 
     onPointerDown = (e: React.PointerEvent) => e.stopPropagation();
     onPointerEnter = (e: React.PointerEvent): void => {
@@ -130,34 +145,6 @@ class TreeView extends React.Component<TreeViewProps> {
         e.stopPropagation();
     }
 
-    @action
-    remove = (document: Document, key: string): boolean => {
-        let children = Cast(this.dataDoc[key], listSpec(Doc), []);
-        if (children.indexOf(document) !== -1) {
-            children.splice(children.indexOf(document), 1);
-            return true;
-        }
-        return false;
-    }
-
-    @action
-    move: DragManager.MoveFunction = (doc: Doc, target: Doc, addDoc) => {
-        return this.props.document !== target && this.props.deleteDoc(doc) && addDoc(doc);
-    }
-    @action
-    indent = () => this.props.addDocument(this.props.document) && this.delete()
-
-    renderBullet() {
-        let docList = Cast(this.dataDoc[this.fieldKey], listSpec(Doc));
-        let doc = Cast(this.dataDoc[this.fieldKey], Doc);
-        let isDoc = doc instanceof Doc || docList;
-        let c;
-        return <div className="bullet" onClick={action(() => this._collapsed = !this._collapsed)} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}>
-            {<FontAwesomeIcon icon={this._collapsed ? (isDoc ? "caret-square-right" : "caret-right") : (isDoc ? "caret-square-down" : "caret-down")} />}
-        </div>;
-    }
-
-    static loadId = "";
     editableView = (key: string, style?: string) => (<EditableView
         oneLine={true}
         display={"inline"}
@@ -178,43 +165,6 @@ class TreeView extends React.Component<TreeViewProps> {
         OnTab={() => this.props.indentDocument && this.props.indentDocument()}
     />)
 
-    /**
-     * Renders the EditableView title element for placement into the tree.
-     */
-    renderTitle() {
-        let reference = React.createRef<HTMLDivElement>();
-        let onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true);
-
-        let headerElements = (
-            <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
-                onPointerDown={action(() => {
-                    this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
-                        this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" : this.fieldKey;
-                    this._collapsed = false;
-                })}>
-                {this.treeViewExpandedView}
-            </span>);
-        let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document[this.fieldKey], listSpec(Doc), []) : [];
-        let openRight = dataDocs && dataDocs.indexOf(this.dataDoc) !== -1 ? (null) : (
-            <div className="treeViewItem-openRight" onPointerDown={this.onPointerDown} onClick={this.openRight}>
-                <FontAwesomeIcon icon="angle-right" size="lg" />
-            </div>);
-        return <>
-            <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
-                style={{
-                    background: BoolCast(this.props.document.libraryBrush) ? "#06121212" : "0",
-                    outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
-                    pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
-                }}
-            >
-                {this.editableView("title")}
-                {/* {<div className="delete-button" onClick={this.delete}><FontAwesomeIcon icon="trash-alt" size="xs" /></div>} */}
-            </div >
-            {headerElements}
-            {openRight}
-        </>;
-    }
-
     onWorkspaceContextMenu = (e: React.MouseEvent): void => {
         if (!e.isPropagationStopped()) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
             if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) {
@@ -275,39 +225,6 @@ class TreeView extends React.Component<TreeViewProps> {
         let finalXf = this.props.ScreenToLocalTransform().translate(offset[0], offset[1]);
         return finalXf;
     }
-
-    renderLinks = () => {
-        let ele: JSX.Element[] = [];
-        let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
-        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.props.document, this.fieldKey, doc, addBefore, before);
-        let groups = LinkManager.Instance.getRelatedGroupedLinks(this.props.document);
-        groups.forEach((groupLinkDocs, groupType) => {
-            // let destLinks = groupLinkDocs.map(d => LinkManager.Instance.getOppositeAnchor(d, this.props.document));
-            let destLinks: Doc[] = [];
-            groupLinkDocs.forEach((doc) => {
-                let opp = LinkManager.Instance.getOppositeAnchor(doc, this.props.document);
-                if (opp) {
-                    destLinks.push(opp);
-                }
-            });
-            ele.push(
-                <div key={"treeviewlink-" + groupType + "subtitle"}>
-                    <div className="collectionTreeView-subtitle">{groupType}:</div>
-                    {
-                        TreeView.GetChildElements(destLinks, this.props.treeViewId, this.props.document, this.props.dataDoc, "treeviewlink-" + groupType, addDoc, remDoc, this.move,
-                            this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)
-                    }
-                </div>
-            );
-        });
-        return ele;
-    }
-
-    @computed get boundsOfCollectionDocument() {
-        if (StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1) return undefined;
-        let layoutDoc = this.props.document;
-        return Doc.ComputeContentBounds(DocListCast(layoutDoc.data));
-    }
     docWidth = () => {
         let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth);
         if (aspect) return Math.min(this.props.document[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.panelWidth() - 5));
@@ -323,39 +240,29 @@ class TreeView extends React.Component<TreeViewProps> {
         })());
     }
 
-    noOverlays = (doc: Doc) => ({ title: "", caption: "" });
-
-    expandedField = (doc?: Doc) => {
-        if (!doc) return <div />;
-        let realDoc = doc;
-
+    expandedField = (doc: Doc) => {
         let ids: { [key: string]: string } = {};
-        Object.keys(doc).forEach(key => {
-            if (!(key in ids) && realDoc[key] !== ComputedField.undefined) {
-                ids[key] = key;
-            }
-        });
+        doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
 
         let rows: JSX.Element[] = [];
         for (let key of Object.keys(ids).sort()) {
-            let contents = realDoc[key] ? realDoc[key] : undefined;
+            let contents = doc[key];
             let contentElement: JSX.Element[] | JSX.Element = [];
 
             if (contents instanceof Doc || Cast(contents, listSpec(Doc))) {
-                let docList = contents;
                 let remDoc = (doc: Doc) => this.remove(doc, key);
                 let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before);
-                contentElement = key === "links" ? this.renderLinks() :
-                    TreeView.GetChildElements(docList instanceof Doc ? [docList] : DocListCast(docList), this.props.treeViewId, realDoc, undefined, key, addDoc, remDoc, this.move,
-                        this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth);
+                contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] :
+                    DocListCast(contents), this.props.treeViewId, doc, undefined, key, addDoc, remDoc, this.move,
+                    this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth);
             } else {
                 contentElement = <EditableView
                     key="editableView"
-                    contents={contents ? contents.toString() : "null"}
+                    contents={contents !== undefined ? contents.toString() : "null"}
                     height={13}
                     fontSize={12}
-                    GetValue={() => Field.toKeyValueString(realDoc, key)}
-                    SetValue={(value: string) => KeyValueBox.SetField(realDoc, key, value)} />;
+                    GetValue={() => Field.toKeyValueString(doc, key)}
+                    SetValue={(value: string) => KeyValueBox.SetField(doc, key, value)} />;
             }
             rows.push(<div style={{ display: "flex" }} key={key}>
                 <span style={{ fontWeight: "bold" }}>{key + ":"}</span>
@@ -366,59 +273,100 @@ class TreeView extends React.Component<TreeViewProps> {
         return rows;
     }
 
-    render() {
-        let contentElement: (JSX.Element | null) = null;
-        let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
-        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc, addBefore, before);
+    noOverlays = (doc: Doc) => ({ title: "", caption: "" });
 
-        if (!this._collapsed) {
-            if (this.treeViewExpandedView === this.fieldKey) {
-                let layout = this.props.document.layout as Doc;
-                let childDocs = (this.props.dataDoc ? Cast(this.props.dataDoc[this.fieldKey], listSpec(Doc)) : undefined) ||
-                    (layout ? Cast(layout[this.fieldKey], listSpec(Doc)) : undefined) ||
-                    Cast(this.props.document[this.fieldKey], listSpec(Doc));
-                contentElement = <ul key={this.fieldKey + "more"}>
-                    {this.fieldKey === "links" ? this.renderLinks() :
-                        !childDocs ? (null) :
-                            TreeView.GetChildElements(childDocs as Doc[], this.props.treeViewId, layout, this.resolvedDataDoc, this.fieldKey, addDoc, remDoc, this.move,
-                                this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
-                </ul >;
-            } else if (this.treeViewExpandedView === "fields") {
-                contentElement = <ul><div ref={this._dref} style={{ display: "inline-block" }} key={this.props.document[Id] + this.props.document.title}>
-                    {this.expandedField(this.dataDoc)}
-                </div></ul>;
-            } else {
-                let layoutDoc = this.props.document;
-                contentElement = <div ref={this._dref} style={{ display: "inline-block", height: this.docHeight() }} key={this.props.document[Id] + this.props.document.title}>
-                    <CollectionSchemaPreview
-                        Document={layoutDoc}
-                        DataDocument={this.resolvedDataDoc}
-                        renderDepth={this.props.renderDepth}
-                        showOverlays={this.noOverlays}
-                        fitToBox={this.boundsOfCollectionDocument !== undefined}
-                        width={this.docWidth}
-                        height={this.docHeight}
-                        getTransform={this.docTransform}
-                        CollectionView={undefined}
-                        addDocument={emptyFunction as any}
-                        moveDocument={this.props.moveDocument}
-                        removeDocument={emptyFunction as any}
-                        active={this.props.active}
-                        whenActiveChanged={emptyFunction as any}
-                        addDocTab={this.props.addDocTab}
-                        setPreviewScript={emptyFunction}>
-                    </CollectionSchemaPreview>
-                </div>;
-            }
+    @computed get renderContent() {
+        if (this.treeViewExpandedView === this.fieldKey) {
+            let remDoc = (doc: Doc) => this.remove(doc, this.fieldKey);
+            let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this.fieldKey, doc, addBefore, before);
+            return <ul key={this.fieldKey + "more"}>
+                {!this.childDocs ? (null) :
+                    TreeView.GetChildElements(this.childDocs as Doc[], this.props.treeViewId, this.props.document.layout as Doc,
+                        this.resolvedDataDoc, this.fieldKey, addDoc, remDoc, this.move,
+                        this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform,
+                        this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth)}
+            </ul >;
+        } else if (this.treeViewExpandedView === "fields") {
+            return <ul><div ref={this._dref} style={{ display: "inline-block" }} key={this.props.document[Id] + this.props.document.title}>
+                {this.dataDoc ? this.expandedField(this.dataDoc) : (null)}
+            </div></ul>;
+        } else {
+            let layoutDoc = this.props.document;
+            return <div ref={this._dref} style={{ display: "inline-block", height: this.docHeight() }} key={this.props.document[Id] + this.props.document.title}>
+                <CollectionSchemaPreview
+                    Document={layoutDoc}
+                    DataDocument={this.resolvedDataDoc}
+                    renderDepth={this.props.renderDepth}
+                    showOverlays={this.noOverlays}
+                    fitToBox={this.boundsOfCollectionDocument !== undefined}
+                    width={this.docWidth}
+                    height={this.docHeight}
+                    getTransform={this.docTransform}
+                    CollectionView={undefined}
+                    addDocument={emptyFunction as any}
+                    moveDocument={this.props.moveDocument}
+                    removeDocument={emptyFunction as any}
+                    active={this.props.active}
+                    whenActiveChanged={emptyFunction as any}
+                    addDocTab={this.props.addDocTab}
+                    setPreviewScript={emptyFunction}>
+                </CollectionSchemaPreview>
+            </div>;
         }
+    }
+
+    @computed
+    get renderBullet() {
+        return <div className="bullet" onClick={action(() => this._collapsed = !this._collapsed)} style={{ color: StrCast(this.props.document.color, "black"), opacity: 0.4 }}>
+            {<FontAwesomeIcon icon={this._collapsed ? (this.childDocs ? "caret-square-right" : "caret-right") : (this.childDocs ? "caret-square-down" : "caret-down")} />}
+        </div>;
+    }
+    /**
+     * Renders the EditableView title element for placement into the tree.
+     */
+    @computed
+    get renderTitle() {
+        let reference = React.createRef<HTMLDivElement>();
+        let onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true);
+
+        let headerElements = (
+            <span className="collectionTreeView-keyHeader" key={this.treeViewExpandedView}
+                onPointerDown={action(() => {
+                    this.props.document.treeViewExpandedView = this.treeViewExpandedView === this.fieldKey ? "fields" :
+                        this.treeViewExpandedView === "fields" && this.props.document.layout ? "layout" :
+                            this.childDocs ? this.fieldKey : "fields";
+                    this._collapsed = false;
+                })}>
+                {this.treeViewExpandedView}
+            </span>);
+        let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document[this.fieldKey], listSpec(Doc), []) : [];
+        let openRight = dataDocs && dataDocs.indexOf(this.dataDoc) !== -1 ? (null) : (
+            <div className="treeViewItem-openRight" onPointerDown={this.onPointerDown} onClick={this.openRight}>
+                <FontAwesomeIcon icon="angle-right" size="lg" />
+            </div>);
+        return <>
+            <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
+                style={{
+                    background: BoolCast(this.props.document.libraryBrush) ? "#06121212" : "0",
+                    outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
+                    pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
+                }} >
+                {this.editableView("title")}
+            </div >
+            {headerElements}
+            {openRight}
+        </>;
+    }
+
+    render() {
         return <div className="treeViewItem-container" ref={this.createTreeDropTarget} onContextMenu={this.onWorkspaceContextMenu}>
             <li className="collection-child">
                 <div className="treeViewItem-header" ref={this._header} onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}>
-                    {this.renderBullet()}
-                    {this.renderTitle()}
+                    {this.renderBullet}
+                    {this.renderTitle}
                 </div>
                 <div className="treeViewItem-border">
-                    {contentElement}
+                    {this._collapsed ? (null) : this.renderContent}
                 </div>
             </li>
         </div>;
@@ -488,7 +436,9 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     private treedropDisposer?: DragManager.DragDropDisposer;
     private _mainEle?: HTMLDivElement;
 
-    @computed get chromeCollapsed() { return this.props.chromeCollapsed; }
+    @observable static NotifsCol: Opt<Doc>;
+
+    @computed get resolvedDataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; }
 
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
         this.treedropDisposer && this.treedropDisposer();
@@ -520,21 +470,15 @@ export class CollectionTreeView extends CollectionSubView(Document) {
             ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
         }
     }
-
-    @computed get resolvedDataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; }
-
     outerXf = () => Utils.GetScreenTransform(this._mainEle!);
     onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {});
-
-
-    @observable static NotifsCol: Opt<Doc>;
-
     openNotifsCol = () => {
         if (CollectionTreeView.NotifsCol && CollectionDockingView.Instance) {
             CollectionDockingView.Instance.AddRightSplit(CollectionTreeView.NotifsCol, undefined);
         }
     }
-    @computed get notifsButton() {
+
+    @computed get renderNotifsButton() {
         const length = CollectionTreeView.NotifsCol ? DocListCast(CollectionTreeView.NotifsCol.data).length : 0;
         const notifsRef = React.createRef<HTMLDivElement>();
         const dragNotifs = action(() => CollectionTreeView.NotifsCol!);
@@ -550,20 +494,16 @@ export class CollectionTreeView extends CollectionSubView(Document) {
             </div>
         </div >;
     }
-    @computed get clearButton() {
+    @computed get renderClearButton() {
         return <div id="toolbar" key="toolbar">
-            <div >
-                <button className="toolbar-button round-button" title="Notifs"
-                    onClick={undoBatch(action(() => Doc.GetProto(this.props.Document)[this.props.fieldKey] = undefined))}>
-                    <FontAwesomeIcon icon={faTrash} size="sm" />
-                </button>
-            </div>
+            <button className="toolbar-button round-button" title="Notifs"
+                onClick={undoBatch(action(() => Doc.GetProto(this.props.Document)[this.props.fieldKey] = undefined))}>
+                <FontAwesomeIcon icon={faTrash} size="sm" />
+            </button>
         </div >;
     }
 
-
     render() {
-        console.log("DTITLE + " + this.props.Document.title);
         Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
         let dropAction = StrCast(this.props.Document.dropAction) as dropActionType;
         let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before);
@@ -588,8 +528,8 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                         TreeView.loadId = doc[Id];
                         Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true);
                     }} />
-                {this.props.Document.workspaceLibrary ? this.notifsButton : (null)}
-                {this.props.Document.allowClear ? this.clearButton : (null)}
+                {this.props.Document.workspaceLibrary ? this.renderNotifsButton : (null)}
+                {this.props.Document.allowClear ? this.renderClearButton : (null)}
                 <ul className="no-indent" style={{ width: "max-content" }} >
                     {
                         TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove,
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 1c52a3f11..91d7ba87d 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -71,7 +71,7 @@ export class CurrentUserUtils {
             doc.sidebar = sidebar;
         }
         StrCast(doc.title).indexOf("@") !== -1 && (doc.title = StrCast(doc.title).split("@")[0] + "'s Library");
-
+        doc.width = 100;
     }
 
     public static loadCurrentUser() {
-- 
cgit v1.2.3-70-g09d2


From a4000aa57c9934ff3a68ba17474936836a5f235e Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 1 Aug 2019 10:35:02 -0400
Subject: tweaks

---
 src/client/views/ContextMenu.tsx                              |  2 +-
 src/client/views/DocumentDecorations.tsx                      |  1 -
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 11 +++++------
 src/client/views/nodes/DocumentView.tsx                       |  6 ------
 4 files changed, 6 insertions(+), 14 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 98025ac31..1bf6e383d 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -42,7 +42,7 @@ export class ContextMenu extends React.Component {
         return this._items.find(menuItem => {
             let reference = menuItem.description;
             toLowerCase && (reference = reference.toLowerCase());
-            reference === target;
+            return reference === target;
         });
     }
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index eccfc7c30..15471371a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -541,7 +541,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 if (fixedAspect && (!nwidth || !nheight)) {
                     proto.nativeWidth = nwidth = doc.width || 0;
                     proto.nativeHeight = nheight = doc.height || 0;
-                    proto.ignoreAspect = true;
                 }
                 if (nwidth > 0 && nheight > 0 && !BoolCast(proto.ignoreAspect)) {
                     if (Math.abs(dW) > Math.abs(dH)) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 33a584c6f..29f9b1429 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -131,10 +131,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
         let xf = this.getTransform();
+        let [xp, yp] = xf.transformPoint(de.x, de.y);
         if (super.drop(e, de)) {
             if (de.data instanceof DragManager.DocumentDragData) {
                 if (de.data.droppedDocuments.length) {
-                    let [xp, yp] = xf.transformPoint(de.x, de.y);
                     let x = xp - de.data.xOffset;
                     let y = yp - de.data.yOffset;
                     let dropX = NumCast(de.data.droppedDocuments[0].x);
@@ -157,7 +157,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             else if (de.data instanceof DragManager.AnnotationDragData) {
                 if (de.data.dropDocument) {
                     let dragDoc = de.data.dropDocument;
-                    let [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
                     let x = xp - de.data.xOffset;
                     let y = yp - de.data.yOffset;
                     let dropX = NumCast(de.data.dropDocument.x);
@@ -224,10 +223,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     this._pheight / this.zoomScaling());
                 let panelwidth = panelDim[0];
                 let panelheight = panelDim[1];
-                // if (ranges[0][0] - dx > (this.panX() + panelwidth / 2)) x = ranges[0][1] + panelwidth / 2;
-                // if (ranges[0][1] - dx < (this.panX() - panelwidth / 2)) x = ranges[0][0] - panelwidth / 2;
-                // if (ranges[1][0] - dy > (this.panY() + panelheight / 2)) y = ranges[1][1] + panelheight / 2;
-                // if (ranges[1][1] - dy < (this.panY() - panelheight / 2)) y = ranges[1][0] - panelheight / 2;
+                if (ranges[0][0] - dx > (this.panX() + panelwidth / 2)) x = ranges[0][1] + panelwidth / 2;
+                if (ranges[0][1] - dx < (this.panX() - panelwidth / 2)) x = ranges[0][0] - panelwidth / 2;
+                if (ranges[1][0] - dy > (this.panY() + panelheight / 2)) y = ranges[1][1] + panelheight / 2;
+                if (ranges[1][1] - dy < (this.panY() - panelheight / 2)) y = ranges[1][0] - panelheight / 2;
             }
             this.setPan(x - dx, y - dy);
             this._lastX = e.pageX;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 14f0b5a5a..d4adcfca1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -586,12 +586,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             }, icon: "window-restore"
         });
         cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" });
-        // cm.addItem({
-        //     description: "Find aliases", event: async () => {
-        //         const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document);
-        //         this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc?
-        //     }, icon: "search"
-        // });
         if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) {
             cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" });
         }
-- 
cgit v1.2.3-70-g09d2


From 837a9690b5fe8c3466a9b0c26ca1e484a0e4b253 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 10 Aug 2019 08:31:17 -0400
Subject: autoHeight fixes

---
 src/client/views/DocumentDecorations.tsx                | 2 +-
 src/client/views/collections/CollectionStackingView.tsx | 2 +-
 src/client/views/nodes/KeyValueBox.tsx                  | 1 +
 3 files changed, 3 insertions(+), 2 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 15471371a..6616d5d58 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -562,7 +562,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 } else {
                     dW && (doc.width = actualdW);
                     dH && (doc.height = actualdH);
-                    dH && Doc.SetInPlace(element.props.Document, "autoHeight", undefined, true);
+                    dH && element.props.Document.autoHeight && Doc.SetInPlace(element.props.Document, "autoHeight", false, true);
                 }
             }
         });
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4a751c84c..b87be5d68 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -76,7 +76,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
 
     componentDidMount() {
         // is there any reason this needs to exist? -syip
-        this._heightDisposer = reaction(() => [this.yMargin, this.props.Document[WidthSym](), this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])],
+        this._heightDisposer = reaction(() => [this.props.Document.autoHeight, this.yMargin, this.props.Document[WidthSym](), this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])],
             () => {
                 if (this.singleColumn && BoolCast(this.props.Document.autoHeight)) {
                     let hgt = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => {
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index f10079169..0d4b377dd 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -73,6 +73,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
 
     public static ApplyKVPScript(doc: Doc, key: string, kvpScript: KVPScript): boolean {
         const { script, type, onDelegate } = kvpScript;
+        //const target = onDelegate ? (doc.layout instanceof Doc ? doc.layout : doc) : Doc.GetProto(doc); // bcz: need to be able to set fields on layout templates
         const target = onDelegate ? doc : Doc.GetProto(doc);
         let field: Field;
         if (type === "computed") {
-- 
cgit v1.2.3-70-g09d2


From afec8d91ec6de13de33e2a31c987727b4cc7101d Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 13 Aug 2019 15:42:05 -0400
Subject: changes to fix stacking layouts used with templates. rearrangement of
 menu options.

---
 src/client/util/TooltipTextMenu.tsx                |   2 +-
 src/client/views/DocumentDecorations.tsx           |   4 +-
 src/client/views/InkingCanvas.tsx                  |  20 ++--
 src/client/views/ScriptBox.tsx                     |  30 +++++-
 .../views/collections/CollectionDockingView.tsx    |   4 +-
 .../views/collections/CollectionStackingView.tsx   |  57 +++++++----
 .../CollectionStackingViewFieldColumn.tsx          |   2 +-
 src/client/views/collections/CollectionView.tsx    |  19 ++--
 .../views/collections/CollectionViewChromes.tsx    |  19 ++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  64 ++-----------
 src/client/views/nodes/DocumentContentsView.tsx    |   3 +-
 src/client/views/nodes/DocumentView.tsx            | 105 ++++++++++++---------
 src/client/views/nodes/FormattedTextBox.tsx        |  15 +--
 src/new_fields/Doc.ts                              |   7 ++
 src/new_fields/Types.ts                            |   4 +
 15 files changed, 193 insertions(+), 162 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 8dc5cdb2a..48f02d38a 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -963,7 +963,7 @@ export class TooltipTextMenu {
                 });
             }
         }
-        if (!ref_node.isLeaf) {
+        if (!ref_node.isLeaf && ref_node.childCount > 0) {
             ref_node = ref_node.child(0);
         }
         return ref_node;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6616d5d58..d537e2dac 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -537,12 +537,12 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 doc.x = (doc.x || 0) + dX * (actualdW - width);
                 doc.y = (doc.y || 0) + dY * (actualdH - height);
                 let proto = doc.isTemplate ? doc : Doc.GetProto(element.props.Document); // bcz: 'doc' didn't work here...
-                let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect) && nwidth && nheight);
+                let fixedAspect = e.ctrlKey || (!BoolCast(doc.ignoreAspect) && nwidth && nheight);
                 if (fixedAspect && (!nwidth || !nheight)) {
                     proto.nativeWidth = nwidth = doc.width || 0;
                     proto.nativeHeight = nheight = doc.height || 0;
                 }
-                if (nwidth > 0 && nheight > 0 && !BoolCast(proto.ignoreAspect)) {
+                if (nwidth > 0 && nheight > 0 && !BoolCast(doc.ignoreAspect)) {
                     if (Math.abs(dW) > Math.abs(dH)) {
                         if (!fixedAspect) {
                             Doc.SetInPlace(element.props.Document, "nativeWidth", actualdW / (doc.width || 1) * (doc.nativeWidth || 0), true);
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 1c221e3df..b08133d80 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -165,14 +165,18 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
             }
             return paths;
         }, [] as JSX.Element[]);
-        return [<svg className={`inkingCanvas-paths-ink`} key="Pens"
-            style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }} >
-            {paths.filter(path => path.props.tool !== InkTool.Highlighter)}
-        </svg>,
-        <svg className={`inkingCanvas-paths-markers`} key="Markers"
-            style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }}>
-            {paths.filter(path => path.props.tool === InkTool.Highlighter)}
-        </svg>];
+        let markerPaths = paths.filter(path => path.props.tool === InkTool.Highlighter);
+        let penPaths = paths.filter(path => path.props.tool !== InkTool.Highlighter);
+        return [!penPaths.length ? (null) :
+            <svg className={`inkingCanvas-paths-ink`} key="Pens"
+                style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }} >
+                {}
+            </svg>,
+        !markerPaths.length ? (null) :
+            <svg className={`inkingCanvas-paths-markers`} key="Markers"
+                style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }}>
+                {}
+            </svg>];
     }
 
     render() {
diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx
index d073945e5..2b862a81e 100644
--- a/src/client/views/ScriptBox.tsx
+++ b/src/client/views/ScriptBox.tsx
@@ -5,7 +5,11 @@ import { observable, action } from "mobx";
 import "./ScriptBox.scss";
 import { OverlayView } from "./OverlayView";
 import { DocumentIconContainer } from "./nodes/DocumentIcon";
-import { Opt } from "../../new_fields/Doc";
+import { Opt, Doc } from "../../new_fields/Doc";
+import { emptyFunction } from "../../Utils";
+import { ScriptCast } from "../../new_fields/Types";
+import { CompileScript } from "../util/Scripting";
+import { ScriptField } from "../../new_fields/ScriptField";
 
 export interface ScriptBoxProps {
     onSave: (text: string, onError: (error: string) => void) => void;
@@ -62,4 +66,26 @@ export class ScriptBox extends React.Component<ScriptBoxProps> {
             </div>
         );
     }
-}
\ No newline at end of file
+    public static EditClickScript(doc: Doc, fieldKey: string) {
+        let overlayDisposer: () => void = emptyFunction;
+        const script = ScriptCast(doc[fieldKey]);
+        let originalText: string | undefined = undefined;
+        if (script) originalText = script.script.originalScript;
+        // tslint:disable-next-line: no-unnecessary-callback-wrapper
+        let scriptingBox = <ScriptBox initialText={originalText} onCancel={() => overlayDisposer()} onSave={(text, onError) => {
+            const script = CompileScript(text, {
+                params: { this: Doc.name },
+                typecheck: false,
+                editable: true,
+                transformer: DocumentIconContainer.getTransformer()
+            });
+            if (!script.compiled) {
+                onError(script.errors.map(error => error.messageText).join("\n"));
+                return;
+            }
+            doc[fieldKey] = new ScriptField(script);
+            overlayDisposer();
+        }} showDocumentIcons />;
+        overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: `${doc.title || ""} OnClick` });
+    }
+}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index c0c82a44e..13bb34037 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -555,8 +555,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     panelWidth = () => this._document!.ignoreAspect ? this._panelWidth : Math.min(this._panelWidth, Math.max(NumCast(this._document!.width), this.nativeWidth()));
     panelHeight = () => this._document!.ignoreAspect ? this._panelHeight : Math.min(this._panelHeight, Math.max(NumCast(this._document!.height), NumCast(this._document!.nativeHeight, this._panelHeight)));
 
-    nativeWidth = () => !BoolCast(this._document!.ignoreAspect) ? NumCast(this._document!.nativeWidth, this._panelWidth) : 0;
-    nativeHeight = () => !BoolCast(this._document!.ignoreAspect) ? NumCast(this._document!.nativeHeight, this._panelHeight) : 0;
+    nativeWidth = () => !this._document!.ignoreAspect ? NumCast(this._document!.nativeWidth) || this._panelWidth : 0;
+    nativeHeight = () => !this._document!.ignoreAspect ? NumCast(this._document!.nativeHeight) || this._panelHeight : 0;
 
     contentScaling = () => {
         const nativeH = this.nativeHeight();
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 9d2671356..ba3d8e6a7 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -9,7 +9,7 @@ import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
-import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../new_fields/Types";
 import { emptyFunction } from "../../../Utils";
 import { DocumentType } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
@@ -20,6 +20,9 @@ import { CollectionSchemaPreview } from "./CollectionSchemaView";
 import "./CollectionStackingView.scss";
 import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewFieldColumn";
 import { CollectionSubView } from "./CollectionSubView";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
+import { ScriptBox } from "../ScriptBox";
 
 @observer
 export class CollectionStackingView extends CollectionSubView(doc => doc) {
@@ -76,17 +79,24 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
 
     componentDidMount() {
         // is there any reason this needs to exist? -syip
-        this._heightDisposer = reaction(() => [this.props.Document.autoHeight, this.yMargin, this.props.Document[WidthSym](), this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])],
-            () => {
-                if (this.singleColumn && BoolCast(this.props.Document.autoHeight)) {
-                    let hgt = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => {
-                        let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d);
-                        return height + this.getDocHeight(pair.layout) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap);
-                    }, this.yMargin);
-                    (this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc)
-                        .height = hgt * (this.props as any).ContentScaling();
+        this._heightDisposer = reaction(() => {
+            if (this.singleColumn && BoolCast(this.props.Document.autoHeight)) {
+                let hgt = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => {
+                    let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d);
+                    return height + this.getDocHeight(pair.layout) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap);
+                }, this.yMargin);
+                return hgt * this.props.ContentScaling();
+            }
+            return -1;
+        },
+            (hgt: number) => {
+                if (hgt !== -1) {
+                    let doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
+                    doc.height = hgt;
                 }
-            }, { fireImmediately: true });
+            },
+            { fireImmediately: true }
+        );
 
         // reset section headers when a new filter is inputted
         this._sectionFilterDisposer = reaction(
@@ -109,9 +119,12 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     overlays = (doc: Doc) => {
-        return doc.type === DocumentType.IMG || doc.type === DocumentType.VID ? { title: "title", caption: "caption" } : {};
+        return doc.type === DocumentType.IMG || doc.type === DocumentType.VID ? { title: StrCast(this.props.Document.showTitles), caption: StrCast(this.props.Document.showCaptions) } : {};
     }
 
+    @computed get onChildClickHandler() { return ScriptCast(this.Document.onChildClick); }
+    @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : ScriptCast(this.Document.onChildClick); }
+
     getDisplayDoc(layoutDoc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
         let height = () => this.getDocHeight(layoutDoc);
         let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]());
@@ -121,7 +134,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             showOverlays={this.overlays}
             renderDepth={this.props.renderDepth}
             fitToBox={this.props.fitToBox}
-            onClick={this.props.onClick}
+            onClick={layoutDoc.isTemplate ? this.onClickHandler : this.onChildClickHandler}
             width={width}
             height={height}
             getTransform={finalDxf}
@@ -141,7 +154,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         let nh = NumCast(d.nativeHeight);
         if (!d.ignoreAspect && nw && nh) {
             let aspect = nw && nh ? nh / nw : 1;
-            let wid = this.props.Document.fillColumn ? this.columnWidth / columnScale : Math.min(d[WidthSym](), this.columnWidth / columnScale);
+            let wid = this.props.Document.fillColumn ? this.columnWidth / columnScale : Math.min(Math.min(d[WidthSym](), NumCast(d.nativeWidth)), this.columnWidth / columnScale);
             return wid * aspect;
         }
         return d[HeightSym]();
@@ -267,7 +280,19 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     onToggle = (checked: Boolean) => {
-        this.props.CollectionView.props.Document.chromeSatus = checked ? "collapsed" : "view-mode";
+        this.props.CollectionView.props.Document.chromeStatus = checked ? "collapsed" : "view-mode";
+    }
+
+    onContextMenu = (e: React.MouseEvent): void => {
+        // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
+        if (!e.isPropagationStopped()) {
+            let subItems: ContextMenuProps[] = [];
+            subItems.push({ description: `${this.props.Document.fillColumn ? "Variable Size" : "Autosize"} Column`, event: () => this.props.Document.fillColumn = !this.props.Document.fillColumn, icon: "plus" });
+            subItems.push({ description: `${this.props.Document.showTitles ? "Hide Titles" : "Show Titles"}`, event: () => this.props.Document.showTitles = !this.props.Document.showTitles ? "title" : "", icon: "plus" });
+            subItems.push({ description: `${this.props.Document.showCaptions ? "Hide Captions" : "Show Captions"}`, event: () => this.props.Document.showCaptions = !this.props.Document.showCaptions ? "caption" : "", icon: "plus" });
+            subItems.push({ description: "Edit onChildClick script", icon: "edit", event: () => ScriptBox.EditClickScript(this.props.Document, "onChildClick") });
+            ContextMenu.Instance.addItem({ description: "Stacking Options ...", subitems: subItems, icon: "eye" });
+        }
     }
 
     render() {
@@ -282,7 +307,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         // let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
         return (
             <div className="collectionStackingView"
-                ref={this.createRef} onDrop={this.onDrop.bind(this)} onWheel={(e: React.WheelEvent) => e.stopPropagation()} >
+                ref={this.createRef} onDrop={this.onDrop.bind(this)} onContextMenu={this.onContextMenu} onWheel={(e: React.WheelEvent) => e.stopPropagation()} >
                 {this.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc).
                     map((section: [SchemaHeaderField, Doc[]]) => this.section(section[0], section[1])) :
                     this.section(undefined, this.filteredChildren)}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 817f9f4cb..9824a501b 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -84,7 +84,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             let headings = this.props.headings();
             let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
             let pair = Doc.GetLayoutDataDocPair(parent.props.Document, parent.props.DataDoc, parent.props.fieldKey, d);
-            let width = () => (d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? Math.min(NumCast(d.nativeWidth), parent.columnWidth / (uniqueHeadings.length + 1)) : parent.columnWidth / (uniqueHeadings.length + 1));/// (uniqueHeadings.length + 1);
+            let width = () => (d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? Math.min(Math.min(d[WidthSym](), NumCast(d.nativeWidth)), parent.columnWidth / (uniqueHeadings.length + 1)) : parent.columnWidth / (uniqueHeadings.length + 1));/// (uniqueHeadings.length + 1);
             let height = () => parent.getDocHeight(pair.layout, uniqueHeadings.length + 1);// / (d.nativeWidth && !BoolCast(d.ignoreAspect) ? uniqueHeadings.length + 1 : 1);
             let dref = React.createRef<HTMLDivElement>();
             // if (uniqueHeadings.length > 0) {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 8b939259c..aaaa623fb 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -30,7 +30,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
 
     public static LayoutString(fieldStr: string = "data", fieldExt: string = "") { return FieldView.LayoutString(CollectionView, fieldStr, fieldExt); }
 
-    constructor(props:any) {
+    constructor(props: any) {
         super(props);
     }
 
@@ -69,7 +69,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
     @action
     private collapse = (value: boolean) => {
         this._collapsed = value;
-        this.props.Document.chromeStatus = value ? "collapsed" : "visible";
+        this.props.Document.chromeStatus = value ? "collapsed" : "enabled";
     }
 
     private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
@@ -90,12 +90,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
     onContextMenu = (e: React.MouseEvent): void => {
         if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document[Id] !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
             let subItems: ContextMenuProps[] = [];
-            subItems.push({
-                description: "Freeform", event: () => {
-                    this.props.Document.viewType = CollectionViewType.Freeform;
-                    delete this.props.Document.usePivotLayout;
-                }, icon: "signature"
-            });
+            subItems.push({ description: "Freeform", event: () => { this.props.Document.viewType = CollectionViewType.Freeform; delete this.props.Document.usePivotLayout; }, icon: "signature" });
             if (CollectionBaseView.InSafeMode()) {
                 ContextMenu.Instance.addItem({ description: "Test Freeform", event: () => this.props.Document.viewType = CollectionViewType.Invalid, icon: "project-diagram" });
             }
@@ -111,10 +106,10 @@ export class CollectionView extends React.Component<FieldViewProps> {
                 }
             }
             ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems, icon: "eye" });
-            ContextMenu.Instance.addItem({ description: "Apply Template", event: () => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" });
-            ContextMenu.Instance.addItem({
-                description: this.props.Document.chromeStatus !== "disabled" ? "Hide Chrome" : "Show Chrome", event: () => this.props.Document.chromeStatus = (this.props.Document.chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram"
-            });
+            let existing = ContextMenu.Instance.findByDescription("Layout...");
+            let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : [];
+            layoutItems.push({ description: "Create Layout Instance", event: () => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight"), icon: "project-diagram" });
+            !existing && ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "hand-point-right" });
         }
     }
 
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 52c47e7e8..bccc0a5b2 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -37,7 +37,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     @observable private _dateWithinValue: string = "";
     @observable private _dateValue: Date | string = "";
     @observable private _keyRestrictions: [JSX.Element, string][] = [];
-    @observable private _collapsed: boolean = false;
     @computed private get filterValue() { return Cast(this.props.CollectionView.props.Document.viewSpecScript, ScriptField); }
 
     private _picker: any;
@@ -61,7 +60,6 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                     throw new Error("how did you get here, if chrome status is 'disabled' on a collection, a chrome shouldn't even be instantiated!");
                 }
                 else if (chromeStatus === "collapsed") {
-                    this._collapsed = true;
                     if (this.props.collapse) {
                         this.props.collapse(true);
                     }
@@ -163,9 +161,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
 
     @action
     toggleCollapse = () => {
-        this._collapsed = !this._collapsed;
+        this.props.CollectionView.props.Document.chromeStatus = this.props.CollectionView.props.Document.chromeStatus === "enabled" ? "collapsed" : "enabled";
         if (this.props.collapse) {
-            this.props.collapse(this._collapsed);
+            this.props.collapse(this.props.CollectionView.props.Document.chromeStatus !== "enabled");
         }
     }
 
@@ -218,16 +216,17 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
     }
 
     render() {
+        let collapsed = this.props.CollectionView.props.Document.chromeStatus !== "enabled";
         return (
-            <div className="collectionViewChrome-cont" style={{ top: this._collapsed ? -70 : 0 }}>
+            <div className="collectionViewChrome-cont" style={{ top: collapsed ? -70 : 0 }}>
                 <div className="collectionViewChrome">
                     <div className="collectionViewBaseChrome">
                         <button className="collectionViewBaseChrome-collapse"
                             style={{
-                                top: this._collapsed ? 70 : 10,
-                                transform: `rotate(${this._collapsed ? 180 : 0}deg) scale(${this._collapsed ? 0.5 : 1}) translate(${this._collapsed ? "-100%, -100%" : "0, 0"})`,
-                                opacity: (this._collapsed && !this.props.CollectionView.props.isSelected()) ? 0 : 0.9,
-                                left: (this._collapsed ? 0 : "unset"),
+                                top: collapsed ? 70 : 10,
+                                transform: `rotate(${collapsed ? 180 : 0}deg) scale(${collapsed ? 0.5 : 1}) translate(${collapsed ? "-100%, -100%" : "0, 0"})`,
+                                opacity: (collapsed && !this.props.CollectionView.props.isSelected()) ? 0 : 0.9,
+                                left: (collapsed ? 0 : "unset"),
                             }}
                             title="Collapse collection chrome" onClick={this.toggleCollapse}>
                             <FontAwesomeIcon icon="caret-up" size="2x" />
@@ -243,7 +242,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                             <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="5">Stacking View</option>
                             <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} value="6">Masonry View</option>
                         </select>
-                        <div className="collectionViewBaseChrome-viewSpecs" style={{ display: this._collapsed ? "none" : "grid" }}>
+                        <div className="collectionViewBaseChrome-viewSpecs" style={{ display: collapsed ? "none" : "grid" }}>
                             <input className="collectionViewBaseChrome-viewSpecsInput"
                                 placeholder="FILTER DOCUMENTS"
                                 value={this.filterValue ? this.filterValue.script.originalScript : ""}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 30010e826..0501bf929 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -816,17 +816,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     onContextMenu = (e: React.MouseEvent) => {
         let layoutItems: ContextMenuProps[] = [];
-        layoutItems.push({
-            description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`,
-            event: this.fitToContainer,
-            icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt"
-        });
-        layoutItems.push({
-            description: "reset view", event: () => {
-                this.props.Document.panX = this.props.Document.panY = 0;
-                this.props.Document.scale = 1;
-            }, icon: "compress-arrows-alt"
-        });
+        layoutItems.push({ description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`, event: this.fitToContainer, icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt" });
+        layoutItems.push({ description: "reset view", event: () => { this.props.Document.panX = this.props.Document.panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" });
         layoutItems.push({
             description: `${this.props.Document.useClusters ? "Uncluster" : "Use Clusters"}`,
             event: async () => {
@@ -841,50 +832,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             event: async () => this.props.Document.clusterOverridesDefaultBackground = !this.props.Document.clusterOverridesDefaultBackground,
             icon: !this.props.Document.useClusters ? "chalkboard" : "chalkboard"
         });
-        layoutItems.push({
-            description: "Arrange contents in grid",
-            event: this.arrangeContents,
-            icon: "table"
-        });
-        ContextMenu.Instance.addItem({
-            description: "Layout...",
-            subitems: layoutItems,
-            icon: "compass"
-        });
-        ContextMenu.Instance.addItem({
-            description: "Analyze Strokes",
-            event: this.analyzeStrokes,
-            icon: "paint-brush"
-        });
-        ContextMenu.Instance.addItem({
-            description: "Import document", icon: "upload", event: () => {
-                const input = document.createElement("input");
-                input.type = "file";
-                input.accept = ".zip";
-                input.onchange = async _e => {
-                    const files = input.files;
-                    if (!files) return;
-                    const file = files[0];
-                    let formData = new FormData();
-                    formData.append('file', file);
-                    formData.append('remap', "true");
-                    const upload = Utils.prepend("/uploadDoc");
-                    const response = await fetch(upload, { method: "POST", body: formData });
-                    const json = await response.json();
-                    if (json === "error") {
-                        return;
-                    }
-                    const doc = await DocServer.GetRefField(json);
-                    if (!doc || !(doc instanceof Doc)) {
-                        return;
-                    }
-                    const [x, y] = this.props.ScreenToLocalTransform().transformPoint(e.pageX, e.pageY);
-                    doc.x = x, doc.y = y;
-                    this.addDocument(doc, false);
-                };
-                input.click();
-            }
-        });
+        layoutItems.push({ description: "Arrange contents in grid", event: this.arrangeContents, icon: "table" });
+        ContextMenu.Instance.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" });
+
+        let existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers...");
+        let analyzers: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
+        analyzers.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" });
+        !existingAnalyze && ContextMenu.Instance.addItem({ description: "Analyzers...", subitems: analyzers, icon: "hand-point-right" });
     }
 
 
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 2466f13f6..c73e960d8 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -85,8 +85,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         let list = {
             ...OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive).omit,
             Document: this.layoutDoc,
-            DataDoc: this.dataDoc,
-            onClick: this.props.onClick
+            DataDoc: this.dataDoc
         };
         return { props: list };
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b8e2eb436..a702ab80e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -8,13 +8,15 @@ import { Copy, Id } from '../../../new_fields/FieldSymbols';
 import { List } from "../../../new_fields/List";
 import { ObjectField } from "../../../new_fields/ObjectField";
 import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
-import { BoolCast, Cast, FieldValue, NumCast, StrCast, PromiseValue } from "../../../new_fields/Types";
+import { ScriptField } from '../../../new_fields/ScriptField';
+import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
 import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { RouteStore } from '../../../server/RouteStore';
 import { emptyFunction, returnTrue, Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { ClientUtils } from '../../util/ClientUtils';
+import { DictationManager } from '../../util/DictationManager';
 import { DocumentManager } from "../../util/DocumentManager";
 import { DragManager, dropActionType } from "../../util/DragManager";
 import { LinkManager } from '../../util/LinkManager';
@@ -29,20 +31,16 @@ import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from "../DocComponent";
 import { EditableView } from '../EditableView';
+import { MainView } from '../MainView';
 import { OverlayView } from '../OverlayView';
 import { PresentationView } from "../presentationview/PresentationView";
+import { ScriptBox } from '../ScriptBox';
 import { ScriptingRepl } from '../ScriptingRepl';
 import { Template } from "./../Templates";
 import { DocumentContentsView } from "./DocumentContentsView";
 import "./DocumentView.scss";
 import { FormattedTextBox } from './FormattedTextBox';
 import React = require("react");
-import { DictationManager } from '../../util/DictationManager';
-import { MainView } from '../MainView';
-import { ScriptBox } from '../ScriptBox';
-import { CompileScript } from '../../util/Scripting';
-import { DocumentIconContainer } from './DocumentIcon';
-import { ScriptField } from '../../../new_fields/ScriptField';
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 library.add(fa.faTrash);
@@ -297,8 +295,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     onClick = async (e: React.MouseEvent) => {
         if (e.nativeEvent.cancelBubble) return; // needed because EditableView may stopPropagation which won't apparently stop this event from firing.
         e.stopPropagation();
-        if (this.onClickHandler) {
-            this.onClickHandler.script.run({ this: this.props.Document });
+        if (this.onClickHandler && this.onClickHandler.script) {
+            this.onClickHandler.script.run({ this: this.props.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document });
             e.preventDefault();
             return;
         }
@@ -573,37 +571,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         subitems.push({ description: "Open Right Alias", event: () => this.props.addDocTab && this.props.addDocTab(Doc.MakeAlias(this.props.Document), this.dataDoc, "onRight"), icon: "caret-square-right" });
         subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" });
         cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" });
-        cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" });
-        cm.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" });
-        cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
-        cm.addItem({ description: "Transcribe Speech", event: this.listen, icon: "microphone" });
-        cm.addItem({
-            description: "Edit OnClick script", icon: "edit", event: () => {
-                let overlayDisposer: () => void = emptyFunction;
-                const script = this.Document.onClick;
-                let originalText: string | undefined = undefined;
-                if (script) originalText = script.script.originalScript;
-                // tslint:disable-next-line: no-unnecessary-callback-wrapper
-                let scriptingBox = <ScriptBox initialText={originalText} onCancel={() => overlayDisposer()} onSave={(text, onError) => {
-                    const script = CompileScript(text, {
-                        params: { this: Doc.name },
-                        typecheck: false,
-                        editable: true,
-                        transformer: DocumentIconContainer.getTransformer()
-                    });
-                    if (!script.compiled) {
-                        onError(script.errors.map(error => error.messageText).join("\n"));
-                        return;
-                    }
-                    this.Document.onClick = new ScriptField(script);
-                    overlayDisposer();
-                }} showDocumentIcons />;
-                overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, { x: 400, y: 200, width: 500, height: 400, title: `${this.Document.title || ""} OnClick` });
-            }
-        });
-        let makes: ContextMenuProps[] = [];
+        let existingMake = ContextMenu.Instance.findByDescription("Make...");
+        let makes: ContextMenuProps[] = existingMake && "subitems" in existingMake ? existingMake.subitems : [];
         makes.push({ description: this.props.Document.isBackground ? "Remove Background" : "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
         makes.push({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" });
+        makes.push({ description: "Edit OnClick script", icon: "edit", event: () => ScriptBox.EditClickScript(this.props.Document, "onClick") });
         makes.push({
             description: "Make Portal", event: () => {
                 let portal = Docs.Create.FreeformDocument([], { width: this.props.Document[WidthSym]() + 10, height: this.props.Document[HeightSym](), title: this.props.Document.title + ".portal" });
@@ -618,15 +590,19 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
             }, icon: "window-restore"
         });
-        cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" });
-        if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) {
-            cm.addItem({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" });
-        }
-        cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
+        !existingMake && cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" });
         let existing = ContextMenu.Instance.findByDescription("Layout...");
         let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : [];
+
+        layoutItems.push({ description: `${this.props.Document.chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.props.Document.chromeStatus = (this.props.Document.chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" });
+        layoutItems.push({ description: `${this.props.Document.autoHeight ? "Variable Height" : "Auto Height"}`, event: () => this.props.Document.autoHeight = !this.props.Document.autoHeight, icon: "plus" });
+        layoutItems.push({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "snowflake" });
+        layoutItems.push({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
         layoutItems.push({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" });
         layoutItems.push({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" });
+        if (this.props.Document.detailedLayout && !this.props.Document.isTemplate) {
+            layoutItems.push({ description: "Toggle detail", event: () => Doc.ToggleDetailLayout(this.props.Document), icon: "image" });
+        }
         !existing && cm.addItem({ description: "Layout...", subitems: layoutItems, icon: "compass" });
         if (!ClientUtils.RELEASE) {
             let copies: ContextMenuProps[] = [];
@@ -634,6 +610,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             copies.push({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" });
             cm.addItem({ description: "Copy...", subitems: copies, icon: "copy" });
         }
+        let existingAnalyze = ContextMenu.Instance.findByDescription("Analyzers...");
+        let analyzers: ContextMenuProps[] = existingAnalyze && "subitems" in existingAnalyze ? existingAnalyze.subitems : [];
+        analyzers.push({ description: "Transcribe Speech", event: this.listen, icon: "microphone" });
+        !existingAnalyze && cm.addItem({ description: "Analyzers...", subitems: analyzers, icon: "hand-point-right" });
+        cm.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" });
+        cm.addItem({ description: "Add Repl", icon: "laptop-code", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
         cm.addItem({
             description: "Download document", icon: "download", event: () => {
                 const a = document.createElement("a");
@@ -643,6 +625,36 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 a.click();
             }
         });
+
+        cm.addItem({
+            description: "Import document", icon: "upload", event: () => {
+                const input = document.createElement("input");
+                input.type = "file";
+                input.accept = ".zip";
+                input.onchange = async _e => {
+                    const files = input.files;
+                    if (!files) return;
+                    const file = files[0];
+                    let formData = new FormData();
+                    formData.append('file', file);
+                    formData.append('remap', "true");
+                    const upload = Utils.prepend("/uploadDoc");
+                    const response = await fetch(upload, { method: "POST", body: formData });
+                    const json = await response.json();
+                    if (json === "error") {
+                        return;
+                    }
+                    const doc = await DocServer.GetRefField(json);
+                    if (!doc || !(doc instanceof Doc)) {
+                        return;
+                    }
+                    const [x, y] = this.props.ScreenToLocalTransform().transformPoint(e.pageX, e.pageY);
+                    doc.x = x, doc.y = y;
+                    this.props.addDocument && this.props.addDocument(doc, false);
+                };
+                input.click();
+            }
+        });
         cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" });
         type User = { email: string, userDocumentId: string };
         let usersMenu: ContextMenuProps[] = [];
@@ -715,7 +727,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document;
     }
 
+    @computed get brushedDegree() { return Doc.IsBrushedDegree(this.layoutDoc); }
+
     render() {
+        trace();
         let backgroundColor = this.layoutDoc.isBackground || (this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document.clusterOverridesDefaultBackground && this.layoutDoc.backgroundColor === this.layoutDoc.defaultBackgroundColor) ?
             this.props.backgroundColor(this.layoutDoc) || StrCast(this.layoutDoc.backgroundColor) :
             StrCast(this.layoutDoc.backgroundColor) || this.props.backgroundColor(this.layoutDoc);
@@ -733,7 +748,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             });
         }
         let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("<FormattedTextBox") ? showTitle : undefined;
-        let brushDegree = Doc.IsBrushedDegree(this.layoutDoc);
+        let brushDegree = 0;//this.brushedDegree;
         return (
             <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
                 ref={this._mainCont}
@@ -779,7 +794,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                                     height={72}
                                     fontSize={12}
                                     GetValue={() => StrCast((this.layoutDoc.isTemplate || !this.dataDoc ? this.layoutDoc : this.dataDoc)[showTitle!])}
-                                    SetValue={(value: string) => (Doc.GetProto(this.layoutDoc)[showTitle!] = value) ? true : true}
+                                    SetValue={(value: string) => ((this.layoutDoc.isTemplate ? this.layoutDoc : Doc.GetProto(this.layoutDoc))[showTitle!] = value) ? true : true}
                                 />
                             </div>
                         }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index cf4f7f668..732576328 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -475,6 +475,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     onPointerDown = (e: React.PointerEvent): void => {
+        if (this.onClick && e.button === 0) {
+            e.preventDefault();
+        }
         if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
             e.stopPropagation();
             if (FormattedTextBox._toolTipTextMenu && FormattedTextBox._toolTipTextMenu.tooltip) {
@@ -643,12 +646,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     specificContextMenu = (e: React.MouseEvent): void => {
-        let subitems: ContextMenuProps[] = [];
-        subitems.push({
-            description: BoolCast(this.props.Document.autoHeight) ? "Manual Height" : "Auto Height",
-            event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
-        });
-        ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
+        // let subitems: ContextMenuProps[] = [];
+        // subitems.push({
+        //     description: BoolCast(this.props.Document.autoHeight) ? "Manual Height" : "Auto Height",
+        //     event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
+        // });
+        // ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
     }
     render() {
         let self = this;
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 4cfd7929b..564446bb8 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -516,6 +516,8 @@ export namespace Doc {
         otherdoc.miniLayout = StrCast(templateDoc.miniLayout);
         otherdoc.detailedLayout = otherdoc.layout;
         otherdoc.type = DocumentType.TEMPLATE;
+        !templateDoc.nativeWidth && (otherdoc.nativeWidth = 0);
+        !templateDoc.nativeHeight && (otherdoc.nativeHeight = 0);
         return otherdoc;
     }
     export function ApplyTemplateTo(templateDoc: Doc, target: Doc, targetData?: Doc) {
@@ -534,6 +536,8 @@ export namespace Doc {
             target.miniLayout = StrCast(templateDoc.miniLayout);
             target.detailedLayout = target.layout;
         }
+        !templateDoc.nativeWidth && (target.nativeWidth = 0);
+        !templateDoc.nativeHeight && (target.nativeHeight = 0);
     }
 
     export function MakeTemplate(fieldTemplate: Doc, metaKey: string, templateDataDoc: Doc) {
@@ -610,4 +614,7 @@ export namespace Doc {
 }
 Scripting.addGlobal(function renameAlias(doc: any, n: any) {
     return StrCast(doc.title).replace(/\([0-9]*\)/, "") + `(${n})`;
+});
+Scripting.addGlobal(function getProto(doc: any) {
+    return Doc.GetProto(doc);
 });
\ No newline at end of file
diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts
index 09cbff25e..0ca35fab2 100644
--- a/src/new_fields/Types.ts
+++ b/src/new_fields/Types.ts
@@ -2,6 +2,7 @@ import { Field, Opt, FieldResult, Doc } from "./Doc";
 import { List } from "./List";
 import { RefField } from "./RefField";
 import { DateField } from "./DateField";
+import { ScriptField } from "./ScriptField";
 
 export type ToType<T extends InterfaceValue> =
     T extends "string" ? string :
@@ -86,6 +87,9 @@ export function BoolCast(field: FieldResult, defaultVal: boolean | null = false)
 export function DateCast(field: FieldResult) {
     return Cast(field, DateField, null);
 }
+export function ScriptCast(field: FieldResult) {
+    return Cast(field, ScriptField, null);
+}
 
 type WithoutList<T extends Field> = T extends List<infer R> ? (R extends RefField ? (R | Promise<R>)[] : R[]) : T;
 
-- 
cgit v1.2.3-70-g09d2


From 5a2f6ca6f8f914e0c355c2211f506fc701451e91 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 14 Aug 2019 23:19:23 -0400
Subject: fixed autoHeight resizing for textboxes.

---
 src/client/views/DocumentDecorations.tsx    |  2 +-
 src/client/views/MainOverlayTextBox.tsx     |  3 +-
 src/client/views/nodes/FormattedTextBox.tsx | 66 ++++++++++-------------------
 3 files changed, 25 insertions(+), 46 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index d537e2dac..df526e01c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -523,7 +523,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 break;
         }
 
-        runInAction(() => FormattedTextBox.InputBoxOverlay = undefined);
+        if (!this._resizing) runInAction(() => FormattedTextBox.InputBoxOverlay = undefined);
         SelectionManager.SelectedDocuments().forEach(element => {
             if (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0) {
                 let doc = PositionDocument(element.props.Document);
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 196e5414d..b14a1e0ea 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -130,12 +130,13 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
     render() {
         this.TextDoc; this.TextDataDoc;
         if (FormattedTextBox.InputBoxOverlay && this._textTargetDiv) {
+            let wid = FormattedTextBox.InputBoxOverlay.props.Document.width; // need to force overlay to render when underlying text box is resized (eg, w/ DocDecorations)
             let textRect = this._textTargetDiv.getBoundingClientRect();
             let s = this._textXf().Scale;
             let location = this._textBottom ? textRect.bottom : textRect.top;
             let hgt = this._textAutoHeight || this._textBottom ? "auto" : this._textTargetDiv.clientHeight;
             return <div ref={this._setouterdiv} className="mainOverlayTextBox-unscaled_div" style={{ transform: `translate(${textRect.left}px, ${location}px)` }} >
-                <div className="mainOverlayTextBox-textInput" style={{ transform: `scale(${1 / s},${1 / s})`, width: "auto", height: "0px" }} >
+                <div className="mainOverlayTextBox-textInput" style={{ transform: `scale(${1 / s})`, width: "auto", height: "0px" }} >
                     <div className="mainOverlayTextBox-textInput" onPointerDown={this.textBoxDown} ref={this._textProxyDiv} onScroll={this.textScroll}
                         style={{ width: `${textRect.width * s}px`, height: "0px" }}>
                         <div style={{ height: hgt, width: "100%", position: "absolute", bottom: this._textBottom ? "0px" : undefined }}>
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 800bbdbf9..516e36d5b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,20 +1,21 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faEdit, faSmile, faTextHeight } from '@fortawesome/free-solid-svg-icons';
-import { action, IReactionDisposer, observable, reaction, runInAction, computed, Lambda, trace } from "mobx";
+import { action, computed, IReactionDisposer, Lambda, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
-import { Node as ProsNode } from "prosemirror-model";
-import { EditorState, Plugin, Transaction, Selection } from "prosemirror-state";
-import { NodeType, Slice, Node, Fragment } from 'prosemirror-model';
+import { Fragment, Node, Node as ProsNode, NodeType, Slice } from "prosemirror-model";
+import { EditorState, Plugin, Transaction } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
-import { Doc, Opt, DocListCast } from "../../../new_fields/Doc";
-import { Id, Copy } from '../../../new_fields/FieldSymbols';
+import { DateField } from '../../../new_fields/DateField';
+import { Doc, DocListCast, Opt, WidthSym } from "../../../new_fields/Doc";
+import { Copy, Id } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
 import { RichTextField } from "../../../new_fields/RichTextField";
-import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
-import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types";
+import { createSchema, makeInterface } from "../../../new_fields/Schema";
+import { BoolCast, Cast, DateCast, NumCast, StrCast } from "../../../new_fields/Types";
+import { Utils } from '../../../Utils';
 import { DocServer } from "../../DocServer";
 import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
@@ -26,16 +27,12 @@ import { SelectionManager } from "../../util/SelectionManager";
 import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu";
 import { TooltipTextMenu } from "../../util/TooltipTextMenu";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { ContextMenu } from "../../views/ContextMenu";
-import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from "../DocComponent";
 import { InkingControl } from "../InkingControl";
+import { MainOverlayTextBox } from '../MainOverlayTextBox';
 import { FieldView, FieldViewProps } from "./FieldView";
 import "./FormattedTextBox.scss";
 import React = require("react");
-import { DateField } from '../../../new_fields/DateField';
-import { Utils } from '../../../Utils';
-import { MainOverlayTextBox } from '../MainOverlayTextBox';
 
 library.add(faEdit);
 library.add(faSmile, faTextHeight);
@@ -70,11 +67,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     private _editorView: Opt<EditorView>;
     private static _toolTipTextMenu: TooltipTextMenu | undefined = undefined;
     private _applyingChange: boolean = false;
-    private _outerdiv?: (dominus: HTMLElement) => void;
     private _linkClicked = "";
     private _reactionDisposer: Opt<IReactionDisposer>;
     private _searchReactionDisposer?: Lambda;
     private _textReactionDisposer: Opt<IReactionDisposer>;
+    private _heightReactionDisposer: Opt<IReactionDisposer>;
     private _proxyReactionDisposer: Opt<IReactionDisposer>;
     private dropDisposer?: DragManager.DragDropDisposer;
     public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
@@ -128,10 +125,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined);
         }
 
-        if (this.props.outer_div) {
-            this._outerdiv = this.props.outer_div;
-        }
-
         document.addEventListener("paste", this.paste);
     }
 
@@ -257,25 +250,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 this.props.Document.layout = de.data.draggedDocuments[0];
                 de.data.draggedDocuments[0].isTemplate = true;
                 e.stopPropagation();
-                // let ldocs = Cast(this.dataDoc.subBulletDocs, listSpec(Doc));
-                // if (!ldocs) {
-                //     this.dataDoc.subBulletDocs = new List<Doc>([]);
-                // }
-                // ldocs = Cast(this.dataDoc.subBulletDocs, listSpec(Doc));
-                // if (!ldocs) return;
-                // if (!ldocs || !ldocs[0] || ldocs[0] instanceof Promise || StrCast((ldocs[0] as Doc).layout).indexOf("CollectionView") === -1) {
-                //     ldocs.splice(0, 0, Docs.StackingDocument([], { title: StrCast(this.dataDoc.title) + "-subBullets", x: NumCast(this.props.Document.x), y: NumCast(this.props.Document.y) + NumCast(this.props.Document.height), width: 300, height: 300 }));
-                //     this.props.addDocument && this.props.addDocument(ldocs[0] as Doc);
-                //     this.props.Document.templates = new List<string>([Templates.Bullet.Layout]);
-                //     this.props.Document.isBullet = true;
-                // }
-                // let stackDoc = (ldocs[0] as Doc);
-                // if (de.data.moveDocument) {
-                //     de.data.moveDocument(de.data.draggedDocuments[0], stackDoc, (doc) => {
-                //         Cast(stackDoc.data, listSpec(Doc))!.push(doc);
-                //         return true;
-                //     });
-                // }
             }
         }
     }
@@ -317,12 +291,15 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined;
                 return field ? field.Data : `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`;
             },
-            field2 => {
-                this._editorView && !this._applyingChange &&
-                    this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2)));
-            }
+            field2 => this._editorView && !this._applyingChange &&
+                this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2)))
         );
 
+        this.props.isOverlay && (this._heightReactionDisposer = reaction(
+            () => this.props.Document[WidthSym](),
+            () => this.tryUpdateHeight()
+        ));
+
         this._textReactionDisposer = reaction(
             () => this.extensionDoc,
             () => {
@@ -479,6 +456,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         this._reactionDisposer && this._reactionDisposer();
         this._proxyReactionDisposer && this._proxyReactionDisposer();
         this._textReactionDisposer && this._textReactionDisposer();
+        this._heightReactionDisposer && this._heightReactionDisposer();
         this._searchReactionDisposer && this._searchReactionDisposer();
     }
 
@@ -631,8 +609,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     @action
     tryUpdateHeight() {
-        if (this.props.isOverlay && this.props.Document.autoHeight) {
-            let self = this;
+        if (this.props.Document.autoHeight && this.props.isOverlay) {
             let xf = this._ref.current!.getBoundingClientRect();
             let scrBounds = this.props.ScreenToLocalTransform().transformBounds(0, 0, xf.width, xf.height);
             let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
@@ -671,8 +648,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         return (
             <div className={`formattedTextBox-cont-${style}`} ref={this._ref}
                 style={{
+                    overflowY: this.props.Document.autoHeight ? "hidden" : "auto",
                     height: this.props.height ? this.props.height : undefined,
-                    background: this.props.hideOnLeave ? "rgba(0,0,0,0.4)" : undefined,
+                    background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : undefined,
                     opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || Doc.IsBrushed(this.props.Document) ? 1 : 0.1) : 1,
                     color: this.props.color ? this.props.color : this.props.hideOnLeave ? "white" : "inherit",
                     pointerEvents: interactive,
-- 
cgit v1.2.3-70-g09d2


From a7307ca3dc46782cc9e4cae4daa9b30911ace1dd Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 15 Aug 2019 23:19:33 -0400
Subject: tweaks for borderRounding in edge cases

---
 src/client/views/DocumentDecorations.tsx     | 3 ++-
 src/client/views/nodes/FormattedTextBox.scss | 4 ++--
 src/client/views/nodes/FormattedTextBox.tsx  | 2 +-
 3 files changed, 5 insertions(+), 4 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9d877e5d6..d24762443 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -349,7 +349,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             document.addEventListener("pointerup", this.onRadiusUp);
         }
         if (!this._isMoving) {
-            SelectionManager.SelectedDocuments().map(dv => dv.props.Document.borderRounding = Doc.GetProto(dv.props.Document).borderRounding = `0%`);
+            SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)).
+                map(d => d.borderRounding = "0%");
         }
     }
 
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 247f7d1ea..d86aab09c 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -33,8 +33,8 @@
 }
 
 .formattedTextBox-inner-rounded {
-    height: calc(100% - 25px);
-    width: calc(100% - 40px);
+    height: calc(90%);
+    width: calc(85%);
     position: absolute;
     overflow: auto;
     top: 15;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 516e36d5b..330bd135d 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -616,7 +616,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             let dh = NumCast(this.props.Document.height, 0);
             let sh = scrBounds.height;
             const ChromeHeight = MainOverlayTextBox.Instance.ChromeHeight;
-            this.props.Document.height = (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0);
+            this.props.Document.height = Math.max(10, (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0));
             this.dataDoc.nativeHeight = nh ? sh : undefined;
         }
     }
-- 
cgit v1.2.3-70-g09d2


From b45bda9a9ab289e9566b764323f517efa5e249f5 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 16 Aug 2019 08:55:08 -0400
Subject: added all closed documents to Recently Closed

---
 src/client/views/DocumentDecorations.tsx               | 8 ++++++--
 src/server/authentication/models/current_user_utils.ts | 2 --
 2 files changed, 6 insertions(+), 4 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index d24762443..aae7f0d3f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -215,10 +215,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     }
     @undoBatch
     @action
-    onCloseUp = (e: PointerEvent): void => {
+    onCloseUp = async (e: PointerEvent) => {
         e.stopPropagation();
         if (e.button === 0) {
-            SelectionManager.SelectedDocuments().map(dv => dv.props.removeDocument && dv.props.removeDocument(dv.props.Document));
+            const recent = await Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc);
+            SelectionManager.SelectedDocuments().map(dv => {
+                recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
+                dv.props.removeDocument && dv.props.removeDocument(dv.props.Document);
+            });
             SelectionManager.DeselectAll();
             document.removeEventListener("pointermove", this.onCloseMove);
             document.removeEventListener("pointerup", this.onCloseUp);
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 91d7ba87d..f36f5b73d 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -41,8 +41,6 @@ export class CurrentUserUtils {
         doc.boxShadow = "0 0";
         doc.excludeFromLibrary = true;
         doc.optionalRightCollection = Docs.Create.StackingDocument([], { title: "New mobile uploads" });
-        // doc.library = Docs.Create.TreeDocument([doc], { title: `Library: ${CurrentUserUtils.email}` });
-        // (doc.library as Doc).excludeFromLibrary = true;
         return doc;
     }
 
-- 
cgit v1.2.3-70-g09d2

