From fed460a9dffd85b32e30aeb112f2c7c47371bce6 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Fri, 22 Feb 2019 03:01:30 -0500
Subject: Added CollectionView Switched sub-collections to not inherit from
 CollectionViewBase

---
 src/client/views/collections/CollectionView.tsx | 116 ++++++++++++++++++++++++
 1 file changed, 116 insertions(+)
 create mode 100644 src/client/views/collections/CollectionView.tsx

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

diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
new file mode 100644
index 000000000..651d85879
--- /dev/null
+++ b/src/client/views/collections/CollectionView.tsx
@@ -0,0 +1,116 @@
+import { action, computed } from "mobx";
+import { observer } from "mobx-react";
+import { Document } from "../../../fields/Document";
+import { Key } from "../../../fields/Key";
+import { ListField } from "../../../fields/ListField";
+import { SelectionManager } from "../../util/SelectionManager";
+import { ContextMenu } from "../ContextMenu";
+import React = require("react");
+import { Transform } from "../../util/Transform";
+import { KeyStore } from "../../../fields/KeyStore";
+import { NumberField } from "../../../fields/NumberField";
+import { CollectionFreeFormView } from "./CollectionFreeFormView";
+import { CollectionDockingView } from "./CollectionDockingView";
+import { CollectionSchemaView } from "./CollectionSchemaView";
+import { Opt } from "../../../fields/Field";
+
+
+export interface CollectionViewProps {
+    fieldKey: Key;
+    Document: Document;
+    ScreenToLocalTransform: () => Transform;
+    isSelected: () => boolean;
+    isTopMost: boolean;
+    select: (ctrlPressed: boolean) => void;
+    BackgroundView?: () => JSX.Element;
+}
+
+export interface SubCollectionViewProps extends CollectionViewProps {
+    active: () => boolean;
+    addDocument: (doc: Document) => void;
+    removeDocument: (doc: Document) => boolean;
+    CollectionView: Opt<CollectionView>;
+}
+
+export enum CollectionViewType {
+    Invalid,
+    Freeform,
+    Schema,
+    Docking,
+}
+
+export const COLLECTION_BORDER_WIDTH = 2;
+
+@observer
+export class CollectionView extends React.Component<CollectionViewProps> {
+
+    public static LayoutString(fieldKey: string = "DataKey") {
+        return `<CollectionView Document={Document}
+                    ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} isSelected={isSelected} select={select}
+                    isTopMost={isTopMost} BackgroundView={BackgroundView} />`;
+    }
+    public active = () => {
+        var isSelected = this.props.isSelected();
+        var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this);
+        var topMost = this.props.isTopMost;
+        return isSelected || childSelected || topMost;
+    }
+    @action
+    addDocument = (doc: Document): void => {
+        //TODO This won't create the field if it doesn't already exist
+        const value = this.props.Document.GetData(this.props.fieldKey, ListField, new Array<Document>())
+        value.push(doc);
+    }
+
+    @action
+    removeDocument = (doc: Document): boolean => {
+        //TODO This won't create the field if it doesn't already exist
+        const value = this.props.Document.GetData(this.props.fieldKey, ListField, new Array<Document>())
+        let index = value.indexOf(doc);
+        if (index !== -1) {
+            value.splice(index, 1)
+
+            SelectionManager.DeselectAll()
+            ContextMenu.Instance.clearItems()
+            return true;
+        }
+        return false
+    }
+
+    get collectionViewType(): CollectionViewType {
+        let Document = this.props.Document;
+        let viewField = Document.GetT(KeyStore.ViewType, NumberField);
+        if (viewField === "<Waiting>") {
+            return CollectionViewType.Invalid;
+        } else if (viewField) {
+            return viewField.Data;
+        } else {
+            return CollectionViewType.Freeform;
+        }
+    }
+
+    set collectionViewType(type: CollectionViewType) {
+        let Document = this.props.Document;
+        Document.SetData(KeyStore.ViewType, type, NumberField);
+    }
+
+    render() {
+        let viewType = this.collectionViewType;
+        switch (viewType) {
+            case CollectionViewType.Freeform:
+                return (<CollectionFreeFormView {...this.props}
+                    addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active}
+                    CollectionView={this} />)
+            case CollectionViewType.Schema:
+                return (<CollectionSchemaView {...this.props}
+                    addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active}
+                    CollectionView={this} />)
+            case CollectionViewType.Docking:
+                return (<CollectionDockingView {...this.props}
+                    addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active}
+                    CollectionView={this} />)
+            default:
+                return <div></div>
+        }
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 9b23c5123abf42c3751938d831556cdb94ad3951 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 22 Feb 2019 13:42:25 -0500
Subject: moved common code into CollectionViewBase.

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/util/DragManager.ts                     |  1 +
 .../views/collections/CollectionDockingView.tsx    |  3 +-
 .../views/collections/CollectionFreeFormView.tsx   | 59 ++--------------
 .../views/collections/CollectionSchemaView.tsx     | 13 ++--
 src/client/views/collections/CollectionView.tsx    | 20 +-----
 .../views/collections/CollectionViewBase.tsx       | 82 ++++++++++++++++++++++
 7 files changed, 102 insertions(+), 78 deletions(-)
 create mode 100644 src/client/views/collections/CollectionViewBase.tsx

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index bfa6cb7a9..156a09316 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -13,7 +13,7 @@ import { CollectionFreeFormView } from "../views/collections/CollectionFreeFormV
 import { FieldId } from "../../fields/Field";
 import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
 
-interface DocumentOptions {
+export interface DocumentOptions {
     x?: number;
     y?: number;
     width?: number;
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 6d5fe12a7..eb4b3aeaa 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -44,6 +44,7 @@ export namespace DragManager {
         drop: (e: Event, de: DropEvent) => void;
     }
 
+
     export function MakeDropTarget(element: HTMLElement, options: DropOptions): DragDropDisposer {
         if ("canDrop" in element.dataset) {
             throw new Error("Element is already droppable, can't make it droppable again");
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 752007439..857af023d 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -14,8 +14,9 @@ import { DragManager } from "../../util/DragManager";
 import { undoBatch } from "../../util/UndoManager";
 import { DocumentView } from "../nodes/DocumentView";
 import "./CollectionDockingView.scss";
-import { CollectionViewProps, COLLECTION_BORDER_WIDTH, SubCollectionViewProps } from "./CollectionView";
+import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
 import React = require("react");
+import { SubCollectionViewProps } from "./CollectionViewBase";
 
 @observer
 export class CollectionDockingView extends React.Component<SubCollectionViewProps> {
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index b78b1a3b6..b8312aff7 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -4,20 +4,18 @@ import { action, computed, trace } from "mobx";
 import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
 import { DragManager } from "../../util/DragManager";
 import "./CollectionFreeFormView.scss";
-import { COLLECTION_BORDER_WIDTH, CollectionViewProps, SubCollectionViewProps } from "./CollectionView";
+import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
 import { KeyStore } from "../../../fields/KeyStore";
 import { Document } from "../../../fields/Document";
 import { ListField } from "../../../fields/ListField";
-import { NumberField } from "../../../fields/NumberField";
-import { Documents } from "../../documents/Documents";
 import { FieldWaiting } from "../../../fields/Field";
 import { Transform } from "../../util/Transform";
 import { DocumentView } from "../nodes/DocumentView";
 import { undoBatch } from "../../util/UndoManager";
-import { jSXElement } from "babel-types";
+import { CollectionViewBase, SubCollectionViewProps } from "./CollectionViewBase";
 
 @observer
-export class CollectionFreeFormView extends React.Component<SubCollectionViewProps> {
+export class CollectionFreeFormView extends CollectionViewBase {
     private _canvasRef = React.createRef<HTMLDivElement>();
     private _lastX: number = 0;
     private _lastY: number = 0;
@@ -45,13 +43,8 @@ export class CollectionFreeFormView extends React.Component<SubCollectionViewPro
     @undoBatch
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
+        super.drop(e, de);
         const doc: DocumentView = de.data["document"];
-        if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this.props.CollectionView) {
-            if (doc.props.RemoveDocument) {
-                doc.props.RemoveDocument(doc.props.Document);
-            }
-            this.props.addDocument(doc.props.Document);
-        }
         const xOffset = de.data["xOffset"] as number || 0;
         const yOffset = de.data["yOffset"] as number || 0;
         //this should be able to use translate and scale methods on an Identity transform, no?
@@ -62,21 +55,6 @@ export class CollectionFreeFormView extends React.Component<SubCollectionViewPro
         doc.props.Document.SetNumber(KeyStore.X, x);
         doc.props.Document.SetNumber(KeyStore.Y, y);
         this.bringToFront(doc);
-        e.stopPropagation();
-    }
-
-    private dropDisposer?: DragManager.DragDropDisposer;
-    createDropTarget = (ele: HTMLDivElement) => {
-        if (this.dropDisposer) {
-            this.dropDisposer();
-        }
-        if (ele) {
-            this.dropDisposer = DragManager.MakeDropTarget(ele, {
-                handlers: {
-                    drop: this.drop
-                }
-            });
-        }
     }
 
     @action
@@ -148,36 +126,11 @@ export class CollectionFreeFormView extends React.Component<SubCollectionViewPro
 
     @action
     onDrop = (e: React.DragEvent): void => {
-        e.stopPropagation()
-        e.preventDefault()
-        let fReader = new FileReader()
-        let file = e.dataTransfer.items[0].getAsFile();
-        let that = this;
         const panx: number = this.props.Document.GetNumber(KeyStore.PanX, 0);
         const pany: number = this.props.Document.GetNumber(KeyStore.PanY, 0);
         let x = e.pageX - panx
         let y = e.pageY - pany
-
-        fReader.addEventListener("load", action("drop", () => {
-            if (fReader.result) {
-                let url = "" + fReader.result;
-                let doc = Documents.ImageDocument(url, {
-                    x: x, y: y
-                })
-                let docs = that.props.Document.GetT(KeyStore.Data, ListField);
-                if (docs != FieldWaiting) {
-                    if (!docs) {
-                        docs = new ListField<Document>();
-                        that.props.Document.Set(KeyStore.Data, docs)
-                    }
-                    docs.Data.push(doc);
-                }
-            }
-        }), false)
-
-        if (file) {
-            fReader.readAsDataURL(file)
-        }
+        super.onDrop(e, { x: x, y: y });
     }
 
     onDragOver = (): void => {
@@ -249,7 +202,7 @@ export class CollectionFreeFormView extends React.Component<SubCollectionViewPro
                 onPointerDown={this.onPointerDown}
                 onWheel={this.onPointerWheel}
                 onContextMenu={(e) => e.preventDefault()}
-                onDrop={this.onDrop}
+                onDrop={this.onDrop.bind(this)}
                 onDragOver={this.onDragOver}
                 style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px`, }}
                 ref={this.createDropTarget}>
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index f25e721c0..df732308a 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -5,7 +5,7 @@ import Measure from "react-measure";
 import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table";
 import "react-table/react-table.css";
 import { Document } from "../../../fields/Document";
-import { Field } from "../../../fields/Field";
+import { Field, FieldWaiting } from "../../../fields/Field";
 import { KeyStore } from "../../../fields/KeyStore";
 import { CompileScript, ToField } from "../../util/Scripting";
 import { Transform } from "../../util/Transform";
@@ -13,10 +13,11 @@ import { EditableView } from "../EditableView";
 import { DocumentView } from "../nodes/DocumentView";
 import { FieldView, FieldViewProps } from "../nodes/FieldView";
 import "./CollectionSchemaView.scss";
-import { COLLECTION_BORDER_WIDTH, CollectionViewProps, SubCollectionViewProps } from "./CollectionView";
+import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
+import { CollectionViewBase } from "./CollectionViewBase";
 
 @observer
-export class CollectionSchemaView extends React.Component<SubCollectionViewProps> {
+export class CollectionSchemaView extends CollectionViewBase {
     private _mainCont = React.createRef<HTMLDivElement>();
 
     private DIVIDER_WIDTH = 5;
@@ -117,6 +118,7 @@ export class CollectionSchemaView extends React.Component<SubCollectionViewProps
         }
     }
 
+
     getTransform = (): Transform => {
         return this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._parentScaling);
     }
@@ -181,7 +183,10 @@ export class CollectionSchemaView extends React.Component<SubCollectionViewProps
                     }
                 </Measure>
                 <div className="collectionSchemaView-dividerDragger" style={{ position: "relative", background: "black", float: "left", width: `${this.DIVIDER_WIDTH}px`, height: "100%" }} onPointerDown={this.onDividerDown} />
-                <div className="collectionSchemaView-previewRegion" style={{ position: "relative", float: "left", width: `calc(${100 - this._splitPercentage}% - ${this.DIVIDER_WIDTH}px)`, height: "100%" }}>
+                <div className="collectionSchemaView-previewRegion"
+                    onDrop={(e: React.DragEvent) => this.onDrop(e, {})}
+                    ref={this.createDropTarget}
+                    style={{ position: "relative", float: "left", width: `calc(${100 - this._splitPercentage}% - ${this.DIVIDER_WIDTH}px)`, height: "100%" }}>
                     {content}
                 </div>
             </div >
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 651d85879..ff1803ec3 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,36 +1,18 @@
 import { action, computed } from "mobx";
 import { observer } from "mobx-react";
 import { Document } from "../../../fields/Document";
-import { Key } from "../../../fields/Key";
 import { ListField } from "../../../fields/ListField";
 import { SelectionManager } from "../../util/SelectionManager";
 import { ContextMenu } from "../ContextMenu";
 import React = require("react");
-import { Transform } from "../../util/Transform";
 import { KeyStore } from "../../../fields/KeyStore";
 import { NumberField } from "../../../fields/NumberField";
 import { CollectionFreeFormView } from "./CollectionFreeFormView";
 import { CollectionDockingView } from "./CollectionDockingView";
 import { CollectionSchemaView } from "./CollectionSchemaView";
-import { Opt } from "../../../fields/Field";
+import { CollectionViewProps } from "./CollectionViewBase";
 
 
-export interface CollectionViewProps {
-    fieldKey: Key;
-    Document: Document;
-    ScreenToLocalTransform: () => Transform;
-    isSelected: () => boolean;
-    isTopMost: boolean;
-    select: (ctrlPressed: boolean) => void;
-    BackgroundView?: () => JSX.Element;
-}
-
-export interface SubCollectionViewProps extends CollectionViewProps {
-    active: () => boolean;
-    addDocument: (doc: Document) => void;
-    removeDocument: (doc: Document) => boolean;
-    CollectionView: Opt<CollectionView>;
-}
 
 export enum CollectionViewType {
     Invalid,
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
new file mode 100644
index 000000000..06de56383
--- /dev/null
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -0,0 +1,82 @@
+import { action, computed } from "mobx";
+import { Document } from "../../../fields/Document";
+import { ListField } from "../../../fields/ListField";
+import React = require("react");
+import { KeyStore } from "../../../fields/KeyStore";
+import { Opt, FieldWaiting } from "../../../fields/Field";
+import { undoBatch } from "../../util/UndoManager";
+import { DragManager } from "../../util/DragManager";
+import { DocumentView } from "../nodes/DocumentView";
+import { Documents, DocumentOptions } from "../../documents/Documents";
+import { Key } from "../../../fields/Key";
+import { Transform } from "../../util/Transform";
+
+
+export interface CollectionViewProps {
+    fieldKey: Key;
+    Document: Document;
+    ScreenToLocalTransform: () => Transform;
+    isSelected: () => boolean;
+    isTopMost: boolean;
+    select: (ctrlPressed: boolean) => void;
+    BackgroundView?: () => JSX.Element;
+}
+export interface SubCollectionViewProps extends CollectionViewProps {
+    active: () => boolean;
+    addDocument: (doc: Document) => void;
+    removeDocument: (doc: Document) => boolean;
+    CollectionView: any;
+}
+
+export class CollectionViewBase extends React.Component<SubCollectionViewProps> {
+    private dropDisposer?: DragManager.DragDropDisposer;
+    protected createDropTarget = (ele: HTMLDivElement) => {
+        if (this.dropDisposer) {
+            this.dropDisposer();
+        }
+        if (ele) {
+            this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
+        }
+    }
+
+    @undoBatch
+    @action
+    protected drop(e: Event, de: DragManager.DropEvent) {
+        const doc: DocumentView = de.data["document"];
+        if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this.props.CollectionView) {
+            if (doc.props.RemoveDocument) {
+                doc.props.RemoveDocument(doc.props.Document);
+            }
+            this.props.addDocument(doc.props.Document);
+        }
+        e.stopPropagation();
+    }
+
+    @action
+    protected onDrop(e: React.DragEvent, options: DocumentOptions): void {
+        e.stopPropagation()
+        e.preventDefault()
+        let fReader = new FileReader()
+        let file = e.dataTransfer.items[0].getAsFile();
+        let that = this;
+
+        fReader.addEventListener("load", action("drop", () => {
+            if (fReader.result) {
+                let url = "" + fReader.result;
+                let doc = Documents.ImageDocument(url, options)
+                let docs = that.props.Document.GetT(KeyStore.Data, ListField);
+                if (docs != FieldWaiting) {
+                    if (!docs) {
+                        docs = new ListField<Document>();
+                        that.props.Document.Set(KeyStore.Data, docs)
+                    }
+                    docs.Data.push(doc);
+                }
+            }
+        }), false)
+
+        if (file) {
+            fReader.readAsDataURL(file)
+        }
+    }
+}
-- 
cgit v1.2.3-70-g09d2


From 5fc58916b07453d212645b313c9074b5dcc1ee84 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 22 Feb 2019 21:39:40 -0500
Subject: moved backgroundLayout to CollectionFreeForm

---
 src/client/views/DocumentDecorations.tsx           |  2 +-
 .../views/collections/CollectionFreeFormView.tsx   | 58 ++++++++++++++--------
 .../views/collections/CollectionSchemaView.tsx     |  3 +-
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../views/collections/CollectionViewBase.tsx       |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 41 ++++-----------
 src/client/views/nodes/FieldView.tsx               |  3 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  1 -
 8 files changed, 55 insertions(+), 57 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index efd50e49e..09df8cdaa 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -101,7 +101,7 @@ export class DocumentDecorations extends React.Component {
         }
 
         SelectionManager.SelectedDocuments().forEach(element => {
-            const rect = element.screenRect;
+            const rect = element.screenRect();
             if (rect.width !== 0) {
                 let doc = element.props.Document;
                 let width = doc.GetOrCreate(KeyStore.Width, NumberField);
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 43bc24a12..565402046 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -1,18 +1,25 @@
+import { action, computed } from "mobx";
 import { observer } from "mobx-react";
-import React = require("react");
-import { action, computed, trace } from "mobx";
-import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
-import { DragManager } from "../../util/DragManager";
-import "./CollectionFreeFormView.scss";
-import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
-import { KeyStore } from "../../../fields/KeyStore";
 import { Document } from "../../../fields/Document";
-import { ListField } from "../../../fields/ListField";
 import { FieldWaiting } from "../../../fields/Field";
+import { KeyStore } from "../../../fields/KeyStore";
+import { ListField } from "../../../fields/ListField";
+import { TextField } from "../../../fields/TextField";
+import { DragManager } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
-import { DocumentView } from "../nodes/DocumentView";
 import { undoBatch } from "../../util/UndoManager";
-import { CollectionViewBase, SubCollectionViewProps } from "./CollectionViewBase";
+import { CollectionDockingView } from "../collections/CollectionDockingView";
+import { CollectionSchemaView } from "../collections/CollectionSchemaView";
+import { CollectionView } from "../collections/CollectionView";
+import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
+import { DocumentView } from "../nodes/DocumentView";
+import { FormattedTextBox } from "../nodes/FormattedTextBox";
+import { ImageBox } from "../nodes/ImageBox";
+import "./CollectionFreeFormView.scss";
+import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
+import { CollectionViewBase } from "./CollectionViewBase";
+import React = require("react");
+const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
 
 @observer
 export class CollectionFreeFormView extends CollectionViewBase {
@@ -145,16 +152,13 @@ export class CollectionFreeFormView extends CollectionViewBase {
         });
     }
 
-    getTransform = (): Transform => {
-        return this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).transform(this.getLocalTransform())
-    }
 
-    getLocalTransform = (): Transform => {
-        return Transform.Identity.translate(-this.panX, -this.panY).scale(1 / this.scale);
+    @computed get backgroundLayout(): string | undefined {
+        let field = this.props.Document.GetT(KeyStore.BackgroundLayout, TextField);
+        if (field && field !== "<Waiting>") {
+            return field.Data;
+        }
     }
-
-    noScaling = () => 1;
-
     @computed
     get views() {
         const { fieldKey, Document } = this.props;
@@ -175,6 +179,21 @@ export class CollectionFreeFormView extends CollectionViewBase {
         return null;
     }
 
+    @computed
+    get backgroundView() {
+        return !this.backgroundLayout ? (null) :
+            (<JsxParser
+                components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView }}
+                bindings={this.props.bindings}
+                jsx={this.backgroundLayout}
+                showWarnings={true}
+                onError={(test: any) => console.log(test)}
+            />);
+    }
+    getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).transform(this.getLocalTransform())
+    getLocalTransform = (): Transform => Transform.Identity.translate(-this.panX, -this.panY).scale(1 / this.scale);
+    noScaling = () => 1;
+
     render() {
         const panx: number = this.props.Document.GetNumber(KeyStore.PanX, 0);
         const pany: number = this.props.Document.GetNumber(KeyStore.PanY, 0);
@@ -190,8 +209,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
                 <div className="collectionfreeformview"
                     style={{ width: "100%", transformOrigin: "left top", transform: ` translate(${panx}px, ${pany}px) scale(${this.zoomScaling}, ${this.zoomScaling})` }}
                     ref={this._canvasRef}>
-
-                    {this.props.BackgroundView ? this.props.BackgroundView() : null}
+                    {this.backgroundView}
                     {this.views}
                 </div>
             </div>
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index ca47f6998..d2db93120 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -34,7 +34,8 @@ export class CollectionSchemaView extends CollectionViewBase {
             fieldKey: rowProps.value[1],
             isSelected: () => false,
             select: () => { },
-            isTopMost: false
+            isTopMost: false,
+            bindings: {}
         }
         let contents = (
             <FieldView {...props} />
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index ff1803ec3..90080ab43 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -28,7 +28,7 @@ export class CollectionView extends React.Component<CollectionViewProps> {
 
     public static LayoutString(fieldKey: string = "DataKey") {
         return `<CollectionView Document={Document}
-                    ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} isSelected={isSelected} select={select}
+                    ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} isSelected={isSelected} select={select} bindings={bindings}
                     isTopMost={isTopMost} BackgroundView={BackgroundView} />`;
     }
     public active = () => {
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index 06de56383..da7f71163 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -19,7 +19,7 @@ export interface CollectionViewProps {
     isSelected: () => boolean;
     isTopMost: boolean;
     select: (ctrlPressed: boolean) => void;
-    BackgroundView?: () => JSX.Element;
+    bindings: any;
 }
 export interface SubCollectionViewProps extends CollectionViewProps {
     active: () => boolean;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d9b1d90d8..a9e211431 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -5,7 +5,6 @@ import { Field, FieldWaiting, Opt } from "../../../fields/Field";
 import { Key } from "../../../fields/Key";
 import { KeyStore } from "../../../fields/KeyStore";
 import { ListField } from "../../../fields/ListField";
-import { TextField } from "../../../fields/TextField";
 import { DragManager } from "../../util/DragManager";
 import { SelectionManager } from "../../util/SelectionManager";
 import { Transform } from "../../util/Transform";
@@ -84,21 +83,13 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     private _downX: number = 0;
     private _downY: number = 0;
 
-    get screenRect(): ClientRect | DOMRect {
-        return (this._mainCont.current) ? this._mainCont.current.getBoundingClientRect() : new DOMRect();
-    }
     @computed get active(): boolean { return SelectionManager.IsSelected(this) || !this.props.ContainingCollectionView || this.props.ContainingCollectionView.active(); }
     @computed get topMost(): boolean { return !this.props.ContainingCollectionView || this.props.ContainingCollectionView.collectionViewType == CollectionViewType.Docking; }
     @computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); }
     @computed get layoutKeys(): Key[] { return this.props.Document.GetData(KeyStore.LayoutKeys, ListField, new Array<Key>()); }
     @computed get layoutFields(): Key[] { return this.props.Document.GetData(KeyStore.LayoutFields, ListField, new Array<Key>()); }
-    @computed get backgroundLayout(): string | undefined {
-        let field = this.props.Document.GetT(KeyStore.BackgroundLayout, TextField);
-        if (field && field !== "<Waiting>") {
-            return field.Data;
-        }
-    }
 
+    screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect();
 
     onPointerDown = (e: React.PointerEvent): void => {
         this._downX = e.clientX;
@@ -174,6 +165,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
     }
 
+    @action
     onContextMenu = (e: React.MouseEvent): void => {
         e.preventDefault()
         e.stopPropagation();
@@ -230,32 +222,19 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             let field = this.props.Document.Get(key);
             this._documentBindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field;
         }
-
-        /*
-        tfs:
-        Should this be moved to CollectionFreeformView or another component that renders
-        Document backgrounds (or contents based on a layout key, which could be used here as well)
-         that CollectionFreeformView uses? It seems like a lot for it to be here considering only one view currently uses it...
-         */
-        let backgroundLayout = this.backgroundLayout;
-        if (backgroundLayout) {
-            let backgroundView = () => (<JsxParser
-                components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView }}
-                bindings={this._documentBindings}
-                jsx={this.backgroundLayout}
-                showWarnings={true}
-                onError={(test: any) => { console.log(test) }}
-            />);
-            this._documentBindings.BackgroundView = backgroundView;
-        }
+        this._documentBindings.bindings = this._documentBindings;
 
         var scaling = this.props.ContentScaling();
         var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0);
         var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0);
-        var nodeWidth = nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%";
-        var nodeHeight = nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%";
         return (
-            <div className="documentView-node" ref={this._mainCont} style={{ width: nodeWidth, height: nodeHeight, transformOrigin: "left top", transform: `scale(${scaling},${scaling})` }}
+            <div className="documentView-node" ref={this._mainCont}
+                style={{
+                    width: nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%",
+                    height: nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%",
+                    transformOrigin: "left top",
+                    transform: `scale(${scaling},${scaling})`
+                }}
                 onContextMenu={this.onContextMenu}
                 onPointerDown={this.onPointerDown} >
                 {this.mainContent}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 821172d71..97d3f2a85 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -22,11 +22,12 @@ export interface FieldViewProps {
     isSelected: () => boolean;
     select: () => void;
     isTopMost: boolean;
+    bindings: any;
 }
 
 @observer
 export class FieldView extends React.Component<FieldViewProps> {
-    public static LayoutString(fieldType: { name: string }) { return `<${fieldType.name} doc={Document} DocumentViewForField={DocumentView} fieldKey={DataKey} isSelected={isSelected} select={select} isTopMost={isTopMost} />`; }
+    public static LayoutString(fieldType: { name: string }) { return `<${fieldType.name} doc={Document} DocumentViewForField={DocumentView} bindings={bindings} fieldKey={DataKey} isSelected={isSelected} select={select} isTopMost={isTopMost} />`; }
     @computed
     get field(): FieldValue<Field> {
         const { doc, fieldKey } = this.props;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index b17650d06..16728d471 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -6,7 +6,6 @@ import { schema } from "prosemirror-schema-basic";
 import { EditorState, Transaction } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { Opt, FieldWaiting, FieldValue } from "../../../fields/Field";
-import { SelectionManager } from "../../util/SelectionManager";
 import "./FormattedTextBox.scss";
 import React = require("react")
 import { RichTextField } from "../../../fields/RichTextField";
-- 
cgit v1.2.3-70-g09d2


From 3213d828b4386eabc2ee19b47279d0053958ea2a Mon Sep 17 00:00:00 2001
From: Jude <julie_wang1@brown.edu>
Date: Sun, 24 Feb 2019 15:27:27 -0500
Subject: why doesn't this work

---
 src/client/views/collections/CollectionFreeFormView.tsx | 1 +
 src/client/views/collections/CollectionTreeView.tsx     | 7 ++++---
 src/client/views/collections/CollectionView.tsx         | 6 ++++++
 3 files changed, 11 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index cb6668634..a6296ba3e 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -10,6 +10,7 @@ import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
 import { CollectionSchemaView } from "../collections/CollectionSchemaView";
+import { CollectionTreeView } from "../collections/CollectionTreeView";
 import { CollectionView } from "../collections/CollectionView";
 import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
 import { DocumentView } from "../nodes/DocumentView";
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index adc2e032d..90cd5a4c0 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -7,14 +7,15 @@ import { ListField } from "../../../fields/ListField";
 @observer
 export class CollectionTreeView extends CollectionViewBase {
 
-    public static makeTreeView(document: Document) {
-        var children = document.GetT<ListField<Document>>(KeyStore.Data, ListField);
+    test = () => {
+        var children = this.props.Document.GetT<ListField<Document>>(KeyStore.Data, ListField);
         if (children != null) {
             console.log("\nNumber of Children: " + children);
         }
+        return "HELLO WORLD";
     }
 
     render() {
-        return "HELLO WORLD";
+        return { test };
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 90080ab43..35ebb5687 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -11,6 +11,7 @@ import { CollectionFreeFormView } from "./CollectionFreeFormView";
 import { CollectionDockingView } from "./CollectionDockingView";
 import { CollectionSchemaView } from "./CollectionSchemaView";
 import { CollectionViewProps } from "./CollectionViewBase";
+import { CollectionTreeView } from "./CollectionTreeView";
 
 
 
@@ -19,6 +20,7 @@ export enum CollectionViewType {
     Freeform,
     Schema,
     Docking,
+    Tree
 }
 
 export const COLLECTION_BORDER_WIDTH = 2;
@@ -91,6 +93,10 @@ export class CollectionView extends React.Component<CollectionViewProps> {
                 return (<CollectionDockingView {...this.props}
                     addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active}
                     CollectionView={this} />)
+            case CollectionViewType.Tree:
+                return (<CollectionTreeView {...this.props}
+                    addDocument={this.addDocument} removeDocument={this.removeDocument} active={this.active}
+                    CollectionView={this} />)
             default:
                 return <div></div>
         }
-- 
cgit v1.2.3-70-g09d2


From fe05db6c34d54e27ceeb853da5718aca4c52dcae Mon Sep 17 00:00:00 2001
From: madelinegr <laura_wilson@brown.edu>
Date: Sun, 24 Feb 2019 23:16:55 -0500
Subject: look it works

---
 .../views/collections/CollectionTreeView.tsx       | 98 ++++++++++++++++++++--
 src/client/views/collections/CollectionView.tsx    |  2 -
 src/client/views/nodes/DocumentView.tsx            |  1 +
 3 files changed, 92 insertions(+), 9 deletions(-)

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

diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 9cead9558..745b06c46 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -3,19 +3,103 @@ import { CollectionViewBase } from "./CollectionViewBase";
 import { Document } from "../../../fields/Document";
 import { KeyStore } from "../../../fields/KeyStore";
 import { ListField } from "../../../fields/ListField";
+import React = require("react")
+import { TextField } from "../../../fields/TextField";
+import { BasicField } from "../../../fields/BasicField";
+import { assertParenthesizedExpression } from "babel-types";
+import { observable, action } from "mobx";
+
+export interface TreeViewProps {
+    document: Document;
+}
 
 @observer
-export class CollectionTreeView extends CollectionViewBase {
+/**
+ * Component that takes in a document prop and a boolean whether it's collapsed or not.
+ */
+class TreeView extends React.Component<TreeViewProps> {
+
+    @observable
+    collapsed: boolean = false;
+
+    /**
+     * Renders a single child document. If this child is a collection, it will call renderTreeView again. Otherwise, it will just append a list element.
+     * @param document The document to render.
+     */
+    renderChild(document: Document) {
+        var children = document.GetT<ListField<Document>>(KeyStore.Data, ListField);
+        let title = document.GetT<TextField>(KeyStore.Title, TextField);
+
+        // if the title hasn't loaded, immediately return the div
+        if (!title || title === "<Waiting>") {
+            return <div key={document.Id}></div>;
+        }
+
+        // otherwise, check if it's a collection.
+        else if (children && children !== "<Waiting>") {
+            // if it's not collapsed, then render the full TreeView.
+            if (!this.collapsed) {
+                return (
+                    <li key={document.Id} onClick={action(() => this.collapsed = true)} >
+                        {title.Data}
+                        <ul key={document.Id}>
+                            <TreeView
+                                document={document}
+                            />
+                        </ul>
+                    </li>
+                );
+            } else {
+                return <li key={document.Id} onClick={action(() => this.collapsed = false)}>{title.Data}</li>
+            }
+        }
+
+        // finally, if it's a normal document, then render it as such.
+        else {
+            return <li key={document.Id}>{title.Data}</li>;
+        }
+    }
+
+    render() {
+        var children = this.props.document.GetT<ListField<Document>>(KeyStore.Data, ListField);
+
+        if (children && children !== "<Waiting>") {
+            return (<div>
+                {children.Data.map(value => this.renderChild(value))}
+            </div>)
+            // let results: JSX.Element[] = [];
+
+            // // append a list item for each child in the collection
+            // children.Data.forEach((value) => {
+            //     results.push(this.renderChild(value));
+            // })
 
-    test = () => {
-        var children = this.props.Document.GetT<ListField<Document>>(KeyStore.Data, ListField);
-        if (children != null) {
-            console.log("\nNumber of Children: " + children);
+            // return results;
+        } else {
+            return <div></div>;
         }
-        return "HELLO WORLD";
     }
+}
+
+
+@observer
+export class CollectionTreeView extends CollectionViewBase {
 
     render() {
-        return { test };
+        let titleStr = "";
+        let title = this.props.Document.GetT<TextField>(KeyStore.Title, TextField);
+        if (title && title !== "<Waiting>") {
+            titleStr = title.Data;
+        }
+        return (
+            <div>
+                <h3>{titleStr}</h3>
+                <ul>
+                    <TreeView
+                        document={this.props.Document}
+                    />
+                </ul>
+            </div>
+        );
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 35ebb5687..37fe43ab3 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -13,8 +13,6 @@ import { CollectionSchemaView } from "./CollectionSchemaView";
 import { CollectionViewProps } from "./CollectionViewBase";
 import { CollectionTreeView } from "./CollectionTreeView";
 
-
-
 export enum CollectionViewType {
     Invalid,
     Freeform,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ad1328e5d..f06ea632c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -189,6 +189,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked })
             ContextMenu.Instance.addItem({ description: "Freeform", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform) })
             ContextMenu.Instance.addItem({ description: "Schema", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema) })
+            ContextMenu.Instance.addItem({ description: "Treeview", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree) })
             ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) })
             ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15)
             SelectionManager.SelectDoc(this, e.ctrlKey);
-- 
cgit v1.2.3-70-g09d2


From c439f11ba9695703697f7abc53a7cc2fd2d5c1a2 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 25 Feb 2019 12:38:47 -0500
Subject: fixes for dropping documents without a know height.

---
 src/client/documents/Documents.ts                  |  6 +---
 src/client/views/DocumentDecorations.tsx           | 23 ++++++++--------
 .../views/collections/CollectionFreeFormView.tsx   | 30 ++++++++++++++------
 src/client/views/collections/CollectionView.tsx    | 11 ++++++--
 .../views/collections/CollectionViewBase.tsx       |  4 +--
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 32 +++++-----------------
 src/client/views/nodes/DocumentView.tsx            |  4 ++-
 src/client/views/nodes/FormattedTextBox.tsx        |  5 +++-
 src/client/views/nodes/ImageBox.tsx                | 13 +++++++--
 src/fields/Document.ts                             |  2 +-
 src/fields/Field.ts                                |  3 ++
 11 files changed, 73 insertions(+), 60 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 2dfff6235..15ecfbfe6 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -112,9 +112,7 @@ export namespace Documents {
             imageProto.Set(KeyStore.X, new NumberField(0));
             imageProto.Set(KeyStore.Y, new NumberField(0));
             imageProto.Set(KeyStore.NativeWidth, new NumberField(300));
-            imageProto.Set(KeyStore.NativeHeight, new NumberField(300));
             imageProto.Set(KeyStore.Width, new NumberField(300));
-            imageProto.Set(KeyStore.Height, new NumberField(300));
             imageProto.Set(KeyStore.Layout, new TextField(CollectionView.LayoutString("AnnotationsKey")));
             imageProto.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform)
             imageProto.Set(KeyStore.BackgroundLayout, new TextField(ImageBox.LayoutString()));
@@ -151,9 +149,7 @@ export namespace Documents {
         doc.Set(KeyStore.BackgroundLayout, new TextField(EmbeddedCaption()));
         doc.Set(KeyStore.OverlayLayout, new TextField(FixedCaption()));
         doc.Set(KeyStore.LayoutKeys, new ListField([KeyStore.Data, KeyStore.Annotations, KeyStore.Caption]));
-
-        let annotation = Documents.TextDocument({ title: "hello" });
-        doc.Set(KeyStore.Annotations, new ListField([annotation]));
+        console.log("" + doc.GetNumber(KeyStore.Height, 311));
         return doc;
     }
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 2f012913d..975a125f7 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -104,25 +104,26 @@ export class DocumentDecorations extends React.Component {
             const rect = element.screenRect();
             if (rect.width !== 0) {
                 let doc = element.props.Document;
-                let width = doc.GetOrCreate(KeyStore.Width, NumberField);
-                let height = doc.GetOrCreate(KeyStore.Height, NumberField);
+                let width = doc.GetNumber(KeyStore.Width, 0);
+                let nwidth = doc.GetNumber(KeyStore.NativeWidth, 0);
+                let nheight = doc.GetNumber(KeyStore.NativeHeight, 0);
+                let height = doc.GetNumber(KeyStore.Height, nwidth ? nheight / nwidth * width : 0);
                 let x = doc.GetOrCreate(KeyStore.X, NumberField);
                 let y = doc.GetOrCreate(KeyStore.Y, NumberField);
-                let scale = width.Data / rect.width;
-                let actualdW = Math.max(width.Data + (dW * scale), 20);
-                let actualdH = Math.max(height.Data + (dH * scale), 20);
-                x.Data += dX * (actualdW - width.Data);
-                y.Data += dY * (actualdH - height.Data);
+                let scale = width / rect.width;
+                let actualdW = Math.max(width + (dW * scale), 20);
+                let actualdH = Math.max(height + (dH * scale), 20);
+                x.Data += dX * (actualdW - width);
+                y.Data += dY * (actualdH - height);
                 var nativeWidth = doc.GetNumber(KeyStore.NativeWidth, 0);
                 var nativeHeight = doc.GetNumber(KeyStore.NativeHeight, 0);
                 if (nativeWidth > 0 && nativeHeight > 0) {
                     if (Math.abs(dW) > Math.abs(dH))
                         actualdH = nativeHeight / nativeWidth * actualdW;
-                    else
-                        actualdW = nativeWidth / nativeHeight * actualdH;
+                    else actualdW = nativeWidth / nativeHeight * actualdH;
                 }
-                width.Data = actualdW;
-                height.Data = actualdH;
+                doc.SetNumber(KeyStore.Width, actualdW);
+                doc.SetNumber(KeyStore.Height, actualdH);
             }
         })
     }
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index c40da6eaa..7cad2cc03 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -102,18 +102,30 @@ export class CollectionFreeFormView extends CollectionViewBase {
         e.stopPropagation();
         e.preventDefault();
         let coefficient = 1000;
-        // if (modes[e.deltaMode] == 'pixels') coefficient = 50;
-        // else if (modes[e.deltaMode] == 'lines') coefficient = 1000; // This should correspond to line-height??
-        let transform = this.getTransform();
 
-        let deltaScale = (1 - (e.deltaY / coefficient));
-        let [x, y] = transform.transformPoint(e.clientX, e.clientY);
+        if (e.ctrlKey) {
+            var nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0);
+            var nativeHeight = this.props.Document.GetNumber(KeyStore.NativeHeight, 0);
+            const coefficient = 1000;
+            let deltaScale = (1 - (e.deltaY / coefficient));
+            this.props.Document.SetNumber(KeyStore.NativeWidth, nativeWidth * deltaScale);
+            this.props.Document.SetNumber(KeyStore.NativeHeight, nativeHeight * deltaScale);
+            e.stopPropagation();
+            e.preventDefault();
+        } else {
+            // if (modes[e.deltaMode] == 'pixels') coefficient = 50;
+            // else if (modes[e.deltaMode] == 'lines') coefficient = 1000; // This should correspond to line-height??
+            let transform = this.getTransform();
 
-        let localTransform = this.getLocalTransform();
-        localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y)
+            let deltaScale = (1 - (e.deltaY / coefficient));
+            let [x, y] = transform.transformPoint(e.clientX, e.clientY);
 
-        this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale);
-        this.SetPan(localTransform.TranslateX, localTransform.TranslateY);
+            let localTransform = this.getLocalTransform();
+            localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y)
+
+            this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale);
+            this.SetPan(localTransform.TranslateX, localTransform.TranslateY);
+        }
     }
 
     @action
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 90080ab43..88c15da07 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -11,6 +11,7 @@ import { CollectionFreeFormView } from "./CollectionFreeFormView";
 import { CollectionDockingView } from "./CollectionDockingView";
 import { CollectionSchemaView } from "./CollectionSchemaView";
 import { CollectionViewProps } from "./CollectionViewBase";
+import { Field } from "../../../fields/Field";
 
 
 
@@ -39,9 +40,13 @@ export class CollectionView extends React.Component<CollectionViewProps> {
     }
     @action
     addDocument = (doc: Document): void => {
-        //TODO This won't create the field if it doesn't already exist
-        const value = this.props.Document.GetData(this.props.fieldKey, ListField, new Array<Document>())
-        value.push(doc);
+        if (this.props.Document.Get(this.props.fieldKey) instanceof Field) {
+            //TODO This won't create the field if it doesn't already exist
+            const value = this.props.Document.GetData(this.props.fieldKey, ListField, new Array<Document>())
+            value.push(doc);
+        } else {
+            this.props.Document.SetData(this.props.fieldKey, [doc], ListField);
+        }
     }
 
     @action
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index 7e269caf1..f64a48c18 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -60,7 +60,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
 
         let html = e.dataTransfer.getData("text/html");
         let text = e.dataTransfer.getData("text/plain");
-        if (html) {
+        if (html && html.indexOf("<img") != 0) {
             let htmlDoc = Documents.HtmlDocument(html, { ...options });
             htmlDoc.SetText(KeyStore.DocumentText, text);
             this.props.addDocument(htmlDoc);
@@ -72,7 +72,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
             if (item.kind === "string" && item.type.indexOf("uri") != -1) {
                 e.dataTransfer.items[i].getAsString(function (s) {
                     action(() => {
-                        var img = Documents.ImageDocument(s, { ...options, nativeWidth: 300, nativeHeight: 300, width: 300, height: 300 })
+                        var img = Documents.ImageDocument(s, { ...options, nativeWidth: 300, width: 300, })
 
                         let docs = that.props.Document.GetT(KeyStore.Data, ListField);
                         if (docs != FieldWaiting) {
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index d7243421a..50dc5a619 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -27,44 +27,26 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
         return `scale(${this.props.ContentScaling()}, ${this.props.ContentScaling()}) translate(${this.props.Document.GetNumber(KeyStore.X, 0)}px, ${this.props.Document.GetNumber(KeyStore.Y, 0)}px)`;
     }
 
-    @computed
-    get width(): number {
-        return this.props.Document.GetNumber(KeyStore.Width, 0);
-    }
-
-    @computed
-    get nativeWidth(): number {
-        return this.props.Document.GetNumber(KeyStore.NativeWidth, 0);
-    }
+    @computed get zIndex(): number { return this.props.Document.GetNumber(KeyStore.ZIndex, 0); }
+    @computed get width(): number { return this.props.Document.Width(); }
+    @computed get height(): number { return this.props.Document.Height(); }
+    @computed get nativeWidth(): number { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
+    @computed get nativeHeight(): number { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
 
     set width(w: number) {
         this.props.Document.SetData(KeyStore.Width, w, NumberField)
-        if (this.nativeWidth > 0 && this.nativeHeight > 0) {
+        if (this.nativeWidth && this.nativeHeight) {
             this.props.Document.SetNumber(KeyStore.Height, this.nativeHeight / this.nativeWidth * w)
         }
     }
 
-    @computed
-    get height(): number {
-        return this.props.Document.GetNumber(KeyStore.Height, 0);
-    }
-    @computed
-    get nativeHeight(): number {
-        return this.props.Document.GetNumber(KeyStore.NativeHeight, 0);
-    }
-
     set height(h: number) {
         this.props.Document.SetData(KeyStore.Height, h, NumberField);
-        if (this.nativeWidth > 0 && this.nativeHeight > 0) {
+        if (this.nativeWidth && this.nativeHeight) {
             this.props.Document.SetNumber(KeyStore.Width, this.nativeWidth / this.nativeHeight * h)
         }
     }
 
-    @computed
-    get zIndex(): number {
-        return this.props.Document.GetNumber(KeyStore.ZIndex, 0);
-    }
-
     set zIndex(h: number) {
         this.props.Document.SetData(KeyStore.ZIndex, h, NumberField)
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ad1328e5d..212697442 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -196,6 +196,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
 
     @computed get mainContent() {
+        var val = this.props.Document.Id;
         return <JsxParser
             components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebView }}
             bindings={this._documentBindings}
@@ -237,7 +238,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                     transform: `scale(${scaling},${scaling})`
                 }}
                 onContextMenu={this.onContextMenu}
-                onPointerDown={this.onPointerDown} >
+                onPointerDown={this.onPointerDown}
+            >
                 {this.mainContent}
             </div>
         )
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 60ee0b5e1..a58e1955f 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -111,10 +111,13 @@ export class FormattedTextBox extends React.Component<FieldViewProps> {
             e.stopPropagation();
         }
     }
+    onPointerWheel = (e: React.WheelEvent): void => {
+        e.stopPropagation();
+    }
     render() {
-        var val = this.props.doc.Get(this.props.fieldKey);
         return (<div className="formattedTextBox-cont"
             onPointerDown={this.onPointerDown}
+            onWheel={this.onPointerWheel}
             ref={this._ref} />)
     }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index b5ce8b28c..4fe73fb8d 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -9,12 +9,14 @@ import { FieldWaiting } from '../../../fields/Field';
 import { observer } from "mobx-react"
 import { observable, action } from 'mobx';
 import { KeyStore } from '../../../fields/KeyStore';
+import { element } from 'prop-types';
 
 @observer
 export class ImageBox extends React.Component<FieldViewProps> {
 
     public static LayoutString() { return FieldView.LayoutString(ImageBox) }
     private _ref: React.RefObject<HTMLDivElement>;
+    private _imgRef: React.RefObject<HTMLImageElement>;
     private _downX: number = 0;
     private _downY: number = 0;
     private _lastTap: number = 0;
@@ -25,12 +27,20 @@ export class ImageBox extends React.Component<FieldViewProps> {
         super(props);
 
         this._ref = React.createRef();
+        this._imgRef = React.createRef();
         this.state = {
             photoIndex: 0,
             isOpen: false,
         };
     }
 
+    @action
+    onLoad = (target: any) => {
+        var h = this._imgRef.current!.naturalHeight;
+        var w = this._imgRef.current!.naturalWidth;
+        this.props.doc.SetNumber(KeyStore.NativeHeight, this.props.doc.GetNumber(KeyStore.NativeWidth, 0) * h / w)
+    }
+
     componentDidMount() {
     }
 
@@ -84,10 +94,9 @@ export class ImageBox extends React.Component<FieldViewProps> {
         let path = field == FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
             field instanceof ImageField ? field.Data.href : "http://www.cs.brown.edu/~bcz/face.gif";
         let nativeWidth = this.props.doc.GetNumber(KeyStore.NativeWidth, 1);
-
         return (
             <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this._ref} >
-                <img src={path} width={nativeWidth} alt="Image not found" />
+                <img src={path} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} />
                 {this.lightbox(path)}
             </div>)
     }
diff --git a/src/fields/Document.ts b/src/fields/Document.ts
index 0d7d357a0..4e68b3b4d 100644
--- a/src/fields/Document.ts
+++ b/src/fields/Document.ts
@@ -31,7 +31,7 @@ export class Document extends Field {
     }
 
     public Width = () => { return this.GetNumber(KeyStore.Width, 0) }
-    public Height = () => { return this.GetNumber(KeyStore.Height, 0) }
+    public Height = () => { return this.GetNumber(KeyStore.Height, this.GetNumber(KeyStore.NativeWidth, 0) ? this.GetNumber(KeyStore.NativeHeight, 0) / this.GetNumber(KeyStore.NativeWidth, 0) * this.GetNumber(KeyStore.Width, 0) : 0) }
     public Scale = () => { return this.GetNumber(KeyStore.Scale, 1) }
 
     @computed
diff --git a/src/fields/Field.ts b/src/fields/Field.ts
index c7e0232af..d48509a47 100644
--- a/src/fields/Field.ts
+++ b/src/fields/Field.ts
@@ -1,6 +1,7 @@
 
 import { Utils } from "../Utils";
 import { Types } from "../server/Message";
+import { computed } from "mobx";
 
 export function Cast<T extends Field>(field: FieldValue<Field>, ctor: { new(): T }): Opt<T> {
     if (field) {
@@ -25,6 +26,8 @@ export abstract class Field {
     }
 
     private id: FieldId;
+
+    @computed
     get Id(): FieldId {
         return this.id;
     }
-- 
cgit v1.2.3-70-g09d2


From ad1aab1e757a2f0d8acc6038c19c54caa5b1ec48 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 25 Feb 2019 13:47:59 -0500
Subject: fixed so that docs are centered in middle of window.

---
 .../views/collections/CollectionDockingView.scss   |  4 ++++
 .../views/collections/CollectionDockingView.tsx    |  7 ++++---
 .../views/collections/CollectionFreeFormView.tsx   | 23 +++++++++++-----------
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../views/collections/CollectionViewBase.tsx       |  2 ++
 5 files changed, 22 insertions(+), 16 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 7c0b512a7..2706c3272 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -1,3 +1,7 @@
+.collectiondockingview-content {
+    height: 100%;
+}
+
 .collectiondockingview-container {
     position: relative;
     top: 0;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 2230ec14f..a0f457ef2 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -265,6 +265,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
 
     @observable private _mainCont = React.createRef<HTMLDivElement>();
     @observable private _panelWidth = 0;
+    @observable private _panelHeight = 0;
     @observable private _document: Opt<Document>;
 
     constructor(props: any) {
@@ -272,8 +273,8 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
         Server.GetField(this.props.documentId, action((f: Opt<Field>) => this._document = f as Document));
     }
 
-    private _nativeWidth = () => { return this._document!.GetNumber(KeyStore.NativeWidth, 0); }
-    private _nativeHeight = () => { return this._document!.GetNumber(KeyStore.NativeHeight, 0); }
+    private _nativeWidth = () => { return this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth); }
+    private _nativeHeight = () => { return this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight); }
     private _contentScaling = () => { return this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth); }
 
     ScreenToLocalTransform = () => {
@@ -297,7 +298,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                     ContainingCollectionView={undefined} />
             </div>
 
-        return <Measure onResize={action((r: any) => this._panelWidth = r.entry.width)}>
+        return <Measure onResize={action((r: any) => { this._panelWidth = r.entry.width; this._panelHeight = r.entry.height; })}>
             {({ measureRef }) => <div ref={measureRef}>  {content} </div>}
         </Measure>
     }
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 7cad2cc03..90eb8a44e 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -20,7 +20,6 @@ import "./CollectionFreeFormView.scss";
 import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
 import { CollectionViewBase } from "./CollectionViewBase";
 import React = require("react");
-import { Documents } from "../../documents/Documents";
 const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
 
 @observer
@@ -31,7 +30,6 @@ export class CollectionFreeFormView extends CollectionViewBase {
     private _downX: number = 0;
     private _downY: number = 0;
 
-
     @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0) }
     @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0) }
     @computed get scale(): number { return this.props.Document.GetNumber(KeyStore.Scale, 1); }
@@ -39,6 +37,8 @@ export class CollectionFreeFormView extends CollectionViewBase {
     @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
     @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
     @computed get zoomScaling() { return this.props.Document.GetNumber(KeyStore.Scale, 1); }
+    @computed get centeringShiftX() { return !this.props.Document.GetNumber(KeyStore.NativeWidth, 0) ? this.props.panelWidth() / 2 : 0; }  // shift so pan position is at center of window for non-overlay collections
+    @computed get centeringShiftY() { return !this.props.Document.GetNumber(KeyStore.NativeHeight, 0) ? this.props.panelHeight() / 2 : 0; }// shift so pan position is at center of window for non-overlay collections
 
     @undoBatch
     @action
@@ -118,6 +118,8 @@ export class CollectionFreeFormView extends CollectionViewBase {
             let transform = this.getTransform();
 
             let deltaScale = (1 - (e.deltaY / coefficient));
+            if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay)
+                deltaScale = 1 / this.zoomScaling;
             let [x, y] = transform.transformPoint(e.clientX, e.clientY);
 
             let localTransform = this.getLocalTransform();
@@ -132,17 +134,13 @@ export class CollectionFreeFormView extends CollectionViewBase {
     private SetPan(panX: number, panY: number) {
         const newPanX = Math.max((1 - this.zoomScaling) * this.nativeWidth, Math.min(0, panX));
         const newPanY = Math.max((1 - this.zoomScaling) * this.nativeHeight, Math.min(0, panY));
-        this.props.Document.SetNumber(KeyStore.PanX, false && this.isAnnotationOverlay ? newPanX : panX);
-        this.props.Document.SetNumber(KeyStore.PanY, false && this.isAnnotationOverlay ? newPanY : panY);
+        this.props.Document.SetNumber(KeyStore.PanX, this.isAnnotationOverlay ? newPanX : panX);
+        this.props.Document.SetNumber(KeyStore.PanY, this.isAnnotationOverlay ? newPanY : panY);
     }
 
     @action
     onDrop = (e: React.DragEvent): void => {
-        const panx: number = this.props.Document.GetNumber(KeyStore.PanX, 0);
-        const pany: number = this.props.Document.GetNumber(KeyStore.PanY, 0);
-        let transform = this.getTransform();
-
-        var pt = transform.transformPoint(e.pageX, e.pageY);
+        var pt = this.getTransform().transformPoint(e.pageX, e.pageY);
         super.onDrop(e, { x: pt[0], y: pt[1] });
     }
 
@@ -222,13 +220,14 @@ export class CollectionFreeFormView extends CollectionViewBase {
                 onError={(test: any) => console.log(test)}
             />);
     }
-    getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).transform(this.getLocalTransform())
+
+    getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH - this.centeringShiftX, -COLLECTION_BORDER_WIDTH - this.centeringShiftY).transform(this.getLocalTransform())
     getLocalTransform = (): Transform => Transform.Identity.translate(-this.panX, -this.panY).scale(1 / this.scale);
     noScaling = () => 1;
 
     render() {
-        const panx: number = this.props.Document.GetNumber(KeyStore.PanX, 0);
-        const pany: number = this.props.Document.GetNumber(KeyStore.PanY, 0);
+        const panx: number = this.props.Document.GetNumber(KeyStore.PanX, 0) + this.centeringShiftX;
+        const pany: number = this.props.Document.GetNumber(KeyStore.PanY, 0) + this.centeringShiftY;
         return (
             <div className="collectionfreeformview-container"
                 onPointerDown={this.onPointerDown}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 88c15da07..6d30cf365 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -29,7 +29,7 @@ export class CollectionView extends React.Component<CollectionViewProps> {
 
     public static LayoutString(fieldKey: string = "DataKey") {
         return `<CollectionView Document={Document}
-                    ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} isSelected={isSelected} select={select} bindings={bindings}
+                    ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings}
                     isTopMost={isTopMost} BackgroundView={BackgroundView} />`;
     }
     public active = () => {
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index f64a48c18..e53485183 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -20,6 +20,8 @@ export interface CollectionViewProps {
     isTopMost: boolean;
     select: (ctrlPressed: boolean) => void;
     bindings: any;
+    panelWidth: () => number;
+    panelHeight: () => number;
 }
 export interface SubCollectionViewProps extends CollectionViewProps {
     active: () => boolean;
-- 
cgit v1.2.3-70-g09d2


From 39215d8999413a5e27d222c6650fc9e84c7a9ae9 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 25 Feb 2019 16:08:36 -0500
Subject: added drag/drop out of schema view

---
 src/client/util/DragManager.ts                     |  20 ++--
 .../views/collections/CollectionFreeFormView.tsx   |  23 ++---
 .../views/collections/CollectionSchemaView.tsx     | 114 ++++++++++++++++-----
 src/client/views/collections/CollectionView.tsx    |   8 +-
 .../views/collections/CollectionViewBase.tsx       |  14 ++-
 src/client/views/nodes/DocumentView.tsx            |   2 +-
 6 files changed, 127 insertions(+), 54 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index eb4b3aeaa..fd026992b 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -61,7 +61,7 @@ export namespace DragManager {
         };
     }
 
-    export function StartDrag(ele: HTMLElement, dragData: { [id: string]: any }, options: DragOptions) {
+    export function StartDrag(ele: HTMLElement, dragData: { [id: string]: any }, options?: DragOptions) {
         DocumentDecorations.Instance.Hidden = true;
         if (!dragDiv) {
             dragDiv = document.createElement("div");
@@ -87,10 +87,12 @@ export namespace DragManager {
         dragDiv.appendChild(dragElement);
 
         let hideSource = false;
-        if (typeof options.hideSource === "boolean") {
-            hideSource = options.hideSource;
-        } else {
-            hideSource = options.hideSource();
+        if (options) {
+            if (typeof options.hideSource === "boolean") {
+                hideSource = options.hideSource;
+            } else {
+                hideSource = options.hideSource();
+            }
         }
         const wasHidden = ele.hidden;
         if (hideSource) {
@@ -107,7 +109,7 @@ export namespace DragManager {
         const upHandler = (e: PointerEvent) => {
             document.removeEventListener("pointermove", moveHandler, true);
             document.removeEventListener("pointerup", upHandler);
-            FinishDrag(dragElement, e, options, dragData);
+            FinishDrag(dragElement, e, dragData, options);
             if (hideSource && !wasHidden) {
                 ele.hidden = false;
             }
@@ -116,7 +118,7 @@ export namespace DragManager {
         document.addEventListener("pointerup", upHandler);
     }
 
-    function FinishDrag(dragEle: HTMLElement, e: PointerEvent, options: DragOptions, dragData: { [index: string]: any }) {
+    function FinishDrag(dragEle: HTMLElement, e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions) {
         dragDiv.removeChild(dragEle);
         const target = document.elementFromPoint(e.x, e.y);
         if (!target) {
@@ -130,7 +132,9 @@ export namespace DragManager {
                 data: dragData
             }
         }));
-        options.handlers.dragComplete({});
+        if (options) {
+            options.handlers.dragComplete({});
+        }
         DocumentDecorations.Instance.Hidden = false;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 90eb8a44e..b54d9e0cf 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -44,16 +44,13 @@ export class CollectionFreeFormView extends CollectionViewBase {
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
         super.drop(e, de);
-        const doc: DocumentView = de.data["document"];
-        const xOffset = de.data["xOffset"] as number || 0;
-        const yOffset = de.data["yOffset"] as number || 0;
-        //this should be able to use translate and scale methods on an Identity transform, no?
-        const transform = this.getTransform();
-        const screenX = de.x - xOffset;
-        const screenY = de.y - yOffset;
-        const [x, y] = transform.transformPoint(screenX, screenY);
-        doc.props.Document.SetNumber(KeyStore.X, x);
-        doc.props.Document.SetNumber(KeyStore.Y, y);
+        const docView: DocumentView = de.data["documentView"];
+        let doc: Document = docView ? docView.props.Document : de.data["document"];
+        let screenX = de.x - (de.data["xOffset"] as number || 0);
+        let screenY = de.y - (de.data["yOffset"] as number || 0);
+        const [x, y] = this.getTransform().transformPoint(screenX, screenY);
+        doc.SetNumber(KeyStore.X, x);
+        doc.SetNumber(KeyStore.Y, y);
         this.bringToFront(doc);
     }
 
@@ -148,15 +145,15 @@ export class CollectionFreeFormView extends CollectionViewBase {
     }
 
     @action
-    bringToFront(doc: DocumentView) {
+    bringToFront(doc: Document) {
         const { fieldKey: fieldKey, Document: Document } = this.props;
 
         const value: Document[] = Document.GetList<Document>(fieldKey, []).slice();
         value.sort((doc1, doc2) => {
-            if (doc1 === doc.props.Document) {
+            if (doc1 === doc) {
                 return 1;
             }
-            if (doc2 === doc.props.Document) {
+            if (doc2 === doc) {
                 return -1;
             }
             return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0);
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index dc952ef82..d5b82cbb6 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -15,6 +15,8 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView";
 import "./CollectionSchemaView.scss";
 import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
 import { CollectionViewBase } from "./CollectionViewBase";
+import { DragManager } from "../../util/DragManager";
+import { CollectionDockingView } from "./CollectionDockingView";
 
 // bcz: need to add drag and drop of rows and columns.  This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
 
@@ -30,6 +32,9 @@ export class CollectionSchemaView extends CollectionViewBase {
     @observable _selectedIndex = 0;
     @observable _splitPercentage: number = 50;
 
+
+
+
     renderCell = (rowProps: CellInfo) => {
         let props: FieldViewProps = {
             doc: rowProps.value[0],
@@ -42,31 +47,55 @@ export class CollectionSchemaView extends CollectionViewBase {
         let contents = (
             <FieldView {...props} />
         )
+        let reference = React.createRef<HTMLDivElement>();
+        let onRowMove = action((e: PointerEvent): void => {
+            e.stopPropagation();
+            e.preventDefault();
+
+            document.removeEventListener("pointermove", onRowMove);
+            document.removeEventListener('pointerup', onRowUp);
+            DragManager.StartDrag(reference.current!, { document: props.doc });
+        });
+        let onRowUp = action((e: PointerEvent): void => {
+            document.removeEventListener("pointermove", onRowMove);
+            document.removeEventListener('pointerup', onRowUp);
+        });
+        let onRowDown = (e: React.PointerEvent) => {
+            if (e.shiftKey) {
+                CollectionDockingView.Instance.StartOtherDrag(reference.current!, props.doc);
+                e.stopPropagation();
+            } else {
+                document.addEventListener("pointermove", onRowMove);
+                document.addEventListener('pointerup', onRowUp);
+            }
+        }
         return (
-            <EditableView contents={contents} height={36} GetValue={() => {
-                let field = props.doc.Get(props.fieldKey);
-                if (field && field instanceof Field) {
-                    return field.ToScriptString();
-                }
-                return field || "";
-            }} SetValue={(value: string) => {
-                let script = CompileScript(value);
-                if (!script.compiled) {
-                    return false;
-                }
-                let field = script();
-                if (field instanceof Field) {
-                    props.doc.Set(props.fieldKey, field);
-                    return true;
-                } else {
-                    let dataField = ToField(field);
-                    if (dataField) {
-                        props.doc.Set(props.fieldKey, dataField);
-                        return true;
-                    }
-                }
-                return false;
-            }}></EditableView>
+            <div onPointerDown={onRowDown} ref={reference}>
+                <EditableView contents={contents}
+                    height={36} GetValue={() => {
+                        let field = props.doc.Get(props.fieldKey);
+                        if (field && field instanceof Field) {
+                            return field.ToScriptString();
+                        }
+                        return field || "";
+                    }} SetValue={(value: string) => {
+                        let script = CompileScript(value);
+                        if (!script.compiled) {
+                            return false;
+                        }
+                        let field = script();
+                        if (field instanceof Field) {
+                            props.doc.Set(props.fieldKey, field);
+                            return true;
+                        } else {
+                            let dataField = ToField(field);
+                            if (dataField) {
+                                props.doc.Set(props.fieldKey, dataField);
+                                return true;
+                            }
+                        }
+                        return false;
+                    }}></EditableView></div>
         )
     }
 
@@ -91,21 +120,49 @@ export class CollectionSchemaView extends CollectionViewBase {
         };
     }
 
+    _startSplitPercent = 0;
     @action
     onDividerMove = (e: PointerEvent): void => {
         let nativeWidth = this._mainCont.current!.getBoundingClientRect();
         this._splitPercentage = Math.round((e.clientX - nativeWidth.left) / nativeWidth.width * 100);
     }
+    @action
     onDividerUp = (e: PointerEvent): void => {
         document.removeEventListener("pointermove", this.onDividerMove);
         document.removeEventListener('pointerup', this.onDividerUp);
+        if (this._startSplitPercent == this._splitPercentage) {
+            this._splitPercentage = this._splitPercentage == 1 ? 66 : 100;
+        }
     }
     onDividerDown = (e: React.PointerEvent) => {
+        this._startSplitPercent = this._splitPercentage;
         e.stopPropagation();
         e.preventDefault();
         document.addEventListener("pointermove", this.onDividerMove);
         document.addEventListener('pointerup', this.onDividerUp);
     }
+    @action
+    onExpanderMove = (e: PointerEvent): void => {
+        e.stopPropagation();
+        e.preventDefault();
+    }
+    @action
+    onExpanderUp = (e: PointerEvent): void => {
+        e.stopPropagation();
+        e.preventDefault();
+        document.removeEventListener("pointermove", this.onExpanderMove);
+        document.removeEventListener('pointerup', this.onExpanderUp);
+        if (this._startSplitPercent == this._splitPercentage) {
+            this._splitPercentage = this._splitPercentage == 100 ? 66 : 100;
+        }
+    }
+    onExpanderDown = (e: React.PointerEvent) => {
+        this._startSplitPercent = this._splitPercentage;
+        e.stopPropagation();
+        e.preventDefault();
+        document.addEventListener("pointermove", this.onExpanderMove);
+        document.addEventListener('pointerup', this.onExpanderUp);
+    }
 
     onPointerDown = (e: React.PointerEvent) => {
         // if (e.button === 2 && this.active) {
@@ -113,8 +170,10 @@ export class CollectionSchemaView extends CollectionViewBase {
         //     e.preventDefault();
         // } else 
         {
-            if (e.buttons === 1 && this.props.active()) {
-                e.stopPropagation();
+            if (e.buttons === 1) {
+                if (this.props.isSelected()) {
+                    e.stopPropagation();
+                }
             }
         }
     }
@@ -155,6 +214,8 @@ export class CollectionSchemaView extends CollectionViewBase {
                 }
             </Measure>
         )
+        let handle = !this.props.active() ? (null) : (
+            <div style={{ position: "absolute", height: "37px", width: "20px", zIndex: 20, right: 0, top: 0, background: "Black" }} onPointerDown={this.onExpanderDown} />);
         return (
             <div onPointerDown={this.onPointerDown} ref={this._mainCont} className="collectionSchemaView-container" style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }} >
                 <Measure onResize={action((r: any) => {
@@ -190,6 +251,7 @@ export class CollectionSchemaView extends CollectionViewBase {
                     style={{ position: "relative", float: "left", width: `calc(${100 - this._splitPercentage}% - ${this.DIVIDER_WIDTH}px)`, height: "100%" }}>
                     {content}
                 </div>
+                {handle}
             </div >
         )
     }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 6d30cf365..83886f933 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -53,7 +53,13 @@ export class CollectionView extends React.Component<CollectionViewProps> {
     removeDocument = (doc: Document): boolean => {
         //TODO This won't create the field if it doesn't already exist
         const value = this.props.Document.GetData(this.props.fieldKey, ListField, new Array<Document>())
-        let index = value.indexOf(doc);
+        let index = -1;
+        for (let i = 0; i < value.length; i++) {
+            if (value[i].Id == doc.Id) {
+                index = i;
+                break;
+            }
+        }
         if (index !== -1) {
             value.splice(index, 1)
 
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index e53485183..217536e2b 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -44,12 +44,16 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
     @undoBatch
     @action
     protected drop(e: Event, de: DragManager.DropEvent) {
-        const doc: DocumentView = de.data["document"];
-        if (doc.props.ContainingCollectionView && doc.props.ContainingCollectionView !== this.props.CollectionView) {
-            if (doc.props.RemoveDocument) {
-                doc.props.RemoveDocument(doc.props.Document);
+        const docView: DocumentView = de.data["documentView"];
+        const doc: Document = de.data["document"];
+        if (docView && docView.props.ContainingCollectionView && docView.props.ContainingCollectionView !== this.props.CollectionView) {
+            if (docView.props.RemoveDocument) {
+                docView.props.RemoveDocument(docView.props.Document);
             }
-            this.props.addDocument(doc.props.Document);
+            this.props.addDocument(docView.props.Document);
+        } else if (doc) {
+            this.props.removeDocument(doc);
+            this.props.addDocument(doc);
         }
         e.stopPropagation();
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 212697442..6fe78daee 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -124,7 +124,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                 this._contextMenuCanOpen = false;
                 const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
                 let dragData: { [id: string]: any } = {};
-                dragData["document"] = this;
+                dragData["documentView"] = this;
                 dragData["xOffset"] = e.x - left;
                 dragData["yOffset"] = e.y - top;
                 DragManager.StartDrag(this._mainCont.current, dragData, {
-- 
cgit v1.2.3-70-g09d2

