From 3442776999d1d7b7bced9bbed601ead637a43cc7 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 22 Jul 2019 10:24:37 -0400
Subject: merged stacking sections branch.

---
 src/client/views/collections/CollectionView.tsx | 28 +++++++++++++++++--------
 1 file changed, 19 insertions(+), 9 deletions(-)

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

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 56750668d..045c8531e 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,11 +1,10 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons';
+import { faProjectDiagram, faSignature, faColumns, faSquare, faTh, faImage, faThList, faTree, faEllipsisV } from '@fortawesome/free-solid-svg-icons';
 import { observer } from "mobx-react";
 import * as React from 'react';
-import { Doc } from '../../../new_fields/Doc';
+import { Doc, DocListCast, WidthSym, HeightSym } from '../../../new_fields/Doc';
 import { Id } from '../../../new_fields/FieldSymbols';
 import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
-import { Docs } from '../../documents/Documents';
 import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from '../ContextMenuItem';
@@ -16,6 +15,8 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV
 import { CollectionSchemaView } from "./CollectionSchemaView";
 import { CollectionStackingView } from './CollectionStackingView';
 import { CollectionTreeView } from "./CollectionTreeView";
+import { StrCast, PromiseValue } from '../../../new_fields/Types';
+import { DocumentType } from '../../documents/Documents';
 export const COLLECTION_BORDER_WIDTH = 2;
 
 library.add(faTh);
@@ -24,6 +25,9 @@ library.add(faSquare);
 library.add(faProjectDiagram);
 library.add(faSignature);
 library.add(faThList);
+library.add(faColumns);
+library.add(faEllipsisV);
+library.add(faImage);
 
 @observer
 export class CollectionView extends React.Component<FieldViewProps> {
@@ -35,7 +39,8 @@ export class CollectionView extends React.Component<FieldViewProps> {
             case CollectionViewType.Schema: return (<CollectionSchemaView {...props} CollectionView={this} />);
             case CollectionViewType.Docking: return (<CollectionDockingView {...props} CollectionView={this} />);
             case CollectionViewType.Tree: return (<CollectionTreeView {...props} CollectionView={this} />);
-            case CollectionViewType.Stacking: return (<CollectionStackingView {...props} CollectionView={this} />);
+            case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (<CollectionStackingView {...props} CollectionView={this} />); }
+            case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (<CollectionStackingView {...props} CollectionView={this} />); }
             case CollectionViewType.Freeform:
             default:
                 return (<CollectionFreeFormView {...props} CollectionView={this} />);
@@ -45,6 +50,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
 
     get isAnnotationOverlay() { return this.props.fieldExt ? true : false; }
 
+    static _applyCount: number = 0;
     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[] = [];
@@ -54,15 +60,19 @@ export class CollectionView extends React.Component<FieldViewProps> {
             }
             subItems.push({ description: "Schema", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Schema), icon: "th-list" });
             subItems.push({ description: "Treeview", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Tree), icon: "tree" });
-            subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "th-list" });
+            subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "ellipsis-v" });
+            subItems.push({ description: "Masonry", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Masonry), icon: "columns" });
             ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems });
             ContextMenu.Instance.addItem({
                 description: "Apply Template", event: undoBatch(() => {
                     let otherdoc = new Doc();
-                    otherdoc.width = 100;
-                    otherdoc.height = 50;
-                    Doc.GetProto(otherdoc).title = "applied(" + this.props.Document.title + ")";
-                    Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document);
+                    otherdoc.width = this.props.Document[WidthSym]();
+                    otherdoc.height = this.props.Document[HeightSym]();
+                    otherdoc.title = this.props.Document.title + "(..." + CollectionView._applyCount++ + ")"; // previously "applied"
+                    otherdoc.layout = Doc.MakeDelegate(this.props.Document);
+                    otherdoc.miniLayout = StrCast(this.props.Document.miniLayout);
+                    otherdoc.detailedLayout = otherdoc.layout;
+                    otherdoc.type = DocumentType.TEMPLATE;
                     this.props.addDocTab && this.props.addDocTab(otherdoc, undefined, "onRight");
                 }), icon: "project-diagram"
             });
-- 
cgit v1.2.3-70-g09d2


From 86971952237b8bd01a23b52db662740126bd8477 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 23 Jul 2019 18:00:52 -0400
Subject: some fixes for fitToBox, templates, and showTitle

---
 src/client/views/DocumentDecorations.tsx           |  4 +-
 src/client/views/EditableView.tsx                  |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  3 +-
 .../views/collections/CollectionTreeView.tsx       | 76 +++++++++++++---------
 src/client/views/collections/CollectionView.tsx    | 15 +----
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  9 +--
 src/client/views/nodes/DocumentContentsView.tsx    |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 17 ++---
 src/new_fields/Doc.ts                              | 26 ++++++--
 9 files changed, 87 insertions(+), 67 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 2f7bea365..989b35581 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -525,8 +525,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 let actualdH = Math.max(height + (dH * scale), 20);
                 doc.x = (doc.x || 0) + dX * (actualdW - width);
                 doc.y = (doc.y || 0) + dY * (actualdH - height);
-                let proto = Doc.GetProto(element.props.Document);
-                let fixedAspect = e.ctrlKey || (!BoolCast(proto.ignoreAspect, false) && nwidth && nheight);
+                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);
                 if (fixedAspect && (!nwidth || !nheight)) {
                     proto.nativeWidth = nwidth = doc.width || 0;
                     proto.nativeHeight = nheight = doc.height || 0;
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index f2cdffd38..c66a92f48 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -93,7 +93,7 @@ export class EditableView extends React.Component<EditableProps> {
                 <div className={`editableView-container-editing${this.props.oneLine ? "-oneLine" : ""}`}
                     style={{ display: this.props.display, height: "auto", maxHeight: `${this.props.height}` }}
                     onClick={this.onClick} >
-                    <span style={{ fontStyle: this.props.fontStyle }}>{this.props.contents}</span>
+                    <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize }}>{this.props.contents}</span>
                 </div>
             );
         }
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 0e5f9a321..54b0e37b5 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -5,7 +5,7 @@ import { observer } from "mobx-react";
 import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { BoolCast, NumCast, Cast, StrCast } from "../../../new_fields/Types";
-import { emptyFunction, Utils } from "../../../Utils";
+import { emptyFunction, Utils, returnTrue } from "../../../Utils";
 import { CollectionSchemaPreview } from "./CollectionSchemaView";
 import "./CollectionStackingView.scss";
 import { CollectionSubView } from "./CollectionSubView";
@@ -74,6 +74,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             DataDocument={resolvedDataDoc}
             showOverlays={this.overlays}
             renderDepth={this.props.renderDepth}
+            fitToBox={true}
             width={width}
             height={height}
             getTransform={finalDxf}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index d05cc375e..f98629c5b 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -74,15 +74,15 @@ class TreeView extends React.Component<TreeViewProps> {
     @observable _collapsed: boolean = true;
 
     @computed get fieldKey() {
-        let keys = Array.from(Object.keys(this.resolvedDataDoc));  // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set
-        if (this.resolvedDataDoc.proto instanceof Doc) {
-            let arr = Array.from(Object.keys(this.resolvedDataDoc.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set
+        let keys = Array.from(Object.keys(this.dataDoc));  // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set
+        if (this.dataDoc.proto instanceof Doc) {
+            let arr = Array.from(Object.keys(this.dataDoc.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set
             keys.push(...arr);
             while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1);
         }
         let keyList: string[] = [];
         keys.map(key => {
-            let docList = Cast(this.resolvedDataDoc[key], listSpec(Doc));
+            let docList = Cast(this.dataDoc[key], listSpec(Doc));
             if (docList && docList.length > 0) {
                 keyList.push(key);
             }
@@ -94,7 +94,16 @@ class TreeView extends React.Component<TreeViewProps> {
         return keyList.length ? keyList[0] : "data";
     }
 
-    @computed get resolvedDataDoc() { return BoolCast(this.props.document.isTemplate) && this.props.dataDoc ? this.props.dataDoc : this.props.document; }
+    @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
+            // has a template layout document, then we will render the template layout but use 
+            // this document as the data document for the layout.
+            return this.props.document;
+        }
+        return this.props.dataDoc ? this.props.dataDoc : undefined;
+    }
 
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
         this._treedropDisposer && this._treedropDisposer();
@@ -103,7 +112,7 @@ class TreeView extends React.Component<TreeViewProps> {
         }
     }
 
-    @undoBatch delete = () => this.props.deleteDoc(this.resolvedDataDoc);
+    @undoBatch delete = () => this.props.deleteDoc(this.dataDoc);
     @undoBatch openRight = async () => this.props.addDocTab(this.props.document, undefined, "onRight");
 
     onPointerDown = (e: React.PointerEvent) => e.stopPropagation();
@@ -135,7 +144,7 @@ class TreeView extends React.Component<TreeViewProps> {
 
     @action
     remove = (document: Document, key: string): boolean => {
-        let children = Cast(this.resolvedDataDoc[key], listSpec(Doc), []);
+        let children = Cast(this.dataDoc[key], listSpec(Doc), []);
         if (children.indexOf(document) !== -1) {
             children.splice(children.indexOf(document), 1);
             return true;
@@ -151,8 +160,8 @@ class TreeView extends React.Component<TreeViewProps> {
     indent = () => this.props.addDocument(this.props.document) && this.delete()
 
     renderBullet() {
-        let docList = Cast(this.resolvedDataDoc[this.fieldKey], listSpec(Doc));
-        let doc = Cast(this.resolvedDataDoc[this.fieldKey], Doc);
+        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 }}>
@@ -164,16 +173,17 @@ class TreeView extends React.Component<TreeViewProps> {
     editableView = (key: string, style?: string) => (<EditableView
         oneLine={true}
         display={"inline"}
-        editing={this.resolvedDataDoc[Id] === TreeView.loadId}
+        editing={this.dataDoc[Id] === TreeView.loadId}
         contents={StrCast(this.props.document[key])}
         height={36}
         fontStyle={style}
         fontSize={12}
         GetValue={() => StrCast(this.props.document[key])}
-        SetValue={(value: string) => (Doc.GetProto(this.resolvedDataDoc)[key] = value) ? true : true}
+        SetValue={(value: string) => (Doc.GetProto(this.dataDoc)[key] = value) ? true : true}
         OnFillDown={(value: string) => {
-            Doc.GetProto(this.resolvedDataDoc)[key] = value;
-            let doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
+            Doc.GetProto(this.dataDoc)[key] = value;
+            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];
             return this.props.addDocument(doc);
         }}
@@ -181,16 +191,16 @@ class TreeView extends React.Component<TreeViewProps> {
     />)
 
     @computed get keyList() {
-        let keys = Array.from(Object.keys(this.resolvedDataDoc));
-        if (this.resolvedDataDoc.proto instanceof Doc) {
-            keys.push(...Array.from(Object.keys(this.resolvedDataDoc.proto)));
+        let keys = Array.from(Object.keys(this.dataDoc));
+        if (this.dataDoc.proto instanceof Doc) {
+            keys.push(...Array.from(Object.keys(this.dataDoc.proto)));
         }
         let keyList: string[] = keys.reduce((l, key) => {
-            let listspec = DocListCast(this.resolvedDataDoc[key]);
+            let listspec = DocListCast(this.dataDoc[key]);
             if (listspec && listspec.length) return [...l, key];
             return l;
         }, [] as string[]);
-        keys.map(key => Cast(this.resolvedDataDoc[key], Doc) instanceof Doc && keyList.push(key));
+        keys.map(key => Cast(this.dataDoc[key], Doc) instanceof Doc && (Cast(this.dataDoc[key], Doc) as Doc).type !== undefined && keyList.push(key));
         if (LinkManager.Instance.getAllRelatedLinks(this.props.document).length > 0) keyList.push("links");
         if (keyList.indexOf(this.fieldKey) !== -1) {
             keyList.splice(keyList.indexOf(this.fieldKey), 1);
@@ -203,7 +213,7 @@ class TreeView extends React.Component<TreeViewProps> {
      */
     renderTitle() {
         let reference = React.createRef<HTMLDivElement>();
-        let onItemDown = SetupDrag(reference, () => this.resolvedDataDoc, this.move, this.props.dropAction, this.props.treeViewId, true);
+        let onItemDown = SetupDrag(reference, () => this.dataDoc, this.move, this.props.dropAction, this.props.treeViewId, true);
 
         let headerElements = (
             <span className="collectionTreeView-keyHeader" key={this._chosenKey + "chosen"}
@@ -215,7 +225,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 {this._chosenKey}
             </span>);
         let dataDocs = CollectionDockingView.Instance ? Cast(CollectionDockingView.Instance.props.Document[this.fieldKey], listSpec(Doc), []) : [];
-        let openRight = dataDocs && dataDocs.indexOf(this.resolvedDataDoc) !== -1 ? (null) : (
+        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>);
@@ -241,12 +251,12 @@ class TreeView extends React.Component<TreeViewProps> {
             if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) {
                 ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "inTab"), icon: "folder" });
                 ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.resolvedDataDoc, "onRight"), icon: "caret-square-right" });
-                if (DocumentManager.Instance.getDocumentViews(this.resolvedDataDoc).length) {
-                    ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.resolvedDataDoc).map(view => view.props.focus(this.props.document, true)), icon: "camera" });
+                if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) {
+                    ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.dataDoc).map(view => view.props.focus(this.props.document, true)), icon: "camera" });
                 }
                 ContextMenu.Instance.addItem({ description: "Delete Item", event: undoBatch(() => this.props.deleteDoc(this.props.document)), icon: "trash-alt" });
             } else {
-                ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.resolvedDataDoc)), icon: "caret-square-right" });
+                ContextMenu.Instance.addItem({ description: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.dataDoc)), icon: "caret-square-right" });
                 ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => 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" });
@@ -274,7 +284,7 @@ class TreeView extends React.Component<TreeViewProps> {
             if (de.data.draggedDocuments[0] === this.props.document) return true;
             let addDoc = (doc: Doc) => this.props.addDocument(doc, this.resolvedDataDoc, before);
             if (inside) {
-                let docList = Cast(this.resolvedDataDoc.data, listSpec(Doc));
+                let docList = Cast(this.dataDoc.data, listSpec(Doc));
                 if (docList !== undefined) {
                     addDoc = (doc: Doc) => { docList && docList.push(doc); return true; };
                 }
@@ -326,7 +336,7 @@ class TreeView extends React.Component<TreeViewProps> {
 
     @computed get boundsOfCollectionDocument() {
         if (StrCast(this.props.document.type).indexOf(DocumentType.COL) === -1) return undefined;
-        let layoutDoc = Doc.expandTemplateLayout(this.props.document, this.props.dataDoc);
+        let layoutDoc = this.props.document;
         return Doc.ComputeContentBounds(DocListCast(layoutDoc.data));
     }
     docWidth = () => {
@@ -344,27 +354,30 @@ class TreeView extends React.Component<TreeViewProps> {
         })());
     }
 
+    noOverlays = (doc: Doc) => { return { title: "", caption: "" } };
+
     render() {
         let contentElement: (JSX.Element | null) = null;
-        let docList = Cast(this.resolvedDataDoc[this._chosenKey], listSpec(Doc));
+        let docList = Cast(this.dataDoc[this._chosenKey], listSpec(Doc));
         let remDoc = (doc: Doc) => this.remove(doc, this._chosenKey);
-        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.resolvedDataDoc, this._chosenKey, doc, addBefore, before);
-        let doc = Cast(this.resolvedDataDoc[this._chosenKey], Doc);
+        let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.dataDoc, this._chosenKey, doc, addBefore, before);
+        let doc = Cast(this.dataDoc[this._chosenKey], Doc);
 
         if (!this._collapsed) {
             if (!this.props.document.embed) {
                 contentElement = <ul key={this._chosenKey + "more"}>
                     {this._chosenKey === "links" ? this.renderLinks() :
-                        TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.props.dataDoc, this._chosenKey, addDoc, remDoc, this.move,
+                        TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.resolvedDataDoc, this._chosenKey, 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 {
-                let layoutDoc = Doc.expandTemplateLayout(this.props.document, this.props.dataDoc);
+                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}
@@ -547,7 +560,8 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                     SetValue={(value: string) => (Doc.GetProto(this.resolvedDataDoc).title = value) ? true : true}
                     OnFillDown={(value: string) => {
                         Doc.GetProto(this.props.Document).title = value;
-                        let doc = Docs.Create.FreeformDocument([], { title: "", x: 0, y: 0, width: 100, height: 25, templates: new List<string>([Templates.Title.Layout]) });
+                        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);
                     }} />
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 045c8531e..4a51a1f58 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -50,7 +50,6 @@ export class CollectionView extends React.Component<FieldViewProps> {
 
     get isAnnotationOverlay() { return this.props.fieldExt ? true : false; }
 
-    static _applyCount: number = 0;
     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[] = [];
@@ -63,19 +62,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
             subItems.push({ description: "Stacking", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Stacking), icon: "ellipsis-v" });
             subItems.push({ description: "Masonry", event: undoBatch(() => this.props.Document.viewType = CollectionViewType.Masonry), icon: "columns" });
             ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems });
-            ContextMenu.Instance.addItem({
-                description: "Apply Template", event: undoBatch(() => {
-                    let otherdoc = new Doc();
-                    otherdoc.width = this.props.Document[WidthSym]();
-                    otherdoc.height = this.props.Document[HeightSym]();
-                    otherdoc.title = this.props.Document.title + "(..." + CollectionView._applyCount++ + ")"; // previously "applied"
-                    otherdoc.layout = Doc.MakeDelegate(this.props.Document);
-                    otherdoc.miniLayout = StrCast(this.props.Document.miniLayout);
-                    otherdoc.detailedLayout = otherdoc.layout;
-                    otherdoc.type = DocumentType.TEMPLATE;
-                    this.props.addDocTab && this.props.addDocTab(otherdoc, undefined, "onRight");
-                }), icon: "project-diagram"
-            });
+            ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight")), icon: "project-diagram" });
         }
     }
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 703873681..6bb082b66 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -195,10 +195,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;
@@ -358,6 +358,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps {
         let self = this;
         let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined;
+        resolvedDataDoc && Doc.UpdateDocumentExtensionForField(resolvedDataDoc, this.props.fieldKey);
         let layoutDoc = Doc.expandTemplateLayout(childDocLayout, resolvedDataDoc);
         return {
             DataDoc: resolvedDataDoc !== layoutDoc && resolvedDataDoc ? resolvedDataDoc : undefined,
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index ed6b224a7..ef65c12cf 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -64,7 +64,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
 
     get dataDoc() {
         if (this.props.DataDoc === undefined && this.props.Document.layout instanceof Doc) {
-            // if there is no dataDoc (ie, we're not rendering a temlplate layout), but this document
+            // if there is no dataDoc (ie, we're not rendering a template layout), but this document
             // has a template layout document, then we will render the template layout but use 
             // this document as the data document for the layout.
             return this.props.Document;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 907ba3713..09a1b49fe 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -503,7 +503,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @undoBatch
     @action
     freezeNativeDimensions = (): void => {
-        let proto = Doc.GetProto(this.props.Document);
+        let proto = this.props.Document.isTemplate ? this.props.Document : Doc.GetProto(this.props.Document);
         if (proto.ignoreAspect === undefined && !proto.nativeWidth) {
             proto.nativeWidth = this.props.PanelWidth();
             proto.nativeHeight = this.props.PanelHeight();
@@ -629,10 +629,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         var nativeWidth = this.nativeWidth > 0 ? `${this.nativeWidth}px` : "100%";
         var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%";
         let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.props.Document) : undefined;
-        let showTitle = showOverlays && showOverlays.title ? showOverlays.title : StrCast(this.props.Document.showTitle);
-        let showCaption = showOverlays && showOverlays.caption ? showOverlays.caption : StrCast(this.props.Document.showCaption);
+        let showTitle = showOverlays && showOverlays.title !== "undefined" ? showOverlays.title : StrCast(this.props.Document.showTitle);
+        let showCaption = showOverlays && showOverlays.caption !== "undefined" ? showOverlays.caption : StrCast(this.props.Document.showCaption);
         let templates = Cast(this.props.Document.templates, listSpec("string"));
-        if (templates instanceof List) {
+        if (!showOverlays && templates instanceof List) {
             templates.map(str => {
                 if (str.indexOf("{props.Document.title}") !== -1) showTitle = "title";
                 if (str.indexOf("fieldKey={\"caption\"}") !== -1) showCaption = "caption";
@@ -663,12 +663,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 {!showTitle && !showCaption ? this.contents :
                     <div style={{ position: "absolute", display: "inline-block", width: "100%", height: "100%", pointerEvents: "none" }}>
 
-                        <div style={{ width: "100%", height: showTextTitle ? "calc(100% - 25px)" : "100%", display: "inline-block", position: "absolute", top: showTextTitle ? "25px" : undefined }}>
+                        <div style={{ width: "100%", height: showTextTitle ? "calc(100% - 33px)" : "100%", display: "inline-block", position: "absolute", top: showTextTitle ? "29px" : undefined }}>
                             {this.contents}
                         </div>
                         {!showTitle ? (null) :
                             <div style={{
-                                position: showTextTitle ? "relative" : "absolute", top: 0, textAlign: "center", textOverflow: "ellipsis", whiteSpace: "pre",
+                                position: showTextTitle ? "relative" : "absolute", top: 0, padding: "4px", textAlign: "center", textOverflow: "ellipsis", whiteSpace: "pre",
                                 pointerEvents: "all",
                                 overflow: "hidden", width: `${100 * this.props.ContentScaling()}%`, height: 25, background: "rgba(0, 0, 0, .4)", color: "white",
                                 transformOrigin: "top left", transform: `scale(${1 / this.props.ContentScaling()})`
@@ -677,8 +677,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                                     contents={this.props.Document[showTitle]}
                                     display={"block"}
                                     height={72}
-                                    GetValue={() => StrCast(this.props.Document[showTitle])}
-                                    SetValue={(value: string) => (Doc.GetProto(this.props.Document)[showTitle] = value) ? true : true}
+                                    fontSize={12}
+                                    GetValue={() => StrCast(this.props.Document[showTitle!])}
+                                    SetValue={(value: string) => (Doc.GetProto(this.props.Document)[showTitle!] = value) ? true : true}
                                 />
                             </div>
                         }
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 2ad6ae5f0..5ae0753d8 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -244,7 +244,7 @@ export namespace Doc {
         let r = (doc === other);
         let r2 = (doc.proto === other);
         let r3 = (other.proto === doc);
-        let r4 = (doc.proto === other.proto);
+        let r4 = (doc.proto === other.proto && other.proto !== undefined);
         return r || r2 || r3 || r4;
     }
 
@@ -298,7 +298,7 @@ export namespace Doc {
                 x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y),
                 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 });
+        }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: -Number.MAX_VALUE, b: -Number.MAX_VALUE });
         return bounds;
     }
 
@@ -350,19 +350,21 @@ export namespace Doc {
         if (expandedTemplateLayout instanceof Doc) {
             return expandedTemplateLayout;
         }
+        expandedTemplateLayout = dataDoc[templateLayoutDoc.title + templateLayoutDoc[Id]];
+        if (expandedTemplateLayout instanceof Doc) {
+            return expandedTemplateLayout;
+        }
         if (expandedTemplateLayout === undefined && BoolCast(templateLayoutDoc.isTemplate)) {
             setTimeout(() => {
                 let expandedDoc = Doc.MakeDelegate(templateLayoutDoc);
                 expandedDoc.title = templateLayoutDoc.title + "[" + StrCast(dataDoc.title).match(/\.\.\.[0-9]*/) + "]";
                 expandedDoc.isExpandedTemplate = templateLayoutDoc;
-                dataDoc[templateLayoutDoc[Id]] = expandedDoc;
+                dataDoc[templateLayoutDoc.title + templateLayoutDoc[Id]] = expandedDoc;
             }, 0);
         }
         return templateLayoutDoc; // use the templateLayout when it's not a template or the expandedTemplate is pending.
     }
 
-    let _pendingExpansions: Map<string, boolean> = new Map();
-
     export function MakeCopy(doc: Doc, copyProto: boolean = false): Doc {
         const copy = new Doc;
         Object.keys(doc).forEach(key => {
@@ -398,6 +400,20 @@ export namespace Doc {
         return undefined;
     }
 
+    let _applyCount: number = 0;
+    export function ApplyTemplate(templateDoc: Doc) {
+        if (!templateDoc) return undefined;
+        let otherdoc = new Doc();
+        otherdoc.width = templateDoc[WidthSym]();
+        otherdoc.height = templateDoc[HeightSym]();
+        otherdoc.title = templateDoc.title + "(..." + _applyCount++ + ")";
+        otherdoc.layout = Doc.MakeDelegate(templateDoc);
+        otherdoc.miniLayout = StrCast(templateDoc.miniLayout);
+        otherdoc.detailedLayout = otherdoc.layout;
+        otherdoc.type = DocumentType.TEMPLATE;
+        return otherdoc;
+    }
+
     export function MakeTemplate(fieldTemplate: Doc, metaKey: string, proto: Doc) {
         // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??)
         let backgroundLayout = StrCast(fieldTemplate.backgroundLayout);
-- 
cgit v1.2.3-70-g09d2

