From cf6949fd114c2619caeaeda0652b1f3a36a69d99 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 21 Oct 2019 01:31:29 -0400
Subject: start of ImageBox cleanup

---
 src/client/views/collections/CollectionMasonryViewFieldRow.tsx | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 1709b9c99..4259e948b 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -4,12 +4,12 @@ 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 { Doc, WidthSym } from "../../../new_fields/Doc";
-import { Id } from "../../../new_fields/FieldSymbols";
+import Measure from "react-measure";
+import { Doc } from "../../../new_fields/Doc";
 import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { ScriptField } from "../../../new_fields/ScriptField";
-import { NumCast, StrCast } from "../../../new_fields/Types";
-import { Utils, numberRange } from "../../../Utils";
+import { StrCast } from "../../../new_fields/Types";
+import { numberRange } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import { CompileScript } from "../../util/Scripting";
@@ -20,7 +20,6 @@ import { anchorPoints, Flyout } from "../DocumentDecorations";
 import { EditableView } from "../EditableView";
 import { CollectionStackingView } from "./CollectionStackingView";
 import "./CollectionStackingView.scss";
-import Measure from "react-measure";
 
 library.add(faPalette);
 
-- 
cgit v1.2.3-70-g09d2


From c97b98c165e318da787361b8fc11382b0b98afa4 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 24 Oct 2019 11:54:03 -0400
Subject: several fixes to audioboxes.

---
 src/client/documents/Documents.ts                  |  3 ++-
 .../collections/CollectionMasonryViewFieldRow.tsx  |  2 +-
 .../views/collections/CollectionStackingView.scss  |  5 ++++
 .../CollectionFreeFormLinkView.scss                |  1 +
 .../CollectionFreeFormLinkView.tsx                 |  3 +++
 src/client/views/nodes/AudioBox.scss               | 28 ++++++++++++++--------
 src/client/views/nodes/AudioBox.tsx                | 19 +++++++--------
 src/client/views/nodes/DocuLinkBox.tsx             |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  2 +-
 9 files changed, 40 insertions(+), 25 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index f26594e04..d1fcabc4a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -171,7 +171,7 @@ export namespace Docs {
             }],
             [DocumentType.AUDIO, {
                 layout: { view: AudioBox, dataField: data },
-                options: { height: 35, backgroundColor: "lightGray", borderRounding: "20%" }
+                options: { height: 35, backgroundColor: "lightGray" }
             }],
             [DocumentType.PDF, {
                 layout: { view: PDFBox, dataField: data },
@@ -714,6 +714,7 @@ export namespace DocUtils {
             linkDocProto.anchor2Timecode = target.doc.currentTimecode;
             linkDocProto.layoutKey1 = DocuLinkBox.LayoutString("anchor1");
             linkDocProto.layoutKey2 = DocuLinkBox.LayoutString("anchor2");
+            linkDocProto.borderRounding = "20";
             linkDocProto.width = linkDocProto.height = 0;
             linkDocProto.isBackground = true;
             linkDocProto.isButton = true;
diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 4259e948b..0249b90b4 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -366,7 +366,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
                         >
                             {headingView}
                             {collapsed ? (null) :
-                                < div >
+                                < div style={{ position: "relative" }}>
                                     <div key={`${heading}-stack`} className={`collectionStackingView-masonryGrid`}
                                         ref={this._contRef}
                                         style={{
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 3f4b678c7..1ff2275d4 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -21,6 +21,11 @@
     overflow-y: auto;
     flex-wrap: wrap;
     transition: top .5s;
+    >div {
+        height: 100%;
+        position: relative;
+        display: inline-block;
+    }
 
     .collectionSchemaView-previewDoc {
         height: 100%;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
index 1f1bca2f2..75af11537 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss
@@ -3,6 +3,7 @@
     opacity: 0.8;
     pointer-events: all;
     stroke-width: 3px;
+    transition: opacity 0.5s ease-in;
 }
 .collectionfreeformlinkview-linkCircle {
     stroke: rgb(0,0,0);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 962fe2a1c..837413842 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -17,10 +17,12 @@ export interface CollectionFreeFormLinkViewProps {
 @observer
 export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFormLinkViewProps> {
     @observable _alive: number = 0;
+    @observable _opacity: number = 1;
     @action
     componentDidMount() {
         this._alive = 1;
         setTimeout(this.rerender, 50);
+        setTimeout(action(() => this._opacity = 0.05), 50);
     }
     @action
     componentWillUnmount() {
@@ -42,6 +44,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         let pt1 = Utils.getNearestPointInPerimeter(a.left, a.top, a.width, a.height, b.left + b.width / 2, b.top + b.height / 2);
         let pt2 = Utils.getNearestPointInPerimeter(b.left, b.top, b.width, b.height, a.left + a.width / 2, a.top + a.height / 2);
         return (<line key="linkLine" className="collectionfreeformlinkview-linkLine"
+            style={{ opacity: this._opacity }}
             x1={`${pt1[0]}`} y1={`${pt1[1]}`}
             x2={`${pt2[0]}`} y2={`${pt2[1]}`} />);
     }
diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss
index ccbf0d75f..3b19a6dba 100644
--- a/src/client/views/nodes/AudioBox.scss
+++ b/src/client/views/nodes/AudioBox.scss
@@ -44,22 +44,27 @@
             width:100%;
             height: 80%;
             position: relative;
+            padding-right: 5px;
             display: flex;
             .audiobox-playhead {
                 position: relative;
                 margin-top: auto;
                 margin-bottom: auto;
                 width: 25px;
+                padding: 2px;
             }
             .audiobox-timeline {
                 position:relative;
                 height:100%;
                 width:100%;
+                background: white;
+                border: gray solid 1px;
+                border-radius: 3px;
                 .audiobox-current {
                     width: 1px;
                     height:100%;
                     background-color: red;
-                    position: absolute;;
+                    position: absolute;
                 }
                 .audiobox-linker, .audiobox-linker-mini {
                     position:absolute;
@@ -72,10 +77,11 @@
                     background-color: transparent;
                     box-shadow: black 2px 2px 1px;
                     .docuLinkBox-cont {
-                        width:15px !important;
-                        height:15px !important;
-                        left: calc(100% - 15px) !important;
-                        top: calc(100% - 15px) !important;
+                        position: relative !important;
+                        height: 100%  !important;
+                        width: 100% !important;
+                        left:unset !important;
+                        top:unset !important;
                     }
                 }
                 .audiobox-linker-mini {
@@ -86,10 +92,11 @@
                     margin-left: -1;
                     margin-top: -2;
                     .docuLinkBox-cont {
-                        width:8px !important;
-                        height:8px !important;
-                        left: calc(100% - 8px) !important;
-                        top: calc(100% - 8px) !important;
+                        position: relative !important;
+                        height: 100%  !important;
+                        width: 100% !important;
+                        left:unset !important;
+                        top:unset !important;
                     }
                 }
                 .audiobox-linker:hover, .audiobox-linker-mini:hover {
@@ -98,7 +105,8 @@
                 .audiobox-marker-container, .audiobox-marker-minicontainer {
                     position:absolute;
                     width:10px;
-                    height:100%;
+                    height:90%;
+                    top:2.5%;
                     background:gray;
                     border-radius: 5px;
                     box-shadow: black 2px 2px 1px;
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index cc1c63d44..bd1caaf1b 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -12,12 +12,11 @@ import { RouteStore } from "../../../server/RouteStore";
 import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx";
 import { DateField } from "../../../new_fields/DateField";
 import { SelectionManager } from "../../util/SelectionManager";
-import { Doc, DocListCast, WidthSym } from "../../../new_fields/Doc";
+import { Doc, DocListCast } from "../../../new_fields/Doc";
 import { ContextMenuProps } from "../ContextMenuItem";
 import { ContextMenu } from "../ContextMenu";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { DocumentManager } from "../../util/DocumentManager";
 import { DocumentView } from "./DocumentView";
 
 interface Window {
@@ -59,7 +58,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
                 scrollLinkId && DocListCast(this.dataDoc.links).filter(l => l[Id] === scrollLinkId).map(l => {
                     let la1 = l.anchor1 as Doc;
                     let linkTime = Doc.AreProtosEqual(la1, this.dataDoc) ? NumCast(l.anchor1Timecode) : NumCast(l.anchor2Timecode);
-                    setTimeout(() => this.playFrom(linkTime), 250);
+                    setTimeout(() => { this.playFrom(linkTime); Doc.linkFollowHighlight(l); }, 250);
                 });
                 scrollLinkId && Doc.SetInPlace(this.layoutDoc, "scrollToLinkID", undefined, false);
             }, { fireImmediately: true });
@@ -75,11 +74,9 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
     }
 
     timecodeChanged = () => {
-        const extensionDoc = this.extensionDoc;
         const htmlEle = this._ele;
-        const start = extensionDoc && DateCast(extensionDoc.recordingStart);
-        if (start && htmlEle) {
-            htmlEle && htmlEle.duration && htmlEle.duration !== Infinity && runInAction(() => this.dataDoc.duration = htmlEle.duration);
+        if (this._audioState === "recorded" && htmlEle) {
+            htmlEle.duration && htmlEle.duration !== Infinity && runInAction(() => this.dataDoc.duration = htmlEle.duration);
             DocListCast(this.dataDoc.links).map(l => {
                 let la1 = l.anchor1 as Doc;
                 let linkTime = NumCast(l.anchor2Timecode);
@@ -195,7 +192,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
     }
 
     setRef = (e: HTMLAudioElement | null) => {
-        e && e.addEventListener("timeupdate", action(() => this.Document.currentTimecode = e!.currentTime));
+        e && e.addEventListener("timeupdate", this.timecodeChanged);
         this._ele = e;
     }
 
@@ -225,13 +222,13 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume
                     </button> :
                     <div className="audiobox-controls">
                         <div className="audiobox-player" onClick={this.onPlay}>
-                            <FontAwesomeIcon className="audiobox-playhead" icon={this._playing ? "pause" : "play"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} />
-                            <div className="audiobox-playhead" onClick={this.onStop}><FontAwesomeIcon className="audiobox-playhead" icon="stop" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div>
+                            <div className="audiobox-playhead"> <FontAwesomeIcon style={{ width: "100%" }} icon={this._playing ? "pause" : "play"} size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div>
+                            <div className="audiobox-playhead" onClick={this.onStop}><FontAwesomeIcon style={{ width: "100%" }} icon="stop" size={this.props.PanelHeight() < 36 ? "1x" : "2x"} /></div>
                             <div className="audiobox-timeline" onClick={e => e.stopPropagation()}
                                 onPointerDown={e => {
                                     if (e.button === 0 && !e.ctrlKey) {
                                         let rect = (e.target as any).getBoundingClientRect();
-                                        this._ele!.currentTime = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
+                                        this._ele!.currentTime = this.Document.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration);
                                         this.pause();
                                         e.stopPropagation();
                                     }
diff --git a/src/client/views/nodes/DocuLinkBox.tsx b/src/client/views/nodes/DocuLinkBox.tsx
index f2ab6fcd8..8f68effe8 100644
--- a/src/client/views/nodes/DocuLinkBox.tsx
+++ b/src/client/views/nodes/DocuLinkBox.tsx
@@ -73,7 +73,7 @@ export class DocuLinkBox extends DocComponent<FieldViewProps, DocLinkSchema>(Doc
         let c = StrCast(this.props.Document.backgroundColor, "lightblue");
         return <div className="docuLinkBox-cont" onPointerDown={this.onPointerDown} onClick={this.onClick} title={StrCast((this.props.Document[this.props.fieldKey === "anchor1" ? "anchor2" : "anchor1"]! as Doc).title)}
             ref={this._ref} style={{
-                background: c, width: "25px", left: `calc(${x}% - 12.5px)`, top: `calc(${y}% - 12.5px)`,
+                background: c, left: `calc(${x}% - 12.5px)`, top: `calc(${y}% - 12.5px)`,
                 transform: `scale(${hasAnchor ? 0.333 : 1 / this.props.ContentScaling()})`
             }} />;
     }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 566b698bd..cf55a10ba 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -192,7 +192,7 @@ export class FormattedTextBox extends DocExtendableComponent<(FieldViewProps & F
             }
 
             let tsel = this._editorView.state.selection.$from;
-            tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 5000 - 5000)));
+            tsel.marks().filter(m => m.type === this._editorView!.state.schema.marks.user_mark).map(m => AudioBox.SetScrubTime(Math.max(0, m.attrs.modified * 5000 - 1000)));
             this._applyingChange = true;
             this.extensionDoc && (this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n"));
             this.extensionDoc && (this.extensionDoc.lastModified = new DateField(new Date(Date.now())));
-- 
cgit v1.2.3-70-g09d2


From 93bbfe84f126c8f02ec2756b8bc236cb93c40d88 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 24 Oct 2019 19:43:46 -0400
Subject: some fixes for stacking view layouts

---
 .../collections/CollectionMasonryViewFieldRow.tsx  | 96 +++++++---------------
 .../views/collections/CollectionStackingView.scss  |  6 +-
 .../authentication/models/current_user_utils.ts    | 11 +--
 3 files changed, 39 insertions(+), 74 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index 0249b90b4..d885f558e 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -20,6 +20,7 @@ import { anchorPoints, Flyout } from "../DocumentDecorations";
 import { EditableView } from "../EditableView";
 import { CollectionStackingView } from "./CollectionStackingView";
 import "./CollectionStackingView.scss";
+import { undo } from "prosemirror-history";
 
 library.add(faPalette);
 
@@ -40,27 +41,28 @@ interface CMVFieldRowProps {
 export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowProps> {
     @observable private _background = "inherit";
     @observable private _createAliasSelected: boolean = false;
+    @observable private _collapsed: boolean = false;
+    @observable private _headingsHack: number = 1;
+    @observable private _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
+    @observable private _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
 
-    private _dropRef: HTMLDivElement | null = null;
-    private dropDisposer?: DragManager.DragDropDisposer;
+    private _dropDisposer?: DragManager.DragDropDisposer;
     private _headerRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _startDragPosition: { x: number, y: number } = { x: 0, y: 0 };
     private _contRef: React.RefObject<HTMLDivElement> = React.createRef();
     private _sensitivity: number = 16;
+    private _counter: number = 0;
 
-    @observable _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
-    @observable _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
 
     createRowDropRef = (ele: HTMLDivElement | null) => {
-        this._dropRef = ele;
-        this.dropDisposer && this.dropDisposer();
+        this._dropDisposer && this._dropDisposer();
         if (ele) {
-            this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.rowDrop.bind(this) } });
+            this._dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.rowDrop.bind(this) } });
         }
     }
 
     getTrueHeight = () => {
-        if (this.collapsed) {
+        if (this._collapsed) {
             this.props.setDocHeight(this._heading, 20);
         } else {
             let rawHeight = this._contRef.current!.getBoundingClientRect().height + 15; //+ 15 accounts for the group header
@@ -76,12 +78,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         if (de.data instanceof DragManager.DocumentDragData) {
             let key = StrCast(this.props.parent.props.Document.sectionFilter);
             let castedValue = this.getValue(this._heading);
-            if (castedValue) {
-                de.data.droppedDocuments.forEach(d => d[key] = castedValue);
-            }
-            else {
-                de.data.droppedDocuments.forEach(d => d[key] = undefined);
-            }
+            de.data.droppedDocuments.forEach(d => d[key] = castedValue);
             this.props.parent.drop(e, de);
             e.stopPropagation();
         }
@@ -89,15 +86,9 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
 
     getValue = (value: string): any => {
         let parsed = parseInt(value);
-        if (!isNaN(parsed)) {
-            return parsed;
-        }
-        if (value.toLowerCase().indexOf("true") > -1) {
-            return true;
-        }
-        if (value.toLowerCase().indexOf("false") > -1) {
-            return false;
-        }
+        if (!isNaN(parsed)) return parsed;
+        if (value.toLowerCase().indexOf("true") > -1) return true;
+        if (value.toLowerCase().indexOf("false") > -1) return false;
         return value;
     }
 
@@ -131,12 +122,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         }
     }
 
-    @action
-    pointerEnteredRow = () => {
-        if (SelectionManager.GetIsDragging()) {
-            this._background = "#b4b4b4";
-        }
-    }
+    pointerEnteredRow = action(() => SelectionManager.GetIsDragging() && (this._background = "#b4b4b4"));
 
     @action
     pointerLeaveRow = () => {
@@ -154,8 +140,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         return this.props.parent.props.addDocument(newDoc);
     }
 
-    @action
-    deleteRow = () => {
+    deleteRow = undoBatch(action(() => {
         this._createAliasSelected = false;
         let key = StrCast(this.props.parent.props.Document.sectionFilter);
         this.props.docList.forEach(d => d[key] = undefined);
@@ -163,7 +148,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
             let index = this.props.parent.sectionHeaders.indexOf(this.props.headingObject);
             this.props.parent.sectionHeaders.splice(index, 1);
         }
-    }
+    }));
 
     @action
     collapseSection = () => {
@@ -205,6 +190,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         document.removeEventListener("pointerup", this.pointerUp);
     }
 
+    @action
     headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
         e.stopPropagation();
         e.preventDefault();
@@ -251,48 +237,31 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         );
     }
 
-    @action
-    toggleAlias = () => {
-        this._createAliasSelected = true;
-    }
+    toggleAlias = action(() => this._createAliasSelected = true);
+    toggleVisibility = action(() => this._collapsed = !this._collapsed);
 
     renderMenu = () => {
         let selected = this._createAliasSelected;
-        return (
-            <div className="collectionStackingView-optionPicker">
-                <div className="optionOptions">
-                    <div className={"optionPicker" + (selected === true ? " active" : "")} onClick={this.toggleAlias}>Create Alias</div>
-                </div>
+        return (<div className="collectionStackingView-optionPicker">
+            <div className="optionOptions">
+                <div className={"optionPicker" + (selected === true ? " active" : "")} onClick={this.toggleAlias}>Create Alias</div>
+                <div className={"optionPicker" + (selected === true ? " active" : "")} onClick={this.deleteRow}>Delete</div>
             </div>
-        );
+        </div>);
     }
 
-    @observable private collapsed: boolean = false;
-
-    private toggleVisibility = action(() => {
-        this.collapsed = !this.collapsed;
-    });
-
-    @observable _headingsHack: number = 1;
-
     handleResize = (size: any) => {
-        this.counter += 1;
-        if (this.counter !== 1) {
+        if (++this._counter !== 1) {
             this.getTrueHeight();
         }
     }
 
-    private counter: number = 0;
 
     render() {
-        let cols = this.props.rows();
         let rows = Math.max(1, Math.min(this.props.docList.length, Math.floor((this.props.parent.props.PanelWidth() - 2 * this.props.parent.xMargin) / (this.props.parent.columnWidth + this.props.parent.gridGap))));
         let key = StrCast(this.props.parent.props.Document.sectionFilter);
-        let templatecols = "";
-        let headings = this.props.headings();
         let heading = this._heading;
         let style = this.props.parent;
-        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 = {
             GetValue: () => evContents,
@@ -315,7 +284,6 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
         };
         let headingView = this.props.headingObject ?
             <div className="collectionStackingView-sectionHeader" ref={this._headerRef} >
-                <div className={"collectionStackingView-collapseBar" + (this.props.headingObject.collapsed === true ? " active" : "")} onClick={this.collapseSection}></div>
                 <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown}
                     title={evContents === `NO ${key.toUpperCase()} VALUE` ?
                         `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""}
@@ -334,16 +302,14 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
                             </ Flyout >
                         </div>
                     }
-                    {evContents === `NO ${key.toUpperCase()} VALUE` ?
-                        (null) :
-                        <button className="collectionStackingView-sectionDelete" onClick={this.deleteRow}>
-                            <FontAwesomeIcon icon="trash" size="lg" />
-                        </button>}
+                    <button className="collectionStackingView-sectionDelete" onClick={this.collapseSection}>
+                        <FontAwesomeIcon icon={this._collapsed ? "chevron-down" : "chevron-up"} size="lg" />
+                    </button>
                     {evContents === `NO  ${key.toUpperCase()} VALUE` ? (null) :
                         <div className="collectionStackingView-sectionOptions">
                             <Flyout anchorPoint={anchorPoints.TOP_RIGHT} content={this.renderMenu()}>
                                 <button className="collectionStackingView-sectionOptionButton">
-                                    <FontAwesomeIcon icon="ellipsis-v" size="lg"></FontAwesomeIcon>
+                                    <FontAwesomeIcon icon="ellipsis-v" size="lg" />
                                 </button>
                             </Flyout>
                         </div>
@@ -351,7 +317,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
                 </div>
             </div > : (null);
         const background = this._background; //to account for observables in Measure
-        const collapsed = this.collapsed;
+        const collapsed = this._collapsed;
         let chromeStatus = this.props.parent.props.Document.chromeStatus;
         return (
             <Measure offset onResize={this.handleResize}>
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 1ff2275d4..f5530ab26 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -22,9 +22,8 @@
     flex-wrap: wrap;
     transition: top .5s;
     >div {
-        height: 100%;
         position: relative;
-        display: inline-block;
+        display: block;
     }
 
     .collectionSchemaView-previewDoc {
@@ -227,7 +226,6 @@
             }
 
             .collectionStackingView-optionPicker {
-                width: 78px;
 
                 .optionOptions {
                     display: inline;
@@ -235,10 +233,10 @@
 
                 .optionPicker {
                     cursor: pointer;
-                    width: 20px;
                     height: 20px;
                     border-radius: 10px;
                     margin: 3px;
+                    width:max-content;
 
                     &.active {
                         color: red;
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index ee9794564..56ea5bfe1 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -71,7 +71,7 @@ export class CurrentUserUtils {
     }
 
     // setup the Creator button which will display the creator panel.  This panel will include the drag creators and the color picker.  when clicked, this panel will be displayed in the target container (ie, sidebarContainer)  
-    static setupCreatePanel(sidebarContainer: Doc, doc: Doc) {
+    static setupToolsPanel(sidebarContainer: Doc, doc: Doc) {
         // setup a masonry view of all he creators
         const dragCreators = Docs.Create.MasonryDocument(CurrentUserUtils.setupCreatorButtons(doc), {
             width: 500, autoHeight: true, columnWidth: 35, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "buttons",
@@ -83,9 +83,9 @@ export class CurrentUserUtils {
         });
 
         return Docs.Create.ButtonDocument({
-            width: 35, height: 35, borderRounding: "50%", boxShadow: "2px 2px 1px", title: "Create", targetContainer: sidebarContainer,
+            width: 35, height: 35, borderRounding: "50%", boxShadow: "2px 2px 1px", title: "Tools", targetContainer: sidebarContainer,
             sourcePanel: Docs.Create.StackingDocument([dragCreators, color], {
-                width: 500, height: 800, chromeStatus: "disabled", title: "creator stack"
+                width: 500, height: 800, lockedPosition: true, chromeStatus: "disabled", title: "tools stack"
             }),
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"),
         });
@@ -125,6 +125,7 @@ export class CurrentUserUtils {
                 title: "search stack", ignoreClick: true
             }),
             targetContainer: sidebarContainer,
+            lockedPosition: true,
             onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel")
         });
     }
@@ -135,12 +136,12 @@ export class CurrentUserUtils {
         (doc.sidebarContainer as Doc).chromeStatus = "disabled";
         (doc.sidebarContainer as Doc).onClick = ScriptField.MakeScript("freezeSidebar()");
 
-        doc.CreateBtn = this.setupCreatePanel(doc.sidebarContainer as Doc, doc);
+        doc.ToolsBtn = this.setupToolsPanel(doc.sidebarContainer as Doc, doc);
         doc.LibraryBtn = this.setupLibraryPanel(doc.sidebarContainer as Doc, doc);
         doc.SearchBtn = this.setupSearchPanel(doc.sidebarContainer as Doc);
 
         // Finally, setup the list of buttons to display in the sidebar
-        doc.sidebarButtons = Docs.Create.StackingDocument([doc.SearchBtn as Doc, doc.LibraryBtn as Doc, doc.CreateBtn as Doc], {
+        doc.sidebarButtons = Docs.Create.StackingDocument([doc.SearchBtn as Doc, doc.LibraryBtn as Doc, doc.ToolsBtn as Doc], {
             width: 500, height: 80, boxShadow: "0 0", sectionFilter: "title", hideHeadings: true, ignoreClick: true,
             backgroundColor: "lightgrey", chromeStatus: "disabled", title: "library stack"
         });
-- 
cgit v1.2.3-70-g09d2


From 2786a2e4b33ff874f320697b89fecec3105df201 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 24 Oct 2019 22:55:57 -0400
Subject: fixed some stacking view layout.  added a miniHeader layout for
 stacks

---
 .../collections/CollectionMasonryViewFieldRow.tsx  | 74 ++++++++++++----------
 .../views/collections/CollectionSchemaView.scss    |  1 -
 .../views/collections/CollectionStackingView.scss  | 33 +++++++++-
 .../views/collections/CollectionStackingView.tsx   |  7 +-
 .../CollectionStackingViewFieldColumn.tsx          |  2 +-
 5 files changed, 77 insertions(+), 40 deletions(-)

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

diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
index d885f558e..52ebfafd3 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -76,6 +76,8 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     rowDrop = action((e: Event, de: DragManager.DropEvent) => {
         this._createAliasSelected = false;
         if (de.data instanceof DragManager.DocumentDragData) {
+            (this.props.parent.Document.dropConverter instanceof ScriptField) &&
+                this.props.parent.Document.dropConverter.script.run({ dragData: de.data });
             let key = StrCast(this.props.parent.props.Document.sectionFilter);
             let castedValue = this.getValue(this._heading);
             de.data.droppedDocuments.forEach(d => d[key] = castedValue);
@@ -282,40 +284,44 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
             toggle: this.toggleVisibility,
             color: this._color
         };
-        let headingView = this.props.headingObject ?
-            <div className="collectionStackingView-sectionHeader" ref={this._headerRef} >
-                <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown}
-                    title={evContents === `NO ${key.toUpperCase()} VALUE` ?
-                        `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""}
-                    style={{
-                        width: "100%",
-                        background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : "lightgrey",
-                        color: "grey"
-                    }}>
-                    {<EditableView {...headerEditableViewProps} />}
-                    {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
-                        <div className="collectionStackingView-sectionColor">
-                            <Flyout anchorPoint={anchorPoints.CENTER_RIGHT} content={this.renderColorPicker()}>
-                                <button className="collectionStackingView-sectionColorButton">
-                                    <FontAwesomeIcon icon="palette" size="lg" />
-                                </button>
-                            </ Flyout >
-                        </div>
-                    }
-                    <button className="collectionStackingView-sectionDelete" onClick={this.collapseSection}>
-                        <FontAwesomeIcon icon={this._collapsed ? "chevron-down" : "chevron-up"} size="lg" />
-                    </button>
-                    {evContents === `NO  ${key.toUpperCase()} VALUE` ? (null) :
-                        <div className="collectionStackingView-sectionOptions">
-                            <Flyout anchorPoint={anchorPoints.TOP_RIGHT} content={this.renderMenu()}>
-                                <button className="collectionStackingView-sectionOptionButton">
-                                    <FontAwesomeIcon icon="ellipsis-v" size="lg" />
-                                </button>
-                            </Flyout>
-                        </div>
-                    }
-                </div>
-            </div > : (null);
+        let headingView = this.props.parent.props.Document.miniHeaders ?
+            <div className="collectionStackingView-miniHeader" style={{ width: "100%" }}>
+                {<EditableView {...headerEditableViewProps} />}
+            </div> :
+            this.props.headingObject ?
+                <div className="collectionStackingView-sectionHeader" ref={this._headerRef} >
+                    <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown}
+                        title={evContents === `NO ${key.toUpperCase()} VALUE` ?
+                            `Documents that don't have a ${key} value will go here. This column cannot be removed.` : ""}
+                        style={{
+                            width: "100%",
+                            background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : "lightgrey",
+                            color: "grey"
+                        }}>
+                        {<EditableView {...headerEditableViewProps} />}
+                        {evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
+                            <div className="collectionStackingView-sectionColor">
+                                <Flyout anchorPoint={anchorPoints.CENTER_RIGHT} content={this.renderColorPicker()}>
+                                    <button className="collectionStackingView-sectionColorButton">
+                                        <FontAwesomeIcon icon="palette" size="lg" />
+                                    </button>
+                                </ Flyout >
+                            </div>
+                        }
+                        <button className="collectionStackingView-sectionDelete" onClick={this.collapseSection}>
+                            <FontAwesomeIcon icon={this._collapsed ? "chevron-down" : "chevron-up"} size="lg" />
+                        </button>
+                        {evContents === `NO  ${key.toUpperCase()} VALUE` ? (null) :
+                            <div className="collectionStackingView-sectionOptions">
+                                <Flyout anchorPoint={anchorPoints.TOP_RIGHT} content={this.renderMenu()}>
+                                    <button className="collectionStackingView-sectionOptionButton">
+                                        <FontAwesomeIcon icon="ellipsis-v" size="lg" />
+                                    </button>
+                                </Flyout>
+                            </div>
+                        }
+                    </div>
+                </div > : (null);
         const background = this._background; //to account for observables in Measure
         const collapsed = this._collapsed;
         let chromeStatus = this.props.parent.props.Document.chromeStatus;
diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss
index e0cedc210..6a9392253 100644
--- a/src/client/views/collections/CollectionSchemaView.scss
+++ b/src/client/views/collections/CollectionSchemaView.scss
@@ -40,7 +40,6 @@
 
 .collectionSchemaView-previewRegion {
     position: relative;
-    background: $light-color;
     height: auto !important;
 
     .collectionSchemaView-previewDoc {
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index f5530ab26..29178b909 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -124,7 +124,38 @@
             background: red;
         }
     }
-
+    .collectionStackingView-miniHeader {
+        width: 100%;
+        .editableView-container-editing-oneLine {
+            min-height: 20px;
+            display: flex;
+            align-items: center;
+            flex-direction: row;
+        }
+        span::before , span::after{
+            content: "";
+            width: 50%;
+            border-top: dashed gray 1px;
+            position: relative;
+            display: inline-block;
+        }
+        span::before {
+            margin-right: 10px;
+        }
+        span::after{
+            margin-left: 10px;
+        }
+        span {
+            position: relative;
+            text-align: center;
+            white-space: nowrap;
+            overflow: visible;
+            width: 100%;
+            display: flex;
+            color:gray;
+            align-items: center;
+        }
+    }
     .collectionStackingView-sectionHeader {
         text-align: center;
         margin-left: 2px;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 96940acbc..7f0165ad4 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -44,7 +44,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); }
     @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.ContainingCollectionDoc && (this.props.ContainingCollectionDoc.chromeStatus !== 'view-mode' && this.props.ContainingCollectionDoc.chromeStatus !== 'disabled')); }
+    @computed get showAddAGroup() { return (this.sectionFilter && (this.props.Document.chromeStatus !== 'view-mode' && this.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));
@@ -121,7 +121,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                     return res;
                 } else {
                     let sum = Array.from(this._heightMap.values()).reduce((acc: number, curr: number) => acc += curr, 0);
-                    return this.props.ContentScaling() * (sum + (this.Sections.size ? 85 : -15));
+                    return this.props.ContentScaling() * (sum + (this.Sections.size ? (this.props.Document.miniHeaders ? 20 : 85) : -15));
                 }
             }
             return -1;
@@ -363,7 +363,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     onToggle = (checked: Boolean) => {
-        this.props.ContainingCollectionDoc && (this.props.ContainingCollectionDoc.chromeStatus = checked ? "collapsed" : "view-mode");
+        this.props.Document.chromeStatus = checked ? "collapsed" : "view-mode";
     }
 
     onContextMenu = (e: React.MouseEvent): void => {
@@ -393,6 +393,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             let entries = Array.from(this.Sections.entries());
             sections = entries.sort(this.sortFunc);
         }
+        console.log("NUM = " + this.numGroupColumns);
         return (
             <div className="collectionStackingMasonry-cont" >
                 <div className={this.isStackingView ? "collectionStackingView" : "collectionMasonryView"}
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index fec3d90b9..b9d334b10 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -295,7 +295,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
                 style={{
                     width: (style.columnWidth) /
                         ((uniqueHeadings.length +
-                            ((this.props.parent.props.ContainingCollectionDoc && this.props.parent.props.ContainingCollectionDoc.chromeStatus !== 'view-mode' && this.props.parent.props.ContainingCollectionDoc.chromeStatus !== 'disabled') ? 1 : 0)) || 1)
+                            ((this.props.parent.props.Document.chromeStatus !== 'view-mode' && this.props.parent.props.Document.chromeStatus !== 'disabled') ? 1 : 0)) || 1)
                 }}>
                 <div className={"collectionStackingView-collapseBar" + (this.props.headingObject.collapsed === true ? " active" : "")} onClick={this.collapseSection}></div>
                 {/* the default bucket (no key value) has a tooltip that describes what it is.
-- 
cgit v1.2.3-70-g09d2

