From b742c8850b184408fd61d8571fa68ecf01386141 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 26 Apr 2019 00:08:21 -0400
Subject: fixed some things with pdfs

---
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx     | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 56342c84c..405594eb1 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -283,7 +283,7 @@ export class CollectionFreeFormView extends CollectionSubView {
         super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY));
     }
 
-    private childViews = () => [...this.views, <CollectionFreeFormBackgroundView key="backgroundView" {...this.getDocumentViewProps(this.props.Document)} />];
+    private childViews = () => [...this.views, <CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} />];
     render() {
         const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         return (
@@ -307,7 +307,7 @@ export class CollectionFreeFormView extends CollectionSubView {
                         </CollectionFreeFormLinksView>
                         <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />
                     </CollectionFreeFormViewPannableContents>
-                    <CollectionFreeFormOverlayView {...this.getDocumentViewProps(this.props.Document)} />
+                    <CollectionFreeFormOverlayView {...this.getDocumentViewProps(this.props.Document)} {...this.props} />
                 </MarqueeView>
             </div>
         );
@@ -328,12 +328,12 @@ class CollectionFreeFormOverlayView extends React.Component<DocumentViewProps> {
 }
 
 @observer
-class CollectionFreeFormBackgroundView extends React.Component<DocumentViewProps> {
+class CollectionFreeFormBackgroundView extends React.Component<DocumentViewProps & { isSelected: () => boolean }> {
     @computed get backgroundView() {
         let backgroundLayout = this.props.Document.GetText(KeyStore.BackgroundLayout, "");
         return !backgroundLayout ? (null) :
             (<DocumentContentsView {...this.props} layoutKey={KeyStore.BackgroundLayout}
-                isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
+                isTopMost={this.props.isTopMost} isSelected={this.props.isSelected} select={emptyFunction} />);
     }
     render() {
         return this.backgroundView;
-- 
cgit v1.2.3-70-g09d2


From b2d9133f2fdb6dd2af3b74c4dd9de49145611b1b Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 26 Apr 2019 22:08:20 -0400
Subject: fixed previewcursor appearing on select. adjusted rounded border
 text.

---
 src/client/views/PreviewCursor.tsx                            |  2 +-
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx |  2 +-
 .../views/collections/collectionFreeForm/MarqueeView.tsx      |  6 +++++-
 src/client/views/nodes/DocumentView.tsx                       |  1 +
 src/client/views/nodes/FormattedTextBox.scss                  | 11 ++++++++++-
 src/client/views/nodes/FormattedTextBox.tsx                   | 11 +++++++----
 6 files changed, 25 insertions(+), 8 deletions(-)

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

diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx
index 2e63f751b..4359ba093 100644
--- a/src/client/views/PreviewCursor.tsx
+++ b/src/client/views/PreviewCursor.tsx
@@ -27,7 +27,7 @@ export class PreviewCursor extends React.Component<{}> {
         // the keyPress here.
         //if not these keys, make a textbox if preview cursor is active!
         if (e.key.startsWith("F") && !e.key.endsWith("F")) {
-        } else if (e.key != "Alt" && e.key != "Shift" && e.key != "Meta" && e.key != "Control" && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) {
+        } else if (e.key != "Escape" && e.key != "Alt" && e.key != "Shift" && e.key != "Meta" && e.key != "Control" && !e.defaultPrevented && !(e as any).DASHFormattedTextBoxHandled) {
             if ((!e.ctrlKey && !e.metaKey) || e.key === "v") {
                 PreviewCursor.Visible && PreviewCursor._onKeyPress && PreviewCursor._onKeyPress(e);
                 PreviewCursor.Visible = false;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 405594eb1..1a953006a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -295,7 +295,7 @@ export class CollectionFreeFormView extends CollectionSubView {
                         {this.props.Document.Title}
                     </text>
                 </svg> */}
-                <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments}
+                <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} isSelected={this.props.isSelected}
                     addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox}
                     getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}>
                     <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index c6681e014..0e2ac0a80 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -24,6 +24,7 @@ interface MarqueeViewProps {
     selectDocuments: (docs: Document[]) => void;
     removeDocument: (doc: Document) => boolean;
     addLiveTextDocument: (doc: Document) => void;
+    isSelected: () => boolean;
 }
 
 @observer
@@ -102,7 +103,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
     onClick = (e: React.MouseEvent): void => {
         if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
             Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
-            PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress);
+            if (this.props.isSelected()) {
+                PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress);
+            }
             // let the DocumentView stopPropagation of this event when it selects this document
         } else {  // why do we get a click event when the cursor have moved a big distance?
             // let's cut it off here so no one else has to deal with it.
@@ -137,6 +140,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             e.stopPropagation();
         }
         if (e.key === "c" || e.key === "r" || e.key === "e") {
+            console.log("DO MARQUEE");
             e.stopPropagation();
             let bounds = this.Bounds;
             let selected = this.marqueeSelect().map(d => {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index aaedd5b1c..3d6e0c4d8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -172,6 +172,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             document.removeEventListener("pointerup", this.onPointerUp);
             document.addEventListener("pointerup", this.onPointerUp);
             e.preventDefault();
+            e.stopPropagation();
         }
     }
     onPointerMove = (e: PointerEvent): void => {
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index f4f37250f..727d3c0b2 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -10,7 +10,7 @@
   outline: none !important;
 }
 
-.formattedTextBox-cont-scroll, .formattedTextBox-cont-hidden {
+.formattedTextBox-cont-scroll, .formattedTextBox-cont-hidden  {
   background: $light-color-secondary;
   padding: 0;
   border-width: 0px;
@@ -24,10 +24,19 @@
   height: 100%;
   pointer-events: all;
 }
+
 .formattedTextBox-cont-hidden {
     overflow: hidden;
     pointer-events: none;
 }
+.formattedTextBox-inner-rounded {
+    height: calc(100% - 40px);
+    width: calc(100% - 40px);
+    position: absolute;
+    overflow: scroll;
+    top: 20;
+    left: 20;
+}
 
 .menuicon {
   display: inline-block;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 8fb86f320..02d98de6b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -270,11 +270,12 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
         };
     }
     render() {
-        let style = this.props.isOverlay ? "scroll" : "hidden";
+        let style = this.props.isOverlay ? "-scroll" : "-hidden";
+        let rounded = this.props.Document.GetNumber(KeyStore.BorderRounding, 0) < 0 ? "-rounded" : "";
         let color = this.props.Document.GetText(KeyStore.BackgroundColor, "");
-        let interactive = InkingControl.Instance.selectedTool ? "" : "interactive";
+        let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive";
         return (
-            <div className={`formattedTextBox-cont-${style}`}
+            <div className={`formattedTextBox-cont${style}`}
                 style={{
                     pointerEvents: interactive ? "all" : "none",
                     background: color,
@@ -288,7 +289,9 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
                 onContextMenu={this.specificContextMenu}
                 // tfs: do we need this event handler
                 onWheel={this.onPointerWheel}
-                ref={this._ref} />
+            >
+                <div className={`formattedTextBox-inner${rounded}`} ref={this._ref} />
+            </div>
         );
     }
 }
-- 
cgit v1.2.3-70-g09d2


From 877b104a61d2ab072e3b6a006168ec03e2c46365 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Tue, 30 Apr 2019 00:11:27 -0400
Subject: Mostly fixed lists

---
 src/client/util/UndoManager.ts                     |   4 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   1 +
 src/debug/Test.tsx                                 |   8 +-
 src/new_fields/Doc.ts                              |  10 +-
 src/new_fields/List.ts                             | 192 +++++++++++++++++----
 src/new_fields/util.ts                             |   8 +
 6 files changed, 179 insertions(+), 44 deletions(-)

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

diff --git a/src/client/util/UndoManager.ts b/src/client/util/UndoManager.ts
index f7c3e5a7b..0b5280c4a 100644
--- a/src/client/util/UndoManager.ts
+++ b/src/client/util/UndoManager.ts
@@ -141,10 +141,10 @@ export namespace UndoManager {
     });
 
     //TODO Make this return the return value
-    export function RunInBatch(fn: () => void, batchName: string) {
+    export function RunInBatch<T>(fn: () => T, batchName: string) {
         let batch = StartBatch(batchName);
         try {
-            runInAction(fn);
+            return runInAction(fn);
         } finally {
             batch.end();
         }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index dcded7648..d796bd8d5 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -272,6 +272,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     get views() {
         let curPage = FieldValue(this.Document.curPage, -1);
         let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => {
+            if (!FieldValue(doc)) return prev;
             var page = Cast(doc.page, "number", -1);
             if (page === curPage || page === -1) {
                 let minim = Cast(doc.isMinimized, "boolean");
diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx
index 7415d4b28..04ef00722 100644
--- a/src/debug/Test.tsx
+++ b/src/debug/Test.tsx
@@ -61,14 +61,12 @@ class Test extends React.Component {
         assert(test2.testDoc === undefined);
         test2.url = 35;
         assert(test2.url === 35);
-        const l = new List<number>();
+        const l = new List<Doc>();
         //TODO push, and other array functions don't go through the proxy
-        l.push(1);
+        l.push(doc2);
         //TODO currently length, and any other string fields will get serialized
-        l.length = 3;
-        l[2] = 5;
+        doc.list = l;
         console.log(l.slice());
-        console.log(SerializationHelper.Serialize(l));
     }
 
     render() {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index d15b6309d..6ddb0df89 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -3,7 +3,7 @@ import { serializable, primitive, map, alias, list } from "serializr";
 import { autoObject, SerializationHelper, Deserializable } from "../client/util/SerializationHelper";
 import { Utils } from "../Utils";
 import { DocServer } from "../client/DocServer";
-import { setter, getter, getField, updateFunction } from "./util";
+import { setter, getter, getField, updateFunction, deleteProperty } from "./util";
 import { Cast, ToConstructor, PromiseValue, FieldValue } from "./Types";
 import { UndoManager, undoBatch } from "../client/util/UndoManager";
 import { listSpec } from "./Schema";
@@ -34,7 +34,7 @@ export class Doc extends RefField {
             set: setter,
             get: getter,
             ownKeys: target => Object.keys(target.__fields),
-            deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); },
+            deleteProperty: deleteProperty,
             defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); },
         });
         if (!id || forceSave) {
@@ -151,8 +151,8 @@ export namespace Doc {
     }
 
     export function MakeLink(source: Doc, target: Doc): Doc {
-        let linkDoc = new Doc;
-        UndoManager.RunInBatch(() => {
+        return UndoManager.RunInBatch(() => {
+            let linkDoc = new Doc;
             linkDoc.title = "New Link";
             linkDoc.linkDescription = "";
             linkDoc.linkTags = "Default";
@@ -171,8 +171,8 @@ export namespace Doc {
                 source.linkedToDocs = linkedTo = new List<Doc>();
             }
             linkedTo.push(linkDoc);
+            return linkDoc;
         }, "make link");
-        return linkDoc;
     }
 
     export function MakeDelegate(doc: Doc): Doc;
diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts
index e4a80f7a1..ec1bf44a9 100644
--- a/src/new_fields/List.ts
+++ b/src/new_fields/List.ts
@@ -1,21 +1,173 @@
 import { Deserializable, autoObject } from "../client/util/SerializationHelper";
 import { Field, Update, Self } from "./Doc";
-import { setter, getter } from "./util";
+import { setter, getter, deleteProperty } from "./util";
 import { serializable, alias, list } from "serializr";
 import { observable, observe, IArrayChange, IArraySplice, IObservableArray, Lambda, reaction } from "mobx";
 import { ObjectField, OnUpdate } from "./ObjectField";
+import { RefField } from "./RefField";
+import { ProxyField } from "./Proxy";
 
 const listHandlers: any = {
-    push(...items: any[]) {
-        // console.log("push");
-        // console.log(...items);
-        return this[Self].__fields.push(...items);
+    /// Mutator methods
+    copyWithin() {
+        throw new Error("copyWithin not supported yet");
+    },
+    fill(value: any, start?: number, end?: number) {
+        if (value instanceof RefField) {
+            throw new Error("fill with RefFields not supported yet");
+        }
+        const res = this[Self].__fields.fill(value, start, end);
+        this[Update]();
+        return res;
     },
     pop(): any {
-        return this[Self].__fields.pop();
+        const field = toRealField(this[Self].__fields.pop());
+        this[Update]();
+        return field;
+    },
+    push(...items: any[]) {
+        items = items.map(toObjectField);
+        const res = this[Self].__fields.push(...items);
+        this[Update]();
+        return res;
+    },
+    reverse() {
+        const res = this[Self].__fields.reverse();
+        this[Update]();
+        return res;
+    },
+    shift() {
+        const res = toRealField(this[Self].__fields.shift());
+        this[Update]();
+        return res;
+    },
+    sort(cmpFunc: any) {
+        const res = this[Self].__fields.sort(cmpFunc ? (first: any, second: any) => cmpFunc(toRealField(first), toRealField(second)) : undefined);
+        this[Update]();
+        return res;
+    },
+    splice(start: number, deleteCount: number, ...items: any[]) {
+        items = items.map(toObjectField);
+        const res = this[Self].__fields.splice(start, deleteCount, ...items);
+        this[Update]();
+        return res.map(toRealField);
+    },
+    unshift(...items: any[]) {
+        items = items.map(toObjectField);
+        const res = this[Self].__fields.unshift(...items);
+        this[Update]();
+        return res;
+
+    },
+    /// Accessor methods
+    concat(...items: any[]) {
+        return this[Self].__fields.map(toRealField).concat(...items);
+    },
+    includes(valueToFind: any, fromIndex: number) {
+        const fields = this[Self].__fields;
+        if (valueToFind instanceof RefField) {
+            return fields.map(toRealField).includes(valueToFind, fromIndex);
+        } else {
+            return fields.includes(valueToFind, fromIndex);
+        }
+    },
+    indexOf(valueToFind: any, fromIndex: number) {
+        const fields = this[Self].__fields;
+        if (valueToFind instanceof RefField) {
+            return fields.map(toRealField).indexOf(valueToFind, fromIndex);
+        } else {
+            return fields.indexOf(valueToFind, fromIndex);
+        }
+    },
+    join(separator: any) {
+        return this[Self].__fields.map(toRealField).join(separator);
+    },
+    lastIndexOf(valueToFind: any, fromIndex: number) {
+        const fields = this[Self].__fields;
+        if (valueToFind instanceof RefField) {
+            return fields.map(toRealField).lastIndexOf(valueToFind, fromIndex);
+        } else {
+            return fields.lastIndexOf(valueToFind, fromIndex);
+        }
+    },
+    slice(begin: number, end: number) {
+        return this[Self].__fields.slice(begin, end).map(toRealField);
+    },
+
+    /// Iteration methods
+    entries() {
+        return this[Self].__fields.map(toRealField).entries();
+    },
+    every(callback: any, thisArg: any) {
+        return this[Self].__fields.map(toRealField).every(callback, thisArg);
+        // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
+        // If we don't want to support the array parameter, we should use this version instead
+        // return this[Self].__fields.every((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+    },
+    filter(callback: any, thisArg: any) {
+        return this[Self].__fields.map(toRealField).filter(callback, thisArg);
+        // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
+        // If we don't want to support the array parameter, we should use this version instead
+        // return this[Self].__fields.filter((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+    },
+    find(callback: any, thisArg: any) {
+        return this[Self].__fields.map(toRealField).find(callback, thisArg);
+        // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
+        // If we don't want to support the array parameter, we should use this version instead
+        // return this[Self].__fields.find((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+    },
+    findIndex(callback: any, thisArg: any) {
+        return this[Self].__fields.map(toRealField).findIndex(callback, thisArg);
+        // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
+        // If we don't want to support the array parameter, we should use this version instead
+        // return this[Self].__fields.findIndex((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+    },
+    forEach(callback: any, thisArg: any) {
+        return this[Self].__fields.map(toRealField).forEach(callback, thisArg);
+        // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
+        // If we don't want to support the array parameter, we should use this version instead
+        // return this[Self].__fields.forEach((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+    },
+    map(callback: any, thisArg: any) {
+        return this[Self].__fields.map(toRealField).map(callback, thisArg);
+        // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
+        // If we don't want to support the array parameter, we should use this version instead
+        // return this[Self].__fields.map((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+    },
+    reduce(callback: any, initialValue: any) {
+        return this[Self].__fields.map(toRealField).reduce(callback, initialValue);
+        // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
+        // If we don't want to support the array parameter, we should use this version instead
+        // return this[Self].__fields.reduce((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue);
+    },
+    reduceRight(callback: any, initialValue: any) {
+        return this[Self].__fields.map(toRealField).reduceRight(callback, initialValue);
+        // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
+        // If we don't want to support the array parameter, we should use this version instead
+        // return this[Self].__fields.reduceRight((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue);
+    },
+    some(callback: any, thisArg: any) {
+        return this[Self].__fields.map(toRealField).some(callback, thisArg);
+        // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway.
+        // If we don't want to support the array parameter, we should use this version instead
+        // return this[Self].__fields.some((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg);
+    },
+    values() {
+        return this[Self].__fields.map(toRealField).values();
+    },
+    [Symbol.iterator]() {
+        return this[Self].__fields.map(toRealField).values();
     }
 };
 
+function toObjectField(field: Field) {
+    return field instanceof RefField ? new ProxyField(field) : field;
+}
+
+function toRealField(field: Field) {
+    return field instanceof ProxyField ? field.value() : field;
+}
+
 function listGetter(target: any, prop: string | number | symbol, receiver: any): any {
     if (listHandlers.hasOwnProperty(prop)) {
         return listHandlers[prop];
@@ -38,36 +190,15 @@ interface ListIndexUpdate<T> {
 
 type ListUpdate<T> = ListSpliceUpdate<T> | ListIndexUpdate<T>;
 
-const ObserveDisposer = Symbol("Observe Disposer");
-
-function listObserver<T extends Field>(this: ListImpl<T>, change: IArrayChange<T> | IArraySplice<T>) {
-    if (change.type === "splice") {
-        this[Update]({
-            index: change.index,
-            removedCount: change.removedCount,
-            added: change.added,
-            type: change.type
-        });
-    } else {
-        //This should already be handled by the getter for the Proxy
-        // this[Update]({
-        //     index: change.index,
-        //     newValue: change.newValue,
-        //     type: change.type
-        // });
-    }
-}
-
 @Deserializable("list")
 class ListImpl<T extends Field> extends ObjectField {
     constructor(fields: T[] = []) {
         super();
         this.___fields = fields;
-        this[ObserveDisposer] = observe(this.__fields as IObservableArray<T>, listObserver.bind(this));
         const list = new Proxy<this>(this, {
             set: setter,
-            get: getter,
-            deleteProperty: () => { throw new Error("Currently properties can't be deleted from documents, assign to undefined instead"); },
+            get: listGetter,
+            deleteProperty: deleteProperty,
             defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); },
         });
         return list;
@@ -82,8 +213,6 @@ class ListImpl<T extends Field> extends ObjectField {
 
     private set __fields(value) {
         this.___fields = value;
-        this[ObserveDisposer]();
-        this[ObserveDisposer] = observe(this.__fields as IObservableArray<T>, listObserver.bind(this));
     }
 
     // @serializable(alias("fields", list(autoObject())))
@@ -97,7 +226,6 @@ class ListImpl<T extends Field> extends ObjectField {
         update && update();
     }
 
-    private [ObserveDisposer]: Lambda;
     private [Self] = this;
 }
 export type List<T extends Field> = ListImpl<T> & T[];
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 511820115..128817ab8 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -78,6 +78,14 @@ export function getField(target: any, prop: string | number, ignoreProto: boolea
     return field;
 }
 
+export function deleteProperty(target: any, prop: string | number | symbol) {
+    if (typeof prop === "symbol") {
+        delete target[prop];
+        return true;
+    }
+    throw new Error("Currently properties can't be deleted from documents, assign to undefined instead");
+}
+
 export function updateFunction(target: any, prop: any, value: any) {
     return (diff?: any) => {
         if (!diff) diff = { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } };
-- 
cgit v1.2.3-70-g09d2


From e013b7b146f91b0ffbc26e3770f5f90f417da60b Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 30 Apr 2019 12:09:54 -0400
Subject: fixed inking

---
 src/client/views/InkingCanvas.tsx                      | 18 +++++++++++-------
 src/client/views/InkingStroke.scss                     |  3 +++
 src/client/views/InkingStroke.tsx                      |  8 ++++++--
 .../collectionFreeForm/CollectionFreeFormView.tsx      | 17 ++++++++++-------
 src/new_fields/Doc.ts                                  |  6 +++++-
 5 files changed, 35 insertions(+), 17 deletions(-)
 create mode 100644 src/client/views/InkingStroke.scss

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

diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 1e26893c5..1c0d13545 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -139,21 +139,25 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
         let curPage = NumCast(this.props.Document.curPage, -1);
         let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => {
             if (strokeData.page === -1 || strokeData.page === curPage) {
-                paths.push(<InkingStroke key={id} id={id} line={strokeData.pathData}
+                paths.push(<InkingStroke key={id} id={id}
+                    line={strokeData.pathData}
+                    count={strokeData.pathData.length}
                     offsetX={this.maxCanvasDim - this.inkMidX}
                     offsetY={this.maxCanvasDim - this.inkMidY}
-                    color={strokeData.color} width={strokeData.width}
-                    tool={strokeData.tool} deleteCallback={this.removeLine} />);
+                    color={strokeData.color}
+                    width={strokeData.width}
+                    tool={strokeData.tool}
+                    deleteCallback={this.removeLine} />);
             }
             return paths;
         }, [] as JSX.Element[]);
-        return [<svg className={`inkingCanvas-paths-markers`} key="Markers"
+        return [<svg className={`inkingCanvas-paths-ink`} key="Pens"
             style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }} >
-            {paths.filter(path => path.props.tool === InkTool.Highlighter)}
+            {paths.filter(path => path.props.tool !== InkTool.Highlighter)}
         </svg>,
-        <svg className={`inkingCanvas-paths-ink`} key="Pens"
+        <svg className={`inkingCanvas-paths-markers`} key="Markers"
             style={{ left: `${this.inkMidX - this.maxCanvasDim}px`, top: `${this.inkMidY - this.maxCanvasDim}px` }}>
-            {paths.filter(path => path.props.tool !== InkTool.Highlighter)}
+            {paths.filter(path => path.props.tool === InkTool.Highlighter)}
         </svg>];
     }
 
diff --git a/src/client/views/InkingStroke.scss b/src/client/views/InkingStroke.scss
new file mode 100644
index 000000000..cdbfdcff3
--- /dev/null
+++ b/src/client/views/InkingStroke.scss
@@ -0,0 +1,3 @@
+.inkingStroke-marker {
+    mix-blend-mode: multiply
+}
\ No newline at end of file
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 616299146..37b1f5899 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -1,14 +1,16 @@
 import { observer } from "mobx-react";
-import { observable } from "mobx";
+import { observable, trace } from "mobx";
 import { InkingControl } from "./InkingControl";
 import React = require("react");
 import { InkTool } from "../../new_fields/InkField";
+import "./InkingStroke.scss";
 
 
 interface StrokeProps {
     offsetX: number;
     offsetY: number;
     id: string;
+    count: number;
     line: Array<{ x: number, y: number }>;
     color: string;
     width: string;
@@ -48,10 +50,12 @@ export class InkingStroke extends React.Component<StrokeProps> {
     render() {
         let pathStyle = this.createStyle();
         let pathData = this.parseData(this.props.line);
+        let pathlength = this.props.count; // bcz: this is needed to force reactions to the line data changes
+        let marker = this.props.tool === InkTool.Highlighter ? "-marker" : "";
 
         let pointerEvents: any = InkingControl.Instance.selectedTool === InkTool.Eraser ? "all" : "none";
         return (
-            <path d={pathData} style={{ ...pathStyle, pointerEvents: pointerEvents }} strokeLinejoin="round" strokeLinecap="round"
+            <path className={`inkingStroke${marker}`} d={pathData} style={{ ...pathStyle, pointerEvents: pointerEvents }} strokeLinejoin="round" strokeLinecap="round"
                 onPointerOver={this.deleteStroke} onPointerDown={this.deleteStroke} />
         );
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d796bd8d5..2689f48cd 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,4 +1,4 @@
-import { action, computed } from "mobx";
+import { action, computed, trace } from "mobx";
 import { observer } from "mobx-react";
 import { emptyFunction, returnFalse, returnOne } from "../../../../Utils";
 import { DocumentManager } from "../../../util/DocumentManager";
@@ -19,7 +19,7 @@ import { MarqueeView } from "./MarqueeView";
 import React = require("react");
 import v5 = require("uuid/v5");
 import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema";
-import { Doc } from "../../../../new_fields/Doc";
+import { Doc, WidthSym, HeightSym } from "../../../../new_fields/Doc";
 import { FieldValue, Cast, NumCast } from "../../../../new_fields/Types";
 import { pageSchema } from "../../nodes/ImageBox";
 import { List } from "../../../../new_fields/List";
@@ -243,11 +243,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     focusDocument = (doc: Doc) => {
         this.setPan(
-            Cast(doc.x, "number", 0) + Cast(doc.width, "number", 0) / 2,
-            Cast(doc.y, "number", 0) + Cast(doc.height, "number", 0) / 2);
+            NumCast(doc.x) + NumCast(doc.width) / 2,
+            NumCast(doc.y) + NumCast(doc.height) / 2);
         this.props.focus(this.props.Document);
     }
 
+
     getDocumentViewProps(document: Doc): DocumentViewProps {
         return {
             Document: document,
@@ -258,8 +259,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             ScreenToLocalTransform: this.getTransform,
             isTopMost: false,
             selectOnLoad: document[Id] === this._selectOnLoaded,
-            PanelWidth: () => Cast(document.width, "number", 0),//TODO Types These are inline functions
-            PanelHeight: () => Cast(document.height, "number", 0),
+            PanelWidth: document[WidthSym],
+            PanelHeight: document[HeightSym],
             ContentScaling: returnOne,
             ContainingCollectionView: this.props.CollectionView,
             focus: this.focusDocument,
@@ -268,8 +269,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         };
     }
 
-    @computed
+    @computed.struct
     get views() {
+        trace();
         let curPage = FieldValue(this.Document.curPage, -1);
         let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => {
             if (!FieldValue(doc)) return prev;
@@ -295,6 +297,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     private childViews = () => [...this.views, <CollectionFreeFormBackgroundView key="backgroundView" {...this.getDocumentViewProps(this.props.Document)} />];
     render() {
+        trace();
         const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         return (
             <div className={containerName} ref={this.createDropTarget} onWheel={this.onPointerWheel}
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 6ddb0df89..0e5105761 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -4,7 +4,7 @@ import { autoObject, SerializationHelper, Deserializable } from "../client/util/
 import { Utils } from "../Utils";
 import { DocServer } from "../client/DocServer";
 import { setter, getter, getField, updateFunction, deleteProperty } from "./util";
-import { Cast, ToConstructor, PromiseValue, FieldValue } from "./Types";
+import { Cast, ToConstructor, PromiseValue, FieldValue, NumCast } from "./Types";
 import { UndoManager, undoBatch } from "../client/util/UndoManager";
 import { listSpec } from "./Schema";
 import { List } from "./List";
@@ -25,6 +25,8 @@ export type FieldResult<T extends Field = Field> = Opt<T> | FieldWaiting<Extract
 
 export const Update = Symbol("Update");
 export const Self = Symbol("Self");
+export const WidthSym = Symbol("Width");
+export const HeightSym = Symbol("Height");
 
 @Deserializable("doc").withFields(["id"])
 export class Doc extends RefField {
@@ -70,6 +72,8 @@ export class Doc extends RefField {
     }
 
     private [Self] = this;
+    public [WidthSym] = () => { return NumCast(this.__fields.width); }  // bcz: is this the right way to access width/height?   it didn't work with : this.width
+    public [HeightSym] = () => { return NumCast(this.__fields.height); }
 }
 
 export namespace Doc {
-- 
cgit v1.2.3-70-g09d2


From 37062ef8b33efebd9fafcd2c076d5cb49f5a288f Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 30 Apr 2019 13:43:15 -0400
Subject: from commit

---
 src/client/documents/Documents.ts                            | 12 ++++--------
 src/client/views/DocumentDecorations.tsx                     |  3 +--
 .../collectionFreeForm/CollectionFreeFormView.tsx            |  8 ++------
 3 files changed, 7 insertions(+), 16 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index aa5277910..ff21dd5b0 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -32,11 +32,7 @@ import { IconField } from "../../new_fields/IconField";
 import { listSpec } from "../../new_fields/Schema";
 import { DocServer } from "../DocServer";
 import { StrokeData, InkField } from "../../new_fields/InkField";
-import { KeyStore } from "../../fields/KeyStore";
 
-// export class stringArray implements List<any>  {
-//     public Values: string[] = [];
-// }
 export interface DocumentOptions {
     x?: number;
     y?: number;
@@ -60,7 +56,7 @@ export interface DocumentOptions {
     curPage?: number;
     documentText?: string;
     borderRounding?: number;
-    //schemaColumns?: stringArray;
+    schemaColumns?: List<string>;
     // [key: string]: Opt<Field>;
 }
 const delegateKeys = ["x", "y", "width", "height", "panX", "panY"];
@@ -243,13 +239,13 @@ export namespace Docs {
         if (!makePrototype) {
             return SetInstanceOptions(collProto, { ...options, viewType: CollectionViewType.Freeform }, new List(documents));
         }
-        return CreateInstance(collProto, new List(documents), { /*schemaColumns: [KeyStore.SchemaColumns],*/...options, viewType: CollectionViewType.Freeform });
+        return CreateInstance(collProto, new List(documents), { schemaColumns: new List(["schemaColumns"]), ...options, viewType: CollectionViewType.Freeform });
     }
     export function SchemaDocument(documents: Array<Doc>, options: DocumentOptions) {
-        return CreateInstance(collProto, new List(documents), { /*schemaColumns: [KeyStore.SchemaColumns], */...options, viewType: CollectionViewType.Schema });
+        return CreateInstance(collProto, new List(documents), { schemaColumns: new List(["schemaColumns"]), ...options, viewType: CollectionViewType.Schema });
     }
     export function TreeDocument(documents: Array<Doc>, options: DocumentOptions) {
-        return CreateInstance(collProto, new List(documents), { /*schemaColumns: [KeyStore.SchemaColumns], */...options, viewType: CollectionViewType.Tree });
+        return CreateInstance(collProto, new List(documents), { schemaColumns: new List(["schemaColumns"]), ...options, viewType: CollectionViewType.Tree });
     }
     export function DockDocument(config: string, options: DocumentOptions) {
         return CreateInstance(collProto, config, { ...options, viewType: CollectionViewType.Docking });
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 556117c54..8632286ab 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -18,7 +18,6 @@ import { Doc, FieldResult } from "../../new_fields/Doc";
 import { listSpec } from "../../new_fields/Schema";
 import { Docs } from "../documents/Documents";
 import { List } from "../../new_fields/List";
-import { KeyStore } from "../../fields/KeyStore";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -40,7 +39,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     @observable private _minimizedY = 0;
     @observable private _title: string = "";
     @observable private _edtingTitle = false;
-    @observable private _fieldKey = KeyStore.Title;
+    @observable private _fieldKey = "title";
     @observable private _hidden = false;
     @observable private _opacity = 1;
     @observable private _iconifying = false;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f99800e21..8d10666b7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -22,9 +22,7 @@ import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Sc
 import { Doc, WidthSym, HeightSym } from "../../../../new_fields/Doc";
 import { FieldValue, Cast, NumCast } from "../../../../new_fields/Types";
 import { pageSchema } from "../../nodes/ImageBox";
-import { List } from "../../../../new_fields/List";
 import { Id } from "../../../../new_fields/RefField";
-import { KeyStore } from "../../../../fields/KeyStore";
 
 export const panZoomSchema = createSchema({
     panX: "number",
@@ -272,7 +270,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     @computed.struct
     get views() {
-        trace();
         let curPage = FieldValue(this.Document.curPage, -1);
         let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => {
             if (!FieldValue(doc)) return prev;
@@ -298,7 +295,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     private childViews = () => [...this.views, <CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} />];
     render() {
-        trace();
         const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         return (
             <div className={containerName} ref={this.createDropTarget} onWheel={this.onPointerWheel}
@@ -333,7 +329,7 @@ class CollectionFreeFormOverlayView extends React.Component<DocumentViewProps> {
     @computed get overlayView() {
         let overlayLayout = Cast(this.props.Document.overlayLayout, "string", "");
         return !overlayLayout ? (null) :
-            (<DocumentContentsView {...this.props} layoutKey={KeyStore.OverlayLayout}
+            (<DocumentContentsView {...this.props} layoutKey={"overlayLayout"}
                 isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
     }
     render() {
@@ -346,7 +342,7 @@ class CollectionFreeFormBackgroundView extends React.Component<DocumentViewProps
     @computed get backgroundView() {
         let backgroundLayout = Cast(this.props.Document.backgroundLayout, "string", "");
         return !backgroundLayout ? (null) :
-            (<DocumentContentsView {...this.props} layoutKey={KeyStore.BackgroundLayout}
+            (<DocumentContentsView {...this.props} layoutKey={"backgroundLayout"}
                 isTopMost={this.props.isTopMost} isSelected={this.props.isSelected} select={emptyFunction} />);
     }
     render() {
-- 
cgit v1.2.3-70-g09d2


From 7261d69c9e9dcdbcc413eff062eb01de2032f9ef Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 30 Apr 2019 15:21:20 -0400
Subject: fixed link lines

---
 src/client/views/DocumentDecorations.tsx              |  2 +-
 .../CollectionFreeFormLinksView.tsx                   |  4 ++--
 .../collectionFreeForm/CollectionFreeFormView.tsx     | 19 +++++--------------
 .../collections/collectionFreeForm/MarqueeView.tsx    |  4 +---
 .../views/nodes/CollectionFreeFormDocumentView.tsx    |  2 ++
 src/client/views/nodes/DocumentView.tsx               |  9 +++++----
 6 files changed, 16 insertions(+), 24 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 8632286ab..1dc7c8394 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -268,7 +268,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 minDocs.map(minDoc => {
                     minDoc.x = NumCast(minDocs[0].x);
                     minDoc.y = NumCast(minDocs[0].y);
-                    minDoc.linkTags = new List(minDocs);
+                    minDoc.linkTags = new List(minDocs.filter(d => d != minDoc));
                     if (this._iconifying && selectedDocs[0].props.removeDocument) {
                         selectedDocs[0].props.removeDocument(minDoc);
                         (minDoc.maximizedDoc as Doc).minimizedDoc = undefined;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index e5dcf8c29..4a75fccff 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -85,10 +85,10 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
             equalViews = DocumentManager.Instance.getDocumentViews(containerDoc.proto!);
         }
         if (view.props.ContainingCollectionView) {
-            let collid = view.props.ContainingCollectionView.props.Document.Id;
+            let collid = view.props.ContainingCollectionView.props.Document[Id];
             Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).
                 filter(child =>
-                    child.Id === collid).map(view =>
+                    child[Id] === collid).map(view =>
                         DocumentManager.Instance.getDocumentViews(view).map(view =>
                             equalViews.push(view)));
         }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 8d10666b7..e54553d2b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -97,7 +97,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     if (!NumCast(d.height)) {
                         let nw = NumCast(d.nativeWidth);
                         let nh = NumCast(d.nativeHeight);
-                        d.height = nw && nh ? nh / nw * NumCast(d.Width) : 300;
+                        d.height = nw && nh ? nh / nw * NumCast(d.width) : 300;
                     }
                     this.bringToFront(d);
                 });
@@ -108,12 +108,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         return false;
     }
 
-    @action
-    cleanupInteractions = () => {
-        document.removeEventListener("pointermove", this.onPointerMove);
-        document.removeEventListener("pointerup", this.onPointerUp);
-    }
-
     @action
     onPointerDown = (e: React.PointerEvent): void => {
         let childSelected = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), [] as Doc[]).filter(doc => doc).reduce((childSelected, doc) => {
@@ -125,7 +119,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                 (e.button === 0 && e.altKey)) && (childSelected || this.props.active()))) ||
             (!CollectionFreeFormView.RIGHT_BTN_DRAG &&
                 ((e.button === 0 && !e.altKey && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) && (childSelected || this.props.active())))) {
-            this.cleanupInteractions();
+            document.removeEventListener("pointermove", this.onPointerMove);
+            document.removeEventListener("pointerup", this.onPointerUp);
             document.addEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointerup", this.onPointerUp);
             this._lastX = e.pageX;
@@ -134,7 +129,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     }
 
     onPointerUp = (e: PointerEvent): void => {
-        this.cleanupInteractions();
+        document.removeEventListener("pointermove", this.onPointerMove);
+        document.removeEventListener("pointerup", this.onPointerUp);
     }
 
     @action
@@ -300,11 +296,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             <div className={containerName} ref={this.createDropTarget} onWheel={this.onPointerWheel}
                 style={{ borderRadius: "inherit" }}
                 onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} >
-                {/* <svg viewBox="0 0 180 18" style={{ top: "50%", opacity: 0.05, position: "absolute" }}>
-                    <text y="15" >
-                        {this.props.Document.Title}
-                    </text>
-                </svg> */}
                 <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} isSelected={this.props.isSelected}
                     addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox}
                     getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}>
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 1d3850a72..85a12defa 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -109,9 +109,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
     onClick = (e: React.MouseEvent): void => {
         if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
             Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
-            if (this.props.isSelected()) {
-                PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress);
-            }
+            PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress);
             // let the DocumentView stopPropagation of this event when it selects this document
         } else {  // why do we get a click event when the cursor have moved a big distance?
             // let's cut it off here so no one else has to deal with it.
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index bd084bfe0..c8f0bca91 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -114,6 +114,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
         let isMinimized: boolean | undefined;
         let minimizedDocSet = Cast(this.props.Document.linkTags, listSpec(Doc));
         if (!minimizedDocSet) return;
+        let docs = minimizedDocSet.map(d => d);
+        docs.push(this.props.Document);
         minimizedDocSet.map(async minimizedDoc => {
             if (minimizedDoc instanceof Document) {
                 this.props.addDocument && this.props.addDocument(minimizedDoc, false);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ac3dcde42..eab068355 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -308,8 +308,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     isSelected = () => SelectionManager.IsSelected(this);
     select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed);
 
-    @computed get nativeWidth() { return FieldValue(this.Document.nativeWidth, 0); }
-    @computed get nativeHeight() { return FieldValue(this.Document.nativeHeight, 0); }
+    @computed get nativeWidth() { return this.Document.nativeWidth || 0; }
+    @computed get nativeHeight() { return this.Document.nativeHeight || 0; }
     @computed get contents() { return (<DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={"layout"} />); }
 
     render() {
@@ -322,8 +322,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 ref={this._mainCont}
                 style={{
                     borderRadius: "inherit",
-                    background: FieldValue(this.Document.backgroundColor) || "",
-                    width: nativeWidth, height: nativeHeight,
+                    background: this.Document.backgroundColor || "",
+                    width: nativeWidth,
+                    height: nativeHeight,
                     transform: `scale(${scaling}, ${scaling})`
                 }}
                 onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
-- 
cgit v1.2.3-70-g09d2

