From a887adb0080d2826b8a8757cd0f5c9fe451a0695 Mon Sep 17 00:00:00 2001
From: kimdahey <claire_kim1@brown.edu>
Date: Wed, 7 Aug 2019 14:21:52 -0400
Subject: moving computers

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

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4a751c84c..ccdffa899 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -266,7 +266,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     onToggle = (checked: Boolean) => {
-        this.props.CollectionView.props.Document.chromeSatus = checked ? "collapsed" : "view-mode";
+        this.props.CollectionView.props.Document.chromeStatus = checked ? "collapsed" : "view-mode";
     }
 
     render() {
-- 
cgit v1.2.3-70-g09d2


From 41974c4abaf9b9a9a66ee91f4199ba430ffa1c3d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 13 Aug 2019 20:35:17 -0400
Subject: stacking view layout fixes.

---
 src/client/views/MainOverlayTextBox.tsx            |  2 +-
 src/client/views/MainView.tsx                      |  4 +-
 .../views/collections/CollectionStackingView.scss  | 26 ++++++++--
 .../views/collections/CollectionStackingView.tsx   | 55 ++++++++++++++++++++--
 4 files changed, 76 insertions(+), 11 deletions(-)

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

diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 0f20dc3a8..2865fe2b6 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -142,7 +142,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
                             <FormattedTextBox color={`${this._textColor}`} fieldKey={this.TextFieldKey} fieldExt="" hideOnLeave={this._textHideOnLeave} isOverlay={true}
                                 Document={FormattedTextBox.InputBoxOverlay.props.Document}
                                 DataDoc={FormattedTextBox.InputBoxOverlay.props.DataDoc}
-                                onClick={emptyFunction}
+                                onClick={undefined}
                                 isSelected={returnTrue} select={emptyFunction} renderDepth={0} selectOnLoad={true}
                                 ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue} ContentScaling={returnOne}
                                 ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} />
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 1f68101f1..110d47941 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -321,7 +321,7 @@ export class MainView extends React.Component {
                             DataDoc={undefined}
                             addDocument={undefined}
                             addDocTab={emptyFunction}
-                            onClick={emptyFunction}
+                            onClick={undefined}
                             removeDocument={undefined}
                             ScreenToLocalTransform={Transform.Identity}
                             ContentScaling={returnOne}
@@ -386,7 +386,7 @@ export class MainView extends React.Component {
             addDocument={undefined}
             addDocTab={this.addDocTabFunc}
             removeDocument={undefined}
-            onClick={emptyFunction}
+            onClick={undefined}
             ScreenToLocalTransform={Transform.Identity}
             ContentScaling={returnOne}
             PanelWidth={this.flyoutWidthFunc}
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 271ad2d58..01d4ea2b6 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -1,10 +1,15 @@
 @import "../globalCssVariables";
 
-.collectionStackingView {
+.collectionMasonryView {
+    display:inline;
+}
+.collectionStackingView{
+    display: flex;
+}
+.collectionStackingView, .collectionMasonryView{
     height: 100%;
     width: 100%;
     position: absolute;
-    display: flex;
     top: 0;
     overflow-y: auto;
     flex-wrap: wrap;
@@ -31,14 +36,20 @@
     .collectionStackingView-masonrySingle,
     .collectionStackingView-masonryGrid {
         width: 100%;
-        height: 100%;
-        position: absolute;
         display: grid;
         top: 0;
         left: 0;
-        width: 100%;
+    }
+    .collectionStackingView-masonrySingle {
+        height: 100%;
         position: absolute;
     }
+    .collectionStackingView-masonryGrid {
+        margin: auto;
+        height: max-content;
+        position: relative;
+        grid-auto-rows: 0px;
+    }
 
     .collectionStackingView-masonrySingle {
         width: 100%;
@@ -80,12 +91,17 @@
         height: 100%;
         margin: auto;
     }
+    
+    .collectionStackingView-masonrySection {
+        margin: auto;
+    }
 
     .collectionStackingView-sectionHeader {
         text-align: center;
         margin-left: 2px;
         margin-right: 2px;
         margin-top: 10px;
+        background: gray;
         // overflow: hidden; overflow is visible so the color menu isn't hidden -ftong
 
         .editableView-input {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index ba3d8e6a7..695c7951f 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -10,7 +10,7 @@ import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../new_fields/Types";
-import { emptyFunction } from "../../../Utils";
+import { emptyFunction, Utils } from "../../../Utils";
 import { DocumentType } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
@@ -40,7 +40,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get singleColumn() { return BoolCast(this.props.Document.singleColumn, true); }
     @computed get columnWidth() { return this.singleColumn ? (this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin) : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); }
     @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); }
-    @computed get sectionFilter() { return this.singleColumn ? StrCast(this.props.Document.sectionFilter) : ""; }
+    @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); }
 
     get layoutDoc() {
         // if this document's layout field contains a document (ie, a rendering template), then we will use that
@@ -241,6 +241,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
     headings = () => Array.from(this.Sections.keys());
     section = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
+        if (!this.singleColumn) return this.sectionMasonry(heading, docList);
         let key = this.sectionFilter;
         let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
         let types = docList.length ? docList.map(d => typeof d[key]) : this.childDocs.map(d => typeof d[key]);
@@ -263,6 +264,54 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         />;
     }
 
+    getDocTransform(doc: Doc, dref: HTMLDivElement) {
+        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);
+        return this.props.ScreenToLocalTransform().
+            translate(offset[0], offset[1]).
+            scale(NumCast(doc.width, 1) / this.columnWidth);
+    }
+    children(docs: Doc[]) {
+        this._docXfs.length = 0;
+        return docs.map((d, i) => {
+            let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc);
+            let width = () => (d.nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? Math.min(Math.min(d[WidthSym](), NumCast(d.nativeWidth)), this.columnWidth) : this.columnWidth);/// (uniqueHeadings.length + 1);
+            let height = () => this.getDocHeight(layoutDoc);
+            let dref = React.createRef<HTMLDivElement>();
+            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}` }} >
+                {this.getDisplayDoc(layoutDoc, d, dxf, width)}
+            </div>;
+        });
+    }
+
+    sectionMasonry(heading: SchemaHeaderField, docList: Doc[]) {
+        let cols = Math.max(1, Math.min(docList.length,
+            Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
+        let templatecols = "";
+        for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `;
+        return <div key={heading.heading} className="collectionStackingView-masonrySection">
+            {!heading ? (null) :
+                <div key={`${heading.heading}`} className="collectionStackingView-sectionHeader" style={{ background: heading.color }}>
+                    {heading.heading}
+                </div>}
+            <div key={`${heading}-stack`} className={`collectionStackingView-masonryGrid`}
+                style={{
+                    padding: `${this.yMargin}px ${this.xMargin}px`,
+                    width: `${cols * (this.columnWidth + this.gridGap) + 2 * this.xMargin - this.gridGap}px`,
+                    gridGap: this.gridGap,
+                    gridTemplateColumns: templatecols,
+                }}
+            >
+                {this.children(docList)}
+                {this.columnDragger}
+            </div>
+        </div>;
+    }
+
     @action
     addGroup = (value: string) => {
         if (value && this.sectionHeaders) {
@@ -306,7 +355,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
 
         // let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
         return (
-            <div className="collectionStackingView"
+            <div className={this.singleColumn ? "collectionStackingView" : "collectionMasonryView"}
                 ref={this.createRef} onDrop={this.onDrop.bind(this)} onContextMenu={this.onContextMenu} onWheel={(e: React.WheelEvent) => e.stopPropagation()} >
                 {this.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc).
                     map((section: [SchemaHeaderField, Doc[]]) => this.section(section[0], section[1])) :
-- 
cgit v1.2.3-70-g09d2


From 01cf655111df11f21da2d0e66eb2f4b70b0827f5 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 13 Aug 2019 21:18:57 -0400
Subject: more layout fixes for masonry/stacking

---
 src/client/views/collections/CollectionStackingView.tsx            | 4 ++--
 src/client/views/collections/CollectionStackingViewFieldColumn.tsx | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 695c7951f..4efd8e050 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -154,7 +154,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         let nh = NumCast(d.nativeHeight);
         if (!d.ignoreAspect && nw && nh) {
             let aspect = nw && nh ? nh / nw : 1;
-            let wid = this.props.Document.fillColumn ? this.columnWidth / columnScale : Math.min(Math.min(d[WidthSym](), NumCast(d.nativeWidth)), this.columnWidth / columnScale);
+            let wid = d.nativeWidth && !d.ignoreAspect && this.props.Document.fillColumn ? this.columnWidth / columnScale : Math.min(d[WidthSym](), this.columnWidth / columnScale);
             return wid * aspect;
         }
         return d[HeightSym]();
@@ -276,7 +276,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         this._docXfs.length = 0;
         return docs.map((d, i) => {
             let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc);
-            let width = () => (d.nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? Math.min(Math.min(d[WidthSym](), NumCast(d.nativeWidth)), this.columnWidth) : this.columnWidth);/// (uniqueHeadings.length + 1);
+            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 dref = React.createRef<HTMLDivElement>();
             let dxf = () => this.getDocTransform(layoutDoc, dref.current!);
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 9824a501b..4a8d7debd 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -84,7 +84,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
             let headings = this.props.headings();
             let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
             let pair = Doc.GetLayoutDataDocPair(parent.props.Document, parent.props.DataDoc, parent.props.fieldKey, d);
-            let width = () => (d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? Math.min(Math.min(d[WidthSym](), NumCast(d.nativeWidth)), parent.columnWidth / (uniqueHeadings.length + 1)) : parent.columnWidth / (uniqueHeadings.length + 1));/// (uniqueHeadings.length + 1);
+            let width = () => (d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? Math.min(d[WidthSym](), parent.columnWidth / (uniqueHeadings.length + 1)) : parent.columnWidth / (uniqueHeadings.length + 1));/// (uniqueHeadings.length + 1);
             let height = () => parent.getDocHeight(pair.layout, uniqueHeadings.length + 1);// / (d.nativeWidth && !BoolCast(d.ignoreAspect) ? uniqueHeadings.length + 1 : 1);
             let dref = React.createRef<HTMLDivElement>();
             // if (uniqueHeadings.length > 0) {
-- 
cgit v1.2.3-70-g09d2


From b74ceb9c9259e5ab0f41922ce22fb5776152579d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 13 Aug 2019 21:57:25 -0400
Subject: fixed exception

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

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4efd8e050..ce4c98671 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -293,7 +293,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
         let templatecols = "";
         for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `;
-        return <div key={heading.heading} className="collectionStackingView-masonrySection">
+        return <div key={heading ? heading.heading : "empty"} className="collectionStackingView-masonrySection">
             {!heading ? (null) :
                 <div key={`${heading.heading}`} className="collectionStackingView-sectionHeader" style={{ background: heading.color }}>
                     {heading.heading}
-- 
cgit v1.2.3-70-g09d2


From 7a71c9005189e111e9c9d197d02cc9a6a1bce389 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 14 Aug 2019 10:32:31 -0400
Subject: fixed autoheight for stacking views

---
 .../views/collections/CollectionStackingView.tsx   | 25 ++++++++++++++++------
 1 file changed, 18 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index ce4c98671..d68ef2bbd 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -81,11 +81,22 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         // is there any reason this needs to exist? -syip
         this._heightDisposer = reaction(() => {
             if (this.singleColumn && BoolCast(this.props.Document.autoHeight)) {
-                let hgt = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => {
-                    let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d);
-                    return height + this.getDocHeight(pair.layout) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap);
-                }, this.yMargin);
-                return hgt * this.props.ContentScaling();
+                let maxHght = 0;
+                Array.from(this.Sections.values()).map(s => {
+                    let hgt = 50 + s.reduce((height, d, i) => {
+                        let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d);
+                        return height + this.getDocHeight(pair.layout, this.Sections.size) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap);
+                    }, this.yMargin);
+                    maxHght = Math.max(hgt, maxHght);
+                })
+                if (!maxHght) {
+                    let hgt = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => {
+                        let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d);
+                        return height + this.getDocHeight(pair.layout) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap);
+                    }, this.yMargin);
+                    maxHght = hgt * this.props.ContentScaling();
+                }
+                return maxHght * this.props.ContentScaling();
             }
             return -1;
         },
@@ -126,7 +137,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : ScriptCast(this.Document.onChildClick); }
 
     getDisplayDoc(layoutDoc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
-        let height = () => this.getDocHeight(layoutDoc);
+        let height = () => this.getDocHeight(layoutDoc, this.singleColumn ? this.Sections.size : 1);
         let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]());
         return <CollectionSchemaPreview
             Document={layoutDoc}
@@ -288,7 +299,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         });
     }
 
-    sectionMasonry(heading: SchemaHeaderField, docList: Doc[]) {
+    sectionMasonry(heading: SchemaHeaderField | undefined, docList: Doc[]) {
         let cols = Math.max(1, Math.min(docList.length,
             Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
         let templatecols = "";
-- 
cgit v1.2.3-70-g09d2


From c357ef923eafc17210f278d36a0693fe902b21fb Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 14 Aug 2019 13:41:23 -0400
Subject: fixed more sizing issues with stacking/masonry views

---
 .../views/collections/CollectionDockingView.tsx    |  2 +-
 .../views/collections/CollectionStackingView.tsx   | 90 +++++++++-------------
 .../CollectionStackingViewFieldColumn.tsx          | 66 +++++-----------
 3 files changed, 60 insertions(+), 98 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 13bb34037..7332a490a 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -389,7 +389,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                 const stack = tab.contentItem.parent;
                 // shifts the focus to this tab when another tab is dragged over it
                 tab.element[0].onmouseenter = (e: any) => {
-                    if (!this._isPointerDown) return;
+                    if (!this._isPointerDown || !SelectionManager.GetIsDragging()) return;
                     var activeContentItem = tab.header.parent.getActiveContentItem();
                     if (tab.contentItem !== activeContentItem) {
                         tab.header.parent.setActiveContentItem(tab.contentItem);
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index d68ef2bbd..4e49e368b 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -10,7 +10,7 @@ import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
 import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from "../../../new_fields/Types";
-import { emptyFunction, Utils } from "../../../Utils";
+import { emptyFunction, Utils, numberRange } from "../../../Utils";
 import { DocumentType } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
@@ -33,14 +33,21 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     _docXfs: any[] = [];
     _columnStart: number = 0;
     @observable private cursor: CursorProperty = "grab";
-    get sectionHeaders() { return Cast(this.props.Document.sectionHeaders, listSpec(SchemaHeaderField)); }
+    @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); }
     @computed get xMargin() { return NumCast(this.props.Document.xMargin, 2 * this.gridGap); }
     @computed get yMargin() { return NumCast(this.props.Document.yMargin, 2 * this.gridGap); }
     @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); }
-    @computed get singleColumn() { return BoolCast(this.props.Document.singleColumn, true); }
-    @computed get columnWidth() { return this.singleColumn ? (this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin) : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); }
-    @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); }
-    @computed get sectionFilter() { return StrCast(this.props.Document.sectionFilter); }
+    @computed get isStackingView() { return BoolCast(this.props.Document.singleColumn, true); }
+    @computed get numGroupColumns() { return this.isStackingView ? Math.max(1, this.Sections.size + (this.showAddAGroup ? 1 : 0)) : 1; }
+    @computed get showAddAGroup() { return (this.sectionFilter && (this.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.CollectionView.props.Document.chromeStatus !== 'disabled')); }
+    @computed get columnWidth() {
+        return Math.min(this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin,
+            this.isStackingView ? Number.MAX_VALUE : NumCast(this.props.Document.columnWidth, 250));
+    }
+
+    childDocHeight(child: Doc) { return this.getDocHeight(Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, child).layout); }
 
     get layoutDoc() {
         // if this document's layout field contains a document (ie, a rendering template), then we will use that
@@ -48,7 +55,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return this.props.Document.layout instanceof Doc ? this.props.Document.layout : this.props.Document;
     }
 
-
     get Sections() {
         if (!this.sectionFilter) return new Map<SchemaHeaderField, Doc[]>();
 
@@ -78,33 +84,19 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     componentDidMount() {
-        // is there any reason this needs to exist? -syip
+        // is there any reason this needs to exist? -syip.  yes, it handles autoHeight for stacking views (masonry isn't yet supported).
         this._heightDisposer = reaction(() => {
-            if (this.singleColumn && BoolCast(this.props.Document.autoHeight)) {
-                let maxHght = 0;
-                Array.from(this.Sections.values()).map(s => {
-                    let hgt = 50 + s.reduce((height, d, i) => {
-                        let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d);
-                        return height + this.getDocHeight(pair.layout, this.Sections.size) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap);
-                    }, this.yMargin);
-                    maxHght = Math.max(hgt, maxHght);
-                })
-                if (!maxHght) {
-                    let hgt = this.Sections.size * 50 + this.filteredChildren.reduce((height, d, i) => {
-                        let pair = Doc.GetLayoutDataDocPair(this.props.Document, this.props.DataDoc, this.props.fieldKey, d);
-                        return height + this.getDocHeight(pair.layout) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap);
-                    }, this.yMargin);
-                    maxHght = hgt * this.props.ContentScaling();
-                }
-                return maxHght * this.props.ContentScaling();
+            if (this.isStackingView && BoolCast(this.props.Document.autoHeight)) {
+                let sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
+                return this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => Math.max(maxHght,
+                    50 + s.reduce((height, d, i) => height + this.childDocHeight(d) + (i === s.length - 1 ? this.yMargin : this.gridGap), this.yMargin)
+                ), 0);
             }
             return -1;
         },
             (hgt: number) => {
-                if (hgt !== -1) {
-                    let doc = this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
-                    doc.height = hgt;
-                }
+                let doc = hgt === -1 ? undefined : this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc;
+                doc && (doc.height = hgt);
             },
             { fireImmediately: true }
         );
@@ -137,7 +129,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : ScriptCast(this.Document.onChildClick); }
 
     getDisplayDoc(layoutDoc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) {
-        let height = () => this.getDocHeight(layoutDoc, this.singleColumn ? this.Sections.size : 1);
+        let height = () => this.getDocHeight(layoutDoc);
         let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]());
         return <CollectionSchemaPreview
             Document={layoutDoc}
@@ -160,12 +152,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             previewScript={undefined}>
         </CollectionSchemaPreview>;
     }
-    getDocHeight(d: Doc, columnScale: number = 1) {
+    getDocHeight(d: Doc) {
         let nw = NumCast(d.nativeWidth);
         let nh = NumCast(d.nativeHeight);
         if (!d.ignoreAspect && nw && nh) {
             let aspect = nw && nh ? nh / nw : 1;
-            let wid = d.nativeWidth && !d.ignoreAspect && this.props.Document.fillColumn ? this.columnWidth / columnScale : Math.min(d[WidthSym](), this.columnWidth / columnScale);
+            let wid = this.columnWidth / (this.isStackingView ? this.numGroupColumns : 1);
+            if (!(d.nativeWidth && !d.ignoreAspect && this.props.Document.fillColumn)) wid = Math.min(d[WidthSym](), wid);
             return wid * aspect;
         }
         return d[HeightSym]();
@@ -251,15 +244,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         });
     }
     headings = () => Array.from(this.Sections.keys());
-    section = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
-        if (!this.singleColumn) return this.sectionMasonry(heading, docList);
+    sectionStacking = (heading: SchemaHeaderField | undefined, docList: Doc[]) => {
         let key = this.sectionFilter;
         let type: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" | undefined = undefined;
         let types = docList.length ? docList.map(d => typeof d[key]) : this.childDocs.map(d => typeof d[key]);
         if (types.map((i, idx) => types.indexOf(i) === idx).length === 1) {
             type = types[0];
         }
-        let cols = () => this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.length,
+        let cols = () => this.isStackingView ? 1 : Math.max(1, Math.min(this.filteredChildren.length,
             Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
         return <CollectionStackingViewFieldColumn
             key={heading ? heading.heading : ""}
@@ -283,13 +275,13 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             translate(offset[0], offset[1]).
             scale(NumCast(doc.width, 1) / this.columnWidth);
     }
-    children(docs: Doc[]) {
+    masonryChildren(docs: Doc[]) {
         this._docXfs.length = 0;
         return docs.map((d, i) => {
+            let dref = React.createRef<HTMLDivElement>();
             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 dref = React.createRef<HTMLDivElement>();
             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 });
@@ -302,8 +294,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     sectionMasonry(heading: SchemaHeaderField | undefined, docList: Doc[]) {
         let cols = Math.max(1, Math.min(docList.length,
             Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
-        let templatecols = "";
-        for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `;
         return <div key={heading ? heading.heading : "empty"} className="collectionStackingView-masonrySection">
             {!heading ? (null) :
                 <div key={`${heading.heading}`} className="collectionStackingView-sectionHeader" style={{ background: heading.color }}>
@@ -314,10 +304,9 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                     padding: `${this.yMargin}px ${this.xMargin}px`,
                     width: `${cols * (this.columnWidth + this.gridGap) + 2 * this.xMargin - this.gridGap}px`,
                     gridGap: this.gridGap,
-                    gridTemplateColumns: templatecols,
-                }}
-            >
-                {this.children(docList)}
+                    gridTemplateColumns: numberRange(cols).reduce((list, i) => list + ` ${this.columnWidth}px`, ""),
+                }}>
+                {this.masonryChildren(docList)}
                 {this.columnDragger}
             </div>
         </div>;
@@ -356,7 +345,6 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     render() {
-        let headings = Array.from(this.Sections.keys());
         let editableViewProps = {
             GetValue: () => "",
             SetValue: this.addGroup,
@@ -364,18 +352,16 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         };
         Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
 
-        // let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
+        let sections = (this.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc) : [[undefined, this.filteredChildren] as [SchemaHeaderField | undefined, Doc[]]])
         return (
-            <div className={this.singleColumn ? "collectionStackingView" : "collectionMasonryView"}
+            <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"}
                 ref={this.createRef} onDrop={this.onDrop.bind(this)} onContextMenu={this.onContextMenu} onWheel={(e: React.WheelEvent) => e.stopPropagation()} >
-                {this.sectionFilter ? Array.from(this.Sections.entries()).sort(this.sortFunc).
-                    map((section: [SchemaHeaderField, Doc[]]) => this.section(section[0], section[1])) :
-                    this.section(undefined, this.filteredChildren)}
-                {(this.sectionFilter && (this.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.CollectionView.props.Document.chromeStatus !== 'disabled')) ?
+                {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"
-                        style={{ width: (this.columnWidth / (headings.length + ((this.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.CollectionView.props.Document.chromeStatus !== 'disabled') ? 1 : 0))) - 10, marginTop: 10 }}>
+                        style={{ width: this.columnWidth / this.numGroupColumns - 10, marginTop: 10 }}>
                         <EditableView {...editableViewProps} />
-                    </div> : null}
+                    </div>}
                 {this.props.CollectionView.props.Document.chromeStatus !== 'disabled' ? <Switch
                     onChange={this.onToggle}
                     onClick={this.onToggle}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 4a8d7debd..74c7ef305 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -1,28 +1,25 @@
 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 { observer } from "mobx-react";
-import { number } from "prop-types";
 import { Doc, WidthSym } from "../../../new_fields/Doc";
-import { CollectionStackingView } from "./CollectionStackingView";
 import { Id } from "../../../new_fields/FieldSymbols";
+import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import { NumCast, StrCast } from "../../../new_fields/Types";
 import { Utils } from "../../../Utils";
-import { NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
-import { EditableView } from "../EditableView";
-import { action, observable, computed } from "mobx";
-import { undoBatch } from "../../util/UndoManager";
-import { DragManager } from "../../util/DragManager";
-import { DocumentManager } from "../../util/DocumentManager";
-import { SelectionManager } from "../../util/SelectionManager";
-import "./CollectionStackingView.scss";
 import { Docs } from "../../documents/Documents";
-import { SchemaHeaderField, PastelSchemaPalette } from "../../../new_fields/SchemaHeaderField";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { ScriptField } from "../../../new_fields/ScriptField";
+import { DragManager } from "../../util/DragManager";
 import { CompileScript } from "../../util/Scripting";
-import { RichTextField } from "../../../new_fields/RichTextField";
+import { SelectionManager } from "../../util/SelectionManager";
 import { Transform } from "../../util/Transform";
-import { Flyout, anchorPoints } from "../DocumentDecorations";
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faPalette } from '@fortawesome/free-solid-svg-icons';
+import { undoBatch } from "../../util/UndoManager";
+import { anchorPoints, Flyout } from "../DocumentDecorations";
+import { EditableView } from "../EditableView";
+import { CollectionStackingView } from "./CollectionStackingView";
+import "./CollectionStackingView.scss";
 
 library.add(faPalette);
 
@@ -81,38 +78,17 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         let parent = this.props.parent;
         parent._docXfs.length = 0;
         return docs.map((d, i) => {
-            let headings = this.props.headings();
-            let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
             let pair = Doc.GetLayoutDataDocPair(parent.props.Document, parent.props.DataDoc, parent.props.fieldKey, d);
-            let width = () => (d.nativeWidth && !d.ignoreAspect && !parent.props.Document.fillColumn ? Math.min(d[WidthSym](), parent.columnWidth / (uniqueHeadings.length + 1)) : parent.columnWidth / (uniqueHeadings.length + 1));/// (uniqueHeadings.length + 1);
-            let height = () => parent.getDocHeight(pair.layout, uniqueHeadings.length + 1);// / (d.nativeWidth && !BoolCast(d.ignoreAspect) ? uniqueHeadings.length + 1 : 1);
+            let 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>();
-            // if (uniqueHeadings.length > 0) {
             let dxf = () => this.getDocTransform(pair.layout, dref.current!);
             this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height });
-            // }
-            // else {
-            //     //have to add the height of all previous single column sections or the doc decorations will be in the wrong place.
-            //     let dxf = () => this.getDocTransform(layoutDoc, i, width());
-            //     this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height });
-            // }
-            let rowHgtPcnt = height();
             let rowSpan = Math.ceil((height() + parent.gridGap) / parent.gridGap);
-            let style = parent.singleColumn ? { width: width(), margin: "auto", marginTop: i === 0 ? 0 : parent.gridGap, height: `${rowHgtPcnt}` } : { gridRowEnd: `span ${rowSpan}` };
-            return <div className={`collectionStackingView-${parent.singleColumn ? "columnDoc" : "masonryDoc"}`} key={d[Id]} ref={dref} style={style} >
+            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)}
             </div>;
-            // } else {
-            // let dref = React.createRef<HTMLDivElement>();
-            // let dxf = () => this.getDocTransform(layoutDoc, dref.current!);
-            // this.props.parent._docXfs.push({ dxf: dxf, width: width, height: height });
-            // let rowHgtPcnt = height();
-            // let rowSpan = Math.ceil((height() + parent.gridGap) / parent.gridGap);
-            // let divStyle = parent.singleColumn ? { width: width(), marginTop: i === 0 ? 0 : parent.gridGap, height: `${rowHgtPcnt}` } : { gridRowEnd: `span ${rowSpan}` };
-            // return <div className="collectionStackingView-masonryDoc" key={d[Id]} ref={dref} style={divStyle} >
-            //     {this.props.parent.getDisplayDoc(layoutDoc, d, dxf, width)}
-            // </div>;
-            // }
         });
     }
 
@@ -278,7 +254,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
         let headings = this.props.headings();
         let heading = this._heading;
         let style = this.props.parent;
-        let singleColumn = style.singleColumn;
+        let singleColumn = style.isStackingView;
         let uniqueHeadings = headings.map((i, idx) => headings.indexOf(i) === idx);
         let evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`;
         let headerEditableViewProps = {
@@ -326,7 +302,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                         </button>}
                 </div>
             </div> : (null);
-        for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth}px `;
+        for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth / style.numGroupColumns}px `;
         return (
             <div className="collectionStackingViewFieldColumn" key={heading} style={{ width: `${100 / ((uniqueHeadings.length + ((this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled') ? 1 : 0)) || 1)}%`, background: this._background }}
                 ref={this.createColumnDropRef} onPointerEnter={this.pointerEntered} onPointerLeave={this.pointerLeave}>
@@ -348,7 +324,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                 </div>
                 {(this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'view-mode' && this.props.parent.props.CollectionView.props.Document.chromeStatus !== 'disabled') ?
                     <div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton"
-                        style={{ width: style.columnWidth / (uniqueHeadings.length + 1) }}>
+                        style={{ width: style.columnWidth / style.numGroupColumns }}>
                         <EditableView {...newEditableViewProps} />
                     </div> : null}
             </div>
-- 
cgit v1.2.3-70-g09d2


From 6c2d425d3724dc4742cd2a844a6e28c4d580b319 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 14 Aug 2019 14:03:10 -0400
Subject: added collapsible headers for masonry view

---
 .../views/collections/CollectionStackingView.tsx   | 26 +++++++++++++---------
 src/new_fields/SchemaHeaderField.ts                | 14 +++++++++---
 2 files changed, 26 insertions(+), 14 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4e49e368b..5713cc770 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -291,24 +291,28 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         });
     }
 
+    @observable _headingsHack: number = 1;
     sectionMasonry(heading: SchemaHeaderField | undefined, docList: Doc[]) {
         let cols = Math.max(1, Math.min(docList.length,
             Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap))));
         return <div key={heading ? heading.heading : "empty"} className="collectionStackingView-masonrySection">
             {!heading ? (null) :
-                <div key={`${heading.heading}`} className="collectionStackingView-sectionHeader" style={{ background: heading.color }}>
+                <div key={`${heading.heading}`} className="collectionStackingView-sectionHeader" style={{ background: heading.color }}
+                    onClick={action(() => this._headingsHack++ && heading.setCollapsed(!heading.collapsed))} >
                     {heading.heading}
                 </div>}
-            <div key={`${heading}-stack`} className={`collectionStackingView-masonryGrid`}
-                style={{
-                    padding: `${this.yMargin}px ${this.xMargin}px`,
-                    width: `${cols * (this.columnWidth + this.gridGap) + 2 * this.xMargin - this.gridGap}px`,
-                    gridGap: this.gridGap,
-                    gridTemplateColumns: numberRange(cols).reduce((list, i) => list + ` ${this.columnWidth}px`, ""),
-                }}>
-                {this.masonryChildren(docList)}
-                {this.columnDragger}
-            </div>
+            {this._headingsHack && heading && heading.collapsed ? (null) :
+                <div key={`${heading}-stack`} className={`collectionStackingView-masonryGrid`}
+                    style={{
+                        padding: `${this.yMargin}px ${this.xMargin}px`,
+                        width: `${cols * (this.columnWidth + this.gridGap) + 2 * this.xMargin - this.gridGap}px`,
+                        gridGap: this.gridGap,
+                        gridTemplateColumns: numberRange(cols).reduce((list, i) => list + ` ${this.columnWidth}px`, ""),
+                    }}>
+                    {this.masonryChildren(docList)}
+                    {this.columnDragger}
+                </div>
+            }
         </div>;
     }
 
diff --git a/src/new_fields/SchemaHeaderField.ts b/src/new_fields/SchemaHeaderField.ts
index 23605cfb0..7494c9bd1 100644
--- a/src/new_fields/SchemaHeaderField.ts
+++ b/src/new_fields/SchemaHeaderField.ts
@@ -1,8 +1,8 @@
 import { Deserializable } from "../client/util/SerializationHelper";
-import { serializable, createSimpleSchema, primitive } from "serializr";
+import { serializable, primitive } from "serializr";
 import { ObjectField } from "./ObjectField";
 import { Copy, ToScriptString, OnUpdate } from "./FieldSymbols";
-import { scriptingGlobal, Scripting } from "../client/util/Scripting";
+import { scriptingGlobal } from "../client/util/Scripting";
 import { ColumnType } from "../client/views/collections/CollectionSchemaView";
 
 export const PastelSchemaPalette = new Map<string, string>([
@@ -53,9 +53,11 @@ export class SchemaHeaderField extends ObjectField {
     @serializable(primitive())
     width: number;
     @serializable(primitive())
+    collapsed: boolean | undefined;
+    @serializable(primitive())
     desc: boolean | undefined; // boolean determines sort order, undefined when no sort
 
-    constructor(heading: string = "", color: string = RandomPastel(), type?: ColumnType, width?: number, desc?: boolean) {
+    constructor(heading: string = "", color: string = RandomPastel(), type?: ColumnType, width?: number, desc?: boolean, collapsed?: boolean) {
         super();
 
         this.heading = heading;
@@ -63,6 +65,7 @@ export class SchemaHeaderField extends ObjectField {
         this.type = type ? type : 0;
         this.width = width ? width : -1;
         this.desc = desc;
+        this.collapsed = collapsed;
     }
 
     setHeading(heading: string) {
@@ -90,6 +93,11 @@ export class SchemaHeaderField extends ObjectField {
         this[OnUpdate]();
     }
 
+    setCollapsed(collapsed: boolean | undefined) {
+        this.collapsed = collapsed;
+        this[OnUpdate]();
+    }
+
     [Copy]() {
         return new SchemaHeaderField(this.heading, this.color, this.type);
     }
-- 
cgit v1.2.3-70-g09d2


From afb3e5d23e101044d148345de731285b468932b2 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 15 Aug 2019 11:05:56 -0400
Subject: adding template drop target to chrome

---
 src/client/views/collections/CollectionStackingView.tsx | 2 +-
 src/client/views/collections/CollectionViewChromes.scss | 5 +++++
 src/client/views/collections/CollectionViewChromes.tsx  | 3 +++
 3 files changed, 9 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index a17ac96e1..9900049c1 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -56,7 +56,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     get Sections() {
-        if (!this.sectionFilter) return new Map<SchemaHeaderField, Doc[]>();
+        if (!this.sectionFilter || this.sectionHeaders instanceof Promise) return new Map<SchemaHeaderField, Doc[]>();
 
         if (this.sectionHeaders === undefined) {
             this.props.Document.sectionHeaders = new List<SchemaHeaderField>();
diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss
index 060e72b7a..6450cdae7 100644
--- a/src/client/views/collections/CollectionViewChromes.scss
+++ b/src/client/views/collections/CollectionViewChromes.scss
@@ -42,6 +42,11 @@
                 transform-origin: top left;
                 // margin-top: 10px;
             }
+            .collectionViewBaseChrome-template {
+                margin-left: 10px;
+                display: grid;
+                background: rgb(238, 238, 238);
+            }
 
             .collectionViewBaseChrome-viewSpecs {
                 margin-left: 10px;
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 000e7b276..e6afc69aa 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -296,6 +296,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                                 </div>
                             </div>
                         </div>
+                        <div className="collectionViewBaseChrome-template" style={{}}>
+                            TEMPLATE
+                        </div>
                     </div>
                     {this.subChrome()}
                 </div>
-- 
cgit v1.2.3-70-g09d2


From 2eb7d4e96a48dc841cece27afac7f6b1d2609ae9 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 15 Aug 2019 16:03:33 -0400
Subject: added childLayout target -- only works for stackingpanel right now.

---
 .../views/collections/CollectionStackingView.tsx   | 16 ++++++++++++++-
 .../views/collections/CollectionViewChromes.scss   |  3 +++
 .../views/collections/CollectionViewChromes.tsx    | 24 +++++++++++++++++++++-
 3 files changed, 41 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 9900049c1..c3c1f2108 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -59,7 +59,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         if (!this.sectionFilter || this.sectionHeaders instanceof Promise) return new Map<SchemaHeaderField, Doc[]>();
 
         if (this.sectionHeaders === undefined) {
-            this.props.Document.sectionHeaders = new List<SchemaHeaderField>();
+            setTimeout(() => this.props.Document.sectionHeaders = new List<SchemaHeaderField>(), 0);
+            return new Map<SchemaHeaderField, Doc[]>();
         }
         const sectionHeaders = this.sectionHeaders!;
         let fields = new Map<SchemaHeaderField, Doc[]>(sectionHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
@@ -83,7 +84,19 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return fields;
     }
 
+    childLayoutDisposer?: IReactionDisposer;
     componentDidMount() {
+        this.childLayoutDisposer = reaction(() => this.props.Document.childLayout,
+            async () => {
+                let chidlLayout = Cast(this.props.Document.childLayout, Doc);
+                if (chidlLayout instanceof Doc) {
+                    const childLayout = chidlLayout;
+                    let list = await this.childDocList;
+                    list && list.map(async doc => {
+                        !Doc.AreProtosEqual(childLayout, (await doc).layout as Doc) && Doc.ApplyTemplateTo(childLayout, (await doc), undefined);
+                    });
+                }
+            });
         // is there any reason this needs to exist? -syip.  yes, it handles autoHeight for stacking views (masonry isn't yet supported).
         this._heightDisposer = reaction(() => {
             if (this.isStackingView && BoolCast(this.props.Document.autoHeight)) {
@@ -108,6 +121,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         );
     }
     componentWillUnmount() {
+        this.childLayoutDisposer && this.childLayoutDisposer();
         this._heightDisposer && this._heightDisposer();
         this._sectionFilterDisposer && this._sectionFilterDisposer();
     }
diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss
index 6450cdae7..a13de6df5 100644
--- a/src/client/views/collections/CollectionViewChromes.scss
+++ b/src/client/views/collections/CollectionViewChromes.scss
@@ -46,6 +46,9 @@
                 margin-left: 10px;
                 display: grid;
                 background: rgb(238, 238, 238);
+                color:grey;
+                margin-top:auto;
+                margin-bottom:auto;
             }
 
             .collectionViewBaseChrome-viewSpecs {
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index e6afc69aa..470085932 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -21,6 +21,7 @@ import { listSpec } from "../../../new_fields/Schema";
 import { List } from "../../../new_fields/List";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { threadId } from "worker_threads";
+import { DragManager } from "../../util/DragManager";
 const datepicker = require('js-datepicker');
 
 interface CollectionViewChromeProps {
@@ -221,6 +222,27 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
             })} />);
     }
 
+    private dropDisposer?: DragManager.DragDropDisposer;
+    protected createDropTarget = (ele: HTMLDivElement) => {
+        this.dropDisposer && this.dropDisposer();
+        if (ele) {
+            this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
+        }
+    }
+
+    @undoBatch
+    @action
+    protected drop(e: Event, de: DragManager.DropEvent): boolean {
+        if (de.data instanceof DragManager.DocumentDragData) {
+            if (de.data.draggedDocuments.length) {
+                this.props.CollectionView.props.Document.childLayout = de.data.draggedDocuments[0];
+                e.stopPropagation();
+                return true;
+            }
+        }
+        return true;
+    }
+
     render() {
         let collapsed = this.props.CollectionView.props.Document.chromeStatus !== "enabled";
         return (
@@ -296,7 +318,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
                                 </div>
                             </div>
                         </div>
-                        <div className="collectionViewBaseChrome-template" style={{}}>
+                        <div className="collectionViewBaseChrome-template" ref={this.createDropTarget} style={{}}>
                             TEMPLATE
                         </div>
                     </div>
-- 
cgit v1.2.3-70-g09d2


From b6b18c2243fb6b6c0e0850962d433b0bb08753c9 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 15 Aug 2019 16:37:18 -0400
Subject: made child layouts sticky.

---
 .../views/collections/CollectionStackingView.tsx      | 19 ++++++-------------
 .../collectionFreeForm/CollectionFreeFormView.tsx     | 12 +++++++++---
 src/new_fields/Doc.ts                                 |  3 ++-
 3 files changed, 17 insertions(+), 17 deletions(-)

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

diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index c3c1f2108..4add7774e 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -29,6 +29,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     _masonryGridRef: HTMLDivElement | null = null;
     _draggerRef = React.createRef<HTMLDivElement>();
     _heightDisposer?: IReactionDisposer;
+    _childLayoutDisposer?: IReactionDisposer;
     _sectionFilterDisposer?: IReactionDisposer;
     _docXfs: any[] = [];
     _columnStart: number = 0;
@@ -84,19 +85,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         return fields;
     }
 
-    childLayoutDisposer?: IReactionDisposer;
     componentDidMount() {
-        this.childLayoutDisposer = reaction(() => this.props.Document.childLayout,
-            async () => {
-                let chidlLayout = Cast(this.props.Document.childLayout, Doc);
-                if (chidlLayout instanceof Doc) {
-                    const childLayout = chidlLayout;
-                    let list = await this.childDocList;
-                    list && list.map(async doc => {
-                        !Doc.AreProtosEqual(childLayout, (await doc).layout as Doc) && Doc.ApplyTemplateTo(childLayout, (await doc), undefined);
-                    });
-                }
-            });
+        this._childLayoutDisposer = reaction(() => [this.childDocs, Cast(this.props.Document.childLayout, Doc)],
+            async (args) => args[1] instanceof Doc &&
+                this.childDocs.map(async doc => !Doc.AreProtosEqual(args[1] as Doc, (await doc).layout as Doc) && Doc.ApplyTemplateTo(args[1] as Doc, (await doc), undefined)));
+
         // is there any reason this needs to exist? -syip.  yes, it handles autoHeight for stacking views (masonry isn't yet supported).
         this._heightDisposer = reaction(() => {
             if (this.isStackingView && BoolCast(this.props.Document.autoHeight)) {
@@ -121,7 +114,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
         );
     }
     componentWillUnmount() {
-        this.childLayoutDisposer && this.childLayoutDisposer();
+        this._childLayoutDisposer && this._childLayoutDisposer();
         this._heightDisposer && this._heightDisposer();
         this._sectionFilterDisposer && this._sectionFilterDisposer();
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 0501bf929..ed7d9a02e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,7 +1,7 @@
 import { library } from "@fortawesome/fontawesome-svg-core";
 import { faEye } from "@fortawesome/free-regular-svg-icons";
 import { faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faPaintBrush, faTable, faUpload, faChalkboard, faBraille } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, observable } from "mobx";
+import { action, computed, observable, IReactionDisposer, reaction } from "mobx";
 import { observer } from "mobx-react";
 import { Doc, DocListCastAsync, HeightSym, WidthSym, DocListCast, FieldResult, Field, Opt } from "../../../../new_fields/Doc";
 import { Id } from "../../../../new_fields/FieldSymbols";
@@ -192,9 +192,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     private get _pwidth() { return this.props.PanelWidth(); }
     private get _pheight() { return this.props.PanelHeight(); }
     private inkKey = "ink";
+    private _childLayoutDisposer?: IReactionDisposer;
 
-    constructor(props: any) {
-        super(props);
+    componentDidMount() {
+        this._childLayoutDisposer = reaction(() => [this.childDocs, Cast(this.props.Document.childLayout, Doc)],
+            async (args) => args[1] instanceof Doc &&
+                this.childDocs.map(async doc => !Doc.AreProtosEqual(args[1] as Doc, (await doc).layout as Doc) && Doc.ApplyTemplateTo(args[1] as Doc, (await doc), undefined)));
+    }
+    componentWillUnmount() {
+        this._childLayoutDisposer && this._childLayoutDisposer();
     }
 
     get parentScaling() {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index bd99a5008..d634cf57f 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -7,7 +7,7 @@ import { Cast, ToConstructor, PromiseValue, FieldValue, NumCast, BoolCast, StrCa
 import { listSpec } from "./Schema";
 import { ObjectField } from "./ObjectField";
 import { RefField, FieldId } from "./RefField";
-import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id } from "./FieldSymbols";
+import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id, Copy } from "./FieldSymbols";
 import { scriptingGlobal, CompileScript, Scripting } from "../client/util/Scripting";
 import { List } from "./List";
 import { DocumentType } from "../client/documents/Documents";
@@ -526,6 +526,7 @@ export namespace Doc {
         target.nativeHeight = Doc.GetProto(target).nativeHeight = undefined;
         target.width = templateDoc.width;
         target.height = templateDoc.height;
+        target.onClick = templateDoc.onClick instanceof ObjectField && templateDoc.onClick[Copy]();
         Doc.GetProto(target).type = DocumentType.TEMPLATE;
         if (targetData && targetData.layout === target) {
             targetData.layout = temp;
-- 
cgit v1.2.3-70-g09d2

