From d0379269b3261f846c42e30f306419044b6025a7 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 14 Apr 2019 10:52:27 -0400
Subject: fixed some scrolling artifacts

---
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx     | 8 ++++++--
 1 file changed, 6 insertions(+), 2 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 d0b1e7f2c..0da6fe49c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -38,7 +38,7 @@ export class CollectionFreeFormView extends CollectionSubView {
     }
 
     public addDocument = (newBox: Document, allowDuplicates: boolean) =>
-        this.props.addDocument(this.bringToFront(newBox), false);
+        this.props.addDocument(this.bringToFront(newBox), false)
 
     public selectDocuments = (docs: Document[]) => {
         SelectionManager.DeselectAll;
@@ -161,7 +161,9 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
-        this.props.select(false);
+        if (!this.props.active()) {
+            return;
+        }
         e.stopPropagation();
         let coefficient = 1000;
 
@@ -191,6 +193,8 @@ export class CollectionFreeFormView extends CollectionSubView {
 
             this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale);
             this.SetPan(-localTransform.TranslateX / localTransform.Scale, -localTransform.TranslateY / localTransform.Scale);
+            e.stopPropagation();
+            e.preventDefault();
         }
     }
 
-- 
cgit v1.2.3-70-g09d2


From 7e05ea0058766a3afa2ec82f6312f2df87178883 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 14 Apr 2019 12:23:10 -0400
Subject: starting to add LOD

---
 src/client/views/Main.tsx                          |  1 +
 .../views/collections/CollectionBaseView.tsx       |  6 +-
 .../views/collections/CollectionDockingView.tsx    |  1 +
 .../views/collections/CollectionSchemaView.tsx     |  1 +
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 72 +++++++++++++---------
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 13 ++--
 src/client/views/nodes/DocumentView.tsx            |  1 +
 src/client/views/nodes/FieldView.tsx               |  1 +
 src/fields/KeyStore.ts                             |  1 +
 9 files changed, 57 insertions(+), 40 deletions(-)

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

diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index ed61aa5a7..babd3be2a 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -295,6 +295,7 @@ export class Main extends React.Component {
             <DocumentView Document={this.mainContainer}
                 addDocument={undefined}
                 removeDocument={undefined}
+                opacity={1}
                 ScreenToLocalTransform={Transform.Identity}
                 ContentScaling={this.noScaling}
                 PanelWidth={this.pwidthFunc}
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index b5eaab349..bff56e8c3 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -1,4 +1,4 @@
-import { action } from 'mobx';
+import { action, computed } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
 import { Document } from '../../../fields/Document';
@@ -80,12 +80,16 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
         }
         return false;
     }
+    @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
 
     @action.bound
     addDocument(doc: Document, allowDuplicates: boolean = false): boolean {
         let props = this.props;
         var curPage = props.Document.GetNumber(KeyStore.CurPage, -1);
         doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage));
+        if (this.isAnnotationOverlay) {
+            doc.SetOnPrototype(KeyStore.Zoom, new NumberField(this.props.Document.GetNumber(KeyStore.Scale, 1)));
+        }
         if (curPage >= 0) {
             doc.SetOnPrototype(KeyStore.AnnotationOn, props.Document);
         }
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index eb1cd1c09..6d772b90e 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -343,6 +343,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                 <DocumentView key={this._document.Id} Document={this._document}
                     addDocument={undefined}
                     removeDocument={undefined}
+                    opacity={1}
                     ContentScaling={this._contentScaling}
                     PanelWidth={this._nativeWidth}
                     PanelHeight={this._nativeHeight}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index fdb82690a..2a1d1dd94 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -307,6 +307,7 @@ export class CollectionSchemaView extends CollectionSubView {
                             <DocumentView Document={doc}
                                 addDocument={this.props.addDocument} removeDocument={this.props.removeDocument}
                                 isTopMost={false}
+                                opacity={1}
                                 selectOnLoad={false}
                                 ScreenToLocalTransform={this.getPreviewTransform}
                                 ContentScaling={this.getContentScaling}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 0da6fe49c..94945bde6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable, runInAction } from "mobx";
+import { action, computed, observable, runInAction, untracked } from "mobx";
 import { observer } from "mobx-react";
 import Measure from "react-measure";
 import { Document } from "../../../../fields/Document";
@@ -37,8 +37,12 @@ export class CollectionFreeFormView extends CollectionSubView {
         this.addDocument(newBox, false);
     }
 
-    public addDocument = (newBox: Document, allowDuplicates: boolean) =>
-        this.props.addDocument(this.bringToFront(newBox), false)
+    public addDocument = (newBox: Document, allowDuplicates: boolean) => {
+        if (this.isAnnotationOverlay) {
+            newBox.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1));
+        }
+        return this.props.addDocument(this.bringToFront(newBox), false);
+    }
 
     public selectDocuments = (docs: Document[]) => {
         SelectionManager.DeselectAll;
@@ -131,25 +135,27 @@ export class CollectionFreeFormView extends CollectionSubView {
                 let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
                 let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
                 let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
-                let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0;
-                let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx;
-                let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0;
-                let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny;
-                let ranges = docs.filter(doc => doc).reduce((range, doc) => {
-                    let x = doc.GetNumber(KeyStore.X, 0);
-                    let xe = x + doc.GetNumber(KeyStore.Width, 0);
-                    let y = doc.GetNumber(KeyStore.Y, 0);
-                    let ye = y + doc.GetNumber(KeyStore.Height, 0);
-                    return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
-                    [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
-                }, [[minx, maxx], [miny, maxy]]);
-                let panelwidth = this._pwidth / this.scale / 2;
-                let panelheight = this._pheight / this.scale / 2;
                 let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
-                if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx;
-                if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx;
-                if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
-                if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy;
+                if (!this.isAnnotationOverlay) {
+                    let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0;
+                    let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx;
+                    let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0;
+                    let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny;
+                    let ranges = docs.filter(doc => doc).reduce((range, doc) => {
+                        let x = doc.GetNumber(KeyStore.X, 0);
+                        let xe = x + doc.GetNumber(KeyStore.Width, 0);
+                        let y = doc.GetNumber(KeyStore.Y, 0);
+                        let ye = y + doc.GetNumber(KeyStore.Height, 0);
+                        return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
+                        [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
+                    }, [[minx, maxx], [miny, maxy]]);
+                    let panelwidth = this._pwidth / this.scale / 2;
+                    let panelheight = this._pheight / this.scale / 2;
+                    if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx;
+                    if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx;
+                    if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
+                    if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy;
+                }
                 this.SetPan(x - dx, y - dy);
                 this._lastX = e.pageX;
                 this._lastY = e.pageY;
@@ -161,9 +167,9 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
-        if (!this.props.active()) {
-            return;
-        }
+        // if (!this.props.active()) {
+        //     return;
+        // }
         e.stopPropagation();
         let coefficient = 1000;
 
@@ -255,9 +261,10 @@ export class CollectionFreeFormView extends CollectionSubView {
         this.props.focus(this.props.Document);
     }
 
-    getDocumentViewProps(document: Document): DocumentViewProps {
+    getDocumentViewProps(document: Document, opacity: number): DocumentViewProps {
         return {
             Document: document,
+            opacity: opacity,
             addDocument: this.props.addDocument,
             removeDocument: this.props.removeDocument,
             moveDocument: this.props.moveDocument,
@@ -277,25 +284,30 @@ export class CollectionFreeFormView extends CollectionSubView {
     @computed
     get views() {
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
-        return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
+        let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
             var page = doc.GetNumber(KeyStore.Page, -1);
-            if (page === curPage || page === -1) {
-                prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />);
+            var zoom = doc.GetNumber(KeyStore.Zoom, 1);
+            var dv = DocumentManager.Instance.getDocumentView(doc);
+            let opacity = this.isAnnotationOverlay && (!dv || !SelectionManager.IsSelected(dv)) ? 1 - Math.abs(zoom - this.scale) : 1;
+            if ((page === curPage || page === -1)) {
+                prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc, opacity)} />);
             }
             return prev;
         }, [] as JSX.Element[]);
+        untracked(() => this._selectOnLoaded = "");
+        return docviews;
     }
 
     @computed
     get backgroundView() {
         return !this.backgroundLayout ? (null) :
-            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
+            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document, 1)}
                 layoutKey={KeyStore.BackgroundLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
     }
     @computed
     get overlayView() {
         return !this.overlayLayout ? (null) :
-            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
+            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document, 1)}
                 layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
     }
 
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 77f41105f..0aa152209 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -6,7 +6,6 @@ import { Transform } from "../../util/Transform";
 import { DocumentView, DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
 import React = require("react");
-import { thisExpression } from "babel-types";
 
 
 @observer
@@ -16,18 +15,13 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
     constructor(props: DocumentViewProps) {
         super(props);
     }
-    get screenRect(): ClientRect | DOMRect {
-        if (this._mainCont.current) {
-            return this._mainCont.current.getBoundingClientRect();
-        }
-        return new DOMRect();
-    }
 
     @computed
     get transform(): string {
-        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)`;
+        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) scale(${this.zoom}, ${this.zoom}) `;
     }
 
+    @computed get zoom(): number { return 1 / this.props.Document.GetNumber(KeyStore.Zoom, 1); }
     @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(); }
@@ -57,7 +51,7 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
     getTransform = (): Transform =>
         this.props.ScreenToLocalTransform()
             .translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0))
-            .scale(1 / this.contentScaling())
+            .scale(1 / this.contentScaling()).scale(1 / this.zoom)
 
     @computed
     get docView() {
@@ -74,6 +68,7 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
     render() {
         return (
             <div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
+                opacity: this.props.opacity,
                 transformOrigin: "left top",
                 transform: this.transform,
                 pointerEvents: "all",
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 4d7a85316..f0f9af89f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -26,6 +26,7 @@ import { undoBatch, UndoManager } from "../../util/UndoManager";
 export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView>;
     Document: Document;
+    opacity: number;
     addDocument?: (doc: Document, allowDuplicates?: boolean) => boolean;
     removeDocument?: (doc: Document) => boolean;
     moveDocument?: (doc: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 0037d7b28..e0c5e19fb 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -79,6 +79,7 @@ export class FieldView extends React.Component<FieldViewProps> {
                 <DocumentContentsView Document={field}
                     addDocument={undefined}
                     removeDocument={undefined}
+                    opacity={1}
                     ScreenToLocalTransform={Transform.Identity}
                     ContentScaling={() => 1}
                     PanelWidth={() => 100}
diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts
index da2d7268f..19431bbe3 100644
--- a/src/fields/KeyStore.ts
+++ b/src/fields/KeyStore.ts
@@ -15,6 +15,7 @@ export namespace KeyStore {
     export const Width = new Key("Width");
     export const Height = new Key("Height");
     export const ZIndex = new Key("ZIndex");
+    export const Zoom = new Key("Zoom");
     export const Data = new Key("Data");
     export const Annotations = new Key("Annotations");
     export const ViewType = new Key("ViewType");
-- 
cgit v1.2.3-70-g09d2


From a12bc4e408119ca2c310c04598c3aa2b424751c5 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 14 Apr 2019 15:10:12 -0400
Subject: restored ContainingCollectionView for use in drawings links (maybe
 brushing later)

---
 src/client/views/Main.tsx                          |  2 +-
 .../views/collections/CollectionSchemaView.tsx     |  4 +++-
 src/client/views/collections/CollectionSubView.tsx |  2 ++
 src/client/views/collections/CollectionView.tsx    |  8 +++----
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |  5 ++--
 src/client/views/nodes/DocumentContentsView.tsx    | 28 ++++++++++++----------
 src/client/views/nodes/FieldView.tsx               |  7 ++++--
 src/client/views/nodes/KeyValuePair.tsx            |  2 ++
 9 files changed, 36 insertions(+), 24 deletions(-)

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

diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index babd3be2a..03cfbe9da 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -282,7 +282,7 @@ export class Main extends React.Component {
             return <div className="mainDiv-textInput" style={{ pointerEvents: "none", transform: `translate(${x}px, ${y}px) scale(${1 / s[0]},${1 / s[0]})`, width: "auto", height: "auto" }} >
                 <div className="mainDiv-textInput" onPointerDown={this.textBoxDown} ref={this._textProxyDiv} onScroll={this.textScroll} style={{ pointerEvents: "none", transform: `scale(${1}, ${1})`, width: `${w * s[0]}px`, height: `${h * s[0]}px` }}>
                     <FormattedTextBox fieldKey={this._textFieldKey!} isOverlay={true} Document={this._textDoc} isSelected={returnTrue} select={emptyFunction} isTopMost={true}
-                        selectOnLoad={true} onActiveChanged={emptyFunction} active={returnTrue} ScreenToLocalTransform={() => this._textXf} focus={emptyDocFunction} />
+                        selectOnLoad={true} ContainingCollectionView={undefined} CollectionView={undefined} onActiveChanged={emptyFunction} active={returnTrue} ScreenToLocalTransform={() => this._textXf} focus={emptyDocFunction} />
                 </div>
             </ div>;
         }
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 2a1d1dd94..63346a4c6 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -75,6 +75,8 @@ export class CollectionSchemaView extends CollectionSubView {
         let props: FieldViewProps = {
             Document: rowProps.value[0],
             fieldKey: rowProps.value[1],
+            CollectionView: this.props.CollectionView,
+            ContainingCollectionView: this.props.CollectionView,
             isSelected: returnFalse,
             select: emptyFunction,
             isTopMost: false,
@@ -313,7 +315,7 @@ export class CollectionSchemaView extends CollectionSubView {
                                 ContentScaling={this.getContentScaling}
                                 PanelWidth={this.getPanelWidth}
                                 PanelHeight={this.getPanelHeight}
-                                ContainingCollectionView={undefined}
+                                ContainingCollectionView={this.props.CollectionView}
                                 focus={emptyDocFunction}
                                 parentActive={this.props.active}
                                 onActiveChanged={this.props.onActiveChanged} /> : null}
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index d91db68bb..61b7787e7 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -16,6 +16,7 @@ import { Server } from "../../Server";
 import { FieldViewProps } from "../nodes/FieldView";
 import * as rp from 'request-promise';
 import { emptyFunction } from "../../../Utils";
+import { CollectionView } from "./CollectionView";
 
 export interface CollectionViewProps extends FieldViewProps {
     addDocument: (document: Document, allowDuplicates?: boolean) => boolean;
@@ -24,6 +25,7 @@ export interface CollectionViewProps extends FieldViewProps {
 }
 
 export interface SubCollectionViewProps extends CollectionViewProps {
+    CollectionView: Opt<CollectionView>;
 }
 
 export type CursorEntry = TupleField<[string, string], [number, number]>;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 8abd0a02d..1f69a69e8 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -18,12 +18,12 @@ export class CollectionView extends React.Component<FieldViewProps> {
     private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
         let props = { ...this.props, ...renderProps };
         switch (type) {
-            case CollectionViewType.Schema: return (<CollectionSchemaView {...props} />);
-            case CollectionViewType.Docking: return (<CollectionDockingView {...props} />);
-            case CollectionViewType.Tree: return (<CollectionTreeView {...props} />);
+            case CollectionViewType.Schema: return (<CollectionSchemaView {...props} CollectionView={this} />);
+            case CollectionViewType.Docking: return (<CollectionDockingView {...props} CollectionView={this} />);
+            case CollectionViewType.Tree: return (<CollectionTreeView {...props} CollectionView={this} />);
             case CollectionViewType.Freeform:
             default:
-                return (<CollectionFreeFormView {...props} />);
+                return (<CollectionFreeFormView {...props} CollectionView={this} />);
         }
         return (null);
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 94945bde6..e9e942b78 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -274,7 +274,7 @@ export class CollectionFreeFormView extends CollectionSubView {
             PanelWidth: document.Width,
             PanelHeight: document.Height,
             ContentScaling: this.noScaling,
-            ContainingCollectionView: undefined,
+            ContainingCollectionView: this.props.CollectionView,
             focus: this.focusDocument,
             parentActive: this.props.active,
             onActiveChanged: this.props.active,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index a4722a6f8..cf75aef40 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -209,10 +209,11 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
         let selRect = this.Bounds;
         let selection: Document[] = [];
         this.props.activeDocuments().map(doc => {
+            var z = doc.GetNumber(KeyStore.Zoom, 1);
             var x = doc.GetNumber(KeyStore.X, 0);
             var y = doc.GetNumber(KeyStore.Y, 0);
-            var w = doc.GetNumber(KeyStore.Width, 0);
-            var h = doc.GetNumber(KeyStore.Height, 0);
+            var w = doc.GetNumber(KeyStore.Width, 0) / z;
+            var h = doc.GetNumber(KeyStore.Height, 0) / z;
             if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) {
                 selection.push(doc);
             }
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 5836da396..a967db000 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -44,19 +44,19 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
 
 
     CreateBindings(): JsxBindings {
-        let
-            {
-                Document,
-                isSelected,
-                select,
-                isTopMost,
-                selectOnLoad,
-                ScreenToLocalTransform,
-                addDocument,
-                removeDocument,
-                onActiveChanged,
-                parentActive: active,
-            } = this.props;
+        let {
+            Document,
+            isSelected,
+            select,
+            isTopMost,
+            selectOnLoad,
+            ScreenToLocalTransform,
+            ContainingCollectionView,
+            addDocument,
+            removeDocument,
+            onActiveChanged,
+            parentActive: active,
+        } = this.props;
         let bindings: JsxBindings = {
             props: {
                 Document,
@@ -65,6 +65,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
                 isTopMost,
                 selectOnLoad,
                 ScreenToLocalTransform,
+                CollectionView: undefined,
+                ContainingCollectionView,
                 active,
                 onActiveChanged,
                 addDocument,
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index e0c5e19fb..755367d23 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -1,7 +1,7 @@
 import React = require("react");
 import { observer } from "mobx-react";
 import { computed } from "mobx";
-import { Field, FieldWaiting, FieldValue } from "../../../fields/Field";
+import { Field, FieldWaiting, FieldValue, Opt } from "../../../fields/Field";
 import { Document } from "../../../fields/Document";
 import { TextField } from "../../../fields/TextField";
 import { NumberField } from "../../../fields/NumberField";
@@ -20,6 +20,7 @@ import { DocumentContentsView } from "./DocumentContentsView";
 import { Transform } from "../../util/Transform";
 import { KeyStore } from "../../../fields/KeyStore";
 import { returnFalse, emptyDocFunction } from "../../../Utils";
+import { CollectionView } from "../collections/CollectionView";
 
 
 //
@@ -29,6 +30,8 @@ import { returnFalse, emptyDocFunction } from "../../../Utils";
 //
 export interface FieldViewProps {
     fieldKey: Key;
+    ContainingCollectionView: Opt<CollectionView>;
+    CollectionView: Opt<CollectionView>;
     Document: Document;
     isSelected: () => boolean;
     select: (isCtrlPressed: boolean) => void;
@@ -90,7 +93,7 @@ export class FieldView extends React.Component<FieldViewProps> {
                     isSelected={returnFalse}
                     select={returnFalse}
                     layoutKey={KeyStore.Layout}
-                    ContainingCollectionView={undefined}
+                    ContainingCollectionView={this.props.ContainingCollectionView}
                     parentActive={this.props.active}
                     onActiveChanged={this.props.onActiveChanged} />
             );
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 3e0b61c3d..1b9dd26bd 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -47,6 +47,8 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
         }
         let props: FieldViewProps = {
             Document: this.props.doc,
+            CollectionView: undefined,
+            ContainingCollectionView: undefined,
             fieldKey: this.key,
             isSelected: returnFalse,
             select: emptyFunction,
-- 
cgit v1.2.3-70-g09d2


From 7f0b7a3e02d2d5ea3bd9f8554f1828d0470b1d04 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 14 Apr 2019 17:46:54 -0400
Subject: tweaks to text input

---
 src/client/documents/Documents.ts                                | 2 +-
 src/client/views/collections/CollectionSubView.tsx               | 2 +-
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx    | 9 ++++++---
 3 files changed, 8 insertions(+), 5 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 3c36fe500..4febfa7eb 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -127,7 +127,7 @@ export namespace Documents {
 
     function CreateImagePrototype(): Document {
         let imageProto = setupPrototypeOptions(imageProtoId, "IMAGE_PROTO", CollectionView.LayoutString("AnnotationsKey"),
-            { x: 0, y: 0, nativeWidth: 300, width: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] });
+            { x: 0, y: 0, nativeWidth: 600, width: 300, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] });
         imageProto.SetText(KeyStore.BackgroundLayout, ImageBox.LayoutString());
         imageProto.SetNumber(KeyStore.CurPage, 0);
         return imageProto;
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 1c927c78d..d3d69b1af 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -197,7 +197,7 @@ export class CollectionSubView extends React.Component<SubCollectionViewProps> {
                 }).then(async (res: Response) => {
                     (await res.json()).map(action((file: any) => {
                         let path = window.location.origin + file;
-                        let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300, title: dropFileName });
+                        let docPromise = this.getDocumentFromType(type, path, { ...options, nativeWidth: 600, width: 300, title: dropFileName });
 
                         docPromise.then(action((doc?: Document) => {
                             let docs = this.props.Document.GetT(KeyStore.Data, ListField);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index e9e942b78..6c382a353 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -4,7 +4,6 @@ import Measure from "react-measure";
 import { Document } from "../../../../fields/Document";
 import { FieldWaiting } from "../../../../fields/Field";
 import { KeyStore } from "../../../../fields/KeyStore";
-import { NumberField } from "../../../../fields/NumberField";
 import { TextField } from "../../../../fields/TextField";
 import { emptyFunction, returnFalse } from "../../../../Utils";
 import { DocumentManager } from "../../../util/DocumentManager";
@@ -18,7 +17,7 @@ import { Main } from "../../Main";
 import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
 import { DocumentContentsView } from "../../nodes/DocumentContentsView";
 import { DocumentViewProps } from "../../nodes/DocumentView";
-import { CollectionSubView } from "../CollectionSubView";
+import { CollectionSubView, SubCollectionViewProps } from "../CollectionSubView";
 import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView";
 import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors";
 import "./CollectionFreeFormView.scss";
@@ -294,7 +293,11 @@ export class CollectionFreeFormView extends CollectionSubView {
             }
             return prev;
         }, [] as JSX.Element[]);
-        untracked(() => this._selectOnLoaded = "");
+
+        setTimeout(() => { // bcz: surely there must be a better way ....
+            this._selectOnLoaded = "";
+        }, 600);
+
         return docviews;
     }
 
-- 
cgit v1.2.3-70-g09d2


From 845057ef78f272faf488b5bbc2fe79d64fb64120 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 14 Apr 2019 19:44:38 -0400
Subject: mostly northstar cleanup, plus cleaning up main.tsx

---
 src/client/northstar/dash-nodes/HistogramBox.tsx   |   2 +-
 src/client/northstar/manager/Gateway.ts            |  16 +-
 .../model/binRanges/VisualBinRangeHelper.ts        |   2 +-
 src/client/util/DragManager.ts                     |   9 +-
 src/client/util/SelectionManager.ts                |   3 +-
 src/client/views/DocumentDecorations.tsx           |  16 +-
 src/client/views/Main.scss                         |  18 --
 src/client/views/Main.tsx                          | 279 ++++++---------------
 src/client/views/MainOverlayTextBox.scss           |  19 ++
 src/client/views/MainOverlayTextBox.tsx            | 110 ++++++++
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   3 +-
 src/client/views/nodes/FormattedTextBox.tsx        |   9 +-
 src/fields/KeyStore.ts                             |   2 +-
 .../authentication/models/current_user_utils.ts    |  99 +++-----
 src/server/authentication/models/user_model.ts     |  21 +-
 15 files changed, 286 insertions(+), 322 deletions(-)
 create mode 100644 src/client/views/MainOverlayTextBox.scss
 create mode 100644 src/client/views/MainOverlayTextBox.tsx

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

diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index 2084fc346..3e94fed81 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -8,7 +8,7 @@ import { KeyStore } from "../../../fields/KeyStore";
 import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { ChartType, VisualBinRange } from '../../northstar/model/binRanges/VisualBinRange';
 import { VisualBinRangeHelper } from "../../northstar/model/binRanges/VisualBinRangeHelper";
-import { AggregateBinRange, AggregateFunction, BinRange, Catalog, DoubleValueAggregateResult, HistogramResult, Result } from "../../northstar/model/idea/idea";
+import { AggregateBinRange, AggregateFunction, BinRange, Catalog, DoubleValueAggregateResult, HistogramResult } from "../../northstar/model/idea/idea";
 import { ModelHelpers } from "../../northstar/model/ModelHelpers";
 import { HistogramOperation } from "../../northstar/operations/HistogramOperation";
 import { SizeConverter } from "../../northstar/utils/SizeConverter";
diff --git a/src/client/northstar/manager/Gateway.ts b/src/client/northstar/manager/Gateway.ts
index 207a9ad19..d26f2724f 100644
--- a/src/client/northstar/manager/Gateway.ts
+++ b/src/client/northstar/manager/Gateway.ts
@@ -36,7 +36,7 @@ export class Gateway {
 
     public async ClearCatalog(): Promise<void> {
         try {
-            const json = await this.MakePostJsonRequest("Datamart/ClearAllAugmentations", {});
+            await this.MakePostJsonRequest("Datamart/ClearAllAugmentations", {});
         }
         catch (error) {
             throw new Error("can not reach northstar's backend");
@@ -180,18 +180,18 @@ export class Gateway {
 
 
     public static ConstructUrl(appendix: string): string {
-        let base = Settings.Instance.ServerUrl;
+        let base = NorthstarSettings.Instance.ServerUrl;
         if (base.slice(-1) === "/") {
             base = base.slice(0, -1);
         }
-        let url = base + "/" + Settings.Instance.ServerApiPath + "/" + appendix;
+        let url = base + "/" + NorthstarSettings.Instance.ServerApiPath + "/" + appendix;
         return url;
     }
 }
 
 declare var ENV: any;
 
-export class Settings {
+export class NorthstarSettings {
     private _environment: any;
 
     @observable
@@ -248,10 +248,10 @@ export class Settings {
         return window.location.origin + "/";
     }
 
-    private static _instance: Settings;
+    private static _instance: NorthstarSettings;
 
     @action
-    public Update(environment: any): void {
+    public UpdateEnvironment(environment: any): void {
         /*let serverParam = new URL(document.URL).searchParams.get("serverUrl");
         if (serverParam) {
             if (serverParam === "debug") {
@@ -278,9 +278,9 @@ export class Settings {
         this.DegreeOfParallelism = environment.DEGREE_OF_PARALLISM;
     }
 
-    public static get Instance(): Settings {
+    public static get Instance(): NorthstarSettings {
         if (!this._instance) {
-            this._instance = new Settings();
+            this._instance = new NorthstarSettings();
         }
         return this._instance;
     }
diff --git a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
index 9671e55f8..a92412686 100644
--- a/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
+++ b/src/client/northstar/model/binRanges/VisualBinRangeHelper.ts
@@ -4,7 +4,7 @@ import { NominalVisualBinRange } from "./NominalVisualBinRange";
 import { QuantitativeVisualBinRange } from "./QuantitativeVisualBinRange";
 import { AlphabeticVisualBinRange } from "./AlphabeticVisualBinRange";
 import { DateTimeVisualBinRange } from "./DateTimeVisualBinRange";
-import { Settings } from "../../manager/Gateway";
+import { NorthstarSettings } from "../../manager/Gateway";
 import { ModelHelpers } from "../ModelHelpers";
 import { AttributeTransformationModel } from "../../core/attribute/AttributeTransformationModel";
 
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 2ee36d2ec..4bd654e15 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -1,13 +1,12 @@
 import { action } from "mobx";
 import { Document } from "../../fields/Document";
+import { FieldWaiting } from "../../fields/Field";
+import { KeyStore } from "../../fields/KeyStore";
 import { emptyFunction } from "../../Utils";
 import { CollectionDockingView } from "../views/collections/CollectionDockingView";
 import { DocumentDecorations } from "../views/DocumentDecorations";
-import { Main } from "../views/Main";
-import { DocumentView } from "../views/nodes/DocumentView";
 import * as globalCssVariables from "../views/globalCssVariables.scss";
-import { KeyStore } from "../../fields/KeyStore";
-import { FieldWaiting } from "../../fields/Field";
+import { MainOverlayTextBox } from "../views/MainOverlayTextBox";
 
 export function SetupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Document, moveFunc?: DragManager.MoveFunction, copyOnDrop: boolean = false) {
     let onRowMove = action((e: PointerEvent): void => {
@@ -177,7 +176,7 @@ export namespace DragManager {
             dragDiv.className = "dragManager-dragDiv";
             DragManager.Root().appendChild(dragDiv);
         }
-        Main.Instance.SetTextDoc();
+        MainOverlayTextBox.Instance.SetTextDoc();
 
         let scaleXs: number[] = [];
         let scaleYs: number[] = [];
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 2fa45a086..c56f6a4ff 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -2,6 +2,7 @@ import { observable, action } from "mobx";
 import { DocumentView } from "../views/nodes/DocumentView";
 import { Document } from "../../fields/Document";
 import { Main } from "../views/Main";
+import { MainOverlayTextBox } from "../views/MainOverlayTextBox";
 
 export namespace SelectionManager {
     class Manager {
@@ -25,7 +26,7 @@ export namespace SelectionManager {
         DeselectAll(): void {
             manager.SelectedDocuments.map(dv => dv.props.onActiveChanged(false));
             manager.SelectedDocuments = [];
-            Main.Instance.SetTextDoc();
+            MainOverlayTextBox.Instance.SetTextDoc();
         }
     }
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 2dc496bc1..b97a47a3c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,24 +1,20 @@
-import { action, computed, observable, trace, runInAction } from "mobx";
+import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
 import { Key } from "../../fields/Key";
 //import ContentEditable from 'react-contenteditable'
 import { KeyStore } from "../../fields/KeyStore";
 import { ListField } from "../../fields/ListField";
 import { NumberField } from "../../fields/NumberField";
-import { Document } from "../../fields/Document";
 import { TextField } from "../../fields/TextField";
-import { DragManager, DragLinksAsDocuments } from "../util/DragManager";
+import { emptyFunction } from "../../Utils";
+import { DragLinksAsDocuments, DragManager } from "../util/DragManager";
 import { SelectionManager } from "../util/SelectionManager";
-import { CollectionView } from "./collections/CollectionView";
+import { undoBatch } from "../util/UndoManager";
 import './DocumentDecorations.scss';
+import { MainOverlayTextBox } from "./MainOverlayTextBox";
 import { DocumentView } from "./nodes/DocumentView";
 import { LinkMenu } from "./nodes/LinkMenu";
 import React = require("react");
-import { FieldWaiting } from "../../fields/Field";
-import { emptyFunction } from "../../Utils";
-import { Main } from "./Main";
-import { undo } from "prosemirror-history";
-import { undoBatch } from "../util/UndoManager";
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -304,7 +300,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 break;
         }
 
-        Main.Instance.SetTextDoc();
+        MainOverlayTextBox.Instance.SetTextDoc();
         SelectionManager.SelectedDocuments().forEach(element => {
             const rect = element.screenRect();
             if (rect.width !== 0) {
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index 13cadb10d..4373534b2 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -168,24 +168,6 @@ button:hover {
     left:0;
     overflow: scroll;
 }
-.mainDiv-textInput {
-    background-color: rgba(248, 6, 6, 0.001);
-    width: 200px;
-    height: 200px;
-    position:absolute;
-    overflow: visible;
-    top: 0;
-    left: 0;
-    z-index: $mainTextInput-zindex;
-    .formattedTextBox-cont {
-        background-color: rgba(248, 6, 6, 0.001);
-        width: 100%;
-        height: 100%;
-        position:absolute;
-        top: 0;
-        left: 0;
-    }
-}
 #mainContent-div {
     width:100%;
     height:100%;
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index f8c6ec0e2..51c076b14 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -15,20 +15,19 @@ import { ListField } from '../../fields/ListField';
 import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
 import { MessageStore } from '../../server/Message';
-import { Utils, returnTrue, emptyFunction, emptyDocFunction } from '../../Utils';
-import * as rp from 'request-promise';
 import { RouteStore } from '../../server/RouteStore';
 import { ServerUtils } from '../../server/ServerUtil';
+import { emptyDocFunction, emptyFunction, returnTrue, Utils } from '../../Utils';
 import { Documents } from '../documents/Documents';
 import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel';
 import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel';
-import { Gateway, Settings } from '../northstar/manager/Gateway';
-import { AggregateFunction, Catalog, Point } from '../northstar/model/idea/idea';
+import { Gateway, NorthstarSettings } from '../northstar/manager/Gateway';
+import { AggregateFunction, Catalog } from '../northstar/model/idea/idea';
 import '../northstar/model/ModelExtensions';
 import { HistogramOperation } from '../northstar/operations/HistogramOperation';
 import '../northstar/utils/Extensions';
 import { Server } from '../Server';
-import { SetupDrag, DragManager } from '../util/DragManager';
+import { SetupDrag } from '../util/DragManager';
 import { Transform } from '../util/Transform';
 import { UndoManager } from '../util/UndoManager';
 import { CollectionDockingView } from './collections/CollectionDockingView';
@@ -36,41 +35,28 @@ import { ContextMenu } from './ContextMenu';
 import { DocumentDecorations } from './DocumentDecorations';
 import { InkingControl } from './InkingControl';
 import "./Main.scss";
+import { MainOverlayTextBox } from './MainOverlayTextBox';
 import { DocumentView } from './nodes/DocumentView';
-import { FormattedTextBox } from './nodes/FormattedTextBox';
-import { REPLCommand } from 'repl';
-import { Key } from '../../fields/Key';
 import { PreviewCursor } from './PreviewCursor';
 
 
 @observer
 export class Main extends React.Component {
-    // dummy initializations keep the compiler happy
-    @observable private mainfreeform?: Document;
+    public static Instance: Main;
+    @observable private _workspacesShown: boolean = false;
     @observable public pwidth: number = 0;
     @observable public pheight: number = 0;
-    private _northstarSchemas: Document[] = [];
 
     @computed private get mainContainer(): Document | undefined {
-        let doc = this.userDocument.GetT(KeyStore.ActiveWorkspace, Document);
+        let doc = CurrentUserUtils.UserDocument.GetT(KeyStore.ActiveWorkspace, Document);
         return doc === FieldWaiting ? undefined : doc;
     }
-
     private set mainContainer(doc: Document | undefined) {
-        if (doc) {
-            this.userDocument.Set(KeyStore.ActiveWorkspace, doc);
-        }
+        doc && CurrentUserUtils.UserDocument.Set(KeyStore.ActiveWorkspace, doc);
     }
 
-    private get userDocument(): Document {
-        return CurrentUserUtils.UserDocument;
-    }
-
-    public static Instance: Main;
-
     constructor(props: Readonly<{}>) {
         super(props);
-        this._textProxyDiv = React.createRef();
         Main.Instance = this;
         // causes errors to be generated when modifying an observable outside of an action
         configure({ enforceActions: "observed" });
@@ -102,6 +88,10 @@ export class Main extends React.Component {
         this.initializeNorthstar();
     }
 
+    componentDidMount() { window.onpopstate = this.onHistory; }
+
+    componentWillUnmount() { window.onpopstate = null; }
+
     onHistory = () => {
         if (window.location.pathname !== RouteStore.home) {
             let pathname = window.location.pathname.split("/");
@@ -114,14 +104,6 @@ export class Main extends React.Component {
         }
     }
 
-    componentDidMount() {
-        window.onpopstate = this.onHistory;
-    }
-
-    componentWillUnmount() {
-        window.onpopstate = null;
-    }
-
     initEventListeners = () => {
         // window.addEventListener("pointermove", (e) => this.reportLocation(e))
         window.addEventListener("drop", (e) => e.preventDefault(), false); // drop event handler
@@ -137,7 +119,7 @@ export class Main extends React.Component {
     initAuthenticationRouters = () => {
         // Load the user's active workspace, or create a new one if initial session after signup
         if (!CurrentUserUtils.MainDocId) {
-            this.userDocument.GetTAsync(KeyStore.ActiveWorkspace, Document).then(doc => {
+            CurrentUserUtils.UserDocument.GetTAsync(KeyStore.ActiveWorkspace, Document).then(doc => {
                 if (doc) {
                     CurrentUserUtils.MainDocId = doc.Id;
                     this.openWorkspace(doc);
@@ -158,7 +140,7 @@ export class Main extends React.Component {
 
     @action
     createNewWorkspace = (id?: string): void => {
-        this.userDocument.GetTAsync<ListField<Document>>(KeyStore.Workspaces, ListField).then(action((list: Opt<ListField<Document>>) => {
+        CurrentUserUtils.UserDocument.GetTAsync<ListField<Document>>(KeyStore.Workspaces, ListField).then(action((list: Opt<ListField<Document>>) => {
             if (list) {
                 let freeformDoc = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" });
                 var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] };
@@ -179,7 +161,7 @@ export class Main extends React.Component {
     openWorkspace = (doc: Document, fromHistory = false): void => {
         this.mainContainer = doc;
         fromHistory || window.history.pushState(null, doc.Title, "/doc/" + doc.Id);
-        this.userDocument.GetTAsync(KeyStore.OptionalRightCollection, Document).then(col => {
+        CurrentUserUtils.UserDocument.GetTAsync(KeyStore.OptionalRightCollection, Document).then(col => {
             // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized)
             setTimeout(() => {
                 if (col) {
@@ -193,119 +175,33 @@ export class Main extends React.Component {
         });
     }
 
-    @observable
-    workspacesShown: boolean = false;
-
-    areWorkspacesShown = () => this.workspacesShown;
-    @action
-    toggleWorkspaces = () => {
-        this.workspacesShown = !this.workspacesShown;
-    }
-
-    pwidthFunc = () => this.pwidth;
-    pheightFunc = () => this.pheight;
-    noScaling = () => 1;
-
-    @observable _textDoc?: Document = undefined;
-    _textRect: any;
-    _textXf: Transform = Transform.Identity();
-    _textScroll: number = 0;
-    _textFieldKey: Key = KeyStore.Data;
-    _textColor: string | null = null;
-    _textTargetDiv: HTMLDivElement | undefined;
-    _textProxyDiv: React.RefObject<HTMLDivElement>;
-    @action
-    SetTextDoc(textDoc?: Document, textFieldKey?: Key, div?: HTMLDivElement, tx?: Transform) {
-        if (this._textTargetDiv) {
-            this._textTargetDiv.style.color = this._textColor;
-        }
-
-        this._textDoc = undefined;
-        this._textDoc = textDoc;
-        this._textFieldKey = textFieldKey!;
-        this._textXf = tx ? tx : Transform.Identity();
-        this._textTargetDiv = div;
-        if (div) {
-            this._textColor = div.style.color;
-            div.style.color = "transparent";
-            this._textRect = div.getBoundingClientRect();
-            this._textScroll = div.scrollTop;
-        }
-    }
-
-    @action
-    textScroll = (e: React.UIEvent) => {
-        if (this._textProxyDiv.current && this._textTargetDiv) {
-            this._textTargetDiv.scrollTop = this._textScroll = this._textProxyDiv.current.children[0].scrollTop;
-        }
-    }
-
-    textBoxDown = (e: React.PointerEvent) => {
-        if (e.button !== 0 || e.metaKey || e.altKey) {
-            document.addEventListener("pointermove", this.textBoxMove);
-            document.addEventListener('pointerup', this.textBoxUp);
-        }
-    }
-    textBoxMove = (e: PointerEvent) => {
-        if (e.movementX > 1 || e.movementY > 1) {
-            document.removeEventListener("pointermove", this.textBoxMove);
-            document.removeEventListener('pointerup', this.textBoxUp);
-            let dragData = new DragManager.DocumentDragData([this._textDoc!]);
-            const [left, top] = this._textXf
-                .inverse()
-                .transformPoint(0, 0);
-            dragData.xOffset = e.clientX - left;
-            dragData.yOffset = e.clientY - top;
-            DragManager.StartDocumentDrag([this._textTargetDiv!], dragData, e.clientX, e.clientY, {
-                handlers: {
-                    dragComplete: action(emptyFunction),
-                },
-                hideSource: false
-            });
-        }
-    }
-    textBoxUp = (e: PointerEvent) => {
-        document.removeEventListener("pointermove", this.textBoxMove);
-        document.removeEventListener('pointerup', this.textBoxUp);
-    }
-
-    @computed
-    get activeTextBox() {
-        if (this._textDoc) {
-            let x: number = this._textRect.x;
-            let y: number = this._textRect.y;
-            let w: number = this._textRect.width;
-            let h: number = this._textRect.height;
-            let t = this._textXf.transformPoint(0, 0);
-            let s = this._textXf.transformPoint(1, 0);
-            s[0] = Math.sqrt((s[0] - t[0]) * (s[0] - t[0]) + (s[1] - t[1]) * (s[1] - t[1]));
-            return <div className="mainDiv-textInput" style={{ pointerEvents: "none", transform: `translate(${x}px, ${y}px) scale(${1 / s[0]},${1 / s[0]})`, width: "auto", height: "auto" }} >
-                <div className="mainDiv-textInput" onPointerDown={this.textBoxDown} ref={this._textProxyDiv} onScroll={this.textScroll} style={{ pointerEvents: "none", transform: `scale(${1}, ${1})`, width: `${w * s[0]}px`, height: `${h * s[0]}px` }}>
-                    <FormattedTextBox fieldKey={this._textFieldKey!} isOverlay={true} Document={this._textDoc} isSelected={returnTrue} select={emptyFunction} isTopMost={true}
-                        selectOnLoad={true} ContainingCollectionView={undefined} onActiveChanged={emptyFunction} active={returnTrue} ScreenToLocalTransform={() => this._textXf} focus={emptyDocFunction} />
-                </div>
-            </ div>;
-        }
-        else return (null);
-    }
-
     @computed
     get mainContent() {
-        return !this.mainContainer ? (null) :
-            <DocumentView Document={this.mainContainer}
-                addDocument={undefined}
-                removeDocument={undefined}
-                opacity={1}
-                ScreenToLocalTransform={Transform.Identity}
-                ContentScaling={this.noScaling}
-                PanelWidth={this.pwidthFunc}
-                PanelHeight={this.pheightFunc}
-                isTopMost={true}
-                selectOnLoad={false}
-                focus={emptyDocFunction}
-                parentActive={returnTrue}
-                onActiveChanged={emptyFunction}
-                ContainingCollectionView={undefined} />;
+        trace();
+        let pwidthFunc = () => this.pwidth;
+        let pheightFunc = () => this.pheight;
+        let noScaling = () => 1;
+        return <Measure onResize={action((r: any) => { this.pwidth = r.entry.width; this.pheight = r.entry.height; })}>
+            {({ measureRef }) =>
+                <div ref={measureRef} id="mainContent-div">
+                    {!this.mainContainer ? (null) :
+                        <DocumentView Document={this.mainContainer}
+                            addDocument={undefined}
+                            removeDocument={undefined}
+                            opacity={1}
+                            ScreenToLocalTransform={Transform.Identity}
+                            ContentScaling={noScaling}
+                            PanelWidth={pwidthFunc}
+                            PanelHeight={pheightFunc}
+                            isTopMost={true}
+                            selectOnLoad={false}
+                            focus={emptyDocFunction}
+                            parentActive={returnTrue}
+                            onActiveChanged={emptyFunction}
+                            ContainingCollectionView={undefined} />}
+                </div>
+            }
+        </Measure>;
     }
 
     /* for the expandable add nodes menu. Not included with the miscbuttons because once it expands it expands the whole div with it, making canvas interactions limited. */
@@ -361,6 +257,7 @@ export class Main extends React.Component {
     get miscButtons() {
         let workspacesRef = React.createRef<HTMLDivElement>();
         let logoutRef = React.createRef<HTMLDivElement>();
+        let toggleWorkspaces = () => runInAction(() => { this._workspacesShown = !this._workspacesShown; });
 
         let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {}));
         return [
@@ -371,55 +268,50 @@ export class Main extends React.Component {
                 <button className="toolbar-button round-button" title="Ink" onClick={() => InkingControl.Instance.toggleDisplay()}><FontAwesomeIcon icon="pen-nib" size="sm" /></button>
             </div >,
             <div className="main-buttonDiv" key="workspaces" style={{ top: '34px', left: '2px', position: 'absolute' }} ref={workspacesRef}>
-                <button onClick={this.toggleWorkspaces}>Workspaces</button></div>,
+                <button onClick={toggleWorkspaces}>Workspaces</button></div>,
             <div className="main-buttonDiv" key="logout" style={{ top: '34px', right: '1px', position: 'absolute' }} ref={logoutRef}>
                 <button onClick={() => request.get(ServerUtils.prepend(RouteStore.logout), emptyFunction)}>Log Out</button></div>
         ];
     }
 
+    @computed
+    get workspaceMenu() {
+        let areWorkspacesShown = () => this._workspacesShown;
+        let toggleWorkspaces = () => runInAction(() => { this._workspacesShown = !this._workspacesShown; });
+        let workspaces = CurrentUserUtils.UserDocument.GetT<ListField<Document>>(KeyStore.Workspaces, ListField);
+        return (!workspaces || workspaces === FieldWaiting) ? (null) :
+            <WorkspacesMenu active={this.mainContainer} open={this.openWorkspace}
+                new={this.createNewWorkspace} allWorkspaces={workspaces.Data}
+                isShown={areWorkspacesShown} toggle={toggleWorkspaces} />;
+    }
+
     render() {
-        let workspaceMenu: any = null;
-        let workspaces = this.userDocument.GetT<ListField<Document>>(KeyStore.Workspaces, ListField);
-        if (workspaces && workspaces !== FieldWaiting) {
-            workspaceMenu = <WorkspacesMenu active={this.mainContainer} open={this.openWorkspace} new={this.createNewWorkspace} allWorkspaces={workspaces.Data}
-                isShown={this.areWorkspacesShown} toggle={this.toggleWorkspaces} />;
-        }
         return (
-            <>
-                <div id="main-div">
-                    <DocumentDecorations />
-                    <Measure onResize={(r: any) => runInAction(() => {
-                        this.pwidth = r.entry.width;
-                        this.pheight = r.entry.height;
-                    })}>
-                        {({ measureRef }) =>
-                            <div ref={measureRef} id="mainContent-div">
-                                {this.mainContent}
-                                <PreviewCursor />
-                            </div>
-                        }
-                    </Measure>
-                    <ContextMenu />
-                    {this.nodesMenu}
-                    {this.miscButtons}
-                    {workspaceMenu}
-                    <InkingControl />
-                </div>
-                {this.activeTextBox}
-            </>
+            <div id="main-div">
+                <DocumentDecorations />
+                {this.mainContent}
+                <PreviewCursor />
+                <ContextMenu />
+                {this.nodesMenu}
+                {this.miscButtons}
+                {this.workspaceMenu}
+                <InkingControl />
+                <MainOverlayTextBox />
+            </div>
         );
     }
 
     // --------------- Northstar hooks ------------- /
+    private _northstarSchemas: Document[] = [];
 
-    @action AddToNorthstarCatalog(ctlog: Catalog) {
-        CurrentUserUtils.NorthstarDBCatalog = CurrentUserUtils.NorthstarDBCatalog ? CurrentUserUtils.NorthstarDBCatalog : ctlog;
+    @action SetNorthstarCatalog(ctlog: Catalog) {
+        CurrentUserUtils.NorthstarDBCatalog = ctlog;
         if (ctlog && ctlog.schemas) {
             ctlog.schemas.map(schema => {
-                let promises: Promise<void>[] = [];
                 let schemaDocuments: Document[] = [];
-                CurrentUserUtils.GetAllNorthstarColumnAttributes(schema).map(attr => {
-                    let prom = Server.GetField(attr.displayName! + ".alias").then(action((field: Opt<Field>) => {
+                let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema);
+                Promise.all(attributesToBecomeDocs.reduce((promises, attr) => {
+                    promises.push(Server.GetField(attr.displayName! + ".alias").then(action((field: Opt<Field>) => {
                         if (field instanceof Document) {
                             schemaDocuments.push(field);
                         } else {
@@ -430,32 +322,17 @@ export class Main extends React.Component {
                                 new AttributeTransformationModel(atmod, AggregateFunction.Count));
                             schemaDocuments.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias"));
                         }
-                    }));
-                    promises.push(prom);
-                });
-                Promise.all(promises).finally(() => {
-                    let schemaDoc = Documents.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! });
-                    this._northstarSchemas.push(schemaDoc);
-                });
+                    })));
+                    return promises;
+                }, [] as Promise<void>[])).finally(() =>
+                    this._northstarSchemas.push(Documents.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! })));
             });
         }
     }
     async initializeNorthstar(): Promise<void> {
-        let envPath = "/assets/env.json";
-        const response = await fetch(envPath, {
-            redirect: "follow",
-            method: "GET",
-            credentials: "include"
-        });
-        const env = await response.json();
-        Settings.Instance.Update(env);
-        let cat = Gateway.Instance.ClearCatalog();
-        cat.then(async () => {
-            this.AddToNorthstarCatalog(await Gateway.Instance.GetCatalog());
-            // if (!CurrentUserUtils.GetNorthstarSchema("Book1"))
-            //     this.AddToNorthstarCatalog(await Gateway.Instance.GetSchema("http://www.cs.brown.edu/~bcz/Book1.csv", "Book1"));
-        });
-
+        const getEnvironment = await fetch("/assets/env.json", { redirect: "follow", method: "GET", credentials: "include" });
+        NorthstarSettings.Instance.UpdateEnvironment(await getEnvironment.json());
+        Gateway.Instance.ClearCatalog().then(async () => this.SetNorthstarCatalog(await Gateway.Instance.GetCatalog()));
     }
 }
 
diff --git a/src/client/views/MainOverlayTextBox.scss b/src/client/views/MainOverlayTextBox.scss
new file mode 100644
index 000000000..697d68c8c
--- /dev/null
+++ b/src/client/views/MainOverlayTextBox.scss
@@ -0,0 +1,19 @@
+@import "globalCssVariables";
+.mainOverlayTextBox-textInput {
+    background-color: rgba(248, 6, 6, 0.001);
+    width: 200px;
+    height: 200px;
+    position:absolute;
+    overflow: visible;
+    top: 0;
+    left: 0;
+    z-index: $mainTextInput-zindex;
+    .formattedTextBox-cont {
+        background-color: rgba(248, 6, 6, 0.001);
+        width: 100%;
+        height: 100%;
+        position:absolute;
+        top: 0;
+        left: 0;
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
new file mode 100644
index 000000000..df1addbc7
--- /dev/null
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -0,0 +1,110 @@
+import { action, observable, trace } from 'mobx';
+import { observer } from 'mobx-react';
+import "normalize.css";
+import * as React from 'react';
+import { Document } from '../../fields/Document';
+import { Key } from '../../fields/Key';
+import { KeyStore } from '../../fields/KeyStore';
+import { emptyDocFunction, emptyFunction, returnTrue } from '../../Utils';
+import '../northstar/model/ModelExtensions';
+import '../northstar/utils/Extensions';
+import { DragManager } from '../util/DragManager';
+import { Transform } from '../util/Transform';
+import "./MainOverlayTextBox.scss";
+import { FormattedTextBox } from './nodes/FormattedTextBox';
+
+interface MainOverlayTextBoxProps {
+}
+
+@observer
+export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps> {
+    public static Instance: MainOverlayTextBox;
+    @observable public TextDoc?: Document = undefined;
+    public TextScroll: number = 0;
+    private _textRect: any;
+    private _textXf: Transform = Transform.Identity();
+    private _textFieldKey: Key = KeyStore.Data;
+    private _textColor: string | null = null;
+    private _textTargetDiv: HTMLDivElement | undefined;
+    private _textProxyDiv: React.RefObject<HTMLDivElement>;
+
+    constructor(props: MainOverlayTextBoxProps) {
+        super(props);
+        this._textProxyDiv = React.createRef();
+        MainOverlayTextBox.Instance = this;
+    }
+
+    @action
+    SetTextDoc(textDoc?: Document, textFieldKey?: Key, div?: HTMLDivElement, tx?: Transform) {
+        if (this._textTargetDiv) {
+            this._textTargetDiv.style.color = this._textColor;
+        }
+
+        this.TextDoc = undefined;
+        this.TextDoc = textDoc;
+        this._textFieldKey = textFieldKey!;
+        this._textXf = tx ? tx : Transform.Identity();
+        this._textTargetDiv = div;
+        if (div) {
+            this._textColor = div.style.color;
+            div.style.color = "transparent";
+            this._textRect = div.getBoundingClientRect();
+            this.TextScroll = div.scrollTop;
+        }
+    }
+
+    @action
+    textScroll = (e: React.UIEvent) => {
+        if (this._textProxyDiv.current && this._textTargetDiv) {
+            this._textTargetDiv.scrollTop = this.TextScroll = this._textProxyDiv.current.children[0].scrollTop;
+        }
+    }
+
+    textBoxDown = (e: React.PointerEvent) => {
+        if (e.button !== 0 || e.metaKey || e.altKey) {
+            document.addEventListener("pointermove", this.textBoxMove);
+            document.addEventListener('pointerup', this.textBoxUp);
+        }
+    }
+    textBoxMove = (e: PointerEvent) => {
+        if (e.movementX > 1 || e.movementY > 1) {
+            document.removeEventListener("pointermove", this.textBoxMove);
+            document.removeEventListener('pointerup', this.textBoxUp);
+            let dragData = new DragManager.DocumentDragData([this.TextDoc!]);
+            const [left, top] = this._textXf
+                .inverse()
+                .transformPoint(0, 0);
+            dragData.xOffset = e.clientX - left;
+            dragData.yOffset = e.clientY - top;
+            DragManager.StartDocumentDrag([this._textTargetDiv!], dragData, e.clientX, e.clientY, {
+                handlers: {
+                    dragComplete: action(emptyFunction),
+                },
+                hideSource: false
+            });
+        }
+    }
+    textBoxUp = (e: PointerEvent) => {
+        document.removeEventListener("pointermove", this.textBoxMove);
+        document.removeEventListener('pointerup', this.textBoxUp);
+    }
+
+    render() {
+        if (this.TextDoc) {
+            let x: number = this._textRect.x;
+            let y: number = this._textRect.y;
+            let w: number = this._textRect.width;
+            let h: number = this._textRect.height;
+            let t = this._textXf.transformPoint(0, 0);
+            let s = this._textXf.transformPoint(1, 0);
+            s[0] = Math.sqrt((s[0] - t[0]) * (s[0] - t[0]) + (s[1] - t[1]) * (s[1] - t[1]));
+            return <div className="mainOverlayTextBox-textInput" style={{ pointerEvents: "none", transform: `translate(${x}px, ${y}px) scale(${1 / s[0]},${1 / s[0]})`, width: "auto", height: "auto" }} >
+                <div className="mainOverlayTextBox-textInput" onPointerDown={this.textBoxDown} ref={this._textProxyDiv} onScroll={this.textScroll} style={{ pointerEvents: "none", transform: `scale(${1}, ${1})`, width: `${w * s[0]}px`, height: `${h * s[0]}px` }}>
+                    <FormattedTextBox fieldKey={this._textFieldKey!} isOverlay={true} Document={this.TextDoc} isSelected={returnTrue} select={emptyFunction} isTopMost={true}
+                        selectOnLoad={true} ContainingCollectionView={undefined} onActiveChanged={emptyFunction} active={returnTrue} ScreenToLocalTransform={() => this._textXf} focus={emptyDocFunction} />
+                </div>
+            </ div>;
+        }
+        else return (null);
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 6c382a353..cb4e8fb2e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -24,6 +24,7 @@ import "./CollectionFreeFormView.scss";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
 import v5 = require("uuid/v5");
+import { MainOverlayTextBox } from "../../MainOverlayTextBox";
 
 @observer
 export class CollectionFreeFormView extends CollectionSubView {
@@ -205,7 +206,7 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @action
     private SetPan(panX: number, panY: number) {
-        Main.Instance.SetTextDoc();
+        MainOverlayTextBox.Instance.SetTextDoc();
         var x1 = this.getLocalTransform().inverse().Scale;
         const newPanX = Math.min((1 - 1 / x1) * this.nativeWidth, Math.max(0, panX));
         const newPanY = Math.min((1 - 1 / x1) * this.nativeHeight, Math.max(0, panY));
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 2e6272836..87c1bcb1e 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -16,6 +16,7 @@ import "./FormattedTextBox.scss";
 import React = require("react");
 import { TextField } from "../../../fields/TextField";
 import { KeyStore } from "../../../fields/KeyStore";
+import { MainOverlayTextBox } from "../MainOverlayTextBox";
 const { buildMenuItems } = require("prosemirror-example-setup");
 const { menuBar } = require("prosemirror-menu");
 
@@ -92,7 +93,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
         };
 
         if (this.props.isOverlay) {
-            this._inputReactionDisposer = reaction(() => Main.Instance._textDoc && Main.Instance._textDoc.Id,
+            this._inputReactionDisposer = reaction(() => MainOverlayTextBox.Instance.TextDoc && MainOverlayTextBox.Instance.TextDoc.Id,
                 () => {
                     if (this._editorView) {
                         this._editorView.destroy();
@@ -103,7 +104,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
             );
         } else {
             this._proxyReactionDisposer = reaction(() => this.props.isSelected(),
-                () => this.props.isSelected() && Main.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform()));
+                () => this.props.isSelected() && MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform()));
         }
 
         this._reactionDisposer = reaction(
@@ -184,10 +185,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
 
     onFocused = (e: React.FocusEvent): void => {
         if (!this.props.isOverlay) {
-            Main.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform());
+            MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform());
         } else {
             if (this._ref.current) {
-                this._ref.current.scrollTop = Main.Instance._textScroll;
+                this._ref.current.scrollTop = MainOverlayTextBox.Instance.TextScroll;
             }
         }
     }
diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts
index 19431bbe3..16a909eb8 100644
--- a/src/fields/KeyStore.ts
+++ b/src/fields/KeyStore.ts
@@ -49,7 +49,7 @@ export namespace KeyStore {
     export const CopyDraggedItems = new Key("CopyDraggedItems");
 
     export const KeyList: Key[] = [Prototype, X, Y, Page, Title, Author, PanX, PanY, Scale, NativeWidth, NativeHeight,
-        Width, Height, ZIndex, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys,
+        Width, Height, ZIndex, Zoom, Data, Annotations, ViewType, Layout, BackgroundColor, BackgroundLayout, OverlayLayout, LayoutKeys,
         LayoutFields, ColumnsKey, SchemaSplitPercentage, Caption, ActiveWorkspace, DocumentText, BrushingDocs, LinkedToDocs, LinkedFromDocs,
         LinkDescription, LinkTags, Thumbnail, ThumbnailPage, CurPage, AnnotationOn, NumPages, Ink, Cursors, OptionalRightCollection,
         Archives, Workspaces, Minimized, CopyDraggedItems
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 13eddafbf..34454eda0 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -1,15 +1,14 @@
-import { DashUserModel } from "./user_model";
+import { computed, observable, action } from "mobx";
 import * as rp from 'request-promise';
-import { RouteStore } from "../../RouteStore";
-import { ServerUtils } from "../../ServerUtil";
+import { Documents } from "../../../client/documents/Documents";
+import { Attribute, AttributeGroup, Catalog, Schema } from "../../../client/northstar/model/idea/idea";
+import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil";
 import { Server } from "../../../client/Server";
 import { Document } from "../../../fields/Document";
 import { KeyStore } from "../../../fields/KeyStore";
 import { ListField } from "../../../fields/ListField";
-import { Documents } from "../../../client/documents/Documents";
-import { Schema, Attribute, AttributeGroup, Catalog } from "../../../client/northstar/model/idea/idea";
-import { observable, computed, action } from "mobx";
-import { ArrayUtil } from "../../../client/northstar/utils/ArrayUtil";
+import { RouteStore } from "../../RouteStore";
+import { ServerUtils } from "../../ServerUtil";
 
 export class CurrentUserUtils {
     private static curr_email: string;
@@ -17,65 +16,22 @@ export class CurrentUserUtils {
     private static user_document: Document;
     //TODO tfs: these should be temporary...
     private static mainDocId: string | undefined;
-    @observable private static catalog?: Catalog;
-
-    public static get email(): string {
-        return this.curr_email;
-    }
-
-    public static get id(): string {
-        return this.curr_id;
-    }
-
-    public static get UserDocument(): Document {
-        return this.user_document;
-    }
 
-    public static get MainDocId(): string | undefined {
-        return this.mainDocId;
-    }
-
-    public static set MainDocId(id: string | undefined) {
-        this.mainDocId = id;
-    }
-
-    @computed public static get NorthstarDBCatalog(): Catalog | undefined {
-        return this.catalog;
-    }
-    public static set NorthstarDBCatalog(ctlog: Catalog | undefined) {
-        this.catalog = ctlog;
-    }
-    public static GetNorthstarSchema(name: string): Schema | undefined {
-        return !this.catalog || !this.catalog.schemas ? undefined :
-            ArrayUtil.FirstOrDefault<Schema>(this.catalog.schemas, (s: Schema) => s.displayName === name);
-    }
-    public static GetAllNorthstarColumnAttributes(schema: Schema) {
-        if (!schema || !schema.rootAttributeGroup) {
-            return [];
-        }
-        const recurs = (attrs: Attribute[], g: AttributeGroup) => {
-            if (g.attributes) {
-                attrs.push.apply(attrs, g.attributes);
-                if (g.attributeGroups) {
-                    g.attributeGroups.forEach(ng => recurs(attrs, ng));
-                }
-            }
-        };
-        const allAttributes: Attribute[] = new Array<Attribute>();
-        recurs(allAttributes, schema.rootAttributeGroup);
-        return allAttributes;
-    }
+    public static get email() { return this.curr_email; }
+    public static get id() { return this.curr_id; }
+    public static get UserDocument() { return this.user_document; }
+    public static get MainDocId() { return this.mainDocId; }
+    public static set MainDocId(id: string | undefined) { this.mainDocId = id; }
 
     private static createUserDocument(id: string): Document {
         let doc = new Document(id);
-
         doc.Set(KeyStore.Workspaces, new ListField<Document>());
         doc.Set(KeyStore.OptionalRightCollection, Documents.SchemaDocument([], { title: "Pending documents" }));
         return doc;
     }
 
     public static loadCurrentUser(): Promise<any> {
-        let userPromise = rp.get(ServerUtils.prepend(RouteStore.getCurrUser)).then((response) => {
+        let userPromise = rp.get(ServerUtils.prepend(RouteStore.getCurrUser)).then(response => {
             if (response) {
                 let obj = JSON.parse(response);
                 CurrentUserUtils.curr_id = obj.id as string;
@@ -86,17 +42,34 @@ export class CurrentUserUtils {
         });
         let userDocPromise = rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)).then(id => {
             if (id) {
-                return Server.GetField(id).then(field => {
-                    if (field instanceof Document) {
-                        this.user_document = field;
-                    } else {
-                        this.user_document = this.createUserDocument(id);
-                    }
-                });
+                return Server.GetField(id).then(field =>
+                    this.user_document = field instanceof Document ? field : this.createUserDocument(id));
             } else {
                 throw new Error("There should be a user id! Why does Dash think there isn't one?");
             }
         });
         return Promise.all([userPromise, userDocPromise]);
     }
+
+    /* Northstar catalog ... really just for testing so this should eventually go away */
+    @observable private static _northstarCatalog?: Catalog;
+    @computed public static get NorthstarDBCatalog() { return this._northstarCatalog; }
+    public static set NorthstarDBCatalog(ctlog: Catalog | undefined) { this._northstarCatalog = ctlog; }
+
+    public static GetNorthstarSchema(name: string): Schema | undefined {
+        return !this._northstarCatalog || !this._northstarCatalog.schemas ? undefined :
+            ArrayUtil.FirstOrDefault<Schema>(this._northstarCatalog.schemas, (s: Schema) => s.displayName === name);
+    }
+    public static GetAllNorthstarColumnAttributes(schema: Schema) {
+        const recurs = (attrs: Attribute[], g?: AttributeGroup) => {
+            if (g && g.attributes) {
+                attrs.push.apply(attrs, g.attributes);
+                if (g.attributeGroups) {
+                    g.attributeGroups.forEach(ng => recurs(attrs, ng));
+                }
+            }
+            return attrs;
+        };
+        return recurs([] as Attribute[], schema ? schema.rootAttributeGroup : undefined);
+    }
 }
\ No newline at end of file
diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts
index 1c6926517..d5c84c311 100644
--- a/src/server/authentication/models/user_model.ts
+++ b/src/server/authentication/models/user_model.ts
@@ -18,8 +18,8 @@ mongoose.connection.on('disconnected', function () {
 export type DashUserModel = mongoose.Document & {
     email: string,
     password: string,
-    passwordResetToken: string | undefined,
-    passwordResetExpires: Date | undefined,
+    passwordResetToken?: string,
+    passwordResetExpires?: Date,
 
     userDocumentId: string;
 
@@ -67,11 +67,17 @@ const userSchema = new mongoose.Schema({
  */
 userSchema.pre("save", function save(next) {
     const user = this as DashUserModel;
-    if (!user.isModified("password")) { return next(); }
+    if (!user.isModified("password")) {
+        return next();
+    }
     bcrypt.genSalt(10, (err, salt) => {
-        if (err) { return next(err); }
+        if (err) {
+            return next(err);
+        }
         bcrypt.hash(user.password, salt, () => void {}, (err: mongoose.Error, hash) => {
-            if (err) { return next(err); }
+            if (err) {
+                return next(err);
+            }
             user.password = hash;
             next();
         });
@@ -79,9 +85,8 @@ userSchema.pre("save", function save(next) {
 });
 
 const comparePassword: comparePasswordFunction = function (this: DashUserModel, candidatePassword, cb) {
-    bcrypt.compare(candidatePassword, this.password, (err: mongoose.Error, isMatch: boolean) => {
-        cb(err, isMatch);
-    });
+    bcrypt.compare(candidatePassword, this.password, (err: mongoose.Error, isMatch: boolean) =>
+        cb(err, isMatch));
 };
 
 userSchema.methods.comparePassword = comparePassword;
-- 
cgit v1.2.3-70-g09d2


From 6c0b421db6aa3204bbc6e42139d240f503000b5d Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 15 Apr 2019 11:59:50 -0400
Subject: fixed zoom fading somewhat.

---
 src/Utils.ts                                       | 15 ++++++++++
 src/client/northstar/dash-fields/HistogramField.ts | 12 ++------
 src/client/views/Main.tsx                          |  3 +-
 src/client/views/MainOverlayTextBox.tsx            |  3 +-
 .../views/collections/CollectionDockingView.tsx    |  3 +-
 .../views/collections/CollectionSchemaView.tsx     |  3 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 19 ++++++-------
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 18 ++++++++----
 src/client/views/nodes/DocumentContentsView.tsx    | 33 ++--------------------
 src/client/views/nodes/DocumentView.tsx            |  1 -
 src/client/views/nodes/FieldView.tsx               |  3 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  4 ++-
 12 files changed, 51 insertions(+), 66 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index e07d4e82d..dec6245ef 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -87,10 +87,25 @@ export class Utils {
     }
 }
 
+export function OmitKeys(obj: any, keys: any, addKeyFunc?: (dup: any) => void) {
+    var dup: any = {};
+    for (var key in obj) {
+        if (keys.indexOf(key) === -1) {
+            dup[key] = obj[key];
+        }
+    }
+    addKeyFunc && addKeyFunc(dup);
+    return dup;
+}
+
 export function returnTrue() { return true; }
 
 export function returnFalse() { return false; }
 
+export function returnOne() { return 1; }
+
+export function returnZero() { return 0; }
+
 export function emptyFunction() { }
 
 export function emptyDocFunction(doc: Document) { }
diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts
index 82de51d56..c699691a4 100644
--- a/src/client/northstar/dash-fields/HistogramField.ts
+++ b/src/client/northstar/dash-fields/HistogramField.ts
@@ -6,6 +6,7 @@ import { BasicField } from "../../../fields/BasicField";
 import { Field, FieldId } from "../../../fields/Field";
 import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { Types } from "../../../server/Message";
+import { OmitKeys } from "../../../Utils";
 
 
 export class HistogramField extends BasicField<HistogramOperation> {
@@ -13,17 +14,8 @@ export class HistogramField extends BasicField<HistogramOperation> {
         super(data ? data : HistogramOperation.Empty, save, id);
     }
 
-    omitKeys(obj: any, keys: any) {
-        var dup: any = {};
-        for (var key in obj) {
-            if (keys.indexOf(key) === -1) {
-                dup[key] = obj[key];
-            }
-        }
-        return dup;
-    }
     toString(): string {
-        return JSON.stringify(this.omitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']));
+        return JSON.stringify(OmitKeys(this.Data, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']));
     }
 
     Copy(): Field {
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index d26586216..98ef329c7 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -17,7 +17,7 @@ import { CurrentUserUtils } from '../../server/authentication/models/current_use
 import { MessageStore } from '../../server/Message';
 import { RouteStore } from '../../server/RouteStore';
 import { ServerUtils } from '../../server/ServerUtil';
-import { emptyDocFunction, emptyFunction, returnTrue, Utils } from '../../Utils';
+import { emptyDocFunction, emptyFunction, returnTrue, Utils, returnOne } from '../../Utils';
 import { Documents } from '../documents/Documents';
 import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel';
 import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel';
@@ -178,7 +178,6 @@ export class Main extends React.Component {
                         <DocumentView Document={mainCont}
                             addDocument={undefined}
                             removeDocument={undefined}
-                            opacity={1}
                             ScreenToLocalTransform={Transform.Identity}
                             ContentScaling={noScaling}
                             PanelWidth={pwidthFunc}
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index df1addbc7..6d43d88f0 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -56,7 +56,8 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
     @action
     textScroll = (e: React.UIEvent) => {
         if (this._textProxyDiv.current && this._textTargetDiv) {
-            this._textTargetDiv.scrollTop = this.TextScroll = this._textProxyDiv.current.children[0].scrollTop;
+            this.TextScroll = (e as any)._targetInst.stateNode.scrollTop;//  this._textProxyDiv.current.children[0].scrollTop;
+            this._textTargetDiv.scrollTop = this.TextScroll;
         }
     }
 
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 4f7d4fc0d..2b96e7678 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -8,7 +8,7 @@ import { Document } from "../../../fields/Document";
 import { KeyStore } from "../../../fields/KeyStore";
 import Measure from "react-measure";
 import { FieldId, Opt, Field, FieldWaiting } from "../../../fields/Field";
-import { Utils, returnTrue, emptyFunction, emptyDocFunction } from "../../../Utils";
+import { Utils, returnTrue, emptyFunction, emptyDocFunction, returnOne } from "../../../Utils";
 import { Server } from "../../Server";
 import { undoBatch } from "../../util/UndoManager";
 import { DocumentView } from "../nodes/DocumentView";
@@ -343,7 +343,6 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                 <DocumentView key={this._document.Id} Document={this._document}
                     addDocument={undefined}
                     removeDocument={undefined}
-                    opacity={1}
                     ContentScaling={this._contentScaling}
                     PanelWidth={this._nativeWidth}
                     PanelHeight={this._nativeHeight}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 2c99c9c67..4f4068e7a 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -12,7 +12,7 @@ import { Field, Opt } from "../../../fields/Field";
 import { Key } from "../../../fields/Key";
 import { KeyStore } from "../../../fields/KeyStore";
 import { ListField } from "../../../fields/ListField";
-import { emptyDocFunction, emptyFunction, returnFalse } from "../../../Utils";
+import { emptyDocFunction, emptyFunction, returnFalse, returnOne } from "../../../Utils";
 import { Server } from "../../Server";
 import { SetupDrag } from "../../util/DragManager";
 import { CompileScript, ToField } from "../../util/Scripting";
@@ -308,7 +308,6 @@ export class CollectionSchemaView extends CollectionSubView {
                             <DocumentView Document={doc}
                                 addDocument={this.props.addDocument} removeDocument={this.props.removeDocument}
                                 isTopMost={false}
-                                opacity={1}
                                 selectOnLoad={false}
                                 ScreenToLocalTransform={this.getPreviewTransform}
                                 ContentScaling={this.getContentScaling}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index cb4e8fb2e..4db3bf81b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -5,7 +5,7 @@ import { Document } from "../../../../fields/Document";
 import { FieldWaiting } from "../../../../fields/Field";
 import { KeyStore } from "../../../../fields/KeyStore";
 import { TextField } from "../../../../fields/TextField";
-import { emptyFunction, returnFalse } from "../../../../Utils";
+import { emptyFunction, returnFalse, returnOne } from "../../../../Utils";
 import { DocumentManager } from "../../../util/DocumentManager";
 import { DragManager } from "../../../util/DragManager";
 import { SelectionManager } from "../../../util/SelectionManager";
@@ -14,7 +14,7 @@ import { undoBatch } from "../../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss";
 import { InkingCanvas } from "../../InkingCanvas";
 import { Main } from "../../Main";
-import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
+import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewProps } from "../../nodes/CollectionFreeFormDocumentView";
 import { DocumentContentsView } from "../../nodes/DocumentContentsView";
 import { DocumentViewProps } from "../../nodes/DocumentView";
 import { CollectionSubView, SubCollectionViewProps } from "../CollectionSubView";
@@ -200,7 +200,6 @@ export class CollectionFreeFormView extends CollectionSubView {
             this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale);
             this.SetPan(-localTransform.TranslateX / localTransform.Scale, -localTransform.TranslateY / localTransform.Scale);
             e.stopPropagation();
-            e.preventDefault();
         }
     }
 
@@ -261,10 +260,9 @@ export class CollectionFreeFormView extends CollectionSubView {
         this.props.focus(this.props.Document);
     }
 
-    getDocumentViewProps(document: Document, opacity: number): DocumentViewProps {
+    getDocumentViewProps(document: Document): DocumentViewProps {
         return {
             Document: document,
-            opacity: opacity,
             addDocument: this.props.addDocument,
             removeDocument: this.props.removeDocument,
             moveDocument: this.props.moveDocument,
@@ -288,9 +286,10 @@ export class CollectionFreeFormView extends CollectionSubView {
             var page = doc.GetNumber(KeyStore.Page, -1);
             var zoom = doc.GetNumber(KeyStore.Zoom, 1);
             var dv = DocumentManager.Instance.getDocumentView(doc);
-            let opacity = this.isAnnotationOverlay && (!dv || !SelectionManager.IsSelected(dv)) ? 1 - Math.abs(zoom - this.scale) : 1;
-            if ((page === curPage || page === -1)) {
-                prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc, opacity)} />);
+            let zoomFade = !this.isAnnotationOverlay || (dv && SelectionManager.IsSelected(dv)) ? 1 :
+                Math.max(0, 2 - (zoom < this.scale ? this.scale / zoom : zoom / this.scale));
+            if (page === curPage || page === -1) {
+                prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} zoomFade={zoomFade} />);
             }
             return prev;
         }, [] as JSX.Element[]);
@@ -305,13 +304,13 @@ export class CollectionFreeFormView extends CollectionSubView {
     @computed
     get backgroundView() {
         return !this.backgroundLayout ? (null) :
-            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document, 1)}
+            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
                 layoutKey={KeyStore.BackgroundLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
     }
     @computed
     get overlayView() {
         return !this.overlayLayout ? (null) :
-            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document, 1)}
+            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
                 layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
     }
 
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 0aa152209..b00cefbf6 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,4 +1,4 @@
-import { computed } from "mobx";
+import { computed, trace } from "mobx";
 import { observer } from "mobx-react";
 import { KeyStore } from "../../../fields/KeyStore";
 import { NumberField } from "../../../fields/NumberField";
@@ -6,13 +6,17 @@ import { Transform } from "../../util/Transform";
 import { DocumentView, DocumentViewProps } from "./DocumentView";
 import "./DocumentView.scss";
 import React = require("react");
+import { OmitKeys } from "../../../Utils";
 
+export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
+    zoomFade: number;
+}
 
 @observer
-export class CollectionFreeFormDocumentView extends React.Component<DocumentViewProps> {
+export class CollectionFreeFormDocumentView extends React.Component<CollectionFreeFormDocumentViewProps> {
     private _mainCont = React.createRef<HTMLDivElement>();
 
-    constructor(props: DocumentViewProps) {
+    constructor(props: CollectionFreeFormDocumentViewProps) {
         super(props);
     }
 
@@ -55,20 +59,24 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView
 
     @computed
     get docView() {
-        return <DocumentView {...this.props}
+        return <DocumentView {...this.docViewProps}
             ContentScaling={this.contentScaling}
             ScreenToLocalTransform={this.getTransform}
             PanelWidth={this.panelWidth}
             PanelHeight={this.panelHeight}
         />;
     }
+    @computed
+    get docViewProps(): DocumentViewProps {
+        return (OmitKeys(this.props, ['zoomFade']));
+    }
     panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth();
     panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight();
 
     render() {
         return (
             <div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
-                opacity: this.props.opacity,
+                opacity: this.props.zoomFade,
                 transformOrigin: "left top",
                 transform: this.transform,
                 pointerEvents: "all",
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 88900c4b1..76f852601 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -23,7 +23,7 @@ import { HistogramBox } from "../../northstar/dash-nodes/HistogramBox";
 import React = require("react");
 import { Document } from "../../../fields/Document";
 import { FieldViewProps } from "./FieldView";
-import { Without } from "../../../Utils";
+import { Without, OmitKeys } from "../../../Utils";
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 type BindingProps = Without<FieldViewProps, 'fieldKey'>;
@@ -44,35 +44,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
 
 
     CreateBindings(): JsxBindings {
-        let {
-            Document,
-            isSelected,
-            select,
-            isTopMost,
-            selectOnLoad,
-            ScreenToLocalTransform,
-            ContainingCollectionView,
-            addDocument,
-            removeDocument,
-            onActiveChanged,
-            parentActive: active,
-        } = this.props;
-        let bindings: JsxBindings = {
-            props: {
-                Document,
-                isSelected,
-                select,
-                isTopMost,
-                selectOnLoad,
-                ScreenToLocalTransform,
-                ContainingCollectionView,
-                active,
-                onActiveChanged,
-                addDocument,
-                removeDocument,
-                focus,
-            }
-        };
+        let bindings: JsxBindings = { props: OmitKeys(this.props, ['parentActive'], (obj: any) => obj.active = this.props.parentActive) };
+
         for (const key of this.layoutKeys) {
             bindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname  e.g,   "DataKey" => KeyStore.Data
         }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 935540af1..bcd746024 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -28,7 +28,6 @@ import React = require("react");
 export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
     Document: Document;
-    opacity: number;
     addDocument?: (doc: Document, allowDuplicates?: boolean) => boolean;
     removeDocument?: (doc: Document) => boolean;
     moveDocument?: (doc: Document, targetCollection: Document, addDocument: (document: Document) => boolean) => boolean;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 562de4827..ebd25f937 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -19,7 +19,7 @@ import { ListField } from "../../../fields/ListField";
 import { DocumentContentsView } from "./DocumentContentsView";
 import { Transform } from "../../util/Transform";
 import { KeyStore } from "../../../fields/KeyStore";
-import { returnFalse, emptyDocFunction } from "../../../Utils";
+import { returnFalse, emptyDocFunction, emptyFunction, returnOne } from "../../../Utils";
 import { CollectionView } from "../collections/CollectionView";
 import { CollectionPDFView } from "../collections/CollectionPDFView";
 import { CollectionVideoView } from "../collections/CollectionVideoView";
@@ -83,7 +83,6 @@ export class FieldView extends React.Component<FieldViewProps> {
                 <DocumentContentsView Document={field}
                     addDocument={undefined}
                     removeDocument={undefined}
-                    opacity={1}
                     ScreenToLocalTransform={Transform.Identity}
                     ContentScaling={() => 1}
                     PanelWidth={() => 100}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 87c1bcb1e..ad1ed5df0 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,4 +1,4 @@
-import { action, IReactionDisposer, reaction } from "mobx";
+import { action, IReactionDisposer, reaction, trace, computed } from "mobx";
 import { baseKeymap } from "prosemirror-commands";
 import { history, redo, undo } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
@@ -17,6 +17,7 @@ import React = require("react");
 import { TextField } from "../../../fields/TextField";
 import { KeyStore } from "../../../fields/KeyStore";
 import { MainOverlayTextBox } from "../MainOverlayTextBox";
+import { observer } from "mobx-react";
 const { buildMenuItems } = require("prosemirror-example-setup");
 const { menuBar } = require("prosemirror-menu");
 
@@ -41,6 +42,7 @@ export interface FormattedTextBoxOverlay {
     isOverlay?: boolean;
 }
 
+@observer
 export class FormattedTextBox extends React.Component<(FieldViewProps & FormattedTextBoxOverlay)> {
     public static LayoutString(fieldStr: string = "DataKey") {
         return FieldView.LayoutString(FormattedTextBox, fieldStr);
-- 
cgit v1.2.3-70-g09d2


From 166c37942ba536f024cbeba6f151da0ed6a3f671 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 15 Apr 2019 16:04:16 -0400
Subject: fixing up small interaction issues with web pages, collections, etc.

---
 src/client/views/EditableView.scss                 |  1 -
 src/client/views/Main.tsx                          |  6 +-
 .../views/collections/CollectionBaseView.tsx       |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 89 +++++++++++++---------
 .../collections/collectionFreeForm/MarqueeView.tsx |  1 -
 src/client/views/nodes/DocumentView.scss           |  5 +-
 src/client/views/nodes/DocumentView.tsx            |  4 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  1 -
 src/client/views/nodes/KeyValueBox.tsx             |  6 --
 src/client/views/nodes/WebBox.scss                 |  6 ++
 src/client/views/nodes/WebBox.tsx                  | 35 +++++++--
 11 files changed, 99 insertions(+), 57 deletions(-)

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

diff --git a/src/client/views/EditableView.scss b/src/client/views/EditableView.scss
index be3c5069a..ea401eaf9 100644
--- a/src/client/views/EditableView.scss
+++ b/src/client/views/EditableView.scss
@@ -2,5 +2,4 @@
     overflow-wrap: break-word;
     word-wrap: break-word;
     hyphens: auto;
-    max-width: 300px;
 }
\ No newline at end of file
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 98ef329c7..6c18e9ad5 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -84,7 +84,11 @@ export class Main extends React.Component {
         this.initEventListeners();
         this.initAuthenticationRouters();
 
-        this.initializeNorthstar();
+        try {
+            this.initializeNorthstar();
+        } catch (e) {
+
+        }
     }
 
     componentDidMount() { window.onpopstate = this.onHistory; }
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index bff56e8c3..444f6fc26 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -88,7 +88,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
         var curPage = props.Document.GetNumber(KeyStore.CurPage, -1);
         doc.SetOnPrototype(KeyStore.Page, new NumberField(curPage));
         if (this.isAnnotationOverlay) {
-            doc.SetOnPrototype(KeyStore.Zoom, new NumberField(this.props.Document.GetNumber(KeyStore.Scale, 1)));
+            doc.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1));
         }
         if (curPage >= 0) {
             doc.SetOnPrototype(KeyStore.AnnotationOn, props.Document);
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4db3bf81b..03426cb27 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -111,7 +111,11 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
-        if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling !== 1)) || e.button === 0) && this.props.active()) {
+        let childSelected = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((childSelected, doc) => {
+            var dv = DocumentManager.Instance.getDocumentView(doc);
+            return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false);
+        }, false);
+        if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling !== 1)) || (e.button === 0 && e.altKey)) && (childSelected || this.props.active())) {
             document.removeEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointermove", this.onPointerMove);
             document.removeEventListener("pointerup", this.onPointerUp);
@@ -130,38 +134,36 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @action
     onPointerMove = (e: PointerEvent): void => {
-        if (!e.cancelBubble && this.props.active()) {
-            if ((!this.isAnnotationOverlay || this.zoomScaling !== 1) && !e.shiftKey) {
-                let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
-                let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
-                let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
-                let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
-                if (!this.isAnnotationOverlay) {
-                    let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0;
-                    let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx;
-                    let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0;
-                    let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny;
-                    let ranges = docs.filter(doc => doc).reduce((range, doc) => {
-                        let x = doc.GetNumber(KeyStore.X, 0);
-                        let xe = x + doc.GetNumber(KeyStore.Width, 0);
-                        let y = doc.GetNumber(KeyStore.Y, 0);
-                        let ye = y + doc.GetNumber(KeyStore.Height, 0);
-                        return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
-                        [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
-                    }, [[minx, maxx], [miny, maxy]]);
-                    let panelwidth = this._pwidth / this.scale / 2;
-                    let panelheight = this._pheight / this.scale / 2;
-                    if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx;
-                    if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx;
-                    if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
-                    if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy;
-                }
-                this.SetPan(x - dx, y - dy);
-                this._lastX = e.pageX;
-                this._lastY = e.pageY;
-                e.stopPropagation();
-                e.preventDefault();
+        if (!e.cancelBubble) {
+            let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
+            let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
+            let docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
+            let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
+            if (!this.isAnnotationOverlay) {
+                let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0;
+                let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx;
+                let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0;
+                let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny;
+                let ranges = docs.filter(doc => doc).reduce((range, doc) => {
+                    let x = doc.GetNumber(KeyStore.X, 0);
+                    let xe = x + doc.GetNumber(KeyStore.Width, 0);
+                    let y = doc.GetNumber(KeyStore.Y, 0);
+                    let ye = y + doc.GetNumber(KeyStore.Height, 0);
+                    return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
+                    [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
+                }, [[minx, maxx], [miny, maxy]]);
+                let panelwidth = this._pwidth / this.scale / 2;
+                let panelheight = this._pheight / this.scale / 2;
+                if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx;
+                if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx;
+                if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
+                if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy;
             }
+            this.SetPan(x - dx, y - dy);
+            this._lastX = e.pageX;
+            this._lastY = e.pageY;
+            e.stopPropagation();
+            e.preventDefault();
         }
     }
 
@@ -170,6 +172,13 @@ export class CollectionFreeFormView extends CollectionSubView {
         // if (!this.props.active()) {
         //     return;
         // }
+        let childSelected = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((childSelected, doc) => {
+            var dv = DocumentManager.Instance.getDocumentView(doc);
+            return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false);
+        }, false);
+        if (!this.props.isSelected() && !childSelected && !this.props.isTopMost) {
+            return;
+        }
         e.stopPropagation();
         let coefficient = 1000;
 
@@ -281,13 +290,23 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @computed
     get views() {
+        let pw = this.props.CollectionView.props
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
         let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
             var page = doc.GetNumber(KeyStore.Page, -1);
             var zoom = doc.GetNumber(KeyStore.Zoom, 1);
-            var dv = DocumentManager.Instance.getDocumentView(doc);
-            let zoomFade = !this.isAnnotationOverlay || (dv && SelectionManager.IsSelected(dv)) ? 1 :
-                Math.max(0, 2 - (zoom < this.scale ? this.scale / zoom : zoom / this.scale));
+            let zoomFade = 1;
+            var documentView = DocumentManager.Instance.getDocumentView(doc);
+            if (documentView) {
+                let transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
+                var [sptX, sptY] = transform.transformPoint(0, 0);
+                let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
+                let w = bptX - sptX;
+                //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1;
+                let fadeUp = .75 * 1800;
+                let fadeDown = .075 * 1800;
+                zoomFade = w < fadeDown || w > fadeUp ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1;
+            }
             if (page === curPage || page === -1) {
                 prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} zoomFade={zoomFade} />);
             }
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index dbab790d4..783470286 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -160,7 +160,6 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 pany: 0,
                 width: bounds.width,
                 height: bounds.height,
-                backgroundColor: "Transparent",
                 ink: inkData ? this.marqueeInkSelect(inkData) : undefined,
                 title: "a nested collection"
             });
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index a946ac1a8..5071c9440 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,6 +1,6 @@
 @import "../globalCssVariables";
 
-.documentView-node {
+.documentView-node .documentView-node-topMost {
   position: inherit;
   top: 0;
   left:0;
@@ -28,6 +28,9 @@
     height: calc(100% - 20px);
   }
 }
+.documentView-node-topMost {
+    background: white;
+}
 
 .minimized-box {
   height: 10px;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index bcd746024..20592894f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -212,7 +212,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         }
     }
     fullScreenClicked = (e: React.MouseEvent): void => {
-        CollectionDockingView.Instance.OpenFullScreen(this.props.Document);
+        CollectionDockingView.Instance.OpenFullScreen((this.props.Document.GetPrototype() as Document).MakeDelegate());
         ContextMenu.Instance.clearItems();
         ContextMenu.Instance.addItem({
             description: "Close Full Screen",
@@ -425,7 +425,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             );
             return (
                 <div
-                    className="documentView-node"
+                    className={`documentView-node${this.props.isTopMost ? "-topmost" : ""}`}
                     ref={this._mainCont}
                     style={{
                         background: backgroundcolor,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index ad1ed5df0..8963484b6 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -42,7 +42,6 @@ export interface FormattedTextBoxOverlay {
     isOverlay?: boolean;
 }
 
-@observer
 export class FormattedTextBox extends React.Component<(FieldViewProps & FormattedTextBoxOverlay)> {
     public static LayoutString(fieldStr: string = "DataKey") {
         return FieldView.LayoutString(FormattedTextBox, fieldStr);
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 29e4af160..ddbec014b 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -26,12 +26,6 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
         super(props);
     }
 
-
-
-    shouldComponentUpdate() {
-        return false;
-    }
-
     @action
     onEnterKey = (e: React.KeyboardEvent): void => {
         if (e.key === 'Enter') {
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index c73bc0c47..2ad1129a4 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -9,6 +9,12 @@
     overflow: scroll;
 }
 
+#webBox-htmlSpan {
+    position: absolute;
+    top:0;
+    left:0;
+}
+
 .webBox-button {
     padding : 0vw;
     border: none;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 90ce72c41..1edb4d826 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -18,21 +18,40 @@ export class WebBox extends React.Component<FieldViewProps> {
 
     @computed get html(): string { return this.props.Document.GetHtml(KeyStore.Data, ""); }
 
+    _ignore = 0;
+    onPreWheel = (e: React.WheelEvent) => {
+        this._ignore = e.timeStamp;
+    }
+    onPrePointer = (e: React.PointerEvent) => {
+        this._ignore = e.timeStamp;
+    }
+    onPostPointer = (e: React.PointerEvent) => {
+        if (this._ignore !== e.timeStamp) {
+            e.stopPropagation();
+        }
+    }
+    onPostWheel = (e: React.WheelEvent) => {
+        if (this._ignore !== e.timeStamp) {
+            e.stopPropagation();
+        }
+    }
     render() {
         let field = this.props.Document.Get(this.props.fieldKey);
         let path = field === FieldWaiting ? "https://image.flaticon.com/icons/svg/66/66163.svg" :
             field instanceof WebField ? field.Data.href : "https://crossorigin.me/" + "https://cs.brown.edu";
 
-        let content = this.html ?
-            <span dangerouslySetInnerHTML={{ __html: this.html }}></span> :
-            <div style={{ width: "100%", height: "100%", position: "absolute" }}>
-                <iframe src={path} style={{ position: "absolute", width: "100%", height: "100%" }}></iframe>
-                {this.props.isSelected() ? (null) : <div style={{ width: "100%", height: "100%", position: "absolute" }} />}
+        let content =
+            <div style={{ width: "100%", height: "100%", position: "absolute" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
+                {this.html ? <span id="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: this.html }} /> :
+                    <iframe src={path} style={{ position: "absolute", width: "100%", height: "100%" }} />}
             </div>;
 
         return (
-            <div className="webBox-cont"  >
-                {content}
-            </div>);
+            <>
+                <div className="webBox-cont"  >
+                    {content}
+                </div>
+                {this.props.isSelected() ? (null) : <div onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer} style={{ width: "100%", height: "100%", position: "absolute" }} />}
+            </>);
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 13ced657b7a3292e57150bf5e44412d7068b7e3d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 16 Apr 2019 00:37:07 -0400
Subject: code clean up and fix to performance issues.

---
 src/client/views/DocumentDecorations.tsx           |   7 +-
 src/client/views/Main.tsx                          |   2 +-
 src/client/views/collections/CollectionView.tsx    |   1 +
 .../CollectionFreeFormLinkView.tsx                 |   8 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 242 ++++++++++-----------
 .../collections/collectionFreeForm/MarqueeView.tsx |   6 +-
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  33 +--
 src/client/views/nodes/DocumentView.scss           |   6 +-
 src/client/views/nodes/DocumentView.tsx            | 241 ++++++--------------
 src/client/views/nodes/ImageBox.tsx                |   2 +-
 10 files changed, 212 insertions(+), 336 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 b97a47a3c..06de3d733 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -124,7 +124,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         this._dragging = true;
         document.removeEventListener("pointermove", this.onBackgroundMove);
         document.removeEventListener("pointerup", this.onBackgroundUp);
-        DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => docView.ContentRef.current!), dragData, e.x, e.y, {
+        DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => docView.ContentDiv!), dragData, e.x, e.y, {
             handlers: {
                 dragComplete: action(() => this._dragging = false),
             },
@@ -176,8 +176,6 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     }
     onMinimizeMove = (e: PointerEvent): void => {
         e.stopPropagation();
-        if (e.button === 0) {
-        }
     }
     onMinimizeUp = (e: PointerEvent): void => {
         e.stopPropagation();
@@ -302,7 +300,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
 
         MainOverlayTextBox.Instance.SetTextDoc();
         SelectionManager.SelectedDocuments().forEach(element => {
-            const rect = element.screenRect();
+            const rect = element.ContentDiv ? element.ContentDiv.getBoundingClientRect() : new DOMRect();
+
             if (rect.width !== 0) {
                 let doc = element.props.Document;
                 let width = doc.GetNumber(KeyStore.Width, 0);
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 6c18e9ad5..0469211fa 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -211,7 +211,7 @@ export class Main extends React.Component {
         let addSchemaNode = action(() => Documents.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" }));
         let addTreeNode = action(() => Documents.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true }));
         let addVideoNode = action(() => Documents.VideoDocument(videourl, { width: 200, height: 200, title: "video node" }));
-        let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, height: 200, title: "a schema collection" }));
+        let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" }));
         let addImageNode = action(() => Documents.ImageDocument(imgurl, { width: 200, height: 200, title: "an image of a cat" }));
         let addWebNode = action(() => Documents.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" }));
         let addAudioNode = action(() => Documents.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" }));
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 1f69a69e8..bd7a5635f 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -10,6 +10,7 @@ import { CurrentUserUtils } from '../../../server/authentication/models/current_
 import { KeyStore } from '../../../fields/KeyStore';
 import { observer } from 'mobx-react';
 import { undoBatch } from '../../util/UndoManager';
+import { trace } from 'mobx';
 
 @observer
 export class CollectionView extends React.Component<FieldViewProps> {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index 081b3eb6c..8868f7df0 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -23,10 +23,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         let l = this.props.LinkDocs;
         let a = this.props.A;
         let b = this.props.B;
-        let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Width, 0) / 2);
-        let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.GetNumber(KeyStore.Height, 0) / 2);
-        let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Width, 0) / 2);
-        let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.GetNumber(KeyStore.Height, 0) / 2);
+        let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.Width() / 2);
+        let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.Minimized, false) ? 5 : a.Height() / 2);
+        let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.Width() / 2);
+        let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.Minimized, false) ? 5 : b.Height() / 2);
         return (
             <line key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine" onPointerDown={this.onPointerDown}
                 style={{ strokeWidth: `${l.length * 5}` }}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 03426cb27..e9ea3013c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable, runInAction, untracked } from "mobx";
+import { action, computed, observable, runInAction, trace, untracked } from "mobx";
 import { observer } from "mobx-react";
 import Measure from "react-measure";
 import { Document } from "../../../../fields/Document";
@@ -13,8 +13,8 @@ import { Transform } from "../../../util/Transform";
 import { undoBatch } from "../../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss";
 import { InkingCanvas } from "../../InkingCanvas";
-import { Main } from "../../Main";
-import { CollectionFreeFormDocumentView, CollectionFreeFormDocumentViewProps } from "../../nodes/CollectionFreeFormDocumentView";
+import { MainOverlayTextBox } from "../../MainOverlayTextBox";
+import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
 import { DocumentContentsView } from "../../nodes/DocumentContentsView";
 import { DocumentViewProps } from "../../nodes/DocumentView";
 import { CollectionSubView, SubCollectionViewProps } from "../CollectionSubView";
@@ -24,12 +24,15 @@ import "./CollectionFreeFormView.scss";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
 import v5 = require("uuid/v5");
-import { MainOverlayTextBox } from "../../MainOverlayTextBox";
+import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
 
 @observer
 export class CollectionFreeFormView extends CollectionSubView {
-    public _canvasRef = React.createRef<HTMLDivElement>();
     private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type)
+    private _lastX: number = 0;
+    private _lastY: number = 0;
+    @observable private _pwidth: number = 0;
+    @observable private _pheight: number = 0;
 
     public addLiveTextBox = (newBox: Document) => {
         // mark this collection so that when the text box is created we can send it the SelectOnLoad prop to focus itself and receive text input
@@ -61,22 +64,15 @@ export class CollectionFreeFormView extends CollectionSubView {
         }, [] as Document[]);
     }
 
-    @observable public DownX: number = 0;
-    @observable public DownY: number = 0;
-    @observable private _lastX: number = 0;
-    @observable private _lastY: number = 0;
-    @observable private _pwidth: number = 0;
-    @observable private _pheight: 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); }
-    @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
+    get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
+    get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
     @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._pwidth / 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._pheight / 2 : 0; }// shift so pan position is at center of window for non-overlay collections
+    panX = () => this.props.Document.GetNumber(KeyStore.PanX, 0);
+    panY = () => this.props.Document.GetNumber(KeyStore.PanY, 0);
+    zoomScaling = () => this.props.Document.GetNumber(KeyStore.Scale, 1);
+    centeringShiftX = () => !this.nativeWidth ? this._pwidth / 2 : 0;  // shift so pan position is at center of window for non-overlay collections
+    centeringShiftY = () => !this.nativeHeight ? this._pheight / 2 : 0;// shift so pan position is at center of window for non-overlay collections
 
     @undoBatch
     @action
@@ -89,6 +85,7 @@ export class CollectionFreeFormView extends CollectionSubView {
                 de.data.droppedDocuments.map(d => {
                     d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - dropX));
                     d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - dropY));
+                    console.log("x = " + d.GetNumber(KeyStore.X, 0) + " y = " + d.GetNumber(KeyStore.X, 0));
                     if (!d.GetNumber(KeyStore.Width, 0)) {
                         d.SetNumber(KeyStore.Width, 300);
                     }
@@ -115,13 +112,13 @@ export class CollectionFreeFormView extends CollectionSubView {
             var dv = DocumentManager.Instance.getDocumentView(doc);
             return childSelected || (dv && SelectionManager.IsSelected(dv) ? true : false);
         }, false);
-        if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling !== 1)) || (e.button === 0 && e.altKey)) && (childSelected || this.props.active())) {
+        if (((e.button === 2 && (!this.isAnnotationOverlay || this.zoomScaling() !== 1)) || (e.button === 0 && e.altKey)) && (childSelected || this.props.active())) {
             document.removeEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointermove", this.onPointerMove);
             document.removeEventListener("pointerup", this.onPointerUp);
             document.addEventListener("pointerup", this.onPointerUp);
-            this._lastX = this.DownX = e.pageX;
-            this._lastY = this.DownY = e.pageY;
+            this._lastX = e.pageX;
+            this._lastY = e.pageY;
         }
     }
 
@@ -141,9 +138,9 @@ export class CollectionFreeFormView extends CollectionSubView {
             let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
             if (!this.isAnnotationOverlay) {
                 let minx = docs.length ? docs[0].GetNumber(KeyStore.X, 0) : 0;
-                let maxx = docs.length ? docs[0].GetNumber(KeyStore.Width, 0) + minx : minx;
+                let maxx = docs.length ? docs[0].Width() + minx : minx;
                 let miny = docs.length ? docs[0].GetNumber(KeyStore.Y, 0) : 0;
-                let maxy = docs.length ? docs[0].GetNumber(KeyStore.Height, 0) + miny : miny;
+                let maxy = docs.length ? docs[0].Height() + miny : miny;
                 let ranges = docs.filter(doc => doc).reduce((range, doc) => {
                     let x = doc.GetNumber(KeyStore.X, 0);
                     let xe = x + doc.GetNumber(KeyStore.Width, 0);
@@ -152,8 +149,8 @@ export class CollectionFreeFormView extends CollectionSubView {
                     return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
                     [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
                 }, [[minx, maxx], [miny, maxy]]);
-                let panelwidth = this._pwidth / this.scale / 2;
-                let panelheight = this._pheight / this.scale / 2;
+                let panelwidth = this._pwidth / this.zoomScaling() / 2;
+                let panelheight = this._pheight / this.zoomScaling() / 2;
                 if (x - dx < ranges[0][0] - panelwidth) x = ranges[0][1] + panelwidth + dx;
                 if (x - dx > ranges[0][1] + panelwidth) x = ranges[0][0] - panelwidth + dx;
                 if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
@@ -180,31 +177,23 @@ export class CollectionFreeFormView extends CollectionSubView {
             return;
         }
         e.stopPropagation();
-        let coefficient = 1000;
+        const coefficient = 1000;
 
         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);
+            this.props.Document.SetNumber(KeyStore.NativeWidth, this.nativeWidth * deltaScale);
+            this.props.Document.SetNumber(KeyStore.NativeHeight, this.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 deltaScale = (1 - (e.deltaY / coefficient));
-            if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) {
-                deltaScale = 1 / this.zoomScaling;
+            if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) {
+                deltaScale = 1 / this.zoomScaling();
             }
-            let [x, y] = transform.transformPoint(e.clientX, e.clientY);
-
-            let localTransform = this.getLocalTransform();
-            localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y);
-            // console.log(localTransform)
+            let [x, y] = this.getTransform().transformPoint(e.clientX, e.clientY);
+            let localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y);
 
             this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale);
             this.SetPan(-localTransform.TranslateX / localTransform.Scale, -localTransform.TranslateY / localTransform.Scale);
@@ -215,9 +204,9 @@ export class CollectionFreeFormView extends CollectionSubView {
     @action
     private SetPan(panX: number, panY: number) {
         MainOverlayTextBox.Instance.SetTextDoc();
-        var x1 = this.getLocalTransform().inverse().Scale;
-        const newPanX = Math.min((1 - 1 / x1) * this.nativeWidth, Math.max(0, panX));
-        const newPanY = Math.min((1 - 1 / x1) * this.nativeHeight, Math.max(0, panY));
+        var scale = this.getLocalTransform().inverse().Scale;
+        const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX));
+        const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY));
         this.props.Document.SetNumber(KeyStore.PanX, this.isAnnotationOverlay ? newPanX : panX);
         this.props.Document.SetNumber(KeyStore.PanY, this.isAnnotationOverlay ? newPanY : panY);
     }
@@ -233,39 +222,18 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @action
     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) {
-                return 1;
-            }
-            if (doc2 === doc) {
-                return -1;
-            }
+        this.props.Document.GetList<Document>(this.props.fieldKey, []).slice().sort((doc1, doc2) => {
+            if (doc1 === doc) return 1;
+            if (doc2 === doc) return -1;
             return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0);
-        }).map((doc, index) =>
-            doc.SetNumber(KeyStore.ZIndex, index + 1));
+        }).map((doc, index) => doc.SetNumber(KeyStore.ZIndex, index + 1));
         return doc;
     }
 
-    @computed get backgroundLayout(): string | undefined {
-        let field = this.props.Document.GetT(KeyStore.BackgroundLayout, TextField);
-        if (field && field !== FieldWaiting) {
-            return field.Data;
-        }
-    }
-    @computed get overlayLayout(): string | undefined {
-        let field = this.props.Document.GetT(KeyStore.OverlayLayout, TextField);
-        if (field && field !== FieldWaiting) {
-            return field.Data;
-        }
-    }
-
     focusDocument = (doc: Document) => {
-        let x = doc.GetNumber(KeyStore.X, 0) + doc.GetNumber(KeyStore.Width, 0) / 2;
-        let y = doc.GetNumber(KeyStore.Y, 0) + doc.GetNumber(KeyStore.Height, 0) / 2;
-        this.SetPan(x, y);
+        this.SetPan(
+            doc.GetNumber(KeyStore.X, 0) + doc.Width() / 2,
+            doc.GetNumber(KeyStore.Y, 0) + doc.Height() / 2);
         this.props.focus(this.props.Document);
     }
 
@@ -290,92 +258,112 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @computed
     get views() {
-        let pw = this.props.CollectionView.props
+        trace();
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
         let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
             var page = doc.GetNumber(KeyStore.Page, -1);
-            var zoom = doc.GetNumber(KeyStore.Zoom, 1);
-            let zoomFade = 1;
-            var documentView = DocumentManager.Instance.getDocumentView(doc);
-            if (documentView) {
-                let transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
-                var [sptX, sptY] = transform.transformPoint(0, 0);
-                let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
-                let w = bptX - sptX;
-                //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1;
-                let fadeUp = .75 * 1800;
-                let fadeDown = .075 * 1800;
-                zoomFade = w < fadeDown || w > fadeUp ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1;
-            }
             if (page === curPage || page === -1) {
-                prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} zoomFade={zoomFade} />);
+                prev.push(<CollectionFreeFormDocumentView key={doc.Id} {...this.getDocumentViewProps(doc)} />);
             }
             return prev;
         }, [] as JSX.Element[]);
 
-        setTimeout(() => { // bcz: surely there must be a better way ....
-            this._selectOnLoaded = "";
-        }, 600);
+        setTimeout(() => this._selectOnLoaded = "", 600);// bcz: surely there must be a better way ....
 
         return docviews;
     }
 
-    @computed
-    get backgroundView() {
-        return !this.backgroundLayout ? (null) :
-            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
-                layoutKey={KeyStore.BackgroundLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
-    }
-    @computed
-    get overlayView() {
-        return !this.overlayLayout ? (null) :
-            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
-                layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
+    @action
+    onResize = (r: any) => {
+        this._pwidth = r.entry.width;
+        this._pheight = r.entry.height;
     }
-
-    @computed
-    get borderWidth() {
-        return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH;
+    @action
+    onCursorMove = (e: React.PointerEvent) => {
+        super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY));
     }
-    getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform());
+    getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
     getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
-    getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.scale).translate(this.panX, this.panY);
-    noScaling = () => 1;
+    getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
+    noScaling = returnOne;
     childViews = () => this.views;
 
     render() {
-        const [dx, dy] = [this.centeringShiftX, this.centeringShiftY];
-        const panx: number = -this.props.Document.GetNumber(KeyStore.PanX, 0);
-        const pany: number = -this.props.Document.GetNumber(KeyStore.PanY, 0);
-        const zoom: number = this.zoomScaling;// needs to be a variable outside of the <Measure> otherwise, reactions won't fire
-        const backgroundView = this.backgroundView; // needs to be a variable outside of the <Measure> otherwise, reactions won't fire
-        const overlayView = this.overlayView;// needs to be a variable outside of the <Measure> otherwise, reactions won't fire
-
+        trace();
+        const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         return (
-            <Measure onResize={(r: any) => runInAction(() => { this._pwidth = r.entry.width; this._pheight = r.entry.height; })}>
+            <Measure onResize={this.onResize}>
                 {({ measureRef }) => (
-                    <div className={`collectionfreeformview-measure`} ref={measureRef}>
-                        <div className={`collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`}
-                            onPointerDown={this.onPointerDown} onPointerMove={(e) => super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY))}
-                            onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} onWheel={this.onPointerWheel} ref={this.createDropTarget}>
+                    <div className="collectionfreeformview-measure" ref={measureRef}>
+                        <div className={containerName} ref={this.createDropTarget} onWheel={this.onPointerWheel}
+                            onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} >
                             <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments}
                                 addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox}
                                 getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}>
-                                <div className="collectionfreeformview" ref={this._canvasRef}
-                                    style={{ transform: `translate(${dx}px, ${dy}px) scale(${zoom}, ${zoom}) translate(${panx}px, ${pany}px)` }}>
-                                    {backgroundView}
-                                    <CollectionFreeFormLinksView {...this.props}>
+                                <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY}
+                                    zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
+                                    <CollectionFreeFormBackgroundView {...this.getDocumentViewProps(this.props.Document)} />
+                                    <CollectionFreeFormLinksView {...this.props} key="freeformLinks">
                                         <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} >
                                             {this.childViews}
                                         </InkingCanvas>
                                     </CollectionFreeFormLinksView>
-                                    <CollectionFreeFormRemoteCursors {...this.props} />
-                                </div>
-                                {overlayView}
+                                    <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />
+                                </CollectionFreeFormViewPannableContents>
+                                <CollectionFreeFormOverlayView {...this.getDocumentViewProps(this.props.Document)} />
                             </MarqueeView>
                         </div>
                     </div>)}
             </Measure>
         );
     }
+}
+
+
+@observer
+class CollectionFreeFormOverlayView extends React.Component<DocumentViewProps> {
+    @computed get overlayView() {
+        let overlayLayout = this.props.Document.GetText(KeyStore.OverlayLayout, "");
+        return !overlayLayout ? (null) :
+            (<DocumentContentsView {...this.props} layoutKey={KeyStore.OverlayLayout}
+                isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />);
+    }
+    render() {
+        return this.overlayView;
+    }
+}
+
+@observer
+class CollectionFreeFormBackgroundView extends React.Component<DocumentViewProps> {
+    @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} />);
+    }
+    render() {
+        return this.backgroundView;
+    }
+}
+
+interface CollectionFreeFormViewPannableContentsProps {
+    centeringShiftX: () => number;
+    centeringShiftY: () => number;
+    panX: () => number;
+    panY: () => number;
+    zoomScaling: () => number;
+}
+
+@observer
+class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{
+    render() {
+        const cenx = this.props.centeringShiftX();
+        const ceny = this.props.centeringShiftY();
+        const panx = -this.props.panX();
+        const pany = -this.props.panY();
+        const zoom = this.props.zoomScaling();// needs to be a variable outside of the <Measure> otherwise, reactions won't fire
+        return <div className="collectionfreeformview" style={{ transform: `translate(${cenx}px, ${ceny}px) scale(${zoom}, ${zoom}) translate(${panx}px, ${pany}px)` }}>
+            {this.props.children}
+        </div>;
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 783470286..96d59c831 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -147,7 +147,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 d.SetNumber(KeyStore.X, d.GetNumber(KeyStore.X, 0) - bounds.left - bounds.width / 2);
                 d.SetNumber(KeyStore.Y, d.GetNumber(KeyStore.Y, 0) - bounds.top - bounds.height / 2);
                 d.SetNumber(KeyStore.Page, -1);
-                d.SetText(KeyStore.Title, "" + d.GetNumber(KeyStore.Width, 0) + " " + d.GetNumber(KeyStore.Height, 0));
+                d.SetText(KeyStore.Title, "" + d.Width() + " " + d.Height());
                 return d;
             });
             let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
@@ -211,8 +211,8 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             var z = doc.GetNumber(KeyStore.Zoom, 1);
             var x = doc.GetNumber(KeyStore.X, 0);
             var y = doc.GetNumber(KeyStore.Y, 0);
-            var w = doc.GetNumber(KeyStore.Width, 0) / z;
-            var h = doc.GetNumber(KeyStore.Height, 0) / z;
+            var w = doc.Width() / z;
+            var h = doc.Height() / z;
             if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) {
                 selection.push(doc);
             }
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index b00cefbf6..68e5a70fb 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -9,17 +9,12 @@ import React = require("react");
 import { OmitKeys } from "../../../Utils";
 
 export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
-    zoomFade: number;
 }
 
 @observer
 export class CollectionFreeFormDocumentView extends React.Component<CollectionFreeFormDocumentViewProps> {
     private _mainCont = React.createRef<HTMLDivElement>();
 
-    constructor(props: CollectionFreeFormDocumentViewProps) {
-        super(props);
-    }
-
     @computed
     get transform(): string {
         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) scale(${this.zoom}, ${this.zoom}) `;
@@ -50,33 +45,41 @@ export class CollectionFreeFormDocumentView extends React.Component<CollectionFr
         this.props.Document.SetData(KeyStore.ZIndex, h, NumberField);
     }
 
-    contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1;
-
     getTransform = (): Transform =>
         this.props.ScreenToLocalTransform()
             .translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0))
             .scale(1 / this.contentScaling()).scale(1 / this.zoom)
 
+    contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1;
+    panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth();
+    panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight();
+
     @computed
     get docView() {
-        return <DocumentView {...this.docViewProps}
+        return <DocumentView {...OmitKeys(this.props, ['zoomFade'])}
             ContentScaling={this.contentScaling}
             ScreenToLocalTransform={this.getTransform}
             PanelWidth={this.panelWidth}
             PanelHeight={this.panelHeight}
         />;
     }
-    @computed
-    get docViewProps(): DocumentViewProps {
-        return (OmitKeys(this.props, ['zoomFade']));
-    }
-    panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth();
-    panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight();
 
     render() {
+        trace();
+        let zoomFade = 1;
+        // //var zoom = doc.GetNumber(KeyStore.Zoom, 1);
+        // let transform = (this.props.ScreenToLocalTransform().scale(this.props.ContentScaling())).inverse();
+        // var [sptX, sptY] = transform.transformPoint(0, 0);
+        // let [bptX, bptY] = transform.transformPoint(this.props.PanelWidth(), this.props.PanelHeight());
+        // let w = bptX - sptX;
+        // //zoomFade = area < 100 || area > 800 ? Math.max(0, Math.min(1, 2 - 5 * (zoom < this.scale ? this.scale / zoom : zoom / this.scale))) : 1;
+        // let fadeUp = .75 * 1800;
+        // let fadeDown = .075 * 1800;
+        // zoomFade = w < fadeDown || w > fadeUp ? Math.max(0, Math.min(1, 2 - (w < fadeDown ? fadeDown / w : w / fadeUp))) : 1;
+
         return (
             <div className="collectionFreeFormDocumentView-container" ref={this._mainCont} style={{
-                opacity: this.props.zoomFade,
+                opacity: zoomFade,
                 transformOrigin: "left top",
                 transform: this.transform,
                 pointerEvents: "all",
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 5071c9440..6383ac3f6 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,10 +1,11 @@
 @import "../globalCssVariables";
 
-.documentView-node .documentView-node-topMost {
+.documentView-node, .documentView-node-topMost {
   position: inherit;
   top: 0;
   left:0;
   background: $light-color; //overflow: hidden;
+  transform-origin: left top;
 
   &.minimized {
     width: 30px;
@@ -36,7 +37,8 @@
   height: 10px;
   width: 10px;
   border-radius: 2px;
-  background: $dark-color
+  background: $dark-color;
+  transform-origin: left top;
 }
 
 .minimized-box:hover {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 20592894f..293fcc087 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -65,14 +65,12 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
     let Keys: { [name: string]: any } = {};
     let Fields: { [name: string]: any } = {};
     for (const key of keys) {
-        let fn = emptyFunction;
-        Object.defineProperty(fn, "name", { value: key + "Key" });
-        Keys[key] = fn;
+        Object.defineProperty(emptyFunction, "name", { value: key + "Key" });
+        Keys[key] = emptyFunction;
     }
     for (const field of fields) {
-        let fn = emptyFunction;
-        Object.defineProperty(fn, "name", { value: field });
-        Fields[field] = fn;
+        Object.defineProperty(emptyFunction, "name", { value: field });
+        Fields[field] = emptyFunction;
     }
     let args: JsxArgs = {
         Document: function Document() { },
@@ -85,18 +83,18 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
 
 @observer
 export class DocumentView extends React.Component<DocumentViewProps> {
-    private _mainCont = React.createRef<HTMLDivElement>();
-    public get ContentRef() {
-        return this._mainCont;
-    }
     private _downX: number = 0;
     private _downY: number = 0;
+    private _mainCont = React.createRef<HTMLDivElement>();
+    private _dropDisposer?: DragManager.DragDropDisposer;
+
+    public get ContentDiv() { return this._mainCont.current; }
     @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); }
     @computed get topMost(): boolean { return this.props.isTopMost; }
     @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>()); }
-    screenRect = (): ClientRect | DOMRect => this._mainCont.current ? this._mainCont.current.getBoundingClientRect() : new DOMRect();
+
     onPointerDown = (e: React.PointerEvent): void => {
         this._downX = e.clientX;
         this._downY = e.clientY;
@@ -118,11 +116,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         }
     }
 
-    private dropDisposer?: DragManager.DragDropDisposer;
-
     componentDidMount() {
         if (this._mainCont.current) {
-            this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
+            this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
                 handlers: { drop: this.drop.bind(this) }
             });
         }
@@ -130,29 +126,26 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
 
     componentDidUpdate() {
-        if (this.dropDisposer) {
-            this.dropDisposer();
+        if (this._dropDisposer) {
+            this._dropDisposer();
         }
         if (this._mainCont.current) {
-            this.dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
+            this._dropDisposer = DragManager.MakeDropTarget(this._mainCont.current, {
                 handlers: { drop: this.drop.bind(this) }
             });
         }
     }
 
     componentWillUnmount() {
-        if (this.dropDisposer) {
-            this.dropDisposer();
+        if (this._dropDisposer) {
+            this._dropDisposer();
         }
         runInAction(() => DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1));
     }
 
     startDragging(x: number, y: number, dropAliasOfDraggedDoc: boolean) {
         if (this._mainCont.current) {
-            const [left, top] = this.props
-                .ScreenToLocalTransform()
-                .inverse()
-                .transformPoint(0, 0);
+            const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
             let dragData = new DragManager.DocumentDragData([this.props.Document]);
             dragData.aliasOnDrop = dropAliasOfDraggedDoc;
             dragData.xOffset = x - left;
@@ -171,10 +164,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         if (e.cancelBubble) {
             return;
         }
-        if (
-            Math.abs(this._downX - e.clientX) > 3 ||
-            Math.abs(this._downY - e.clientY) > 3
-        ) {
+        if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
             document.removeEventListener("pointermove", this.onPointerMove);
             document.removeEventListener("pointerup", this.onPointerUp);
             if (!this.topMost || e.buttons === 2 || e.altKey) {
@@ -188,22 +178,17 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         document.removeEventListener("pointermove", this.onPointerMove);
         document.removeEventListener("pointerup", this.onPointerUp);
         e.stopPropagation();
-        if (!SelectionManager.IsSelected(this) &&
-            e.button !== 2 &&
-            Math.abs(e.clientX - this._downX) < 4 &&
-            Math.abs(e.clientY - this._downY) < 4
-        ) {
+        if (!SelectionManager.IsSelected(this) && e.button !== 2 &&
+            Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientY - this._downY) < 4) {
             SelectionManager.SelectDoc(this, e.ctrlKey);
         }
     }
-    stopPropogation = (e: React.SyntheticEvent) => {
+    stopPropagation = (e: React.SyntheticEvent) => {
         e.stopPropagation();
     }
 
     deleteClicked = (): void => {
-        if (this.props.removeDocument) {
-            this.props.removeDocument(this.props.Document);
-        }
+        this.props.removeDocument && this.props.removeDocument(this.props.Document);
     }
 
     fieldsClicked = (e: React.MouseEvent): void => {
@@ -214,30 +199,20 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     fullScreenClicked = (e: React.MouseEvent): void => {
         CollectionDockingView.Instance.OpenFullScreen((this.props.Document.GetPrototype() as Document).MakeDelegate());
         ContextMenu.Instance.clearItems();
-        ContextMenu.Instance.addItem({
-            description: "Close Full Screen",
-            event: this.closeFullScreenClicked
-        });
+        ContextMenu.Instance.addItem({ description: "Close Full Screen", event: this.closeFullScreenClicked });
         ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
     }
 
     closeFullScreenClicked = (e: React.MouseEvent): void => {
         CollectionDockingView.Instance.CloseFullScreen();
         ContextMenu.Instance.clearItems();
-        ContextMenu.Instance.addItem({
-            description: "Full Screen",
-            event: this.fullScreenClicked
-        });
+        ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked });
         ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
     }
 
     @action
     public minimize = (): void => {
-        this.props.Document.SetData(
-            KeyStore.Minimized,
-            true as boolean,
-            BooleanField
-        );
+        this.props.Document.SetBoolean(KeyStore.Minimized, true);
         SelectionManager.DeselectAll();
     }
 
@@ -253,9 +228,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                 sourceDoc.GetTAsync(KeyStore.Prototype, Document).then(protoSrc =>
                     runInAction(() => {
                         let batch = UndoManager.StartBatch("document view drop");
-                        linkDoc.Set(KeyStore.Title, new TextField("New Link"));
-                        linkDoc.Set(KeyStore.LinkDescription, new TextField(""));
-                        linkDoc.Set(KeyStore.LinkTags, new TextField("Default"));
+                        linkDoc.SetText(KeyStore.Title, "New Link");
+                        linkDoc.SetText(KeyStore.LinkDescription, "");
+                        linkDoc.SetText(KeyStore.LinkTags, "Default");
 
                         let dstTarg = protoDest ? protoDest : destDoc;
                         let srcTarg = protoSrc ? protoSrc : sourceDoc;
@@ -286,11 +261,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     }
 
     onDrop = (e: React.DragEvent) => {
-        if (e.isDefaultPrevented()) {
-            return;
-        }
         let text = e.dataTransfer.getData("text/plain");
-        if (text && text.startsWith("<div")) {
+        if (!e.isDefaultPrevented() && text && text.startsWith("<div")) {
             let oldLayout = this.props.Document.GetText(KeyStore.Layout, "");
             let layout = text.replace("{layout}", oldLayout);
             this.props.Document.SetText(KeyStore.Layout, layout);
@@ -302,145 +274,56 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     @action
     onContextMenu = (e: React.MouseEvent): void => {
         e.stopPropagation();
-        let moved =
-            Math.abs(this._downX - e.clientX) > 3 ||
-            Math.abs(this._downY - e.clientY) > 3;
-        if (moved || e.isDefaultPrevented()) {
-            e.preventDefault();
+        e.preventDefault();
+        if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3 ||
+            e.isDefaultPrevented()) {
             return;
         }
-        e.preventDefault();
 
-        if (!this.isMinimized()) {
-            ContextMenu.Instance.addItem({
-                description: "Minimize",
-                event: this.minimize
-            });
-        }
-        ContextMenu.Instance.addItem({
-            description: "Full Screen",
-            event: this.fullScreenClicked
-        });
-        ContextMenu.Instance.addItem({
-            description: "Fields",
-            event: this.fieldsClicked
-        });
-        ContextMenu.Instance.addItem({
-            description: "Center",
-            event: () => this.props.focus(this.props.Document)
-        });
-        ContextMenu.Instance.addItem({
-            description: "Open Right",
-            event: () =>
-                CollectionDockingView.Instance.AddRightSplit(this.props.Document)
-        });
-        ContextMenu.Instance.addItem({
-            description: "Copy URL",
-            event: () => {
-                Utils.CopyText(ServerUtils.prepend("/doc/" + this.props.Document.Id));
-            }
-        });
-        ContextMenu.Instance.addItem({
-            description: "Copy ID",
-            event: () => {
-                Utils.CopyText(this.props.Document.Id);
-            }
-        });
+        !this.isMinimized() && ContextMenu.Instance.addItem({ description: "Minimize", event: this.minimize });
+        ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked });
+        ContextMenu.Instance.addItem({ description: "Fields", event: this.fieldsClicked });
+        ContextMenu.Instance.addItem({ description: "Center", event: () => this.props.focus(this.props.Document) });
+        ContextMenu.Instance.addItem({ description: "Open Right", event: () => CollectionDockingView.Instance.AddRightSplit(this.props.Document) });
+        ContextMenu.Instance.addItem({ description: "Copy URL", event: () => Utils.CopyText(ServerUtils.prepend("/doc/" + this.props.Document.Id)) });
+        ContextMenu.Instance.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document.Id) });
         //ContextMenu.Instance.addItem({ description: "Docking", event: () => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Docking) })
-        ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
-        if (!this.topMost) {
-            // DocumentViews should stop propagation of this event
-            e.stopPropagation();
-        }
-
-        ContextMenu.Instance.addItem({
-            description: "Delete",
-            event: this.deleteClicked
-        });
+        ContextMenu.Instance.addItem({ description: "Delete", event: this.deleteClicked });
         ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
         SelectionManager.SelectDoc(this, e.ctrlKey);
     }
 
-    isMinimized = () => {
-        let field = this.props.Document.GetT(KeyStore.Minimized, BooleanField);
-        if (field && field !== FieldWaiting) {
-            return field.Data;
-        }
-    }
-
     @action
-    expand = () => {
-        this.props.Document.SetData(
-            KeyStore.Minimized,
-            false as boolean,
-            BooleanField
-        );
-    }
-
+    expand = () => this.props.Document.SetBoolean(KeyStore.Minimized, false)
+    isMinimized = () => this.props.Document.GetBoolean(KeyStore.Minimized, false);
     isSelected = () => SelectionManager.IsSelected(this);
+    select = (ctrlPressed: boolean) => SelectionManager.SelectDoc(this, ctrlPressed);
 
-    select = (ctrlPressed: boolean) => {
-        SelectionManager.SelectDoc(this, ctrlPressed);
-    }
-
-    @computed get nativeWidth(): number { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
-    @computed get nativeHeight(): number { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
-    @computed
-    get contents() {
-        return (<DocumentContentsView
-            {...this.props}
-            isSelected={this.isSelected}
-            select={this.select}
-            layoutKey={KeyStore.Layout}
-        />);
-    }
+    @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
+    @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
+    @computed get contents() { return (<DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={KeyStore.Layout} />); }
 
     render() {
-        if (!this.props.Document) {
-            return null;
-        }
-
         var scaling = this.props.ContentScaling();
-        var nativeWidth = this.nativeWidth;
-        var nativeHeight = this.nativeHeight;
+        var nativeHeight = this.nativeHeight > 0 ? this.nativeHeight.toString() + "px" : "100%";
+        var nativeWidth = this.nativeWidth > 0 ? this.nativeWidth.toString() + "px" : "100%";
 
         if (this.isMinimized()) {
-            return (
-                <div
-                    className="minimized-box"
-                    ref={this._mainCont}
-                    style={{
-                        transformOrigin: "left top",
-                        transform: `scale(${scaling} , ${scaling})`
-                    }}
-                    onClick={this.expand}
-                    onDrop={this.onDrop}
-                    onPointerDown={this.onPointerDown}
-                />
-            );
-        } else {
-            var backgroundcolor = this.props.Document.GetText(
-                KeyStore.BackgroundColor,
-                ""
-            );
-            return (
-                <div
-                    className={`documentView-node${this.props.isTopMost ? "-topmost" : ""}`}
-                    ref={this._mainCont}
-                    style={{
-                        background: backgroundcolor,
-                        width: nativeWidth > 0 ? nativeWidth.toString() + "px" : "100%",
-                        height: nativeHeight > 0 ? nativeHeight.toString() + "px" : "100%",
-                        transformOrigin: "left top",
-                        transform: `scale(${scaling} , ${scaling})`
-                    }}
-                    onDrop={this.onDrop}
-                    onContextMenu={this.onContextMenu}
-                    onPointerDown={this.onPointerDown}
-                >
-                    {this.contents}
-                </div>
-            );
+            return <div className="minimized-box" ref={this._mainCont} onClick={this.expand} onDrop={this.onDrop}
+                style={{ transform: `scale(${scaling} , ${scaling})` }} onPointerDown={this.onPointerDown} />;
         }
+        return (
+            <div className={`documentView-node${this.props.isTopMost ? "-topmost" : ""}`}
+                ref={this._mainCont}
+                style={{
+                    background: this.props.Document.GetText(KeyStore.BackgroundColor, ""),
+                    width: nativeWidth, height: nativeHeight,
+                    transform: `scale(${scaling}, ${scaling})`
+                }}
+                onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown}
+            >
+                {this.contents}
+            </div>
+        );
     }
 }
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 9bdbfbb5d..edd7f55fc 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -81,7 +81,7 @@ export class ImageBox extends React.Component<FieldViewProps> {
                     }
                     e.stopPropagation();
                 }
-            }))
+            }));
             // de.data.removeDocument()  bcz: need to implement
         }
     }
-- 
cgit v1.2.3-70-g09d2


From 5acba4487b3cb66d194e7e3c4c06c5ed8e2c04b4 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 16 Apr 2019 00:50:14 -0400
Subject: more cleanup

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 58 +++++++++-------------
 1 file changed, 24 insertions(+), 34 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 e9ea3013c..fa3017258 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,10 +1,8 @@
-import { action, computed, observable, runInAction, trace, untracked } from "mobx";
+import { action, computed, observable, trace } from "mobx";
 import { observer } from "mobx-react";
 import Measure from "react-measure";
 import { Document } from "../../../../fields/Document";
-import { FieldWaiting } from "../../../../fields/Field";
 import { KeyStore } from "../../../../fields/KeyStore";
-import { TextField } from "../../../../fields/TextField";
 import { emptyFunction, returnFalse, returnOne } from "../../../../Utils";
 import { DocumentManager } from "../../../util/DocumentManager";
 import { DragManager } from "../../../util/DragManager";
@@ -17,14 +15,13 @@ import { MainOverlayTextBox } from "../../MainOverlayTextBox";
 import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
 import { DocumentContentsView } from "../../nodes/DocumentContentsView";
 import { DocumentViewProps } from "../../nodes/DocumentView";
-import { CollectionSubView, SubCollectionViewProps } from "../CollectionSubView";
+import { CollectionSubView } from "../CollectionSubView";
 import { CollectionFreeFormLinksView } from "./CollectionFreeFormLinksView";
 import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors";
 import "./CollectionFreeFormView.scss";
 import { MarqueeView } from "./MarqueeView";
 import React = require("react");
 import v5 = require("uuid/v5");
-import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView";
 
 @observer
 export class CollectionFreeFormView extends CollectionSubView {
@@ -34,25 +31,34 @@ export class CollectionFreeFormView extends CollectionSubView {
     @observable private _pwidth: number = 0;
     @observable private _pheight: number = 0;
 
-    public addLiveTextBox = (newBox: Document) => {
-        // mark this collection so that when the text box is created we can send it the SelectOnLoad prop to focus itself and receive text input
-        this._selectOnLoaded = newBox.Id;
+    @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
+    @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
+    private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
+    private get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
+    private childViews = () => this.views;
+    private panX = () => this.props.Document.GetNumber(KeyStore.PanX, 0);
+    private panY = () => this.props.Document.GetNumber(KeyStore.PanY, 0);
+    private zoomScaling = () => this.props.Document.GetNumber(KeyStore.Scale, 1);
+    private centeringShiftX = () => !this.nativeWidth ? this._pwidth / 2 : 0;  // shift so pan position is at center of window for non-overlay collections
+    private centeringShiftY = () => !this.nativeHeight ? this._pheight / 2 : 0;// shift so pan position is at center of window for non-overlay collections
+    private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
+    private getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
+    private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
+    private addLiveTextBox = (newBox: Document) => {
+        this._selectOnLoaded = newBox.Id;// track the new text box so we can give it a prop that tells it to focus itself when it's displayed
         this.addDocument(newBox, false);
     }
-
-    public addDocument = (newBox: Document, allowDuplicates: boolean) => {
+    private addDocument = (newBox: Document, allowDuplicates: boolean) => {
         if (this.isAnnotationOverlay) {
             newBox.SetNumber(KeyStore.Zoom, this.props.Document.GetNumber(KeyStore.Scale, 1));
         }
         return this.props.addDocument(this.bringToFront(newBox), false);
     }
-
-    public selectDocuments = (docs: Document[]) => {
+    private selectDocuments = (docs: Document[]) => {
         SelectionManager.DeselectAll;
         docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).filter(dv => dv).map(dv =>
             SelectionManager.SelectDoc(dv!, true));
     }
-
     public getActiveDocuments = () => {
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
         return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).reduce((active, doc) => {
@@ -64,16 +70,6 @@ export class CollectionFreeFormView extends CollectionSubView {
         }, [] as Document[]);
     }
 
-    get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
-    get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
-    @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); }
-    @computed get nativeHeight() { return this.props.Document.GetNumber(KeyStore.NativeHeight, 0); }
-    panX = () => this.props.Document.GetNumber(KeyStore.PanX, 0);
-    panY = () => this.props.Document.GetNumber(KeyStore.PanY, 0);
-    zoomScaling = () => this.props.Document.GetNumber(KeyStore.Scale, 1);
-    centeringShiftX = () => !this.nativeWidth ? this._pwidth / 2 : 0;  // shift so pan position is at center of window for non-overlay collections
-    centeringShiftY = () => !this.nativeHeight ? this._pheight / 2 : 0;// shift so pan position is at center of window for non-overlay collections
-
     @undoBatch
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
@@ -156,7 +152,7 @@ export class CollectionFreeFormView extends CollectionSubView {
                 if (y - dy < ranges[1][0] - panelheight) y = ranges[1][1] + panelheight + dy;
                 if (y - dy > ranges[1][1] + panelheight) y = ranges[1][0] - panelheight + dy;
             }
-            this.SetPan(x - dx, y - dy);
+            this.setPan(x - dx, y - dy);
             this._lastX = e.pageX;
             this._lastY = e.pageY;
             e.stopPropagation();
@@ -196,13 +192,13 @@ export class CollectionFreeFormView extends CollectionSubView {
             let localTransform = this.getLocalTransform().inverse().scaleAbout(deltaScale, x, y);
 
             this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale);
-            this.SetPan(-localTransform.TranslateX / localTransform.Scale, -localTransform.TranslateY / localTransform.Scale);
+            this.setPan(-localTransform.TranslateX / localTransform.Scale, -localTransform.TranslateY / localTransform.Scale);
             e.stopPropagation();
         }
     }
 
     @action
-    private SetPan(panX: number, panY: number) {
+    setPan(panX: number, panY: number) {
         MainOverlayTextBox.Instance.SetTextDoc();
         var scale = this.getLocalTransform().inverse().Scale;
         const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX));
@@ -231,7 +227,7 @@ export class CollectionFreeFormView extends CollectionSubView {
     }
 
     focusDocument = (doc: Document) => {
-        this.SetPan(
+        this.setPan(
             doc.GetNumber(KeyStore.X, 0) + doc.Width() / 2,
             doc.GetNumber(KeyStore.Y, 0) + doc.Height() / 2);
         this.props.focus(this.props.Document);
@@ -248,7 +244,7 @@ export class CollectionFreeFormView extends CollectionSubView {
             selectOnLoad: document.Id === this._selectOnLoaded,
             PanelWidth: document.Width,
             PanelHeight: document.Height,
-            ContentScaling: this.noScaling,
+            ContentScaling: returnOne,
             ContainingCollectionView: this.props.CollectionView,
             focus: this.focusDocument,
             parentActive: this.props.active,
@@ -282,11 +278,6 @@ export class CollectionFreeFormView extends CollectionSubView {
     onCursorMove = (e: React.PointerEvent) => {
         super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY));
     }
-    getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
-    getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
-    getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
-    noScaling = returnOne;
-    childViews = () => this.views;
 
     render() {
         trace();
@@ -319,7 +310,6 @@ export class CollectionFreeFormView extends CollectionSubView {
     }
 }
 
-
 @observer
 class CollectionFreeFormOverlayView extends React.Component<DocumentViewProps> {
     @computed get overlayView() {
-- 
cgit v1.2.3-70-g09d2


From feae8f4d314ef389cc544fd3ad0792a6bb04832c Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 16 Apr 2019 12:38:42 -0400
Subject: fixed some text focus issues. fixed contextmenu a bit.  removed
 upload files.

---
 package.json                                       |   2 +-
 src/client/util/SelectionManager.ts                |  14 ++++++
 src/client/views/MainOverlayTextBox.tsx            |   1 -
 src/client/views/_global_variables.ts              |   8 ---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   2 +-
 src/client/views/nodes/DocumentView.tsx            |   3 +-
 src/client/views/nodes/FormattedTextBox.scss       |   6 ++-
 src/client/views/nodes/FormattedTextBox.tsx        |  55 ++++++++++-----------
 .../upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg    | Bin 26946 -> 0 bytes
 .../upload_1f1c6cfef33e5992fa860802e8c466a7.jpg    | Bin 45309 -> 0 bytes
 .../upload_2045f363aa9cf281407703ca242aad1a.jpg    | Bin 9009 -> 0 bytes
 .../upload_25bffd90c080c27f5ac822984406b958.jpg    | Bin 43534 -> 0 bytes
 .../upload_261f11dc39ad568212b5c7e39d1e6d13.jpg    | Bin 27259 -> 0 bytes
 .../upload_26bcc62639141ba64e603daebb5bf5d3.png    | Bin 2757327 -> 0 bytes
 .../upload_2d77d0773612e4723b78118ac50a2929.jpg    | Bin 1805512 -> 0 bytes
 .../upload_2de9ad4dc687c53760c39f724c9a08a5.jpg    | Bin 77462 -> 0 bytes
 .../upload_4abb568aa7cce9d291532c3d0da97102.jpg    | Bin 22445 -> 0 bytes
 .../upload_54c34aaca5a7bf510cebad461ec39512.png    | Bin 2757327 -> 0 bytes
 .../upload_562b1e527300df8b350eeab094b3e1f1.jpg    | Bin 15988 -> 0 bytes
 .../upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg    | Bin 45025 -> 0 bytes
 .../upload_70fa5e0c3f393504349d5865e28f4cac.jpg    | Bin 18041 -> 0 bytes
 .../upload_8155b5b0f57da107bb07083c04e78943.jpg    | Bin 31103 -> 0 bytes
 .../upload_88f588574e0efc415186af935114af9a.jpg    | Bin 40249 -> 0 bytes
 .../upload_8d1c253f93f77c69c0c04ae3efb7d714.png    | Bin 2757327 -> 0 bytes
 .../upload_9ef80158609f5ff739087aecad367b9d.jpg    | Bin 28523 -> 0 bytes
 .../upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg    | Bin 13811 -> 0 bytes
 .../upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg    | Bin 28566 -> 0 bytes
 .../upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg    | Bin 21995 -> 0 bytes
 .../upload_cec1cfcc67cfe5889de4098a49fec45e.jpg    | Bin 22125 -> 0 bytes
 .../upload_f27688fe92dc7de398e957e5d96e1a22.jpg    | Bin 18964 -> 0 bytes
 30 files changed, 48 insertions(+), 43 deletions(-)
 delete mode 100644 src/client/views/_global_variables.ts
 delete mode 100644 src/server/public/files/upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg
 delete mode 100644 src/server/public/files/upload_1f1c6cfef33e5992fa860802e8c466a7.jpg
 delete mode 100644 src/server/public/files/upload_2045f363aa9cf281407703ca242aad1a.jpg
 delete mode 100644 src/server/public/files/upload_25bffd90c080c27f5ac822984406b958.jpg
 delete mode 100644 src/server/public/files/upload_261f11dc39ad568212b5c7e39d1e6d13.jpg
 delete mode 100644 src/server/public/files/upload_26bcc62639141ba64e603daebb5bf5d3.png
 delete mode 100644 src/server/public/files/upload_2d77d0773612e4723b78118ac50a2929.jpg
 delete mode 100644 src/server/public/files/upload_2de9ad4dc687c53760c39f724c9a08a5.jpg
 delete mode 100644 src/server/public/files/upload_4abb568aa7cce9d291532c3d0da97102.jpg
 delete mode 100644 src/server/public/files/upload_54c34aaca5a7bf510cebad461ec39512.png
 delete mode 100644 src/server/public/files/upload_562b1e527300df8b350eeab094b3e1f1.jpg
 delete mode 100644 src/server/public/files/upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg
 delete mode 100644 src/server/public/files/upload_70fa5e0c3f393504349d5865e28f4cac.jpg
 delete mode 100644 src/server/public/files/upload_8155b5b0f57da107bb07083c04e78943.jpg
 delete mode 100644 src/server/public/files/upload_88f588574e0efc415186af935114af9a.jpg
 delete mode 100644 src/server/public/files/upload_8d1c253f93f77c69c0c04ae3efb7d714.png
 delete mode 100644 src/server/public/files/upload_9ef80158609f5ff739087aecad367b9d.jpg
 delete mode 100644 src/server/public/files/upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg
 delete mode 100644 src/server/public/files/upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg
 delete mode 100644 src/server/public/files/upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg
 delete mode 100644 src/server/public/files/upload_cec1cfcc67cfe5889de4098a49fec45e.jpg
 delete mode 100644 src/server/public/files/upload_f27688fe92dc7de398e957e5d96e1a22.jpg

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

diff --git a/package.json b/package.json
index 489bce7e1..2463afa74 100644
--- a/package.json
+++ b/package.json
@@ -170,4 +170,4 @@
         "uuid": "^3.3.2",
         "xoauth2": "^1.2.0"
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index c56f6a4ff..320553952 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -28,6 +28,16 @@ export namespace SelectionManager {
             manager.SelectedDocuments = [];
             MainOverlayTextBox.Instance.SetTextDoc();
         }
+        @action
+        ReselectAll() {
+            let sdocs = manager.SelectedDocuments.map(d => d);
+            manager.SelectedDocuments = [];
+            return sdocs;
+        }
+        @action
+        ReselectAll2(sdocs: DocumentView[]) {
+            sdocs.map(s => SelectionManager.SelectDoc(s, false));
+        }
     }
 
     const manager = new Manager();
@@ -52,6 +62,10 @@ export namespace SelectionManager {
         if (found) manager.SelectDoc(found, false);
     }
 
+    export function ReselectAll() {
+        let sdocs = manager.ReselectAll();
+        manager.ReselectAll2(sdocs);
+    }
     export function SelectedDocuments(): Array<DocumentView> {
         return manager.SelectedDocuments;
     }
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 422a45d59..141b3ad74 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -40,7 +40,6 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
             this._textTargetDiv.style.color = this._textColor;
         }
 
-        this.TextDoc = undefined;
         this.TextDoc = textDoc;
         this._textFieldKey = textFieldKey!;
         this._textXf = tx ? tx : Transform.Identity();
diff --git a/src/client/views/_global_variables.ts b/src/client/views/_global_variables.ts
deleted file mode 100644
index 10482bc8d..000000000
--- a/src/client/views/_global_variables.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import * as globalStyleVariables from "../views/globalCssVariables.scss"
-
-export interface I_globalScss {
-    contextMenuZindex: string;  // context menu shows up over everything
-}
-let globalStyles = globalStyleVariables as any as I_globalScss;
-
-export default globalStyles;
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index fa3017258..50f0a6164 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -81,7 +81,6 @@ export class CollectionFreeFormView extends CollectionSubView {
                 de.data.droppedDocuments.map(d => {
                     d.SetNumber(KeyStore.X, x + (d.GetNumber(KeyStore.X, 0) - dropX));
                     d.SetNumber(KeyStore.Y, y + (d.GetNumber(KeyStore.Y, 0) - dropY));
-                    console.log("x = " + d.GetNumber(KeyStore.X, 0) + " y = " + d.GetNumber(KeyStore.X, 0));
                     if (!d.GetNumber(KeyStore.Width, 0)) {
                         d.SetNumber(KeyStore.Width, 300);
                     }
@@ -90,6 +89,7 @@ export class CollectionFreeFormView extends CollectionSubView {
                     }
                     this.bringToFront(d);
                 });
+                SelectionManager.ReselectAll();
             }
             return true;
         }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 0d974c97e..1cbb24223 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -277,11 +277,12 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     @action
     onContextMenu = (e: React.MouseEvent): void => {
         e.stopPropagation();
-        e.preventDefault();
         if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3 ||
             e.isDefaultPrevented()) {
+            e.preventDefault();
             return;
         }
+        e.preventDefault();
 
         !this.isMinimized() && ContextMenu.Instance.addItem({ description: "Minimize", event: this.minimize });
         ContextMenu.Instance.addItem({ description: "Full Screen", event: this.fullScreenClicked });
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 3978c3d38..5eb2bf7ce 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -10,7 +10,7 @@
   outline: none !important;
 }
 
-.formattedTextBox-cont {
+.formattedTextBox-cont-scroll, .formattedTextBox-cont-hidden {
   background: $light-color-secondary;
   padding: 0.9em;
   border-width: 0px;
@@ -24,6 +24,10 @@
   height: 100%;
   pointer-events: all;
 }
+.formattedTextBox-cont-hidden {
+    overflow: hidden;
+    pointer-events: none;
+}
 
 .menuicon {
   display: inline-block;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index c380ef650..bff8ca7a4 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,27 +1,24 @@
-import { action, IReactionDisposer, reaction, trace, computed } from "mobx";
+import { action, IReactionDisposer, reaction } from "mobx";
 import { baseKeymap } from "prosemirror-commands";
-import { history, redo, undo } from "prosemirror-history";
+import { history } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
 import { EditorState, Plugin, Transaction } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { FieldWaiting, Opt } from "../../../fields/Field";
+import { KeyStore } from "../../../fields/KeyStore";
 import { RichTextField } from "../../../fields/RichTextField";
+import { TextField } from "../../../fields/TextField";
+import { Document } from "../../../fields/Document";
+import buildKeymap from "../../util/ProsemirrorKeymap";
 import { inpRules } from "../../util/RichTextRules";
-import { Schema } from "prosemirror-model";
 import { schema } from "../../util/RichTextSchema";
+import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu";
 import { TooltipTextMenu } from "../../util/TooltipTextMenu";
 import { ContextMenu } from "../../views/ContextMenu";
-import { Main } from "../Main";
+import { MainOverlayTextBox } from "../MainOverlayTextBox";
 import { FieldView, FieldViewProps } from "./FieldView";
 import "./FormattedTextBox.scss";
 import React = require("react");
-import { undoItem } from "prosemirror-menu";
-import buildKeymap from "../../util/ProsemirrorKeymap";
-import { TextField } from "../../../fields/TextField";
-import { KeyStore } from "../../../fields/KeyStore";
-import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu";
-import { MainOverlayTextBox } from "../MainOverlayTextBox";
-import { observer } from "mobx-react";
 const { buildMenuItems } = require("prosemirror-example-setup");
 const { menuBar } = require("prosemirror-menu");
 
@@ -52,6 +49,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
     }
     private _ref: React.RefObject<HTMLDivElement>;
     private _editorView: Opt<EditorView>;
+    private _gotDown: boolean = false;
     private _reactionDisposer: Opt<IReactionDisposer>;
     private _inputReactionDisposer: Opt<IReactionDisposer>;
     private _proxyReactionDisposer: Opt<IReactionDisposer>;
@@ -109,8 +107,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
                     if (this._editorView) {
                         this._editorView.destroy();
                     }
-
-                    this.setupEditor(config);
+                    this.setupEditor(config, MainOverlayTextBox.Instance.TextDoc); // bcz: not sure why, but the order of events is such that this.props.Document hasn't updated yet, so without forcing the editor to the MainOverlayTextBox, it will display the previously focused textbox
                 }
             );
         } else {
@@ -131,20 +128,18 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
                 }
             }
         );
-        this.setupEditor(config);
+        this.setupEditor(config, this.props.Document);
     }
 
-    private setupEditor(config: any) {
-        let state: EditorState;
-        let field = this.props.Document ? this.props.Document.GetT(this.props.fieldKey, RichTextField) : undefined;
-        if (field && field !== FieldWaiting && field.Data) {
-            state = EditorState.fromJSON(config, JSON.parse(field.Data));
-        } else {
-            state = EditorState.create(config);
-        }
+    shouldComponentUpdate() {
+        return false;
+    }
+
+    private setupEditor(config: any, doc?: Document) {
+        let field = doc ? doc.GetT(this.props.fieldKey, RichTextField) : undefined;
         if (this._ref.current) {
             this._editorView = new EditorView(this._ref.current, {
-                state,
+                state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config),
                 dispatchTransaction: this.dispatchTransaction
             });
         }
@@ -170,10 +165,6 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
         }
     }
 
-    shouldComponentUpdate() {
-        return false;
-    }
-
     @action
     onChange(e: React.ChangeEvent<HTMLInputElement>) {
         const { fieldKey, Document } = this.props;
@@ -186,6 +177,7 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
             e.stopPropagation();
         }
         if (e.button === 2) {
+            this._gotDown = true;
             console.log("second");
             e.preventDefault();
         }
@@ -211,6 +203,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
     textCapability = (e: React.MouseEvent): void => { };
 
     specificContextMenu = (e: React.MouseEvent): void => {
+        if (!this._gotDown) {
+            e.preventDefault();
+            return;
+        }
         ContextMenu.Instance.addItem({
             description: "Text Capability",
             event: this.textCapability
@@ -262,10 +258,9 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte
         // (e.nativeEvent as any).DASHFormattedTextBoxHandled = true;
     }
     render() {
+        let style = this.props.isSelected() || this.props.isOverlay ? "scroll" : "hidden";
         return (
-            <div
-                style={{ overflowY: this.props.isSelected() || this.props.isOverlay ? "scroll" : "hidden" }}
-                className={`formattedTextBox-cont`}
+            <div className={`formattedTextBox-cont-${style}`}
                 onKeyDown={this.onKeyPress}
                 onKeyPress={this.onKeyPress}
                 onFocus={this.onFocused}
diff --git a/src/server/public/files/upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg b/src/server/public/files/upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg
deleted file mode 100644
index aeb10c4b0..000000000
Binary files a/src/server/public/files/upload_1b4818f39ea324b5a687bb1ade3dca6c.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_1f1c6cfef33e5992fa860802e8c466a7.jpg b/src/server/public/files/upload_1f1c6cfef33e5992fa860802e8c466a7.jpg
deleted file mode 100644
index a2c1d8a46..000000000
Binary files a/src/server/public/files/upload_1f1c6cfef33e5992fa860802e8c466a7.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_2045f363aa9cf281407703ca242aad1a.jpg b/src/server/public/files/upload_2045f363aa9cf281407703ca242aad1a.jpg
deleted file mode 100644
index c19b31a38..000000000
Binary files a/src/server/public/files/upload_2045f363aa9cf281407703ca242aad1a.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_25bffd90c080c27f5ac822984406b958.jpg b/src/server/public/files/upload_25bffd90c080c27f5ac822984406b958.jpg
deleted file mode 100644
index 3614b42eb..000000000
Binary files a/src/server/public/files/upload_25bffd90c080c27f5ac822984406b958.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_261f11dc39ad568212b5c7e39d1e6d13.jpg b/src/server/public/files/upload_261f11dc39ad568212b5c7e39d1e6d13.jpg
deleted file mode 100644
index ecd12d9cb..000000000
Binary files a/src/server/public/files/upload_261f11dc39ad568212b5c7e39d1e6d13.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_26bcc62639141ba64e603daebb5bf5d3.png b/src/server/public/files/upload_26bcc62639141ba64e603daebb5bf5d3.png
deleted file mode 100644
index e2297cb3c..000000000
Binary files a/src/server/public/files/upload_26bcc62639141ba64e603daebb5bf5d3.png and /dev/null differ
diff --git a/src/server/public/files/upload_2d77d0773612e4723b78118ac50a2929.jpg b/src/server/public/files/upload_2d77d0773612e4723b78118ac50a2929.jpg
deleted file mode 100644
index 261a0ceff..000000000
Binary files a/src/server/public/files/upload_2d77d0773612e4723b78118ac50a2929.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_2de9ad4dc687c53760c39f724c9a08a5.jpg b/src/server/public/files/upload_2de9ad4dc687c53760c39f724c9a08a5.jpg
deleted file mode 100644
index 6b6ec3c3f..000000000
Binary files a/src/server/public/files/upload_2de9ad4dc687c53760c39f724c9a08a5.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_4abb568aa7cce9d291532c3d0da97102.jpg b/src/server/public/files/upload_4abb568aa7cce9d291532c3d0da97102.jpg
deleted file mode 100644
index f6332670c..000000000
Binary files a/src/server/public/files/upload_4abb568aa7cce9d291532c3d0da97102.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_54c34aaca5a7bf510cebad461ec39512.png b/src/server/public/files/upload_54c34aaca5a7bf510cebad461ec39512.png
deleted file mode 100644
index e2297cb3c..000000000
Binary files a/src/server/public/files/upload_54c34aaca5a7bf510cebad461ec39512.png and /dev/null differ
diff --git a/src/server/public/files/upload_562b1e527300df8b350eeab094b3e1f1.jpg b/src/server/public/files/upload_562b1e527300df8b350eeab094b3e1f1.jpg
deleted file mode 100644
index db40705dd..000000000
Binary files a/src/server/public/files/upload_562b1e527300df8b350eeab094b3e1f1.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg b/src/server/public/files/upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg
deleted file mode 100644
index f0417a752..000000000
Binary files a/src/server/public/files/upload_6a26d3f7008a8c79ee5fc8054ba69996.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_70fa5e0c3f393504349d5865e28f4cac.jpg b/src/server/public/files/upload_70fa5e0c3f393504349d5865e28f4cac.jpg
deleted file mode 100644
index 395f8ec21..000000000
Binary files a/src/server/public/files/upload_70fa5e0c3f393504349d5865e28f4cac.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_8155b5b0f57da107bb07083c04e78943.jpg b/src/server/public/files/upload_8155b5b0f57da107bb07083c04e78943.jpg
deleted file mode 100644
index 53d9315a9..000000000
Binary files a/src/server/public/files/upload_8155b5b0f57da107bb07083c04e78943.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_88f588574e0efc415186af935114af9a.jpg b/src/server/public/files/upload_88f588574e0efc415186af935114af9a.jpg
deleted file mode 100644
index b72dbc482..000000000
Binary files a/src/server/public/files/upload_88f588574e0efc415186af935114af9a.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_8d1c253f93f77c69c0c04ae3efb7d714.png b/src/server/public/files/upload_8d1c253f93f77c69c0c04ae3efb7d714.png
deleted file mode 100644
index e2297cb3c..000000000
Binary files a/src/server/public/files/upload_8d1c253f93f77c69c0c04ae3efb7d714.png and /dev/null differ
diff --git a/src/server/public/files/upload_9ef80158609f5ff739087aecad367b9d.jpg b/src/server/public/files/upload_9ef80158609f5ff739087aecad367b9d.jpg
deleted file mode 100644
index 84423538c..000000000
Binary files a/src/server/public/files/upload_9ef80158609f5ff739087aecad367b9d.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg b/src/server/public/files/upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg
deleted file mode 100644
index dc7ec2f33..000000000
Binary files a/src/server/public/files/upload_c39a7e0d7e8d35bb18461a5a0aa063bf.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg b/src/server/public/files/upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg
deleted file mode 100644
index 4422124a1..000000000
Binary files a/src/server/public/files/upload_c6b81ab4eb70465a7e9b45d5c8f3ecaa.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg b/src/server/public/files/upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg
deleted file mode 100644
index 3747ca985..000000000
Binary files a/src/server/public/files/upload_c99ec7a8a2df0b2f90479fde7d70c2eb.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_cec1cfcc67cfe5889de4098a49fec45e.jpg b/src/server/public/files/upload_cec1cfcc67cfe5889de4098a49fec45e.jpg
deleted file mode 100644
index 95053d772..000000000
Binary files a/src/server/public/files/upload_cec1cfcc67cfe5889de4098a49fec45e.jpg and /dev/null differ
diff --git a/src/server/public/files/upload_f27688fe92dc7de398e957e5d96e1a22.jpg b/src/server/public/files/upload_f27688fe92dc7de398e957e5d96e1a22.jpg
deleted file mode 100644
index 9841bad3f..000000000
Binary files a/src/server/public/files/upload_f27688fe92dc7de398e957e5d96e1a22.jpg and /dev/null differ
-- 
cgit v1.2.3-70-g09d2


From caecf2452c4af5caf8b298719d53274b6709c194 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 16 Apr 2019 15:00:14 -0400
Subject: removed traces()played with image box stacking.

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 --
 .../views/nodes/CollectionFreeFormDocumentView.tsx |  1 -
 src/client/views/nodes/ImageBox.scss               | 12 +++++++-
 src/client/views/nodes/ImageBox.tsx                | 34 +++++++++++++++++++---
 4 files changed, 41 insertions(+), 8 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 50f0a6164..3ae64d2c6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -254,7 +254,6 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @computed
     get views() {
-        trace();
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1);
         let docviews = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => {
             var page = doc.GetNumber(KeyStore.Page, -1);
@@ -280,7 +279,6 @@ export class CollectionFreeFormView extends CollectionSubView {
     }
 
     render() {
-        trace();
         const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         return (
             <Measure onResize={this.onResize}>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 68e5a70fb..8cf7a0dd2 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -65,7 +65,6 @@ export class CollectionFreeFormDocumentView extends React.Component<CollectionFr
     }
 
     render() {
-        trace();
         let zoomFade = 1;
         // //var zoom = doc.GetNumber(KeyStore.Zoom, 1);
         // let transform = (this.props.ScreenToLocalTransform().scale(this.props.ContentScaling())).inverse();
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 487038841..f4b3837ff 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -8,6 +8,16 @@
   max-height: 100%;
 }
 
+.imageBox-dot {
+    position:absolute;
+    bottom: 10;
+    left: 0;
+    border-radius: 10px;
+    width:20px;
+    height:20px;
+    background:gray;
+}
+
 .imageBox-cont img {
     height: 100%;
     width:100%;
@@ -18,4 +28,4 @@
   border: none;
   width: 100%;
   height: 100%;
-}
+}
\ No newline at end of file
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index edd7f55fc..ac54321d5 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -13,9 +13,12 @@ import React = require("react");
 import { Utils } from '../../../Utils';
 import { ListField } from '../../../fields/ListField';
 import { DragManager } from '../../util/DragManager';
-import { undoBatch } from '../../util/UndoManager';
+import { undoBatch, UndoManager } from '../../util/UndoManager';
 import { TextField } from '../../../fields/TextField';
 import { Document } from '../../../fields/Document';
+import { RouteStore } from '../../../server/RouteStore';
+import { ServerUtils } from '../../../server/ServerUtil';
+import { CollectionSubView } from '../collections/CollectionSubView';
 
 @observer
 export class ImageBox extends React.Component<FieldViewProps> {
@@ -43,7 +46,7 @@ export class ImageBox extends React.Component<FieldViewProps> {
     onLoad = (target: any) => {
         var h = this._imgRef.current!.naturalHeight;
         var w = this._imgRef.current!.naturalWidth;
-        this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w);
+        if (this._photoIndex == 0) this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w);
     }
 
     componentDidMount() {
@@ -61,6 +64,12 @@ export class ImageBox extends React.Component<FieldViewProps> {
     componentWillUnmount() {
     }
 
+    onDrop = (e: React.DragEvent) => {
+        e.stopPropagation();
+        e.preventDefault();
+        console.log("IMPLEMENT ME PLEASE")
+    }
+
 
     @undoBatch
     drop = (e: Event, de: DragManager.DropEvent) => {
@@ -139,6 +148,22 @@ export class ImageBox extends React.Component<FieldViewProps> {
         }
     }
 
+    @action
+    onDotDown(index: number) {
+        this._photoIndex = index;
+    }
+
+    dots(paths: string[]) {
+        let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1);
+        let dist = Math.min(nativeWidth / paths.length, 40);
+        let left = (nativeWidth - paths.length * dist) / 2;
+        return paths.map((p, i) =>
+            <div className="imageBox-placer"  >
+                <div className="imageBox-dot" style={{ transform: `translate(${i * dist + left}px, 0px)` }} key={`i`} onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); this.onDotDown(i); }} />
+            </div>
+        )
+    }
+
     render() {
         let field = this.props.Document.Get(this.props.fieldKey);
         let paths: string[] = ["http://www.cs.brown.edu/~bcz/face.gif"];
@@ -147,8 +172,9 @@ export class ImageBox extends React.Component<FieldViewProps> {
         else if (field instanceof ListField) paths = field.Data.filter(val => val as ImageField).map(p => (p as ImageField).Data.href);
         let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 1);
         return (
-            <div className="imageBox-cont" onPointerDown={this.onPointerDown} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
-                <img src={paths[0]} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} />
+            <div className="imageBox-cont" onPointerDown={this.onPointerDown} onDrop={this.onDrop} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
+                <img src={paths[Math.min(paths.length, this._photoIndex)]} style={{ objectFit: (this._photoIndex == 0 ? undefined : "contain") }} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} />
+                {this.dots(paths)}
                 {this.lightbox(paths)}
             </div>);
     }
-- 
cgit v1.2.3-70-g09d2


From 21b1e20106ff49c02657c88f503ef46bc7e4fb07 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 16 Apr 2019 23:09:03 -0400
Subject: various bug fixes

---
 src/client/northstar/dash-nodes/HistogramBox.tsx   |  2 +-
 .../views/collections/CollectionBaseView.tsx       |  9 ++++--
 .../views/collections/CollectionDockingView.scss   |  5 ++++
 .../views/collections/CollectionDockingView.tsx    |  7 ++++-
 .../views/collections/CollectionSchemaView.tsx     | 14 ++++++----
 src/client/views/collections/CollectionView.tsx    |  4 ++-
 .../CollectionFreeFormLinksView.tsx                |  4 +--
 .../CollectionFreeFormRemoteCursors.tsx            |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |  1 -
 src/client/views/nodes/DocumentView.scss           |  4 +--
 src/client/views/nodes/ImageBox.tsx                | 32 ++++++----------------
 12 files changed, 44 insertions(+), 42 deletions(-)

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

diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index 3e94fed81..0e84ace50 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -118,7 +118,7 @@ export class HistogramBox extends React.Component<FieldViewProps> {
             this.props.Document.GetTAsync(this.props.fieldKey, HistogramField).then((histoOp: Opt<HistogramField>) => runInAction(() => {
                 this.HistoOp = histoOp ? histoOp.Data : HistogramOperation.Empty;
                 if (this.HistoOp !== HistogramOperation.Empty) {
-                    reaction(() => this.props.Document.GetList(KeyStore.LinkedFromDocs, []), (docs: Document[]) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true });
+                    reaction(() => this.props.Document.GetList(KeyStore.LinkedFromDocs, [] as Document[]), (docs) => this.HistoOp.Links.splice(0, this.HistoOp.Links.length, ...docs), { fireImmediately: true });
                     reaction(() => this.props.Document.GetList(KeyStore.BrushingDocs, []).length,
                         () => {
                             let brushingDocs = this.props.Document.GetList(KeyStore.BrushingDocs, [] as Document[]);
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 444f6fc26..4fda38a26 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -61,13 +61,16 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
     }
 
     createsCycle(documentToAdd: Document, containerDocument: Document): boolean {
-        let data = documentToAdd.GetList<Document>(KeyStore.Data, []);
-        for (const doc of data) {
+        if (!(documentToAdd instanceof Document)) {
+            return false;
+        }
+        let data = documentToAdd.GetList(KeyStore.Data, [] as Document[]);
+        for (const doc of data.filter(d => d instanceof Document)) {
             if (this.createsCycle(doc, containerDocument)) {
                 return true;
             }
         }
-        let annots = documentToAdd.GetList<Document>(KeyStore.Annotations, []);
+        let annots = documentToAdd.GetList(KeyStore.Annotations, [] as Document[]);
         for (const annot of annots) {
             if (this.createsCycle(annot, containerDocument)) {
                 return true;
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 0e7e0afa7..5ed4567cf 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -2,6 +2,11 @@
 
 .collectiondockingview-content {
     height: 100%;
+    text-align:center;
+    .documentView-node-topmost {
+        transform-origin: center top;
+        display: inline-block;
+    }
 }
 .lm_active .messageCounter{
     color:white;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 4ea21b2f5..b998362f4 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -327,7 +327,12 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
 
     private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth);
     private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight);
-    private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth);
+    private _contentScaling = () => {
+        let wscale = this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth);
+        if (wscale * this._nativeHeight() > this._panelHeight)
+            return this._panelHeight / (this._nativeHeight() ? this._nativeHeight() : this._panelHeight);
+        return wscale;
+    }
 
     ScreenToLocalTransform = () => {
         let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!);
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 4f4068e7a..1defdba7e 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -167,7 +167,7 @@ export class CollectionSchemaView extends CollectionSubView {
 
     @computed
     get columns() {
-        return this.props.Document.GetList<Key>(KeyStore.ColumnsKey, []);
+        return this.props.Document.GetList(KeyStore.ColumnsKey, [] as Key[]);
     }
 
     @action
@@ -195,7 +195,7 @@ export class CollectionSchemaView extends CollectionSubView {
 
     @computed
     get findAllDocumentKeys(): { [id: string]: boolean } {
-        const docs = this.props.Document.GetList<Document>(this.props.fieldKey, []);
+        const docs = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
         let keys: { [id: string]: boolean } = {};
         if (this._optionsActivated > -1) {
             // bcz: ugh.  this is untracked since otherwise a large collection of documents will blast the server for all their fields.
@@ -237,7 +237,7 @@ export class CollectionSchemaView extends CollectionSubView {
     }
     @action
     setScaling = (r: any) => {
-        const children = this.props.Document.GetList<Document>(this.props.fieldKey, []);
+        const children = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
         const selected = children.length > this._selectedIndex ? children[this._selectedIndex] : undefined;
         this._panelWidth = r.entry.width;
         this._panelHeight = r.entry.height ? r.entry.height : this._panelHeight;
@@ -253,8 +253,10 @@ export class CollectionSchemaView extends CollectionSubView {
     getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- this.borderWidth - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - this.borderWidth).scale(1 / this._contentScaling);
 
     onPointerDown = (e: React.PointerEvent): void => {
-        if (e.button === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
-            e.stopPropagation();
+        if (e.button === 0 && !e.altKey && !e.ctrlKey && !e.metaKey) {
+            if (this.props.isSelected())
+                e.stopPropagation();
+            else e.preventDefault();
         }
     }
 
@@ -293,7 +295,7 @@ export class CollectionSchemaView extends CollectionSubView {
         library.add(faCog);
         library.add(faPlus);
         const columns = this.columns;
-        const children = this.props.Document.GetList<Document>(this.props.fieldKey, []);
+        const children = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
         const selected = children.length > this._selectedIndex ? children[this._selectedIndex] : undefined;
         //all the keys/columns that will be displayed in the schema
         const allKeys = this.findAllDocumentKeys;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index bd7a5635f..675e720e2 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -29,8 +29,10 @@ export class CollectionView extends React.Component<FieldViewProps> {
         return (null);
     }
 
+    get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's?
+
     onContextMenu = (e: React.MouseEvent): void => {
-        if (!e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
+        if (!this.isAnnotationOverlay && !e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
             ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform)) });
             ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema)) });
             ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree)) });
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index 2f684a54e..cd74d3a84 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -16,9 +16,9 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
 
     _brushReactionDisposer?: IReactionDisposer;
     componentDidMount() {
-        this._brushReactionDisposer = reaction(() => this.props.Document.GetList<Document>(this.props.fieldKey, []).map(doc => doc.GetNumber(KeyStore.X, 0)),
+        this._brushReactionDisposer = reaction(() => this.props.Document.GetList(this.props.fieldKey, [] as Document[]).map(doc => doc.GetNumber(KeyStore.X, 0)),
             () => {
-                let views = this.props.Document.GetList<Document>(this.props.fieldKey, []);
+                let views = this.props.Document.GetList(this.props.fieldKey, [] as Document[]);
                 for (let i = 0; i < views.length; i++) {
                     for (let j = 0; j < views.length; j++) {
                         let srcDoc = views[j];
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
index 751ea8190..cf0a6de00 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx
@@ -12,7 +12,7 @@ export class CollectionFreeFormRemoteCursors extends React.Component<CollectionV
     protected getCursors(): CursorEntry[] {
         let doc = this.props.Document;
         let id = CurrentUserUtils.id;
-        let cursors = doc.GetList<CursorEntry>(KeyStore.Cursors, []);
+        let cursors = doc.GetList(KeyStore.Cursors, [] as CursorEntry[]);
         let notMe = cursors.filter(entry => entry.Data[0][0] !== id);
         return id ? notMe : [];
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3ae64d2c6..97708ce19 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -218,7 +218,7 @@ export class CollectionFreeFormView extends CollectionSubView {
 
     @action
     bringToFront(doc: Document) {
-        this.props.Document.GetList<Document>(this.props.fieldKey, []).slice().sort((doc1, doc2) => {
+        this.props.Document.GetList(this.props.fieldKey, [] as Document[]).slice().sort((doc1, doc2) => {
             if (doc1 === doc) return 1;
             if (doc2 === doc) return -1;
             return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0);
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 96d59c831..65f461b27 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -147,7 +147,6 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 d.SetNumber(KeyStore.X, d.GetNumber(KeyStore.X, 0) - bounds.left - bounds.width / 2);
                 d.SetNumber(KeyStore.Y, d.GetNumber(KeyStore.Y, 0) - bounds.top - bounds.height / 2);
                 d.SetNumber(KeyStore.Page, -1);
-                d.SetText(KeyStore.Title, "" + d.Width() + " " + d.Height());
                 return d;
             });
             let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 6383ac3f6..690ee50e8 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -1,6 +1,6 @@
 @import "../globalCssVariables";
 
-.documentView-node, .documentView-node-topMost {
+.documentView-node, .documentView-node-topmost {
   position: inherit;
   top: 0;
   left:0;
@@ -29,7 +29,7 @@
     height: calc(100% - 20px);
   }
 }
-.documentView-node-topMost {
+.documentView-node-topmost {
     background: white;
 }
 
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index ac54321d5..fe0b07bc0 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -1,24 +1,20 @@
 
-import { action, observable, trace } from 'mobx';
+import { action, observable } from 'mobx';
 import { observer } from "mobx-react";
 import Lightbox from 'react-image-lightbox';
 import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
+import { Document } from '../../../fields/Document';
 import { FieldWaiting } from '../../../fields/Field';
 import { ImageField } from '../../../fields/ImageField';
 import { KeyStore } from '../../../fields/KeyStore';
+import { ListField } from '../../../fields/ListField';
+import { Utils } from '../../../Utils';
+import { DragManager } from '../../util/DragManager';
+import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from "../../views/ContextMenu";
 import { FieldView, FieldViewProps } from './FieldView';
 import "./ImageBox.scss";
 import React = require("react");
-import { Utils } from '../../../Utils';
-import { ListField } from '../../../fields/ListField';
-import { DragManager } from '../../util/DragManager';
-import { undoBatch, UndoManager } from '../../util/UndoManager';
-import { TextField } from '../../../fields/TextField';
-import { Document } from '../../../fields/Document';
-import { RouteStore } from '../../../server/RouteStore';
-import { ServerUtils } from '../../../server/ServerUtil';
-import { CollectionSubView } from '../collections/CollectionSubView';
 
 @observer
 export class ImageBox extends React.Component<FieldViewProps> {
@@ -36,10 +32,6 @@ export class ImageBox extends React.Component<FieldViewProps> {
         super(props);
 
         this._imgRef = React.createRef();
-        this.state = {
-            photoIndex: 0,
-            isOpen: false,
-        };
     }
 
     @action
@@ -49,8 +41,6 @@ export class ImageBox extends React.Component<FieldViewProps> {
         if (this._photoIndex == 0) this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w);
     }
 
-    componentDidMount() {
-    }
 
     protected createDropTarget = (ele: HTMLDivElement) => {
         if (this.dropDisposer) {
@@ -60,10 +50,6 @@ export class ImageBox extends React.Component<FieldViewProps> {
             this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
         }
     }
-
-    componentWillUnmount() {
-    }
-
     onDrop = (e: React.DragEvent) => {
         e.stopPropagation();
         e.preventDefault();
@@ -158,8 +144,8 @@ export class ImageBox extends React.Component<FieldViewProps> {
         let dist = Math.min(nativeWidth / paths.length, 40);
         let left = (nativeWidth - paths.length * dist) / 2;
         return paths.map((p, i) =>
-            <div className="imageBox-placer"  >
-                <div className="imageBox-dot" style={{ transform: `translate(${i * dist + left}px, 0px)` }} key={`i`} onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); this.onDotDown(i); }} />
+            <div className="imageBox-placer" key={i} >
+                <div className="imageBox-dot" style={{ background: (i == this._photoIndex ? "black" : "gray"), transform: `translate(${i * dist + left}px, 0px)` }} onPointerDown={(e: React.PointerEvent) => { e.stopPropagation(); this.onDotDown(i); }} />
             </div>
         )
     }
@@ -174,7 +160,7 @@ export class ImageBox extends React.Component<FieldViewProps> {
         return (
             <div className="imageBox-cont" onPointerDown={this.onPointerDown} onDrop={this.onDrop} ref={this.createDropTarget} onContextMenu={this.specificContextMenu}>
                 <img src={paths[Math.min(paths.length, this._photoIndex)]} style={{ objectFit: (this._photoIndex == 0 ? undefined : "contain") }} width={nativeWidth} alt="Image not found" ref={this._imgRef} onLoad={this.onLoad} />
-                {this.dots(paths)}
+                {paths.length > 1 ? this.dots(paths) : (null)}
                 {this.lightbox(paths)}
             </div>);
     }
-- 
cgit v1.2.3-70-g09d2

