From 1c0e229f9c298281cdeab64532334e0b875cd2e4 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 27 Apr 2020 16:21:56 -0400
Subject: cleaned up masonry events a bit.  changed buxton template to have 3
 sections.

---
 .../collections/CollectionMasonryViewFieldRow.tsx  | 133 ++++++++-------------
 1 file changed, 49 insertions(+), 84 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 42f0c4311..3bada43f0 100644
--- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
+++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx
@@ -2,13 +2,13 @@ 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, computed, observable } from "mobx";
+import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { Doc } from "../../../new_fields/Doc";
 import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField";
 import { ScriptField } from "../../../new_fields/ScriptField";
 import { StrCast, NumCast } from "../../../new_fields/Types";
-import { numberRange } from "../../../Utils";
+import { numberRange, setupMoveUpEvents, emptyFunction } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import { CompileScript } from "../../util/Scripting";
@@ -44,37 +44,44 @@ 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 _heading = this.props.headingObject ? this.props.headingObject.heading : this.props.heading;
-    @observable private _color = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
+    @observable private heading: string = "";
+    @observable private color: string = "#f1efeb";
+    @observable private collapsed: boolean = false;
+    private set _heading(value: string) { runInAction(() => this.props.headingObject && (this.props.headingObject.heading = this.heading = value)); }
+    private set _color(value: string) { runInAction(() => this.props.headingObject && (this.props.headingObject.color = this.color = value)); }
+    private set _collapsed(value: boolean) { runInAction(() => this.props.headingObject && (this.props.headingObject.collapsed = this.collapsed = value)); }
 
     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 _ele: any;
 
     createRowDropRef = (ele: HTMLDivElement | null) => {
-        this._dropDisposer && this._dropDisposer();
+        this._dropDisposer?.();
         if (ele) {
             this._ele = ele;
             this.props.observeHeight(ele);
             this._dropDisposer = DragManager.MakeDropTarget(ele, this.rowDrop.bind(this));
         }
     }
+    @action
+    componentDidMount() {
+        this.heading = this.props.headingObject?.heading || "";
+        this.color = this.props.headingObject?.color || "#f1efeb";
+        this.collapsed = this.props.headingObject?.collapsed || false;
+    }
     componentWillUnmount() {
         this.props.unobserveHeight(this._ele);
     }
 
     getTrueHeight = () => {
-        if (this._collapsed) {
-            this.props.setDocHeight(this._heading, 20);
+        if (this.collapsed) {
+            this.props.setDocHeight(this.heading, 20);
         } else {
             const rawHeight = this._contRef.current!.getBoundingClientRect().height + 15; //+ 15 accounts for the group header
             const transformScale = this.props.screenToLocalTransform().Scale;
             const trueHeight = rawHeight * transformScale;
-            this.props.setDocHeight(this._heading, trueHeight);
+            this.props.setDocHeight(this.heading, trueHeight);
         }
     }
 
@@ -86,7 +93,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
             (this.props.parent.Document.dropConverter instanceof ScriptField) &&
                 this.props.parent.Document.dropConverter.script.run({ dragData: de.complete.docDragData });
             const key = StrCast(this.props.parent.props.Document._pivotField);
-            const castedValue = this.getValue(this._heading);
+            const castedValue = this.getValue(this.heading);
             de.complete.docDragData.droppedDocuments.forEach(d => d[key] = castedValue);
             this.props.parent.onInternalDrop(e, de);
             e.stopPropagation();
@@ -113,10 +120,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
                 }
             }
             this.props.docList.forEach(d => d[key] = castedValue);
-            if (this.props.headingObject) {
-                this.props.headingObject.setHeading(castedValue.toString());
-                this._heading = this.props.headingObject.heading;
-            }
+            this._heading = castedValue.toString();
             return true;
         }
         return false;
@@ -125,10 +129,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     @action
     changeColumnColor = (color: string) => {
         this._createAliasSelected = false;
-        if (this.props.headingObject) {
-            this.props.headingObject.setColor(color);
-            this._color = color;
-        }
+        this._color = color;
     }
 
     pointerEnteredRow = action(() => SelectionManager.GetIsDragging() && (this._background = "#b4b4b4"));
@@ -137,7 +138,6 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     pointerLeaveRow = () => {
         this._createAliasSelected = false;
         this._background = "inherit";
-        document.removeEventListener("pointermove", this.startDrag);
     }
 
     @action
@@ -161,65 +161,34 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     }));
 
     @action
-    collapseSection = () => {
+    collapseSection = (e: any) => {
         this._createAliasSelected = false;
-        if (this.props.headingObject) {
-            this.props.headingObject.setCollapsed(!this.props.headingObject.collapsed);
-            this.toggleVisibility();
-        }
-    }
-
-    startDrag = (e: PointerEvent) => {
-        const [dx, dy] = this.props.screenToLocalTransform().transformDirection(e.clientX - this._startDragPosition.x, e.clientY - this._startDragPosition.y);
-        if (Math.abs(dx) + Math.abs(dy) > this._sensitivity) {
-            const alias = Doc.MakeAlias(this.props.parent.props.Document);
-            const key = StrCast(this.props.parent.props.Document._pivotField);
-            let value = this.getValue(this._heading);
-            value = typeof value === "string" ? `"${value}"` : value;
-            const script = `return doc.${key} === ${value}`;
-            const compiled = CompileScript(script, { params: { doc: Doc.name } });
-            if (compiled.compiled) {
-                alias.viewSpecScript = new ScriptField(compiled);
-                DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY);
-            }
-
-            e.stopPropagation();
-            document.removeEventListener("pointermove", this.startDrag);
-            document.removeEventListener("pointerup", this.pointerUp);
-        }
-    }
-
-    pointerUp = (e: PointerEvent) => {
+        this.toggleVisibility();
         e.stopPropagation();
-        e.preventDefault();
+    }
 
-        if (this.props.parent.props.Document._chromeStatus === "disabled") {
-            this.collapseSection();
+    headerMove = (e: PointerEvent) => {
+        const alias = Doc.MakeAlias(this.props.parent.props.Document);
+        const key = StrCast(this.props.parent.props.Document._pivotField);
+        let value = this.getValue(this.heading);
+        value = typeof value === "string" ? `"${value}"` : value;
+        const script = `return doc.${key} === ${value}`;
+        const compiled = CompileScript(script, { params: { doc: Doc.name } });
+        if (compiled.compiled) {
+            alias.viewSpecScript = new ScriptField(compiled);
+            DragManager.StartDocumentDrag([this._headerRef.current!], new DragManager.DocumentDragData([alias]), e.clientX, e.clientY);
         }
-
-        document.removeEventListener("pointermove", this.startDrag);
-        document.removeEventListener("pointerup", this.pointerUp);
+        return true;
     }
 
     @action
     headerDown = (e: React.PointerEvent<HTMLDivElement>) => {
-        e.stopPropagation();
-        e.preventDefault();
-
-        const [dx, dy] = this.props.screenToLocalTransform().transformDirection(e.clientX, e.clientY);
-        this._startDragPosition = { x: dx, y: dy };
-
-        if (this.props.parent.props.Document._chromeStatus === "disabled" || this._createAliasSelected) {
-            document.removeEventListener("pointermove", this.startDrag);
-            document.addEventListener("pointermove", this.startDrag);
-            document.removeEventListener("pointerup", this.pointerUp);
-            document.addEventListener("pointerup", this.pointerUp);
-        }
+        setupMoveUpEvents(this, e, this.headerMove, emptyFunction, () => (this.props.parent.props.Document._chromeStatus === "disabled") && this.collapseSection(e));
         this._createAliasSelected = false;
     }
 
     renderColorPicker = () => {
-        const selected = this.props.headingObject ? this.props.headingObject.color : "#f1efeb";
+        const selected = this.color;
 
         const pink = PastelSchemaPalette.get("pink2");
         const purple = PastelSchemaPalette.get("purple4");
@@ -249,7 +218,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     }
 
     toggleAlias = action(() => this._createAliasSelected = true);
-    toggleVisibility = action(() => this._collapsed = !this._collapsed);
+    toggleVisibility = () => this._collapsed = !this.collapsed;
 
     renderMenu = () => {
         const selected = this._createAliasSelected;
@@ -264,7 +233,6 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     @computed get contentLayout() {
         const 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))));
         const style = this.props.parent;
-        const collapsed = this._collapsed;
         const chromeStatus = this.props.parent.props.Document._chromeStatus;
         const newEditableViewProps = {
             GetValue: () => "",
@@ -272,9 +240,9 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
             contents: "+ NEW",
             HeadingObject: this.props.headingObject,
             toggle: this.toggleVisibility,
-            color: this._color
+            color: this.color
         };
-        return collapsed ? (null) :
+        return this.collapsed ? (null) :
             <div style={{ position: "relative" }}>
                 {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ?
                     <div className="collectionStackingView-addDocumentButton"
@@ -300,10 +268,9 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
     }
 
     @computed get headingView() {
-        const heading = this._heading;
         const noChrome = this.props.parent.props.Document._chromeStatus === "disabled";
         const key = StrCast(this.props.parent.props.Document._pivotField);
-        const evContents = heading ? heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`;
+        const evContents = this.heading ? this.heading : this.props.type && this.props.type === "number" ? "0" : `NO ${key.toUpperCase()} VALUE`;
         const headerEditableViewProps = {
             GetValue: () => evContents,
             SetValue: this.headingChanged,
@@ -311,7 +278,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
             oneLine: true,
             HeadingObject: this.props.headingObject,
             toggle: this.toggleVisibility,
-            color: this._color
+            color: this.color
         };
         return this.props.parent.props.Document.miniHeaders ?
             <div className="collectionStackingView-miniHeader">
@@ -319,11 +286,11 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
             </div> :
             !this.props.headingObject ? (null) :
                 <div className="collectionStackingView-sectionHeader" ref={this._headerRef} >
-                    <div className="collectionStackingView-sectionHeader-subCont" onPointerDown={this.headerDown} onClick={noChrome ? undefined : this.collapseSection}
+                    <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={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this._color : "lightgrey" }}>
-                        <EditableView {...headerEditableViewProps} />
+                        style={{ background: evContents !== `NO ${key.toUpperCase()} VALUE` ? this.color : "lightgrey" }}>
+                        {noChrome ? evContents : <EditableView {...headerEditableViewProps} />}
                         {noChrome || evContents === `NO ${key.toUpperCase()} VALUE` ? (null) :
                             <div className="collectionStackingView-sectionColor">
                                 <Flyout anchorPoint={anchorPoints.CENTER_RIGHT} content={this.renderColorPicker()}>
@@ -334,7 +301,7 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
                             </div>
                         }
                         {noChrome ? (null) : <button className="collectionStackingView-sectionDelete" onClick={noChrome ? undefined : this.collapseSection}>
-                            <FontAwesomeIcon icon={this._collapsed ? "chevron-down" : "chevron-up"} size="lg" />
+                            <FontAwesomeIcon icon={this.collapsed ? "chevron-down" : "chevron-up"} size="lg" />
                         </button>}
                         {noChrome || evContents === `NO  ${key.toUpperCase()} VALUE` ? (null) :
                             <div className="collectionStackingView-sectionOptions">
@@ -349,17 +316,15 @@ export class CollectionMasonryViewFieldRow extends React.Component<CMVFieldRowPr
                 </div>;
     }
     render() {
-        const background = this._background; //to account for observables in Measure
-        const contentlayout = this.contentLayout;
-        const headingview = this.headingView;
+        const background = this._background;
         return <div className="collectionStackingView-masonrySection"
             style={{ width: this.props.parent.NodeWidth, background }}
             ref={this.createRowDropRef}
             onPointerEnter={this.pointerEnteredRow}
             onPointerLeave={this.pointerLeaveRow}
         >
-            {headingview}
-            {contentlayout}
+            {this.headingView}
+            {this.contentLayout}
         </div >;
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2

