From 700dfc5add1ecd9c2b1ecafcdc593ff821b7a6a6 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 20 Aug 2019 17:20:27 -0400
Subject: UI enhancements and other backend fixes for templates.

---
 .../views/collections/CollectionStackingViewFieldColumn.tsx      | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 74c7ef305..cc8476548 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -78,11 +78,14 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         let parent = this.props.parent;
         parent._docXfs.length = 0;
         return docs.map((d, i) => {
-            let pair = Doc.GetLayoutDataDocPair(parent.props.Document, parent.props.DataDoc, parent.props.fieldKey, d);
+            const pair = Doc.GetLayoutDataDocPair(parent.props.Document, parent.props.DataDoc, parent.props.fieldKey, d);
+            if (!pair.layout || pair.data instanceof Promise) {
+                return (null);
+            }
             let width = () => Math.min(d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, parent.columnWidth / parent.numGroupColumns);
-            let height = () => parent.getDocHeight(pair.layout);
+            let height = () => parent.getDocHeight(pair!.layout);
             let dref = React.createRef<HTMLDivElement>();
-            let dxf = () => this.getDocTransform(pair.layout, dref.current!);
+            let dxf = () => this.getDocTransform(pair!.layout, dref.current!);
             this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height });
             let rowSpan = Math.ceil((height() + parent.gridGap) / parent.gridGap);
             let style = parent.isStackingView ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : parent.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
-- 
cgit v1.2.3-70-g09d2


From 43d731ef2a6b2bd3fcdb7dd26fb6a8beac8e1306 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 21 Aug 2019 16:23:38 -0400
Subject: from last with presentations and small tweaks.

---
 src/client/views/MetadataEntryMenu.tsx                             | 2 +-
 src/client/views/collections/CollectionStackingView.tsx            | 4 ++--
 src/client/views/collections/CollectionStackingViewFieldColumn.tsx | 4 ++--
 src/client/views/nodes/KeyValueBox.tsx                             | 2 +-
 src/client/views/nodes/PresBox.tsx                                 | 7 ++++---
 src/client/views/presentationview/PresentationElement.tsx          | 2 --
 src/client/views/presentationview/PresentationView.scss            | 4 ----
 src/server/authentication/models/current_user_utils.ts             | 2 +-
 8 files changed, 11 insertions(+), 16 deletions(-)

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

diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx
index 4d696e37a..ec628c5a3 100644
--- a/src/client/views/MetadataEntryMenu.tsx
+++ b/src/client/views/MetadataEntryMenu.tsx
@@ -172,7 +172,7 @@ export class MetadataEntryMenu extends React.Component<MetadataEntryProps>{
                 </div>
                 <div className="metadataEntry-keys" >
                     <ul>
-                        {this._allSuggestions.sort().map(s => <li key={s} onClick={action(() => { this._currentKey = s; this.previewValue(); })} >{s}</li>)}
+                        {this._allSuggestions.slice().sort().map(s => <li key={s} onClick={action(() => { this._currentKey = s; this.previewValue(); })} >{s}</li>)}
                     </ul>
                 </div>
             </div>
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index c74c60d8f..be6ee1756 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -291,10 +291,10 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc);
             let width = () => (d.nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth);/// (uniqueHeadings.length + 1);
             let height = () => this.getDocHeight(layoutDoc);
-            let dxf = () => this.getDocTransform(layoutDoc, dref.current!);
+            let dxf = () => this.getDocTransform(layoutDoc!, dref.current!);
             let rowSpan = Math.ceil((height() + this.gridGap) / this.gridGap);
             this._docXfs.push({ dxf: dxf, width: width, height: height });
-            return <div className="collectionStackingView-masonryDoc" key={d[Id]} ref={dref} style={{ gridRowEnd: `span ${rowSpan}` }} >
+            return !layoutDoc ? (null) : <div className="collectionStackingView-masonryDoc" key={d[Id]} ref={dref} style={{ gridRowEnd: `span ${rowSpan}` }} >
                 {this.getDisplayDoc(layoutDoc, d, dxf, width)}
             </div>;
         });
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index cc8476548..2536eff00 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -83,9 +83,9 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                 return (null);
             }
             let width = () => Math.min(d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, parent.columnWidth / parent.numGroupColumns);
-            let height = () => parent.getDocHeight(pair!.layout);
+            let height = () => parent.getDocHeight(pair.layout);
             let dref = React.createRef<HTMLDivElement>();
-            let dxf = () => this.getDocTransform(pair!.layout, dref.current!);
+            let dxf = () => this.getDocTransform(pair.layout!, dref.current!);
             this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height });
             let rowSpan = Math.ceil((height() + parent.gridGap) / parent.gridGap);
             let style = parent.isStackingView ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : parent.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 0d4b377dd..653c5c27f 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -128,7 +128,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
         let rows: JSX.Element[] = [];
         let i = 0;
         const self = this;
-        for (let key of Object.keys(ids).sort()) {
+        for (let key of Object.keys(ids).slice().sort()) {
             rows.push(<KeyValuePair doc={realDoc} ref={(function () {
                 let oldEl: KeyValuePair | undefined;
                 return (el: KeyValuePair) => {
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index cf222601f..e376fbddb 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -116,9 +116,9 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
 
         let presDocs = DocListCast(this.curPresentation.data);
         for (; nextSelected < presDocs.length - 1; nextSelected++) {
-            if (!this.presElementsMappings.get(presDocs[nextSelected + 1])!.props.document.groupButton)
+            if (!this.presElementsMappings.get(presDocs[nextSelected + 1])!.props.document.groupButton) {
                 break;
-
+            }
         }
 
         this.gotoDocument(nextSelected, current);
@@ -239,8 +239,9 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
         let nextSelected = presDocs.indexOf(curDoc);
         let currentDocGroups: Doc[] = [];
         for (; nextSelected < presDocs.length - 1; nextSelected++) {
-            if (!this.presElementsMappings.get(presDocs[nextSelected + 1])!.props.document.groupButton)
+            if (!this.presElementsMappings.get(presDocs[nextSelected + 1])!.props.document.groupButton) {
                 break;
+            }
             currentDocGroups.push(presDocs[nextSelected]);
         }
 
diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx
index 68c5a5b8d..83413814f 100644
--- a/src/client/views/presentationview/PresentationElement.tsx
+++ b/src/client/views/presentationview/PresentationElement.tsx
@@ -261,8 +261,6 @@ export default class PresentationElement extends React.Component<PresentationEle
 
     //This is used to remove the dragging when dropped.
     onPointerLeave = (e: React.PointerEvent): void => {
-        //to get currently selected presentation doc
-
         this.header!.className = "presentationView-item";
 
         if (this.currentIndex === this.props.index) {
diff --git a/src/client/views/presentationview/PresentationView.scss b/src/client/views/presentationview/PresentationView.scss
index bc1899811..5c40a8808 100644
--- a/src/client/views/presentationview/PresentationView.scss
+++ b/src/client/views/presentationview/PresentationView.scss
@@ -23,14 +23,11 @@
     user-select: none;
     transition: all .1s;
 
-    
-
     .documentView-node {
         
         position: absolute;
         z-index: 1;
     }
-
 }
 
 .presentationView-item-above {
@@ -73,7 +70,6 @@
     display: inline-block;
     width: calc(100% - 200px);
     letter-spacing: 2px;
-
 }
 
 .presentation-icon {
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index aa3da0034..f7ce24967 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -29,7 +29,7 @@ export class CurrentUserUtils {
         doc.viewType = CollectionViewType.Tree;
         doc.dropAction = "alias";
         doc.layout = CollectionView.LayoutString();
-        doc.title = Doc.CurrentUserEmail
+        doc.title = Doc.CurrentUserEmail;
         this.updateUserDocument(doc);
         doc.data = new List<Doc>();
         doc.gridGap = 5;
-- 
cgit v1.2.3-70-g09d2


From b5345b69abbb20c060c8fc9f47dfcaded7f308f8 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 25 Aug 2019 10:21:53 -0400
Subject: fixed sync of doc decorations with scrolled stacking/masonry views

---
 src/client/views/collections/CollectionStackingView.tsx   |  8 +++++++-
 .../collections/CollectionStackingViewFieldColumn.tsx     | 15 +++------------
 2 files changed, 10 insertions(+), 13 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4ab656744..a70743030 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -34,6 +34,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     _docXfs: any[] = [];
     _columnStart: number = 0;
     @observable private cursor: CursorProperty = "grab";
+    @observable _scroll = 0; // used to force the document decoration to update when scrolling
     @computed get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); }
     @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); }
     @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); }
@@ -277,6 +278,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     getDocTransform(doc: Doc, dref: HTMLDivElement) {
+        let y = this._scroll;
         let { scale, translateX, translateY } = Utils.GetScreenTransform(dref);
         let outerXf = Utils.GetScreenTransform(this._masonryGridRef!);
         let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
@@ -371,7 +373,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         let sections = (this.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc) : [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]]);
         return (
             <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"}
-                ref={this.createRef} onDrop={this.onDrop.bind(this)} onContextMenu={this.onContextMenu} onWheel={(e: React.WheelEvent) => e.stopPropagation()} >
+                ref={this.createRef}
+                onScroll={action((e: React.UIEvent<HTMLDivElement>) => this._scroll = e.currentTarget.scrollTop)}
+                onDrop={this.onDrop.bind(this)}
+                onContextMenu={this.onContextMenu}
+                onWheel={(e: React.WheelEvent) => e.stopPropagation()} >
                 {sections.map(section => this.isStackingView ? this.sectionStacking(section[0], section[1]) : this.sectionMasonry(section[0], section[1]))}
                 {!this.showAddAGroup ? (null) :
                     <div key={`${this.props.Document[Id]}-addGroup`} className="collectionStackingView-addGroupButton"
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 2536eff00..a134f8008 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -85,25 +85,16 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             let width = () => Math.min(d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, parent.columnWidth / parent.numGroupColumns);
             let height = () => parent.getDocHeight(pair.layout);
             let dref = React.createRef<HTMLDivElement>();
-            let dxf = () => this.getDocTransform(pair.layout!, dref.current!);
-            this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height });
+            let dxf = () => parent.getDocTransform(pair.layout!, dref.current!);
+            parent._docXfs.push({ dxf: dxf, width: width, height: height });
             let rowSpan = Math.ceil((height() + parent.gridGap) / parent.gridGap);
             let style = parent.isStackingView ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : parent.gridGap, height: height() } : { gridRowEnd: `span ${rowSpan}` };
             return <div className={`collectionStackingView-${parent.isStackingView ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} >
-                {this.props.parent.getDisplayDoc(pair.layout, pair.data, dxf, width)}
+                {parent.getDisplayDoc(pair.layout, pair.data, dxf, width)}
             </div>;
         });
     }
 
-    getDocTransform(doc: Doc, dref: HTMLDivElement) {
-        let { scale, translateX, translateY } = Utils.GetScreenTransform(dref);
-        let outerXf = Utils.GetScreenTransform(this.props.parent._masonryGridRef!);
-        let offset = this.props.parent.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
-        return this.props.parent.props.ScreenToLocalTransform().
-            translate(offset[0], offset[1]).
-            scale(NumCast(doc.width, 1) / this.props.parent.columnWidth);
-    }
-
     getValue = (value: string): any => {
         let parsed = parseInt(value);
         if (!isNaN(parsed)) {
-- 
cgit v1.2.3-70-g09d2


From 6e7473a555df2631c917db3350d75986fa95b046 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 25 Aug 2019 12:49:15 -0400
Subject: fixed sorting for treeviews.  fixed adding text items to stacking
 views.  fixed how commands are added to collection view sub types.

---
 src/client/documents/Documents.ts                  |  1 +
 .../views/collections/CollectionStackingView.tsx   |  7 +-
 .../CollectionStackingViewFieldColumn.tsx          |  2 +-
 .../views/collections/CollectionTreeView.tsx       | 22 +++---
 src/client/views/collections/CollectionView.tsx    | 10 +--
 .../views/collections/CollectionViewChromes.tsx    | 85 ++++++++--------------
 6 files changed, 54 insertions(+), 73 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 47df17329..1e9d1687f 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -77,6 +77,7 @@ export interface DocumentOptions {
     borderRounding?: string;
     schemaColumns?: List<SchemaHeaderField>;
     dockingConfig?: string;
+    autoHeight?: boolean;
     dbDoc?: Doc;
     // [key: string]: Opt<Field>;
 }
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a70743030..6f22f2d2a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -369,8 +369,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             contents: "+ ADD A GROUP"
         };
         Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
-
-        let sections = (this.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc) : [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]]);
+        let sections = [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]];
+        if (this.sectionFilter) {
+            let entries = Array.from(this.Sections.entries());
+            sections = entries.sort(this.sortFunc);
+        }
         return (
             <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"}
                 ref={this.createRef}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index a134f8008..f30e99362 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -153,7 +153,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
     @action
     addDocument = (value: string, shiftDown?: boolean) => {
         let key = StrCast(this.props.parent.props.Document.sectionFilter);
-        let newDoc = Docs.Create.TextDocument({ height: 18, width: 200, title: value });
+        let newDoc = Docs.Create.TextDocument({ height: 18, width: 200, documentText: "@@@" + value, title: value, autoHeight: true });
         newDoc[key] = this.getValue(this.props.heading);
         return this.props.parent.props.addDocument(newDoc);
     }
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 380054eb6..04133fb5b 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -271,7 +271,7 @@ class TreeView extends React.Component<TreeViewProps> {
 
             if (contents instanceof Doc || Cast(contents, listSpec(Doc))) {
                 let remDoc = (doc: Doc) => this.remove(doc, key);
-                let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, !BoolCast(this.props.document.stackingHeadersSortDescending, true));
+                let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true);
                 contentElement = TreeView.GetChildElements(contents instanceof Doc ? [contents] :
                     DocListCast(contents), this.props.treeViewId, doc, undefined, key, addDoc, remDoc, this.move,
                     this.props.dropAction, this.props.addDocTab, this.props.pinToPres, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth, this.props.renderDepth, this.props.showHeaderFields, this.props.preventTreeViewOpen);
@@ -299,7 +299,7 @@ class TreeView extends React.Component<TreeViewProps> {
         const expandKey = this.treeViewExpandedView === this.fieldKey ? this.fieldKey : this.treeViewExpandedView === "links" ? "links" : undefined;
         if (expandKey !== undefined) {
             let remDoc = (doc: Doc) => this.remove(doc, expandKey);
-            let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, !BoolCast(this.props.document.stackingHeadersSortDescending, true));
+            let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true);
             let docs = expandKey === "links" ? this.childLinks : this.childDocs;
             return <ul key={expandKey + "more"}>
                 {!docs ? (null) :
@@ -431,12 +431,12 @@ class TreeView extends React.Component<TreeViewProps> {
             });
         }
 
-        let descending = BoolCast(containingCollection.stackingHeadersSortDescending, true);
-        docs.slice().sort(function (a, b): 1 | -1 {
-            let descA = descending ? b : a;
-            let descB = descending ? a : b;
-            let first = descA[String(containingCollection.sectionFilter)];
-            let second = descB[String(containingCollection.sectionFilter)];
+        let ascending = Cast(containingCollection.sortAscending, "boolean", null);
+        if (ascending !== undefined) docs.sort(function (a, b): 1 | -1 {
+            let descA = ascending ? b : a;
+            let descB = ascending ? a : b;
+            let first = descA.title;
+            let second = descB.title;
             // TODO find better way to sort how to sort..................
             if (typeof first === 'number' && typeof second === 'number') {
                 return (first - second) > 0 ? 1 : -1;
@@ -450,7 +450,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 // }
                 return first > second ? 1 : -1;
             }
-            return descending ? 1 : -1;
+            return ascending ? 1 : -1;
         });
 
         let rowWidth = () => panelWidth() - 20;
@@ -583,7 +583,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     render() {
         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, false, false, !BoolCast(this.props.Document.stackingHeadersSortDescending, true));
+        let addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before, false, false, false);
         let moveDoc = (d: Doc, target: Doc, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc);
         return !this.childDocs ? (null) : (
             <div id="body" className="collectionTreeView-dropTarget"
@@ -603,7 +603,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                         let doc = this.props.Document.detailedLayout instanceof Doc ? Doc.ApplyTemplate(Doc.GetProto(this.props.Document.detailedLayout)) : undefined;
                         if (!doc) doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
                         TreeView.loadId = doc[Id];
-                        Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true, false, false, !BoolCast(this.props.Document.stackingHeadersSortDescending, true));
+                        Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true, false, false, false);
                     })} />
                 {this.props.Document.workspaceLibrary ? this.renderNotifsButton : (null)}
                 {this.props.Document.allowClear ? this.renderClearButton : (null)}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 3a8253720..6182e82f4 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -77,12 +77,10 @@ export class CollectionView extends React.Component<FieldViewProps> {
         if (this.isAnnotationOverlay || this.props.Document.chromeStatus === "disabled" || type === CollectionViewType.Docking) {
             return [(null), this.SubViewHelper(type, renderProps)];
         }
-        else {
-            return [
-                (<CollectionViewBaseChrome CollectionView={this} key="chrome" type={type} collapse={this.collapse} />),
-                this.SubViewHelper(type, renderProps)
-            ];
-        }
+        return [
+            <CollectionViewBaseChrome CollectionView={this} key="chrome" type={type} collapse={this.collapse} />,
+            this.SubViewHelper(type, renderProps)
+        ];
     }
 
     get isAnnotationOverlay() { return this.props.fieldExt ? true : false; }
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 1156d8fa7..b2df0e747 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -20,7 +20,6 @@ import { CollectionView } from "./CollectionView";
 import "./CollectionViewChromes.scss";
 import * as Autosuggest from 'react-autosuggest';
 import KeyRestrictionRow from "./KeyRestrictionRow";
-import { Docs } from "../../documents/Documents";
 const datepicker = require('js-datepicker');
 
 interface CollectionViewChromeProps {
@@ -41,20 +40,33 @@ let stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation();
 export class CollectionViewBaseChrome extends React.Component<CollectionViewChromeProps> {
     //(!)?\(\(\(doc.(\w+) && \(doc.\w+ as \w+\).includes\(\"(\w+)\"\)
 
-    private _buttonizableCommands = [{
+    _templateCommand = {
+        title: "set template", script: "this.target.childLayout = this.source ? this.source[0] : undefined", params: ["target", "source"],
+        immediate: (draggedDocs: Doc[]) => this.props.CollectionView.props.Document.childLayout = draggedDocs.length ? draggedDocs[0] : undefined
+    };
+    _contentCommand = {
         // title: "set content", script: "getProto(this.target).data = aliasDocs(this.source.map(async p => await p));", params: ["target", "source"],  // bcz: doesn't look like we can do async stuff in scripting...
         title: "set content", script: "getProto(this.target).data = aliasDocs(this.source);", params: ["target", "source"],
         immediate: (draggedDocs: Doc[]) => Doc.GetProto(this.props.CollectionView.props.Document).data = new List<Doc>(draggedDocs.map((d: any) => Doc.MakeAlias(d)))
-    },
-    {
-        title: "set template", script: "this.target.childLayout = this.source ? this.source[0] : undefined", params: ["target", "source"],
-        immediate: (draggedDocs: Doc[]) => this.props.CollectionView.props.Document.childLayout = draggedDocs.length ? draggedDocs[0] : undefined
-    },
-    {
+    };
+    _viewCommand = {
         title: "restore view", script: "this.target.panX = this.restoredPanX; this.target.panY = this.restoredPanY; this.target.scale = this.restoredScale;", params: ["target"],
         immediate: (draggedDocs: Doc[]) => { this.props.CollectionView.props.Document.panX = 0; this.props.CollectionView.props.Document.panY = 0; this.props.CollectionView.props.Document.scale = 1 },
         initialize: (button: Doc) => { button.restoredPanX = this.props.CollectionView.props.Document.panX; button.restoredPanY = this.props.CollectionView.props.Document.panY; button.restoredScale = this.props.CollectionView.props.Document.scale; }
-    }];
+    };
+    _freeform_commands = [this._contentCommand, this._templateCommand, this._viewCommand];
+    _stacking_commands = [this._contentCommand, this._templateCommand];
+    _masonry_commands = [this._contentCommand, this._templateCommand];
+    _tree_commands = [];
+    private get _buttonizableCommands() {
+        switch (this.props.type) {
+            case CollectionViewType.Tree: return this._tree_commands;
+            case CollectionViewType.Stacking: return this._stacking_commands;
+            case CollectionViewType.Masonry: return this._stacking_commands;
+            case CollectionViewType.Freeform: return this._freeform_commands;
+        }
+        return [];
+    }
     private _picker: any;
     private _commandRef = React.createRef<HTMLInputElement>();
     private _autosuggestRef = React.createRef<Autosuggest>();
@@ -520,18 +532,13 @@ export class CollectionStackingViewChrome extends React.Component<CollectionView
     render() {
         return (
             <div className="collectionStackingViewChrome-cont">
-                <button className="collectionStackingViewChrome-sort" onClick={this.toggleSort}>
-                    <div className="collectionStackingViewChrome-sortLabel">
-                        Sort
-                        </div>
-                    <div className="collectionStackingViewChrome-sortIcon" style={{ transform: `rotate(${this.descending ? "180" : "0"}deg)` }}>
-                        <FontAwesomeIcon icon="caret-up" size="2x" color="white" />
-                    </div>
-                </button>
                 <div className="collectionStackingViewChrome-sectionFilter-cont">
                     <div className="collectionStackingViewChrome-sectionFilter-label">
                         GROUP ITEMS BY:
-                        </div>
+                    </div>
+                    <div className="collectionStackingViewChrome-sortIcon" onClick={this.toggleSort} style={{ transform: `rotate(${this.descending ? "180" : "0"}deg)` }}>
+                        <FontAwesomeIcon icon="caret-up" size="2x" color="white" />
+                    </div>
                     <div className="collectionStackingViewChrome-sectionFilter">
                         <EditableView
                             GetValue={() => this.sectionFilter}
@@ -637,7 +644,7 @@ export class CollectionTreeViewChrome extends React.Component<CollectionViewChro
     @observable private _currentKey: string = "";
     @observable private suggestions: string[] = [];
 
-    @computed private get descending() { return BoolCast(this.props.CollectionView.props.Document.stackingHeadersSortDescending); }
+    @computed private get descending() { return Cast(this.props.CollectionView.props.Document.sortAscending, "boolean", null); }
     @computed get sectionFilter() { return StrCast(this.props.CollectionView.props.Document.sectionFilter); }
 
     getKeySuggestions = async (value: string): Promise<string[]> => {
@@ -685,7 +692,11 @@ export class CollectionTreeViewChrome extends React.Component<CollectionViewChro
         return true;
     }
 
-    @action toggleSort = () => { this.props.CollectionView.props.Document.stackingHeadersSortDescending = !this.props.CollectionView.props.Document.stackingHeadersSortDescending; };
+    @action toggleSort = () => {
+        if (this.props.CollectionView.props.Document.sortAscending) this.props.CollectionView.props.Document.sortAscending = undefined;
+        else if (this.props.CollectionView.props.Document.sortAscending === undefined) this.props.CollectionView.props.Document.sortAscending = false;
+        else this.props.CollectionView.props.Document.sortAscending = true;
+    }
     @action resetValue = () => { this._currentKey = this.sectionFilter; };
 
     render() {
@@ -695,42 +706,10 @@ export class CollectionTreeViewChrome extends React.Component<CollectionViewChro
                     <div className="collectionTreeViewChrome-sortLabel">
                         Sort
                         </div>
-                    <div className="collectionTreeViewChrome-sortIcon" style={{ transform: `rotate(${this.descending ? "180" : "0"}deg)` }}>
+                    <div className="collectionTreeViewChrome-sortIcon" style={{ transform: `rotate(${this.descending === undefined ? "90" : this.descending ? "180" : "0"}deg)` }}>
                         <FontAwesomeIcon icon="caret-up" size="2x" color="white" />
                     </div>
                 </button>
-                <div className="collectionTreeViewChrome-sectionFilter-cont">
-                    <div className="collectionTreeViewChrome-sectionFilter-label">
-                        GROUP ITEMS BY:
-                        </div>
-                    <div className="collectionTreeViewChrome-sectionFilter">
-                        <EditableView
-                            GetValue={() => this.sectionFilter}
-                            autosuggestProps={
-                                {
-                                    resetValue: this.resetValue,
-                                    value: this._currentKey,
-                                    onChange: this.onKeyChange,
-                                    autosuggestProps: {
-                                        inputProps:
-                                        {
-                                            value: this._currentKey,
-                                            onChange: this.onKeyChange
-                                        },
-                                        getSuggestionValue: this.getSuggestionValue,
-                                        suggestions: this.suggestions,
-                                        alwaysRenderSuggestions: true,
-                                        renderSuggestion: this.renderSuggestion,
-                                        onSuggestionsFetchRequested: this.onSuggestionFetch,
-                                        onSuggestionsClearRequested: this.onSuggestionClear
-                                    }
-                                }}
-                            oneLine
-                            SetValue={this.setValue}
-                            contents={this.sectionFilter ? this.sectionFilter : "N/A"}
-                        />
-                    </div>
-                </div>
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From 8b210d872e3a9c540825be0e9fbb912514092def Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 27 Aug 2019 12:03:16 -0400
Subject: fixes for doc decorations with resizing textboxes.

---
 src/client/views/DocumentDecorations.tsx                | 17 +++++++++++------
 src/client/views/MainOverlayTextBox.tsx                 | 14 ++++++++++++--
 src/client/views/collections/CollectionStackingView.tsx |  3 ++-
 .../collections/CollectionStackingViewFieldColumn.tsx   |  2 +-
 4 files changed, 26 insertions(+), 10 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 579806a89..e93893586 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -200,14 +200,22 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         this.onBackgroundUp(e);
     }
 
+    @observable _forceUpdate = 0;
+    _lastBox = { x: 0, y: 0, r: 0, b: 0 }
     @computed
     get Bounds(): { x: number, y: number, b: number, r: number } {
-        return SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
+        let x = this._forceUpdate;
+        this._lastBox = SelectionManager.SelectedDocuments().reduce((bounds, documentView) => {
             if (documentView.props.renderDepth === 0 ||
                 Doc.AreProtosEqual(documentView.props.Document, CurrentUserUtils.UserDocument)) {
                 return bounds;
             }
             let transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
+            if (transform.TranslateX === 0 && transform.TranslateY === 0) {
+                setTimeout(action(() => this._forceUpdate++), 0); // bcz: fix CollectionStackingView's getTransform() somehow...
+                return this._lastBox;
+            }
+
             var [sptX, sptY] = transform.transformPoint(0, 0);
             let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
             return {
@@ -215,6 +223,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b)
             };
         }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE });
+        return this._lastBox;
     }
 
     onBackgroundDown = (e: React.PointerEvent): void => {
@@ -821,11 +830,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
 
         let templates: Map<Template, boolean> = new Map();
         Array.from(Object.values(Templates.TemplateList)).map(template => {
-            let sorted = SelectionManager.ViewsSortedVertically(); // slice().sort((doc1, doc2) => {
-            //     if (NumCast(doc1.props.Document.y) > NumCast(doc2.props.Document.x)) return 1;
-            //     if (NumCast(doc1.props.Document.x) < NumCast(doc2.props.Document.x)) return -1;
-            //     return 0;
-            // });
+            let sorted = SelectionManager.ViewsSortedVertically();
             let docTemps = sorted.reduce((res: string[], doc: DocumentView, i) => {
                 let temps = doc.props.Document.templates;
                 if (temps instanceof List) {
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index e95e5b777..65a291d99 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -2,7 +2,7 @@ import { action, observable, reaction, trace } from 'mobx';
 import { observer } from 'mobx-react';
 import "normalize.css";
 import * as React from 'react';
-import { Doc } from '../../new_fields/Doc';
+import { Doc, DocListCast } from '../../new_fields/Doc';
 import { BoolCast } from '../../new_fields/Types';
 import { emptyFunction, returnTrue, returnZero, Utils, returnOne } from '../../Utils';
 import { DragManager } from '../util/DragManager';
@@ -42,13 +42,23 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
         return this._textBox && this._textBox.setFontColor(color);
     }
 
-
     constructor(props: MainOverlayTextBoxProps) {
         super(props);
         this._textProxyDiv = React.createRef();
         MainOverlayTextBox.Instance = this;
         reaction(() => FormattedTextBox.InputBoxOverlay,
             (box?: FormattedTextBox) => {
+                const tb = this._textBox;
+                const container = tb && tb.props.ContainingCollectionView;
+                if (tb && container) { // this hacky section is needed to force the edited text box to completely recreate itself since things can get out synch -- specifically, the bullet label state which is computed when the dom elements are created
+                    var dl = DocListCast(container.props.Document[container.props.fieldKey]);
+                    let dli = dl.indexOf(tb.props.Document);
+                    if (dli !== -1) {
+                        let prev = dli > 0 ? dl[dli - 1] : undefined;
+                        tb.props.removeDocument && tb.props.removeDocument(tb.props.Document);
+                        setTimeout(() => Doc.AddDocToList(container.props.Document, container.props.fieldKey, tb.props.Document, prev, false, dli === 0), 0);
+                    }
+                }
                 this._textBox = box;
                 if (box) {
                     this.ChromeHeight = box.props.ChromeHeight;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 6f22f2d2a..97b31bf2a 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -278,7 +278,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     getDocTransform(doc: Doc, dref: HTMLDivElement) {
-        let y = this._scroll;
+        if (!dref) return Transform.Identity();
+        let y = this._scroll; // required for document decorations to update when the text box container is scrolled
         let { scale, translateX, translateY } = Utils.GetScreenTransform(dref);
         let outerXf = Utils.GetScreenTransform(this._masonryGridRef!);
         let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY);
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index f30e99362..bc4fe7dd7 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -2,7 +2,7 @@ import React = require("react");
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { faPalette } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, observable } from "mobx";
+import { action, observable, trace } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, WidthSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
-- 
cgit v1.2.3-70-g09d2


From 4ec15a9576a27b8290fb37b6959cb13ae76feeaa Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Sat, 14 Sep 2019 11:18:51 -0400
Subject: various fixes for templating and publishing document ids

---
 src/client/documents/Documents.ts                  | 39 ++++++++++-------
 .../CollectionStackingViewFieldColumn.tsx          |  3 ++
 .../views/collections/CollectionTreeView.tsx       |  1 +
 src/client/views/nodes/DocumentView.tsx            | 49 +++++++++++++++++-----
 src/client/views/nodes/FormattedTextBox.tsx        | 28 +++++++++----
 src/new_fields/Doc.ts                              | 23 ++++++++++
 6 files changed, 110 insertions(+), 33 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 2eff73b87..e7ac1e321 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -610,23 +610,30 @@ export namespace DocUtils {
     export function Publish(promoteDoc: Doc, targetID: string, addDoc: any, remDoc: any) {
         targetID = targetID.replace(/^-/, "").replace(/\([0-9]*\)$/, "");
         DocServer.GetRefField(targetID).then(doc => {
-            let copy = doc instanceof Doc ? doc : Doc.MakeCopy(promoteDoc, true, targetID);
-            !doc && (copy.title = undefined) && (Doc.GetProto(copy).title = targetID);
-            addDoc && addDoc(copy);
-            !doc && remDoc && remDoc(promoteDoc);
-            if (!doc) {
-                DocListCastAsync(promoteDoc.links).then(links => {
-                    links && links.map(async link => {
-                        if (link) {
-                            let a1 = await Cast(link.anchor1, Doc);
-                            if (a1 && Doc.AreProtosEqual(a1, promoteDoc)) link.anchor1 = copy;
-                            let a2 = await Cast(link.anchor2, Doc);
-                            if (a2 && Doc.AreProtosEqual(a2, promoteDoc)) link.anchor2 = copy;
-                            LinkManager.Instance.deleteLink(link);
-                            LinkManager.Instance.addLink(link);
-                        }
+            if (promoteDoc !== doc) {
+                let copy = doc as Doc;
+                if (copy) {
+                    Doc.Overwrite(promoteDoc, copy, true);
+                } else {
+                    copy = Doc.MakeCopy(promoteDoc, true, targetID);
+                }
+                !doc && (copy.title = undefined) && (Doc.GetProto(copy).title = targetID);
+                addDoc && addDoc(copy);
+                remDoc && remDoc(promoteDoc);
+                if (!doc) {
+                    DocListCastAsync(promoteDoc.links).then(links => {
+                        links && links.map(async link => {
+                            if (link) {
+                                let a1 = await Cast(link.anchor1, Doc);
+                                if (a1 && Doc.AreProtosEqual(a1, promoteDoc)) link.anchor1 = copy;
+                                let a2 = await Cast(link.anchor2, Doc);
+                                if (a2 && Doc.AreProtosEqual(a2, promoteDoc)) link.anchor2 = copy;
+                                LinkManager.Instance.deleteLink(link);
+                                LinkManager.Instance.addLink(link);
+                            }
+                        })
                     })
-                })
+                }
             }
         });
     }
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index bc4fe7dd7..185bec7a2 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -155,6 +155,9 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         let key = StrCast(this.props.parent.props.Document.sectionFilter);
         let newDoc = Docs.Create.TextDocument({ height: 18, width: 200, documentText: "@@@" + value, title: value, autoHeight: true });
         newDoc[key] = this.getValue(this.props.heading);
+        let maxHeading = this.props.docList.reduce((maxHeading, doc) => NumCast(doc.heading) > maxHeading ? NumCast(doc.heading) : maxHeading, 0);
+        let heading = maxHeading === 0 || this.props.docList.length === 0 ? 1 : maxHeading === 1 ? 2 : 3;
+        newDoc.heading = heading;
         return this.props.parent.props.addDocument(newDoc);
     }
 
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index b1e063997..6217ef859 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -201,6 +201,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 ContextMenu.Instance.addItem({ description: "Delete Workspace", event: () => this.props.deleteDoc(this.props.document), icon: "trash-alt" });
             }
             ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.Create.KVPDocument(this.props.document, { width: 300, height: 300 }); this.props.addDocTab(kvp, this.props.dataDoc ? this.props.dataDoc : kvp, "onRight"); }, icon: "layer-group" });
+            ContextMenu.Instance.addItem({ description: "Publish", event: () => DocUtils.Publish(this.props.document, StrCast(this.props.document.title), () => { }, () => { }), icon: "file" });
             ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15);
             e.stopPropagation();
             e.preventDefault();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d37a0ee59..d90224eae 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -441,22 +441,39 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @undoBatch
     makeNativeViewClicked = (): void => {
         this.props.Document.layout = this.props.Document.nativeLayout;
-        this.props.Document.type = this.props.Document.nativeType;
-        this.props.Document.nativeWidth = this.props.Document.nativeNativeWidth;
-        this.props.Document.nativeHeight = this.props.Document.nativeNativeHeight;
-        this.props.Document.ignoreAspect = this.props.Document.nativeIgnoreAspect;
         this.props.Document.nativeLayout = undefined;
-        this.props.Document.nativeNativeWidth = undefined;
-        this.props.Document.nativeNativeHeight = undefined;
-        this.props.Document.nativeIgnoreAspect = undefined;
+        this.props.Document.type = this.props.Document.nativeType;
+
+        this.props.Document.customAutoHeight = this.props.Document.autoHeight;
+        this.props.Document.customWidth = this.props.Document.nativeWidth;
+        this.props.Document.customHeight = this.props.Document.nativeHeight;
+        this.props.Document.customNativeWidth = this.props.Document.nativeWidth;
+        this.props.Document.customNativeHeight = this.props.Document.nativeHeight;
+        this.props.Document.customIgnoreAspect = this.props.Document.ignoreAspect;
+
+        this.props.Document.autoHeight = this.props.Document.nonCustomAutoHeight;
+        this.props.Document.width = this.props.Document.nonCustomWidth;
+        this.props.Document.height = this.props.Document.nonCustomHeight;
+        this.props.Document.nativeWidth = this.props.Document.nonCustomNativeWidth;
+        this.props.Document.nativeHeight = this.props.Document.nonCustomNativeHeight;
+        this.props.Document.ignoreAspect = this.props.Document.nonCustomIgnoreAspect;
+        this.props.Document.nonCustomAutoHeight = undefined;
+        this.props.Document.nonCustomWidth = undefined;
+        this.props.Document.nonCustomHeight = undefined;
+        this.props.Document.nonCustomNativeWidth = undefined;
+        this.props.Document.nonCustomNativeHeight = undefined;
+        this.props.Document.nonCustomIgnoreAspect = undefined;
     }
     @undoBatch
     makeCustomViewClicked = (): void => {
         this.props.Document.nativeLayout = this.props.Document.layout;
         this.props.Document.nativeType = this.props.Document.type;
-        this.props.Document.nativeNativeWidth = this.props.Document.nativeWidth;
-        this.props.Document.nativeNativeHeight = this.props.Document.nativeHeight;
-        this.props.Document.nativeIgnoreAspect = this.props.Document.ignoreAspect;
+        this.props.Document.nonCustomAutoHeight = this.props.Document.autoHeight;
+        this.props.Document.nonCustomWidth = this.props.Document.nativeWidth;
+        this.props.Document.nonCustomHeight = this.props.Document.nativeHeight;
+        this.props.Document.nonCustomNativeWidth = this.props.Document.nativeWidth;
+        this.props.Document.nonCustomNativeHeight = this.props.Document.nativeHeight;
+        this.props.Document.nonCustomIgnoreAspect = this.props.Document.ignoreAspect;
         PromiseValue(Cast(this.props.Document.customLayout, Doc)).then(custom => {
             if (custom) {
                 this.props.Document.type = DocumentType.TEMPLATE;
@@ -464,6 +481,18 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 !custom.nativeWidth && (this.props.Document.nativeWidth = 0);
                 !custom.nativeHeight && (this.props.Document.nativeHeight = 0);
                 !custom.nativeWidth && (this.props.Document.ignoreAspect = true);
+                this.props.Document.autoHeight = this.props.Document.autoHeight;
+                this.props.Document.width = this.props.Document.customWidth;
+                this.props.Document.height = this.props.Document.customHeight;
+                this.props.Document.nativeWidth = this.props.Document.customNativeWidth;
+                this.props.Document.nativeHeight = this.props.Document.customNativeHeight;
+                this.props.Document.ignoreAspect = this.props.Document.ignoreAspect;
+                this.props.Document.customAutoHeight = undefined;
+                this.props.Document.customWidth = undefined;
+                this.props.Document.customHeight = undefined;
+                this.props.Document.customNativeWidth = undefined;
+                this.props.Document.customNativeHeight = undefined;
+                this.props.Document.customIgnoreAspect = undefined;
             } else {
                 let options = { title: "data", width: NumCast(this.props.Document.width), height: NumCast(this.props.Document.height) + 25, x: -NumCast(this.props.Document.width) / 2, y: -NumCast(this.props.Document.height) / 2, };
                 let fieldTemplate = this.props.Document.type === DocumentType.TEXT ? Docs.Create.TextDocument(options) :
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 2e05268a6..77e29632e 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -169,6 +169,25 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
+    linkOnDeselect: Map<string, string> = new Map();
+
+    doLinkOnDeselect() {
+        Array.from(this.linkOnDeselect.entries()).map(entry => {
+            let key = entry[0];
+            let value = entry[1];
+            let id = Utils.GenerateDeterministicGuid(this.dataDoc[Id] + key);
+            DocServer.GetRefField(value).then(doc => {
+                DocServer.GetRefField(id).then(linkDoc => {
+                    this.dataDoc[key] = doc || Docs.Create.FreeformDocument([], { title: value, width: 500, height: 500 }, value);
+                    DocUtils.Publish(this.dataDoc[key] as Doc, value, this.props.addDocument, this.props.removeDocument);
+                    if (linkDoc) { (linkDoc as Doc).anchor2 = this.dataDoc[key] as Doc; }
+                    else DocUtils.MakeLink(this.dataDoc, this.dataDoc[key] as Doc, undefined, "Ref:" + value, undefined, undefined, id, true);
+                })
+            });
+        })
+        this.linkOnDeselect.clear();
+    }
+
     dispatchTransaction = (tx: Transaction) => {
         if (this._editorView) {
             let metadata = tx.selection.$from.marks().find((m: Mark) => m.type === schema.marks.metadata);
@@ -183,15 +202,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 if (split.length > 1 && split[1]) {
                     let key = split[0];
                     let value = split[split.length - 1];
+                    this.linkOnDeselect.set(key, value);
 
                     let id = Utils.GenerateDeterministicGuid(this.dataDoc[Id] + key);
-                    DocServer.GetRefField(value).then(doc => {
-                        DocServer.GetRefField(id).then(linkDoc => {
-                            this.dataDoc[key] = doc || Docs.Create.FreeformDocument([], { title: value, width: 500, height: 500 }, value);
-                            if (linkDoc) { (linkDoc as Doc).anchor2 = this.dataDoc[key] as Doc; }
-                            else DocUtils.MakeLink(this.dataDoc, this.dataDoc[key] as Doc, undefined, "Ref:" + value, undefined, undefined, id, true);
-                        })
-                    });
                     const link = this._editorView!.state.schema.marks.link.create({ href: `http://localhost:1050/doc/${id}`, location: "onRight", title: value });
                     const mval = this._editorView!.state.schema.marks.metadataVal.create();
                     let offset = (tx.selection.to === range!.end - 1 ? -1 : 0);
@@ -875,6 +888,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             this._undoTyping.end();
             this._undoTyping = undefined;
         }
+        this.doLinkOnDeselect();
     }
     onKeyPress = (e: React.KeyboardEvent) => {
         if (e.key === "Escape") {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index b6b3bf73e..eef14ad25 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -475,6 +475,29 @@ export namespace Doc {
         return { layout: layoutDoc, data: resolvedDataDoc };
     }
 
+    export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc {
+        Object.keys(doc).forEach(key => {
+            const field = ProxyField.WithoutProxy(() => doc[key]);
+            if (key === "proto" && copyProto) {
+                if (doc.proto instanceof Doc && overwrite.proto instanceof Doc) {
+                    overwrite[key] = Doc.Overwrite(doc[key]!, overwrite.proto);
+                }
+            } else {
+                if (field instanceof RefField) {
+                    overwrite[key] = field;
+                } else if (field instanceof ObjectField) {
+                    overwrite[key] = ObjectField.MakeCopy(field);
+                } else if (field instanceof Promise) {
+                    debugger; //This shouldn't happend...
+                } else {
+                    overwrite[key] = field;
+                }
+            }
+        });
+
+        return overwrite;
+    }
+
     export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string): Doc {
         const copy = new Doc(copyProtoId, true);
         Object.keys(doc).forEach(key => {
-- 
cgit v1.2.3-70-g09d2

