From a51439a6569079ca2652ce28745317fecce3a353 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 24 Apr 2020 10:53:51 -0400
Subject: changing how multiple images are imported -- now a pile.  imagebox
 chooses render quality based on image width.

---
 src/client/views/collections/CollectionSubView.tsx | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index ca38a21b8..78ba3d6e6 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -398,8 +398,15 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
                 generatedDocuments.push(doc);
             }
             if (generatedDocuments.length) {
-                generatedDocuments.forEach(addDocument);
-                completed && completed();
+                const set = generatedDocuments.length > 1 && generatedDocuments.map(d => Doc.iconify(d));
+                if (set) {
+                    const pile = Docs.Create.FreeformDocument(generatedDocuments, { ...options, title: "pile", _LODdisable: true, });
+                    Doc.pileup(pile, generatedDocuments);
+                    addDocument(pile);
+                } else {
+                    generatedDocuments.forEach(addDocument);
+                }
+                completed?.();
             } else {
                 if (text && !text.includes("https://")) {
                     addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 }));
-- 
cgit v1.2.3-70-g09d2


From efd038bd12de35abc80141b130be523e3fea077a Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 25 Apr 2020 03:42:51 -0400
Subject: hopefully final cleanup of pile up collection view.   added doubleTap
 support in setupMoveUpEvents

---
 src/Utils.ts                                       | 12 ++-
 src/client/documents/Documents.ts                  |  4 +
 .../views/collections/CollectionPileView.scss      |  8 ++
 .../views/collections/CollectionPileView.tsx       | 97 ++++++++++++++++++++++
 src/client/views/collections/CollectionSubView.tsx |  4 +-
 .../views/collections/CollectionTimeView.tsx       |  3 +-
 src/client/views/collections/CollectionView.tsx    |  5 +-
 .../CollectionFreeFormLayoutEngines.tsx            | 95 ++++++++++-----------
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 19 +++--
 .../collections/collectionFreeForm/MarqueeView.tsx | 16 ++--
 src/new_fields/Doc.ts                              | 35 ++------
 11 files changed, 189 insertions(+), 109 deletions(-)
 create mode 100644 src/client/views/collections/CollectionPileView.scss
 create mode 100644 src/client/views/collections/CollectionPileView.tsx

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 9acdc8731..ad12c68a1 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -504,8 +504,9 @@ export function setupMoveUpEvents(
     e: React.PointerEvent,
     moveEvent: (e: PointerEvent, down: number[], delta: number[]) => boolean,
     upEvent: (e: PointerEvent) => void,
-    clickEvent: (e: PointerEvent) => void,
-    stopPropagation: boolean = true
+    clickEvent: (e: PointerEvent, doubleTap?: boolean) => void,
+    stopPropagation: boolean = true,
+    stopMovePropagation: boolean = true
 ) {
     (target as any)._downX = (target as any)._lastX = e.clientX;
     (target as any)._downY = (target as any)._lastY = e.clientY;
@@ -520,12 +521,15 @@ export function setupMoveUpEvents(
         }
         (target as any)._lastX = e.clientX;
         (target as any)._lastY = e.clientY;
-        e.stopPropagation();
+        stopMovePropagation && e.stopPropagation();
     };
+    (target as any)._doubleTap = false;
     const _upEvent = (e: PointerEvent): void => {
+        (target as any)._doubleTap = (Date.now() - (target as any)._lastTap < 300);
+        (target as any)._lastTap = Date.now();
         upEvent(e);
         if (Math.abs(e.clientX - (target as any)._downX) < 4 && Math.abs(e.clientY - (target as any)._downY) < 4) {
-            clickEvent(e);
+            clickEvent(e, (target as any)._doubleTap);
         }
         document.removeEventListener("pointermove", _moveEvent);
         document.removeEventListener("pointerup", _upEvent);
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 578d337d6..1268c97b0 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -612,6 +612,10 @@ export namespace Docs {
             return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Freeform }, id);
         }
 
+        export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
+            return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Pile }, id);
+        }
+
         export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
             return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", schemaColumns: new List([new SchemaHeaderField("title", "#f1efeb")]), ...options, _viewType: CollectionViewType.Linear }, id);
         }
diff --git a/src/client/views/collections/CollectionPileView.scss b/src/client/views/collections/CollectionPileView.scss
new file mode 100644
index 000000000..ac874b663
--- /dev/null
+++ b/src/client/views/collections/CollectionPileView.scss
@@ -0,0 +1,8 @@
+.collectionPileView {
+    display: flex;
+    flex-direction: row;
+    position: absolute;
+    height: 100%;
+    width: 100%;
+    overflow: visible;
+}
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
new file mode 100644
index 000000000..511efe0a7
--- /dev/null
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -0,0 +1,97 @@
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
+import { ScriptField } from "../../../new_fields/ScriptField";
+import { BoolCast, NumCast, StrCast } from "../../../new_fields/Types";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
+import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
+import { CollectionSubView } from "./CollectionSubView";
+import "./CollectionPileView.scss";
+import React = require("react");
+import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../../Utils";
+import { SelectionManager } from "../../util/SelectionManager";
+
+@observer
+export class CollectionPileView extends CollectionSubView(doc => doc) {
+    _lastTap = 0;
+    _doubleTap: boolean | undefined = false;
+    _originalChrome: string = "";
+    @observable _contentsActive = true;
+    @observable _layoutEngine = "pass";
+    @observable _collapsed: boolean = false;
+    @observable _childClickedScript: Opt<ScriptField>;
+    componentDidMount() {
+        this._originalChrome = StrCast(this.layoutDoc._chromeStatus);
+        this.layoutDoc._chromeStatus = "disabled";
+        this.layoutDoc.hideFilterView = true;
+    }
+    componentWillUnmount() {
+        this.layoutDoc.hideFilterView = false;
+        this.layoutDoc._chromeStatus = this._originalChrome;
+    }
+
+    layoutEngine = () => this._layoutEngine;
+
+    @computed get contents() {
+        return <div className="collectionPileView-innards" style={{ width: "100%", pointerEvents: this._contentsActive && (this.props.active() || this.layoutEngine() === "starburst") ? undefined : "none" }} >
+            <CollectionFreeFormView {...this.props} layoutEngine={this.layoutEngine} />
+        </div>;
+    }
+
+    specificMenu = (e: React.MouseEvent) => {
+        const layoutItems: ContextMenuProps[] = [];
+        const doc = this.props.Document;
+
+        ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" });
+    }
+
+    toggleStarburst = action(() => {
+        if (this._layoutEngine === 'starburst') {
+            const defaultSize = 110;
+            this.layoutDoc.overflow = undefined;
+            this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2;
+            this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2;
+            this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize);
+            this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize);
+            this._layoutEngine = 'pass';
+        } else {
+            const defaultSize = 25;
+            this.layoutDoc.overflow = 'visible';
+            !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 500);
+            !this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5);
+            if (this._layoutEngine === 'pass') {
+                this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - defaultSize / 2;
+                this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - defaultSize / 2;
+                this.layoutDoc._starburstPileWidth = this.layoutDoc[WidthSym]();
+                this.layoutDoc._starburstPileHeight = this.layoutDoc[HeightSym]();
+            }
+            this.layoutDoc._width = this.layoutDoc._height = defaultSize;
+            this._layoutEngine = 'starburst';
+        }
+    });
+
+    pointerDown = (e: React.PointerEvent) => {
+        // this._lastTap should be set to 0, and this._doubleTap should be set to false in the class header
+        setupMoveUpEvents(this, e, returnFalse, emptyFunction, emptyFunction, false, false); // this sets _doubleTap
+    }
+
+    onClick = (e: React.MouseEvent) => {
+        if (e.button === 0 && (this._doubleTap || this.layoutEngine() === "starburst")) {
+            SelectionManager.DeselectAll();
+            this.toggleStarburst();
+            e.stopPropagation();
+        } else if (this.layoutEngine() === "pass") {
+            runInAction(() => this._contentsActive = false);
+            setTimeout(action(() => this._contentsActive = true), 300);
+        }
+    }
+
+    render() {
+
+        return <div className={"collectionPileView"} onContextMenu={this.specificMenu} onClick={this.onClick} onPointerDown={this.pointerDown}
+            style={{ width: this.props.PanelWidth(), height: `calc(100%  - ${this.props.Document._chromeStatus === "enabled" ? 51 : 0}px)` }}>
+            {this.contents}
+        </div>;
+    }
+}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 78ba3d6e6..c530b24fb 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -400,9 +400,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             if (generatedDocuments.length) {
                 const set = generatedDocuments.length > 1 && generatedDocuments.map(d => Doc.iconify(d));
                 if (set) {
-                    const pile = Docs.Create.FreeformDocument(generatedDocuments, { ...options, title: "pile", _LODdisable: true, });
-                    Doc.pileup(pile, generatedDocuments);
-                    addDocument(pile);
+                    addDocument(Doc.pileup(generatedDocuments, options.x!, options.y!));
                 } else {
                     generatedDocuments.forEach(addDocument);
                 }
diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx
index 63498cea1..045134225 100644
--- a/src/client/views/collections/CollectionTimeView.tsx
+++ b/src/client/views/collections/CollectionTimeView.tsx
@@ -19,7 +19,6 @@ const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
 import React = require("react");
-import { DocumentView } from "../nodes/DocumentView";
 
 @observer
 export class CollectionTimeView extends CollectionSubView(doc => doc) {
@@ -84,7 +83,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
     }
 
     @computed get contents() {
-        return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%" }} onPointerDown={this.contentsDown}>
+        return <div className="collectionTimeView-innards" key="timeline" style={{ width: "100%", pointerEvents: this.props.active() ? undefined : "none" }} onPointerDown={this.contentsDown}>
             <CollectionFreeFormView {...this.props} childClickScript={this._childClickedScript} viewDefDivClick={this._viewDefDivClick} fitToBox={true} freezeChildDimensions={BoolCast(this.layoutDoc._freezeChildDimensions, true)} layoutEngine={this.layoutEngine} />
         </div>;
     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 47e79f088..f82c6d8a6 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -46,6 +46,7 @@ import { InteractionUtils } from '../../util/InteractionUtils';
 import { ObjectField } from '../../../new_fields/ObjectField';
 import CollectionMapView from './CollectionMapView';
 import { Transform } from 'prosemirror-transform';
+import { CollectionPileView } from './CollectionPileView';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -67,7 +68,8 @@ export enum CollectionViewType {
     Carousel = "carousel",
     Linear = "linear",
     Staff = "staff",
-    Map = "map"
+    Map = "map",
+    Pile = "pileup"
 }
 
 export interface CollectionRenderProps {
@@ -169,6 +171,7 @@ export class CollectionView extends Touchable<FieldViewProps> {
             case CollectionViewType.Multicolumn: return (<CollectionMulticolumnView key="collview" {...props} />);
             case CollectionViewType.Multirow: return (<CollectionMultirowView key="rpwview" {...props} />);
             case CollectionViewType.Linear: { return (<CollectionLinearView key="collview" {...props} />); }
+            case CollectionViewType.Pile: { return (<CollectionPileView key="collview" {...props} />); }
             case CollectionViewType.Carousel: { return (<CollectionCarouselView key="collview" {...props} />); }
             case CollectionViewType.Stacking: { this.props.Document.singleColumn = true; return (<CollectionStackingView key="collview" {...props} />); }
             case CollectionViewType.Masonry: { this.props.Document.singleColumn = false; return (<CollectionStackingView key="collview" {...props} />); }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index d8bd18ec7..9ca747113 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -13,10 +13,11 @@ import { listSpec } from "../../../../new_fields/Schema";
 
 export interface ViewDefBounds {
     type: string;
-    text?: string;
+    payload: any;
     x: number;
     y: number;
     z?: number;
+    text?: string;
     zIndex?: number;
     width?: number;
     height?: number;
@@ -24,14 +25,13 @@ export interface ViewDefBounds {
     fontSize?: number;
     highlight?: boolean;
     color?: string;
-    payload: any;
     replica?: string;
     pair?: { layout: Doc, data?: Doc };
 }
 
 export interface PoolData {
-    x?: number;
-    y?: number;
+    x: number;
+    y: number;
     z?: number;
     zIndex?: number;
     width?: number;
@@ -40,7 +40,7 @@ export interface PoolData {
     transition?: string;
     highlight?: boolean;
     replica?: string;
-    pair: { layout: Doc, data?: Doc }
+    pair: { layout: Doc, data?: Doc };
 }
 
 export interface ViewDefResult {
@@ -84,96 +84,88 @@ interface PivotColumn {
 export function computerPassLayout(
     poolData: Map<string, PoolData>,
     pivotDoc: Doc,
-    filterDocs: Doc[],
     childPairs: { layout: Doc, data?: Doc }[],
     panelDim: number[],
     viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
 ) {
-    const docMap = new Map<string, ViewDefBounds>();
+    const docMap = new Map<string, PoolData>();
     childPairs.forEach(({ layout, data }, i) => {
         docMap.set(layout[Id], {
-            type: "doc",
             x: NumCast(layout.x),
             y: NumCast(layout.y),
             width: layout[WidthSym](),
             height: layout[HeightSym](),
-            payload: undefined,
             pair: { layout, data },
             replica: ""
         });
     });
-    return normalizeResults(panelDim, 12, childPairs, docMap, poolData, viewDefsToJSX, [], 0, [], childPairs.filter(c => !filterDocs.includes(c.layout)));
+    return normalizeResults(panelDim, 12, docMap, poolData, viewDefsToJSX, [], 0, []);
 }
 
 export function computerStarburstLayout(
     poolData: Map<string, PoolData>,
     pivotDoc: Doc,
-    filterDocs: Doc[],
     childPairs: { layout: Doc, data?: Doc }[],
     panelDim: number[],
     viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
 ) {
-    const docMap = new Map<string, ViewDefBounds>();
+    const docMap = new Map<string, PoolData>();
     const burstRadius = [NumCast(pivotDoc._starburstRadius, panelDim[0]), NumCast(pivotDoc._starburstRadius, panelDim[1])];
     const docScale = NumCast(pivotDoc._starburstDocScale);
     const docSize = docScale * 100; // assume a icon sized at 100
     const scaleDim = [burstRadius[0] + docSize, burstRadius[1] + docSize];
-    childPairs.forEach((pair, i) => {
+    childPairs.forEach(({ layout, data }, i) => {
         const deg = i / childPairs.length * Math.PI * 2;
-        docMap.set(pair.layout[Id], {
-            type: "doc",
-            x: Math.cos(deg) * (burstRadius[0] / 3) - docScale * pair.layout[WidthSym]() / 2,
-            y: Math.sin(deg) * (burstRadius[1] / 3) - docScale * pair.layout[HeightSym]() / 2,
-            width: docScale * pair.layout[WidthSym](),
-            height: docScale * pair.layout[HeightSym](),
-            payload: undefined,
+        docMap.set(layout[Id], {
+            x: Math.cos(deg) * (burstRadius[0] / 3) - docScale * layout[WidthSym]() / 2,
+            y: Math.sin(deg) * (burstRadius[1] / 3) - docScale * layout[HeightSym]() / 2,
+            width: docScale * layout[WidthSym](),
+            height: docScale * layout[HeightSym](),
+            pair: { layout, data },
             replica: ""
         });
     });
-    return normalizeResults(scaleDim, 12, childPairs, docMap, poolData, viewDefsToJSX, [], 0, [], childPairs.filter(c => !filterDocs.includes(c.layout)));
+    return normalizeResults(scaleDim, 12, docMap, poolData, viewDefsToJSX, [], 0, []);
 }
 
 
 export function computePivotLayout(
     poolData: Map<string, PoolData>,
     pivotDoc: Doc,
-    filterDocs: Doc[],
     childPairs: { layout: Doc, data?: Doc }[],
     panelDim: number[],
     viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
 ) {
-    const docMap = new Map<string, ViewDefBounds>();
+    const docMap = new Map<string, PoolData>();
     const fieldKey = "data";
     const pivotColumnGroups = new Map<FieldResult<Field>, PivotColumn>();
 
     const pivotFieldKey = toLabel(pivotDoc._pivotField);
-    for (const doc of filterDocs) {
-        const lval = Cast(doc[pivotFieldKey], listSpec("string"), null);
-        const val = Field.toString(doc[pivotFieldKey] as Field);
+    childPairs.map(pair => {
+        const lval = Cast(pair.layout[pivotFieldKey], listSpec("string"), null);
+        const val = Field.toString(pair.layout[pivotFieldKey] as Field);
         if (lval) {
             lval.forEach((val, i) => {
                 !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val], replicas: [] });
-                pivotColumnGroups.get(val)!.docs.push(doc);
+                pivotColumnGroups.get(val)!.docs.push(pair.layout);
                 pivotColumnGroups.get(val)!.replicas.push(i.toString());
             });
         } else if (val) {
             !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val], replicas: [] });
-            pivotColumnGroups.get(val)!.docs.push(doc);
+            pivotColumnGroups.get(val)!.docs.push(pair.layout);
             pivotColumnGroups.get(val)!.replicas.push("");
         } else {
-            docMap.set(doc[Id], {
-                type: "doc",
+            docMap.set(pair.layout[Id], {
                 x: 0,
                 y: 0,
                 zIndex: -99,
                 width: 0,
                 height: 0,
-                payload: undefined,
-                pair: { layout: doc },
+                pair,
                 replica: ""
-            })
+            });
         }
-    }
+    });
     let nonNumbers = 0;
     childPairs.map(pair => {
         const num = toNumber(pair.layout[pivotFieldKey]);
@@ -252,12 +244,10 @@ export function computePivotLayout(
                 wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth;
             }
             docMap.set(doc[Id] + (val.replicas || ""), {
-                type: "doc",
                 x: x + xCount * pivotAxisWidth * expander + (pivotAxisWidth - wid) / 2 + (val.docs.length < numCols ? (numCols - val.docs.length) * pivotAxisWidth / 2 : 0),
                 y: -y + (pivotAxisWidth - hgt) / 2,
                 width: wid,
                 height: hgt,
-                payload: undefined,
                 pair: { layout: doc },
                 replica: val.replicas[i]
             });
@@ -273,7 +263,7 @@ export function computePivotLayout(
     const dividers = sortedPivotKeys.map((key, i) =>
         ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap) - pivotAxisWidth * (expander - 1) / 2, y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters }));
     groupNames.push(...dividers);
-    return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, [], childPairs.filter(c => !filterDocs.includes(c.layout)));
+    return normalizeResults(panelDim, max_text, docMap, poolData, viewDefsToJSX, groupNames, 0, []);
 }
 
 function toNumber(val: FieldResult<Field>) {
@@ -283,14 +273,13 @@ function toNumber(val: FieldResult<Field>) {
 export function computeTimelineLayout(
     poolData: Map<string, PoolData>,
     pivotDoc: Doc,
-    filterDocs: Doc[],
     childPairs: { layout: Doc, data?: Doc }[],
     panelDim: number[],
     viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[]
 ) {
     const fieldKey = "data";
     const pivotDateGroups = new Map<number, Doc[]>();
-    const docMap = new Map<string, ViewDefBounds>();
+    const docMap = new Map<string, PoolData>();
     const groupNames: ViewDefBounds[] = [];
     const timelineFieldKey = Field.toString(pivotDoc._pivotField as Field);
     const curTime = toNumber(pivotDoc[fieldKey + "-timelineCur"]);
@@ -306,11 +295,11 @@ export function computeTimelineLayout(
 
     let minTime = minTimeReq === undefined ? Number.MAX_VALUE : minTimeReq;
     let maxTime = maxTimeReq === undefined ? -Number.MAX_VALUE : maxTimeReq;
-    filterDocs.map(doc => {
-        const num = NumCast(doc[timelineFieldKey], Number(StrCast(doc[timelineFieldKey])));
+    childPairs.forEach(pair => {
+        const num = NumCast(pair.layout[timelineFieldKey], Number(StrCast(pair.layout[timelineFieldKey])));
         if (!Number.isNaN(num) && (!minTimeReq || num >= minTimeReq) && (!maxTimeReq || num <= maxTimeReq)) {
             !pivotDateGroups.get(num) && pivotDateGroups.set(num, []);
-            pivotDateGroups.get(num)!.push(doc);
+            pivotDateGroups.get(num)!.push(pair.layout);
             minTime = Math.min(num, minTime);
             maxTime = Math.max(num, maxTime);
         }
@@ -369,7 +358,7 @@ export function computeTimelineLayout(
     }
 
     const divider = { type: "div", color: Cast(Doc.UserDoc().activeWorkspace, Doc, null)?.darkScheme ? "dimGray" : "black", x: 0, y: 0, width: panelDim[0], height: -1, payload: undefined };
-    return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider], childPairs.filter(c => !filterDocs.includes(c.layout)));
+    return normalizeResults(panelDim, fontHeight, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]);
 
     function layoutDocsAtTime(keyDocs: Doc[], key: number) {
         keyDocs.forEach(doc => {
@@ -382,13 +371,11 @@ export function computeTimelineLayout(
                 wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth;
             }
             docMap.set(doc[Id], {
-                type: "doc",
                 x: x, y: -Math.sqrt(stack) * pivotAxisWidth / 2 - pivotAxisWidth + (pivotAxisWidth - hgt) / 2,
                 zIndex: (curTime === key ? 1000 : zind++),
                 highlight: curTime === key,
                 width: wid / (Math.max(stack, 1)),
                 height: hgt / (Math.max(stack, 1)),
-                payload: undefined,
                 pair: { layout: doc },
                 replica: ""
             });
@@ -397,12 +384,19 @@ export function computeTimelineLayout(
     }
 }
 
-function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: Map<string, ViewDefBounds>,
-    poolData: Map<string, PoolData>, viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], groupNames: ViewDefBounds[], minWidth: number, extras: ViewDefBounds[],
-    extraDocs: { data?: Doc, layout: Doc }[]): ViewDefResult[] {
+function normalizeResults(
+    panelDim: number[],
+    fontHeight: number,
+    docMap: Map<string, PoolData>,
+    poolData: Map<string, PoolData>,
+    viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[],
+    groupNames: ViewDefBounds[],
+    minWidth: number,
+    extras: ViewDefBounds[]
+): ViewDefResult[] {
     const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds);
     const docEles = Array.from(docMap.entries()).map(ele => ele[1]);
-    const aggBounds = aggregateBounds(docEles.concat(grpEles).filter(e => e.zIndex !== -99), 0, 0);
+    const aggBounds = aggregateBounds(grpEles.concat(docEles.map(de => ({ ...de, type: "doc", payload: "" }))).filter(e => e.zIndex !== -99), 0, 0);
     aggBounds.r = Math.max(minWidth, aggBounds.r - aggBounds.x);
     const wscale = panelDim[0] / (aggBounds.r - aggBounds.x);
     let scale = wscale * (aggBounds.b - aggBounds.y) > panelDim[1] ? (panelDim[1]) / (aggBounds.b - aggBounds.y) : wscale;
@@ -420,12 +414,11 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: {
                 zIndex: newPosRaw.zIndex,
                 width: (newPosRaw.width || 0) * scale,
                 height: newPosRaw.height! * scale,
-                pair: ele[1].pair!
+                pair: ele[1].pair
             };
             poolData.set(newPos.pair.layout[Id] + (newPos.replica || ""), { transition: "transform 1s", ...newPos });
         }
     });
-    extraDocs.map(ed => poolData.set(ed.layout[Id], { x: 0, y: 0, zIndex: -99, pair: ed }));
 
     return viewDefsToJSX(extras.concat(groupNames).map(gname => ({
         type: gname.type,
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 5555d9e84..af9d3c5be 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -902,7 +902,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
     getCalculatedPositions(params: { pair: { layout: Doc, data?: Doc }, index: number, collection: Doc, docs: Doc[], state: any }): PoolData {
         const result = this.Document.arrangeScript?.script.run(params, console.log);
         if (result?.success) {
-            return { ...result, pair: params.pair, transition: "transform 1s" };
+            return { x: 0, y: 0, transition: "transform 1s", ...result, pair: params.pair };
         }
         const layoutDoc = Doc.Layout(params.pair.layout);
         const { x, y, z, color, zIndex } = params.pair.layout;
@@ -954,12 +954,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         engine: (
             poolData: Map<string, PoolData>,
             pivotDoc: Doc,
-            filterDocs: Doc[],
             childPairs: { layout: Doc, data?: Doc }[],
             panelDim: number[],
-            viewDefsToJSX: ((views: ViewDefBounds[]) => ViewDefResult[])) => ViewDefResult[]) {
-        return engine(poolData, this.props.Document, this.childDocs,
-            this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX);
+            viewDefsToJSX: ((views: ViewDefBounds[]) => ViewDefResult[])) => ViewDefResult[]
+    ) {
+        return engine(poolData, this.props.Document, this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX);
     }
 
     doFreeformLayout(poolData: Map<string, PoolData>) {
@@ -977,7 +976,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
 
     @computed get doInternalLayoutComputation() {
         const newPool = new Map<string, PoolData>();
-        const engine = StrCast(this.layoutDoc._layoutEngine) || this.props.layoutEngine?.();
+        const engine = this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine);
         switch (engine) {
             case "pass": return { newPool, computedElementData: this.doEngineLayout(newPool, computerPassLayout) };
             case "timeline": return { newPool, computedElementData: this.doEngineLayout(newPool, computeTimelineLayout) };
@@ -1001,6 +1000,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         this._cachedPool.clear();
         Array.from(newPool.entries()).forEach(k => this._cachedPool.set(k[0], k[1]));
         const elements: ViewDefResult[] = computedElementData.slice();
+        const engine = this.props.layoutEngine?.() || StrCast(this.props.Document._layoutEngine);
         Array.from(newPool.entries()).filter(entry => this.isCurrent(entry[1].pair.layout)).forEach(entry =>
             elements.push({
                 ele: <CollectionFreeFormDocumentView
@@ -1009,8 +1009,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
                     replica={entry[1].replica}
                     dataProvider={this.childDataProvider}
                     LayoutDoc={this.childLayoutDocFunc}
-                    pointerEvents={this.props.viewDefDivClick ? false : undefined}
-                    jitterRotation={NumCast(this.props.Document.jitterRotation)}
+                    pointerEvents={this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true)) ?
+                        false : undefined}
+                    jitterRotation={NumCast(this.props.Document._jitterRotation)}
                     fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)}
                     FreezeDimensions={BoolCast(this.props.freezeChildDimensions)}
                 />,
@@ -1082,7 +1083,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
         this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" });
         optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
         // layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" });
-        optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = (this.props.Document.jitterRotation ? 0 : 10)), icon: "paint-brush" });
+        optionItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document._jitterRotation = (this.props.Document._jitterRotation ? 0 : 10)), icon: "paint-brush" });
         optionItems.push({
             description: "Import document", icon: "upload", event: ({ x, y }) => {
                 const input = document.createElement("input");
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index ab8174ba1..cd8166309 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,12 +1,12 @@
 import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
-import { Doc, DocListCast, DataSym, WidthSym, HeightSym } from "../../../../new_fields/Doc";
+import { Doc, DocListCast, DataSym, WidthSym, HeightSym, Opt } from "../../../../new_fields/Doc";
 import { InkField, InkData } from "../../../../new_fields/InkField";
 import { List } from "../../../../new_fields/List";
 import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField";
 import { Cast, NumCast, FieldValue, StrCast } from "../../../../new_fields/Types";
 import { Utils } from "../../../../Utils";
-import { Docs, DocUtils } from "../../../documents/Documents";
+import { Docs, DocUtils, DocumentOptions } from "../../../documents/Documents";
 import { SelectionManager } from "../../../util/SelectionManager";
 import { Transform } from "../../../util/Transform";
 import { undoBatch } from "../../../util/UndoManager";
@@ -310,11 +310,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         this.hideMarquee();
     }
 
-    getCollection = (selected: Doc[], asTemplate: boolean, isBackground?: boolean) => {
+    getCollection = (selected: Doc[], creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, isBackground?: boolean) => {
         const bounds = this.Bounds;
         // const inkData = this.ink ? this.ink.inkData : undefined;
-        const creator = asTemplate ? Docs.Create.StackingDocument : Docs.Create.FreeformDocument;
-        const newCollection = creator(selected, {
+        const newCollection = (creator || Docs.Create.FreeformDocument)(selected, {
             x: bounds.left,
             y: bounds.top,
             _panX: 0,
@@ -338,8 +337,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
         const selected = this.marqueeSelect(false);
         SelectionManager.DeselectAll();
         selected.forEach(d => this.props.removeDocument(d));
-        const newCollection = this.getCollection(selected, false);
-        Doc.pileup(newCollection, selected);
+        const newCollection = Doc.pileup(selected, this.Bounds.left + this.Bounds.width / 2, this.Bounds.top + this.Bounds.height / 2);
         this.props.addDocument(newCollection);
         this.props.selectDocuments([newCollection], []);
         MarqueeOptionsMenu.Instance.fadeOut(true);
@@ -359,7 +357,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
                 return d;
             });
         }
-        const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t");
+        const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined);
         this.props.addDocument(newCollection);
         this.props.selectDocuments([newCollection], []);
         MarqueeOptionsMenu.Instance.fadeOut(true);
@@ -470,7 +468,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
     }
     @action
     background = (e: KeyboardEvent | React.PointerEvent | undefined) => {
-        const newCollection = this.getCollection([], false, true);
+        const newCollection = this.getCollection([], undefined, true);
         this.props.addDocument(newCollection);
         MarqueeOptionsMenu.Instance.fadeOut(true);
         this.hideMarquee();
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 18ffc38f5..337274774 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -976,7 +976,8 @@ export namespace Doc {
         if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") doc.deiconifyLayout = layoutKey.replace("layout_", "");
     }
 
-    export function pileup(newCollection: Doc, selected: Doc[]) {
+    export function pileup(selected: Doc[], x: number, y: number) {
+        const newCollection = Docs.Create.PileDocument(selected, { title: "pileup", x: x - 55, y: y - 55, _width: 110, _height: 100, _LODdisable: true });
         let w = 0, h = 0;
         selected.forEach((d, i) => {
             Doc.iconify(d);
@@ -993,12 +994,10 @@ export namespace Doc {
         newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55;
         newCollection._width = newCollection._height = 110;
         //newCollection.borderRounding = "40px";
-        newCollection.jitterRotation = 10;
+        newCollection._jitterRotation = 10;
         newCollection._backgroundColor = "gray";
-
-        newCollection._layoutEngine = "pass";
         newCollection.overflow = "visible";
-        newCollection.onClick = ScriptField.MakeScript("toggleStarburst(self, this)", { self: Doc.name, this: Doc.name });
+        return newCollection;
     }
 
 
@@ -1055,28 +1054,4 @@ Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: bo
     return docs.length ? new List(docs) : prevValue;
 });
 Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: "check" | "x" | undefined) { Doc.setDocFilter(container, key, value, modifiers); });
-Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number[]) { Doc.setDocFilterRange(container, key, range); });
-Scripting.addGlobal(function toggleStarburst(self: Doc, tLayout: Doc) {
-    if (self._layoutEngine === 'starburst') {
-        const defaultSize = 110;
-        tLayout.overflow = undefined;
-        self.x = NumCast(self.x) + tLayout[WidthSym]() / 2 - NumCast(tLayout._starburstPileWidth, defaultSize) / 2;
-        self.y = NumCast(self.y) + tLayout[HeightSym]() / 2 - NumCast(tLayout._starburstPileHeight, defaultSize) / 2;
-        tLayout._width = NumCast(tLayout._starburstPileWidth, defaultSize);
-        tLayout._height = NumCast(tLayout._starburstPileHeight, defaultSize);
-        self._layoutEngine = 'pass';
-    } else {
-        const defaultSize = 25;
-        tLayout.overflow = 'visible';
-        !tLayout._starburstRadius && (tLayout._starburstRadius = 500);
-        !tLayout._starburstDocScale && (tLayout._starburstDocScale = 2.5);
-        if (self._layoutEngine === 'pass') {
-            self.x = NumCast(self.x) + tLayout[WidthSym]() / 2 - defaultSize / 2;
-            self.y = NumCast(self.y) + tLayout[HeightSym]() / 2 - defaultSize / 2;
-            tLayout._starburstPileWidth = tLayout[WidthSym]();
-            tLayout._starburstPileHeight = tLayout[HeightSym]();
-        }
-        tLayout._width = tLayout._height = defaultSize;
-        self._layoutEngine = 'starburst';
-    }
-});
\ No newline at end of file
+Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number[]) { Doc.setDocFilterRange(container, key, range); });
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 627adb92b604e117694e26af65afdc19920ac509 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 25 Apr 2020 21:26:28 -0400
Subject: added internalPreDrop to set dropActions.  made linksView turn off
 during dragging.

---
 src/client/util/DragManager.ts                     | 22 ++++++++++++++++++++--
 .../views/collections/CollectionPileView.tsx       |  2 ++
 src/client/views/collections/CollectionSubView.tsx |  7 ++++++-
 .../CollectionFreeFormLinksView.tsx                |  2 +-
 4 files changed, 29 insertions(+), 4 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 6bb44f7d6..6a55f4a00 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -179,7 +179,8 @@ export namespace DragManager {
 
     export function MakeDropTarget(
         element: HTMLElement,
-        dropFunc: (e: Event, de: DropEvent) => void
+        dropFunc: (e: Event, de: DropEvent) => void,
+        preDropFunc?: (e: Event, de: DropEvent) => void
     ): DragDropDisposer {
         if ("canDrop" in element.dataset) {
             throw new Error(
@@ -187,10 +188,13 @@ export namespace DragManager {
             );
         }
         element.dataset.canDrop = "true";
-        const handler = (e: Event) => { dropFunc(e, (e as CustomEvent<DropEvent>).detail); };
+        const handler = (e: Event) => dropFunc(e, (e as CustomEvent<DropEvent>).detail);
+        const preDropHandler = (e: Event) => preDropFunc?.(e, (e as CustomEvent<DropEvent>).detail);
         element.addEventListener("dashOnDrop", handler);
+        preDropFunc && element.addEventListener("dashPreDrop", preDropHandler);
         return () => {
             element.removeEventListener("dashOnDrop", handler);
+            preDropFunc && element.removeEventListener("dashPreDrop", preDropHandler);
             delete element.dataset.canDrop;
         };
     }
@@ -425,6 +429,20 @@ export namespace DragManager {
         });
         if (target) {
             const complete = new DragCompleteEvent(false, dragData);
+            target.dispatchEvent(
+                new CustomEvent<DropEvent>("dashPreDrop", {
+                    bubbles: true,
+                    detail: {
+                        x: e.x,
+                        y: e.y,
+                        complete: complete,
+                        shiftKey: e.shiftKey,
+                        altKey: e.altKey,
+                        metaKey: e.metaKey,
+                        ctrlKey: e.ctrlKey
+                    }
+                })
+            );
             finishDrag?.(complete);
             target.dispatchEvent(
                 new CustomEvent<DropEvent>("dashOnDrop", {
diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx
index 410b16ec7..3bbfcc4d7 100644
--- a/src/client/views/collections/CollectionPileView.tsx
+++ b/src/client/views/collections/CollectionPileView.tsx
@@ -78,6 +78,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
     _undoBatch: UndoManager.Batch | undefined;
     pointerDown = (e: React.PointerEvent) => {
         let dist = 0;
+        SelectionManager.SetIsDragging(true);
         // this._lastTap should be set to 0, and this._doubleTap should be set to false in the class header
         setupMoveUpEvents(this, e, (e: PointerEvent, down: number[], delta: number[]) => {
             if (this.layoutEngine() === "pass" && this.childDocs.length && this.props.isSelected(true)) {
@@ -97,6 +98,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) {
         }, () => {
             this._undoBatch?.end();
             this._undoBatch = undefined;
+            SelectionManager.SetIsDragging(false);
             if (!this.childDocs.length) {
                 this.props.ContainingCollectionView?.removeDocument(this.props.Document);
             }
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index c530b24fb..60cc1bd49 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -64,7 +64,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             this.multiTouchDisposer?.();
             if (ele) {
                 this._mainCont = ele;
-                this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
+                this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.onInternalPreDrop.bind(this));
                 this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this));
                 this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this));
             }
@@ -208,6 +208,11 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {
         }
 
+        protected onInternalPreDrop(e: Event, de: DragManager.DropEvent): boolean {
+            // de.complete.docDragData!.dropAction = "alias";  bcz: for example, you can convert all drops to aliases here
+            return true;
+        }
+
         @undoBatch
         @action
         protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 702b02a20..4b5e977df 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -36,7 +36,7 @@ export class CollectionFreeFormLinksView extends React.Component {
     }
 
     render() {
-        return <div className="collectionfreeformlinksview-container">
+        return SelectionManager.GetIsDragging() ? (null) : <div className="collectionfreeformlinksview-container">
             <svg className="collectionfreeformlinksview-svgCanvas">
                 {this.uniqueConnections}
             </svg>
-- 
cgit v1.2.3-70-g09d2


From f1ac48c19b4683668b0df91bd4ad68690a069029 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 25 Apr 2020 21:43:21 -0400
Subject: added a targetDropAction field to specify the drop action from the
 target's side

---
 src/client/util/DragManager.ts                            | 15 ++++++++++-----
 src/client/views/collections/CollectionCarouselView.tsx   |  2 +-
 src/client/views/collections/CollectionLinearView.tsx     |  2 +-
 .../views/collections/CollectionSchemaMovableTableHOC.tsx |  2 +-
 src/client/views/collections/CollectionSubView.tsx        |  9 ++-------
 src/client/views/collections/CollectionTreeView.tsx       |  4 ++--
 src/client/views/collections/CollectionViewChromes.tsx    |  4 ++--
 src/client/views/nodes/DocumentView.tsx                   |  4 ++--
 src/client/views/nodes/FormattedTextBox.tsx               |  2 +-
 src/client/views/nodes/ImageBox.tsx                       |  2 +-
 src/client/views/nodes/LabelBox.tsx                       |  2 +-
 src/new_fields/documentSchemas.ts                         |  3 ++-
 12 files changed, 26 insertions(+), 25 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 6a55f4a00..577366cd4 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -1,5 +1,5 @@
 import { Doc, Field, DocListCast } from "../../new_fields/Doc";
-import { Cast, ScriptCast } from "../../new_fields/Types";
+import { Cast, ScriptCast, StrCast } from "../../new_fields/Types";
 import { emptyFunction } from "../../Utils";
 import { CollectionDockingView } from "../views/collections/CollectionDockingView";
 import * as globalCssVariables from "../views/globalCssVariables.scss";
@@ -180,7 +180,7 @@ export namespace DragManager {
     export function MakeDropTarget(
         element: HTMLElement,
         dropFunc: (e: Event, de: DropEvent) => void,
-        preDropFunc?: (e: Event, de: DropEvent) => void
+        doc?:Doc
     ): DragDropDisposer {
         if ("canDrop" in element.dataset) {
             throw new Error(
@@ -189,12 +189,17 @@ export namespace DragManager {
         }
         element.dataset.canDrop = "true";
         const handler = (e: Event) => dropFunc(e, (e as CustomEvent<DropEvent>).detail);
-        const preDropHandler = (e: Event) => preDropFunc?.(e, (e as CustomEvent<DropEvent>).detail);
+        const preDropHandler = (e:Event) => {
+            const de = (e as CustomEvent<DropEvent>).detail;
+            if (de.complete.docDragData && doc?.targetDropAction) {
+                de.complete.docDragData!.dropAction = StrCast(doc.targetDropAction) as dropActionType;
+            }
+        }
         element.addEventListener("dashOnDrop", handler);
-        preDropFunc && element.addEventListener("dashPreDrop", preDropHandler);
+        doc && element.addEventListener("dashPreDrop", preDropHandler);
         return () => {
             element.removeEventListener("dashOnDrop", handler);
-            preDropFunc && element.removeEventListener("dashPreDrop", preDropHandler);
+            doc && element.removeEventListener("dashPreDrop", preDropHandler);
             delete element.dataset.canDrop;
         };
     }
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 9e7248db2..2453acddf 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -27,7 +27,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
     protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
         this._dropDisposer?.();
         if (ele) {
-            this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
+            this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
         }
     }
 
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index cb0206260..344dca23a 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -64,7 +64,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
     protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
         this._dropDisposer && this._dropDisposer();
         if (ele) {
-            this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
+            this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
         }
     }
 
diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
index 670d6dbb2..972714e34 100644
--- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
+++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx
@@ -54,7 +54,7 @@ export class MovableColumn extends React.Component<MovableColumnProps> {
     }
 
     createColDropTarget = (ele: HTMLDivElement) => {
-        this._colDropDisposer && this._colDropDisposer();
+        this._colDropDisposer?.();
         if (ele) {
             this._colDropDisposer = DragManager.MakeDropTarget(ele, this.colDrop.bind(this));
         }
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 60cc1bd49..49abc6ee6 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -11,7 +11,7 @@ import { Utils } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { DocumentType } from "../../documents/DocumentTypes";
 import { Docs, DocumentOptions } from "../../documents/Documents";
-import { DragManager } from "../../util/DragManager";
+import { DragManager, dropActionType } from "../../util/DragManager";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
 import { DocComponent } from "../DocComponent";
 import { FieldViewProps } from "../nodes/FieldView";
@@ -64,7 +64,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
             this.multiTouchDisposer?.();
             if (ele) {
                 this._mainCont = ele;
-                this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.onInternalPreDrop.bind(this));
+                this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.layoutDoc);
                 this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this));
                 this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this));
             }
@@ -208,11 +208,6 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
         protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {
         }
 
-        protected onInternalPreDrop(e: Event, de: DragManager.DropEvent): boolean {
-            // de.complete.docDragData!.dropAction = "alias";  bcz: for example, you can convert all drops to aliases here
-            return true;
-        }
-
         @undoBatch
         @action
         protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index ca2004b79..8c5a4538e 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -143,7 +143,7 @@ class TreeView extends React.Component<TreeViewProps> {
 
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
         this._treedropDisposer && this._treedropDisposer();
-        ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this)));
+        ele && (this._treedropDisposer = DragManager.MakeDropTarget(ele, this.treeDrop.bind(this)), this.props.document);
     }
 
     onPointerEnter = (e: React.PointerEvent): void => {
@@ -663,7 +663,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
     protected createTreeDropTarget = (ele: HTMLDivElement) => {
         this.treedropDisposer?.();
         if (this._mainEle = ele) {
-            this.treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
+            this.treedropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.props.Document);
         }
     }
 
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 7315d2c4e..d26e3a38b 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -215,9 +215,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
 
     private dropDisposer?: DragManager.DragDropDisposer;
     protected createDropTarget = (ele: HTMLDivElement) => {
-        this.dropDisposer && this.dropDisposer();
+        this.dropDisposer?.();
         if (ele) {
-            this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
+            this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.document);
         }
     }
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7ae77fc65..2aee49ad3 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -191,7 +191,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     @action
     componentDidMount() {
-        this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this)));
+        this._mainCont.current && (this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document));
         this._mainCont.current && (this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this)));
         this._mainCont.current && (this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this)));
         // this._mainCont.current && (this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this)));
@@ -208,7 +208,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this.multiTouchDisposer?.();
         this.holdDisposer?.();
         if (this._mainCont.current) {
-            this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this));
+            this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, this.drop.bind(this), this.props.Document);
             this._gestureEventDisposer = GestureUtils.MakeGestureTarget(this._mainCont.current, this.onGesture.bind(this));
             this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(this._mainCont.current, this.onTouchStart.bind(this));
             this.holdDisposer = InteractionUtils.MakeHoldTouchTarget(this._mainCont.current, this.handle1PointerHoldStart.bind(this));
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index d7cfbae9f..815b8b3ae 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -253,7 +253,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     protected createDropTarget = (ele: HTMLDivElement) => {
         this.ProseRef = ele;
         this.dropDisposer?.();
-        ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
+        ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document));
     }
 
     @undoBatch
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 14b367868..08917d281 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -76,7 +76,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps, ImageD
 
     protected createDropTarget = (ele: HTMLDivElement) => {
         this._dropDisposer && this._dropDisposer();
-        ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
+        ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document));
     }
 
     @undoBatch
diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx
index 5c2fc3ffe..a41e4fac4 100644
--- a/src/client/views/nodes/LabelBox.tsx
+++ b/src/client/views/nodes/LabelBox.tsx
@@ -32,7 +32,7 @@ export class LabelBox extends ViewBoxBaseComponent<FieldViewProps, LabelDocument
     protected createDropTarget = (ele: HTMLDivElement) => {
         this.dropDisposer?.();
         if (ele) {
-            this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
+            this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.props.Document);
         }
     }
 
diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts
index 61b185e5c..f24ad42b2 100644
--- a/src/new_fields/documentSchemas.ts
+++ b/src/new_fields/documentSchemas.ts
@@ -8,7 +8,8 @@ export const documentSchema = createSchema({
     layout: "string",           // this is the native layout string for the document.  templates can be added using other fields and setting layoutKey below
     layoutKey: "string",        // holds the field key for the field that actually holds the current lyoat
     title: "string",            // document title (can be on either data document or layout)
-    dropAction: "string",       // override specifying what should happen when this document is dropped (can be "alias" or "copy")
+    dropAction: "string",       // override specifying what should happen when this document is dropped (can be "alias", "copy", "move")
+    targetDropAction: "string",  // allows the target of a drop event to specify the dropAction ("alias", "copy", "move")
     childDropAction: "string",  // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy")
     _autoHeight: "boolean",     // whether the height of the document should be computed automatically based on its contents
     _nativeWidth: "number",     // native width of document which determines how much document contents are scaled when the document's width is set
-- 
cgit v1.2.3-70-g09d2

