From 75d9e15ab363c196d16a60602ac7f6b0b8bcf6a1 Mon Sep 17 00:00:00 2001
From: Hannah Chow <hannah_chow@brown.edu>
Date: Thu, 28 Feb 2019 22:59:10 -0500
Subject: styling fixed

---
 src/client/views/collections/CollectionFreeFormView.tsx | 3 +++
 1 file changed, 3 insertions(+)

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

diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 63255dd90..75f019fd5 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -52,6 +52,9 @@ export class CollectionFreeFormView extends CollectionViewBase {
     @undoBatch
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
+        if (!("documentView" in de.data)) {
+            return;
+        }
         super.drop(e, de);
         const docView: DocumentView = de.data["documentView"];
         let doc: Document = docView ? docView.props.Document : de.data["document"];
-- 
cgit v1.2.3-70-g09d2


From d9b2e678dafbcd4c2717ff484da48607e78d37fa Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 11 Mar 2019 11:51:07 -0400
Subject: selection marquee without selection

---
 .../views/collections/CollectionFreeFormView.scss  |  7 +++
 .../views/collections/CollectionFreeFormView.tsx   | 68 ++++++++++++++++++----
 2 files changed, 65 insertions(+), 10 deletions(-)

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

diff --git a/src/client/views/collections/CollectionFreeFormView.scss b/src/client/views/collections/CollectionFreeFormView.scss
index b059163ed..d487cd7ce 100644
--- a/src/client/views/collections/CollectionFreeFormView.scss
+++ b/src/client/views/collections/CollectionFreeFormView.scss
@@ -22,6 +22,13 @@
         height: 100%;
     }
 }
+.collectionfreeformview-marquee{
+    border-style: dashed;
+    box-sizing: border-box;
+    position: absolute;
+    border-width: 1px;
+    border-color: black;
+}
 .collectionfreeformview-overlay {
 
     .collectionfreeformview > .jsx-parser{
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 16002ad9f..bc6d02757 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -25,13 +25,16 @@ import "./CollectionFreeFormView.scss";
 import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
 import { CollectionViewBase } from "./CollectionViewBase";
 import React = require("react");
-import { render } from "pug";
+import { Utils } from "../../../Utils";
+import { SelectionManager } from "../../util/SelectionManager";
 const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
 
 @observer
 export class CollectionFreeFormView extends CollectionViewBase {
     private _canvasRef = React.createRef<HTMLDivElement>();
+    @observable
     private _lastX: number = 0;
+    @observable
     private _lastY: number = 0;
     private _selectOnLoaded: string = ""; // id of document that should be selected once it's loaded (used for click-to-type)
 
@@ -68,10 +71,13 @@ export class CollectionFreeFormView extends CollectionViewBase {
         this.bringToFront(doc);
     }
 
+    @observable
+    _marquee = false;
+
     @action
     onPointerDown = (e: React.PointerEvent): void => {
-        if (((e.button === 2 && this.props.active()) ||
-            !e.defaultPrevented) && (!this.isAnnotationOverlay || this.zoomScaling != 1 || e.button == 0)) {
+        if (((e.button === 2 && this.props.active()) || !e.defaultPrevented) &&
+            (!this.isAnnotationOverlay || this.zoomScaling != 1 || e.button == 0)) {
             document.removeEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointermove", this.onPointerMove);
             document.removeEventListener("pointerup", this.onPointerUp);
@@ -80,6 +86,11 @@ export class CollectionFreeFormView extends CollectionViewBase {
             this._lastY = e.pageY;
             this._downX = e.pageX;
             this._downY = e.pageY;
+            this._marquee = e.shiftKey;
+            if (this._marquee) {
+                e.stopPropagation();
+                e.preventDefault();
+            }
         }
     }
 
@@ -88,7 +99,12 @@ export class CollectionFreeFormView extends CollectionViewBase {
         document.removeEventListener("pointermove", this.onPointerMove);
         document.removeEventListener("pointerup", this.onPointerUp);
         e.stopPropagation();
-        if (Math.abs(this._downX - e.clientX) < 3 && Math.abs(this._downY - e.clientY) < 3) {
+
+        if (this._marquee) {
+            this.marqueeSelect();
+            this._marquee = false;
+        }
+        else if (!this._marquee && Math.abs(this._downX - e.clientX) < 3 && Math.abs(this._downY - e.clientY) < 3) {
             //show preview text cursor on tap
             this._previewCursorVisible = true;
             //select is not already selected
@@ -99,16 +115,43 @@ export class CollectionFreeFormView extends CollectionViewBase {
 
     }
 
+    @action
+    marqueeSelect() {
+        var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1);
+        let p = this.getTransform().transformPoint(this._downX, this._downY);
+        let v = this.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
+
+        var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1);
+        const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField);
+        if (lvalue && lvalue != FieldWaiting) {
+            lvalue.Data.map(doc => {
+                var page = doc.GetNumber(KeyStore.Page, 0);
+                if (page == curPage || page == 0) {
+                    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);
+                    if (x > p[0] && x < p[0] + v[0] && y > p[1] && y < p[1] + v[1]) {
+                        // SelectionManager.SelectDoc(doc as any as DocumentView, true);
+                    }
+                }
+            })
+        }
+    }
+
     @action
     onPointerMove = (e: PointerEvent): void => {
         if (!e.cancelBubble && this.props.active()) {
             e.stopPropagation();
             e.preventDefault();
-            let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
-            let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
-            let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
-            this._previewCursorVisible = false;
-            this.SetPan(x - dx, y - dy);
+
+            if (!this._marquee) {
+                let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
+                let y = this.props.Document.GetNumber(KeyStore.PanY, 0);
+                let [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY);
+                this._previewCursorVisible = false;
+                this.SetPan(x - dx, y - dy);
+            }
         }
         this._lastX = e.pageX;
         this._lastY = e.pageY;
@@ -291,6 +334,10 @@ export class CollectionFreeFormView extends CollectionViewBase {
             cursor = <div id="prevCursor" onKeyPress={this.onKeyDown} style={{ color: "black", position: "absolute", transformOrigin: "left top", transform: `translate(${x}px, ${y}px)` }}>I</div>
         }
 
+        let p = this.getTransform().transformPoint(this._downX, this._downY);
+        let v = this.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
+        var marquee = this._marquee ? <div className="collectionfreeformview-marquee" style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, width: `${v[0]}`, height: `${v[1]}` }}></div> : (null);
+
         let [dx, dy] = [this.centeringShiftX, this.centeringShiftY];
 
         const panx: number = -this.props.Document.GetNumber(KeyStore.PanX, 0);
@@ -313,7 +360,8 @@ export class CollectionFreeFormView extends CollectionViewBase {
                     {this.backgroundView}
                     <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} />
                     {cursor}
-                    {this.views}
+                    {React.Children.map(this.views, (child) => child)}
+                    {marquee}
                 </div>
                 {this.overlayView}
             </div>
-- 
cgit v1.2.3-70-g09d2


From 933cfacdeed99da38070790c5ec17cbdeb755267 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 11 Mar 2019 12:54:32 -0400
Subject: added marquee selection.

---
 .../views/collections/CollectionFreeFormView.tsx   | 16 +++++++++++---
 src/client/views/collections/CollectionPDFView.tsx |  2 ++
 src/client/views/collections/CollectionView.tsx    |  7 ++++--
 src/client/views/nodes/DocumentView.tsx            | 25 +++++++++++++++++++---
 4 files changed, 42 insertions(+), 8 deletions(-)

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

diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index bc6d02757..37b3d6adb 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -27,6 +27,7 @@ import { CollectionViewBase } from "./CollectionViewBase";
 import React = require("react");
 import { Utils } from "../../../Utils";
 import { SelectionManager } from "../../util/SelectionManager";
+import anymatch = require("anymatch");
 const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
 
 @observer
@@ -115,12 +116,22 @@ export class CollectionFreeFormView extends CollectionViewBase {
 
     }
 
+    intersectRect(r1: { left: number, right: number, top: number, bottom: number },
+        r2: { left: number, right: number, top: number, bottom: number }) {
+        return !(r2.left > r1.right ||
+            r2.right < r1.left ||
+            r2.top > r1.bottom ||
+            r2.bottom < r1.top);
+    }
+
     @action
     marqueeSelect() {
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1);
         let p = this.getTransform().transformPoint(this._downX, this._downY);
         let v = this.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
+        let selRect = { left: p[0], top: p[1], right: p[0] + v[0], bottom: p[1] + v[1] }
 
+        this.props.CollectionView.SelectedDocs.length = 0;
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1);
         const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField);
         if (lvalue && lvalue != FieldWaiting) {
@@ -131,9 +142,8 @@ export class CollectionFreeFormView extends CollectionViewBase {
                     var y = doc.GetNumber(KeyStore.Y, 0);
                     var w = doc.GetNumber(KeyStore.Width, 0);
                     var h = doc.GetNumber(KeyStore.Height, 0);
-                    if (x > p[0] && x < p[0] + v[0] && y > p[1] && y < p[1] + v[1]) {
-                        // SelectionManager.SelectDoc(doc as any as DocumentView, true);
-                    }
+                    if (this.intersectRect({ left: x, top: y, right: x + w, bottom: y + h }, selRect))
+                        this.props.CollectionView.SelectedDocs.push(doc.Id)
                 }
             })
         }
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 7fd9f0f11..f22c07060 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -6,6 +6,7 @@ import { ContextMenu } from "../ContextMenu";
 import { CollectionView, CollectionViewType } from "./CollectionView";
 import { CollectionViewProps } from "./CollectionViewBase";
 import React = require("react");
+import { FieldId } from "../../../fields/Field";
 
 
 @observer
@@ -17,6 +18,7 @@ export class CollectionPDFView extends React.Component<CollectionViewProps> {
                     isTopMost={isTopMost} SelectOnLoad={selectOnLoad} BackgroundView={BackgroundView} focus={focus}/>`;
     }
 
+    public SelectedDocs: FieldId[] = []
     @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : 0;
     @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : 0;
 
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index f154909bb..548a51bf1 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -1,4 +1,4 @@
-import { action, computed } from "mobx";
+import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
 import { Document } from "../../../fields/Document";
 import { ListField } from "../../../fields/ListField";
@@ -12,7 +12,7 @@ import { CollectionDockingView } from "./CollectionDockingView";
 import { CollectionSchemaView } from "./CollectionSchemaView";
 import { CollectionViewProps } from "./CollectionViewBase";
 import { CollectionTreeView } from "./CollectionTreeView";
-import { Field } from "../../../fields/Field";
+import { Field, FieldId } from "../../../fields/Field";
 
 export enum CollectionViewType {
     Invalid,
@@ -27,6 +27,9 @@ export const COLLECTION_BORDER_WIDTH = 2;
 @observer
 export class CollectionView extends React.Component<CollectionViewProps> {
 
+    @observable
+    public SelectedDocs: FieldId[] = [];
+
     public static LayoutString(fieldKey: string = "DataKey") {
         return `<${CollectionView.name} Document={Document}
                     ScreenToLocalTransform={ScreenToLocalTransform} fieldKey={${fieldKey}} panelWidth={PanelWidth} panelHeight={PanelHeight} isSelected={isSelected} select={select} bindings={bindings}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 263bb31d7..7627fbf6c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,4 +1,4 @@
-import { action, computed } from "mobx";
+import { action, computed, IReactionDisposer, reaction } from "mobx";
 import { observer } from "mobx-react";
 import { Document } from "../../../fields/Document";
 import { Field, FieldWaiting, Opt } from "../../../fields/Field";
@@ -16,8 +16,8 @@ import { CollectionPDFView } from "../collections/CollectionPDFView";
 import { ContextMenu } from "../ContextMenu";
 import { FormattedTextBox } from "../nodes/FormattedTextBox";
 import { ImageBox } from "../nodes/ImageBox";
-import { VideoBox } from "../nodes/VideoBox"; 
-import { AudioBox } from "../nodes/AudioBox"; 
+import { VideoBox } from "../nodes/VideoBox";
+import { AudioBox } from "../nodes/AudioBox";
 import { Documents } from "../../documents/Documents"
 import { KeyValueBox } from "./KeyValueBox"
 import { WebBox } from "../nodes/WebBox";
@@ -88,6 +88,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     private _documentBindings: any = null;
     private _downX: number = 0;
     private _downY: number = 0;
+    private _reactionDisposer: Opt<IReactionDisposer>;
     @computed get active(): boolean { return SelectionManager.IsSelected(this) || !this.props.ContainingCollectionView || this.props.ContainingCollectionView.active(); }
     @computed get topMost(): boolean { return !this.props.ContainingCollectionView || this.props.ContainingCollectionView.collectionViewType == CollectionViewType.Docking; }
     @computed get layout(): string { return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); }
@@ -113,6 +114,24 @@ export class DocumentView extends React.Component<DocumentViewProps> {
             }
         }
     }
+
+
+    componentDidMount() {
+        this._reactionDisposer = reaction(
+            () => this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.slice(),
+            () => {
+                if (this.props.ContainingCollectionView && this.props.ContainingCollectionView.SelectedDocs.indexOf(this.props.Document.Id) != -1)
+                    SelectionManager.SelectDoc(this, true);
+            });
+    }
+
+    componentWillUnmount() {
+        if (this._reactionDisposer) {
+            this._reactionDisposer();
+        }
+    }
+
+
     onPointerMove = (e: PointerEvent): void => {
         if (e.cancelBubble) {
             return;
-- 
cgit v1.2.3-70-g09d2


From 501a74c77bda9256f449c7009194a6964819841a Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 11 Mar 2019 13:38:34 -0400
Subject: cleanup

---
 src/client/views/collections/CollectionFreeFormView.tsx | 9 +++------
 src/client/views/collections/CollectionViewBase.tsx     | 1 -
 2 files changed, 3 insertions(+), 7 deletions(-)

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

diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 37b3d6adb..07f022382 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -1,4 +1,4 @@
-import { action, computed, observable, reaction, trace } from "mobx";
+import { action, computed, observable } from "mobx";
 import { observer } from "mobx-react";
 import { Document } from "../../../fields/Document";
 import { FieldWaiting } from "../../../fields/Field";
@@ -10,9 +10,9 @@ import { DragManager } from "../../util/DragManager";
 import { Transform } from "../../util/Transform";
 import { undoBatch } from "../../util/UndoManager";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
+import { CollectionPDFView } from "../collections/CollectionPDFView";
 import { CollectionSchemaView } from "../collections/CollectionSchemaView";
 import { CollectionView } from "../collections/CollectionView";
-import { CollectionPDFView } from "../collections/CollectionPDFView";
 import { InkingCanvas } from "../InkingCanvas";
 import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
 import { DocumentView } from "../nodes/DocumentView";
@@ -25,9 +25,6 @@ import "./CollectionFreeFormView.scss";
 import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
 import { CollectionViewBase } from "./CollectionViewBase";
 import React = require("react");
-import { Utils } from "../../../Utils";
-import { SelectionManager } from "../../util/SelectionManager";
-import anymatch = require("anymatch");
 const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
 
 @observer
@@ -370,7 +367,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
                     {this.backgroundView}
                     <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} />
                     {cursor}
-                    {React.Children.map(this.views, (child) => child)}
+                    {this.views}
                     {marquee}
                 </div>
                 {this.overlayView}
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index 38271e7bf..59fa61800 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -11,7 +11,6 @@ import { Documents, DocumentOptions } from "../../documents/Documents";
 import { Key } from "../../../fields/Key";
 import { Transform } from "../../util/Transform";
 import { CollectionView } from "./CollectionView";
-import * as request from "request";
 
 export interface CollectionViewProps {
     fieldKey: Key;
-- 
cgit v1.2.3-70-g09d2


From 3c65e18a455eda378e24162ae4aaf5e37e6d107d Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 11 Mar 2019 13:43:56 -0400
Subject: fixed drag drop of documents

---
 src/client/views/collections/CollectionFreeFormView.tsx | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

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

diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index e12d3d15c..6733d5116 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -57,18 +57,17 @@ export class CollectionFreeFormView extends CollectionViewBase {
     @undoBatch
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
-        if (!("documentView" in de.data)) {
-            return;
-        }
         super.drop(e, de);
         const docView: DocumentView = de.data["documentView"];
         let doc: Document = docView ? docView.props.Document : de.data["document"];
-        let screenX = de.x - (de.data["xOffset"] as number || 0);
-        let screenY = de.y - (de.data["yOffset"] as number || 0);
-        const [x, y] = this.getTransform().transformPoint(screenX, screenY);
-        doc.SetNumber(KeyStore.X, x);
-        doc.SetNumber(KeyStore.Y, y);
-        this.bringToFront(doc);
+        if (doc) {
+            let screenX = de.x - (de.data["xOffset"] as number || 0);
+            let screenY = de.y - (de.data["yOffset"] as number || 0);
+            const [x, y] = this.getTransform().transformPoint(screenX, screenY);
+            doc.SetNumber(KeyStore.X, x);
+            doc.SetNumber(KeyStore.Y, y);
+            this.bringToFront(doc);
+        }
     }
 
     @action
-- 
cgit v1.2.3-70-g09d2


From e0d33c6092e5fb62343ef38d8734fa342e6dff84 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 11 Mar 2019 13:57:54 -0400
Subject: fixed marquee modifiers.

---
 src/client/views/collections/CollectionDockingView.tsx  | 15 +++++----------
 src/client/views/collections/CollectionFreeFormView.tsx | 16 +++++++---------
 src/client/views/nodes/DocumentView.tsx                 |  3 ---
 3 files changed, 12 insertions(+), 22 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index f01c538e6..70549099e 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -174,17 +174,12 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
     }
     @action
     onPointerDown = (e: React.PointerEvent): void => {
-        if (e.button === 2 && this.props.active()) {
+        var className = (e.target as any).className;
+        if (className == "lm_drag_handle" || className == "lm_close" || className == "lm_maximise" || className == "lm_minimise" || className == "lm_close_tab") {
+            this._flush = true;
+        }
+        if (this.props.active()) {
             e.stopPropagation();
-            e.preventDefault();
-        } else {
-            var className = (e.target as any).className;
-            if (className == "lm_drag_handle" || className == "lm_close" || className == "lm_maximise" || className == "lm_minimise" || className == "lm_close_tab") {
-                this._flush = true;
-            }
-            if (e.buttons === 1 && this.props.active()) {
-                e.stopPropagation();
-            }
         }
     }
 
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 24c47a558..1d1a748e4 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -61,14 +61,12 @@ export class CollectionFreeFormView extends CollectionViewBase {
         super.drop(e, de);
         const docView: DocumentView = de.data["documentView"];
         let doc: Document = docView ? docView.props.Document : de.data["document"];
-        if (doc) {
-            let screenX = de.x - (de.data["xOffset"] as number || 0);
-            let screenY = de.y - (de.data["yOffset"] as number || 0);
-            const [x, y] = this.getTransform().transformPoint(screenX, screenY);
-            doc.SetNumber(KeyStore.X, x);
-            doc.SetNumber(KeyStore.Y, y);
-            this.bringToFront(doc);
-        }
+        let screenX = de.x - (de.data["xOffset"] as number || 0);
+        let screenY = de.y - (de.data["yOffset"] as number || 0);
+        const [x, y] = this.getTransform().transformPoint(screenX, screenY);
+        doc.SetNumber(KeyStore.X, x);
+        doc.SetNumber(KeyStore.Y, y);
+        this.bringToFront(doc);
     }
 
     @observable
@@ -86,7 +84,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
             this._lastY = e.pageY;
             this._downX = e.pageX;
             this._downY = e.pageY;
-            this._marquee = e.shiftKey;
+            this._marquee = e.button != 2 && e.shiftKey;
             if (this._marquee) {
                 e.stopPropagation();
                 e.preventDefault();
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 915e78e82..ee19c2b80 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -106,9 +106,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         } else {
             if (this.active && !e.isDefaultPrevented()) {
                 e.stopPropagation();
-                if (e.buttons === 2) {
-                    e.preventDefault();
-                }
                 document.removeEventListener("pointermove", this.onPointerMove)
                 document.addEventListener("pointermove", this.onPointerMove);
                 document.removeEventListener("pointerup", this.onPointerUp)
-- 
cgit v1.2.3-70-g09d2


From 6e66622439eff11e69c8fa71c477ce0f8f5cc104 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 11 Mar 2019 15:27:20 -0400
Subject: cleaned up drag/drop interactions to be more consistent and complete.

---
 .../views/collections/CollectionDockingView.tsx    |  2 +-
 .../views/collections/CollectionFreeFormView.tsx   | 18 +++++-----
 .../views/collections/CollectionViewBase.tsx       |  2 +-
 src/client/views/nodes/DocumentView.tsx            | 38 +++++++++++++---------
 4 files changed, 34 insertions(+), 26 deletions(-)

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

diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 70549099e..6a0404663 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -44,7 +44,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
         (window as any).ReactDOM = ReactDOM;
     }
     public StartOtherDrag(dragDoc: Document, e: any) {
-        this.AddRightSplit(dragDoc, true).contentItems[0].tab._dragListener.onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: e.button })
+        this.AddRightSplit(dragDoc, true).contentItems[0].tab._dragListener.onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: () => { }, button: 0 })
     }
 
     @action
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 1d1a748e4..ab6b9d533 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -25,6 +25,7 @@ import "./CollectionFreeFormView.scss";
 import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
 import { CollectionViewBase } from "./CollectionViewBase";
 import React = require("react");
+import { SelectionManager } from "../../util/SelectionManager";
 const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
 
 @observer
@@ -74,7 +75,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
-        if (((e.button === 2 && this.props.active()) || !e.defaultPrevented) &&
+        if (((e.button === 2 && this.props.active()) || !e.defaultPrevented) && !e.shiftKey &&
             (!this.isAnnotationOverlay || this.zoomScaling != 1 || e.button == 0)) {
             document.removeEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointermove", this.onPointerMove);
@@ -84,11 +85,6 @@ export class CollectionFreeFormView extends CollectionViewBase {
             this._lastY = e.pageY;
             this._downX = e.pageX;
             this._downY = e.pageY;
-            this._marquee = e.button != 2 && e.shiftKey;
-            if (this._marquee) {
-                e.stopPropagation();
-                e.preventDefault();
-            }
         }
     }
 
@@ -99,6 +95,9 @@ export class CollectionFreeFormView extends CollectionViewBase {
         e.stopPropagation();
 
         if (this._marquee) {
+            if (!e.shiftKey) {
+                SelectionManager.DeselectAll();
+            }
             this.marqueeSelect();
             this._marquee = false;
         }
@@ -123,12 +122,12 @@ export class CollectionFreeFormView extends CollectionViewBase {
 
     @action
     marqueeSelect() {
+        this.props.CollectionView.SelectedDocs.length = 0;
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1);
         let p = this.getTransform().transformPoint(this._downX, this._downY);
         let v = this.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
         let selRect = { left: p[0], top: p[1], right: p[0] + v[0], bottom: p[1] + v[1] }
 
-        this.props.CollectionView.SelectedDocs.length = 0;
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1);
         const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField);
         if (lvalue && lvalue != FieldWaiting) {
@@ -151,6 +150,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
         if (!e.cancelBubble && this.props.active()) {
             e.stopPropagation();
             e.preventDefault();
+            this._marquee = e.buttons != 2;
 
             if (!this._marquee) {
                 let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
@@ -341,9 +341,9 @@ export class CollectionFreeFormView extends CollectionViewBase {
             cursor = <div id="prevCursor" onKeyPress={this.onKeyDown} style={{ color: "black", position: "absolute", transformOrigin: "left top", transform: `translate(${x}px, ${y}px)` }}>I</div>
         }
 
-        let p = this.getTransform().transformPoint(this._downX, this._downY);
+        let p = this.getTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY);
         let v = this.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
-        var marquee = this._marquee ? <div className="collectionfreeformview-marquee" style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, width: `${v[0]}`, height: `${v[1]}` }}></div> : (null);
+        var marquee = this._marquee ? <div className="collectionfreeformview-marquee" style={{ transform: `translate(${p[0]}px, ${p[1]}px)`, width: `${Math.abs(v[0])}`, height: `${Math.abs(v[1])}` }}></div> : (null);
 
         let [dx, dy] = [this.centeringShiftX, this.centeringShiftY];
 
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index 59fa61800..b126b40a9 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -47,7 +47,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
     protected drop(e: Event, de: DragManager.DropEvent) {
         const docView: DocumentView = de.data["documentView"];
         const doc: Document = de.data["document"];
-        if (docView && docView.props.ContainingCollectionView && docView.props.ContainingCollectionView !== this.props.CollectionView) {
+        if (docView && (!docView.props.ContainingCollectionView || docView.props.ContainingCollectionView !== this.props.CollectionView)) {
             if (docView.props.RemoveDocument) {
                 docView.props.RemoveDocument(docView.props.Document);
             }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index ee19c2b80..dc793c16d 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -100,8 +100,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     onPointerDown = (e: React.PointerEvent): void => {
         this._downX = e.clientX;
         this._downY = e.clientY;
-        if (e.shiftKey && e.buttons === 1) {
-            CollectionDockingView.Instance.StartOtherDrag(this.props.Document, e);
+        if (e.shiftKey && e.buttons === 2) {
+            if (this.props.isTopMost) {
+                this.startDragging(e.pageX, e.pageY);
+            }
+            else CollectionDockingView.Instance.StartOtherDrag(this.props.Document, e);
             e.stopPropagation();
         } else {
             if (this.active && !e.isDefaultPrevented()) {
@@ -156,6 +159,21 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         }
     }
 
+    startDragging(x: number, y: number) {
+        if (this._mainCont.current) {
+            const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+            let dragData: { [id: string]: any } = {};
+            dragData["documentView"] = this;
+            dragData["xOffset"] = x - left;
+            dragData["yOffset"] = y - top;
+            DragManager.StartDrag(this._mainCont.current, dragData, {
+                handlers: {
+                    dragComplete: action(() => { }),
+                },
+                hideSource: true
+            })
+        }
+    }
 
     onPointerMove = (e: PointerEvent): void => {
         if (e.cancelBubble) {
@@ -163,19 +181,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         }
         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._mainCont.current != null && !this.topMost) {
-                const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
-                let dragData: { [id: string]: any } = {};
-                dragData["documentView"] = this;
-                dragData["xOffset"] = e.x - left;
-                dragData["yOffset"] = e.y - top;
-                DragManager.StartDrag(this._mainCont.current, dragData, {
-                    handlers: {
-                        dragComplete: action(() => { }),
-                    },
-                    hideSource: true
-                })
+            document.removeEventListener("pointerup", this.onPointerUp);
+            if (!this.topMost || e.buttons == 2) {
+                this.startDragging(e.x, e.y);
             }
         }
         e.stopPropagation();
-- 
cgit v1.2.3-70-g09d2


From faf0cc17a47aacaef48b4fe18c2f52af0a360805 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 11 Mar 2019 15:47:15 -0400
Subject: cleaned up linkmenu.

---
 .../views/collections/CollectionFreeFormView.tsx   | 14 +++---
 src/client/views/nodes/LinkBox.tsx                 |  5 +-
 src/client/views/nodes/LinkMenu.scss               |  6 +--
 src/client/views/nodes/LinkMenu.tsx                | 58 ++++++++--------------
 4 files changed, 37 insertions(+), 46 deletions(-)

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

diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index ab6b9d533..cd5f92623 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -62,12 +62,14 @@ export class CollectionFreeFormView extends CollectionViewBase {
         super.drop(e, de);
         const docView: DocumentView = de.data["documentView"];
         let doc: Document = docView ? docView.props.Document : de.data["document"];
-        let screenX = de.x - (de.data["xOffset"] as number || 0);
-        let screenY = de.y - (de.data["yOffset"] as number || 0);
-        const [x, y] = this.getTransform().transformPoint(screenX, screenY);
-        doc.SetNumber(KeyStore.X, x);
-        doc.SetNumber(KeyStore.Y, y);
-        this.bringToFront(doc);
+        if (doc) {
+            let screenX = de.x - (de.data["xOffset"] as number || 0);
+            let screenY = de.y - (de.data["yOffset"] as number || 0);
+            const [x, y] = this.getTransform().transformPoint(screenX, screenY);
+            doc.SetNumber(KeyStore.X, x);
+            doc.SetNumber(KeyStore.Y, y);
+            this.bringToFront(doc);
+        }
     }
 
     @observable
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index c7911f554..69df676ff 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -10,6 +10,7 @@ import { Document } from "../../../fields/Document";
 import { ListField } from "../../../fields/ListField";
 import { DocumentManager } from "../../util/DocumentManager";
 import { LinkEditor } from "./LinkEditor";
+import { CollectionDockingView } from "../collections/CollectionDockingView";
 
 interface Props {
     linkDoc: Document;
@@ -28,6 +29,8 @@ export class LinkBox extends React.Component<Props> {
         let docView = DocumentManager.Instance.getDocumentView(this.props.pairedDoc);
         if (docView) {
             docView.props.focus(this.props.pairedDoc);
+        } else {
+            CollectionDockingView.Instance.AddRightSplit(this.props.pairedDoc)
         }
     }
 
@@ -66,7 +69,7 @@ export class LinkBox extends React.Component<Props> {
         return (
             //<LinkEditor linkBox={this} linkDoc={this.props.linkDoc} />
             <div className="link-container">
-                <div className="info-container">
+                <div className="info-container" onPointerDown={this.onViewButtonPressed}>
                     <div className="link-name">
                         <p>{this.props.linkName}</p>
                     </div>
diff --git a/src/client/views/nodes/LinkMenu.scss b/src/client/views/nodes/LinkMenu.scss
index af5b84ec6..a120ab2a7 100644
--- a/src/client/views/nodes/LinkMenu.scss
+++ b/src/client/views/nodes/LinkMenu.scss
@@ -1,18 +1,18 @@
-#menu-container {
+#linkMenu-container {
     width: 100%;
     height: auto;
     display: flex;
     flex-direction: column;
 }
 
-#search-bar {
+#linkMenu-searchBar {
     width: 100%;
     padding: 5px;
     margin-bottom: 10px;
     font-size: 12px;
 }
 
-#link-list {
+#linkMenu-list {
     margin-top: 5px;
     width: 100%;
     height: 100px;
diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx
index 9a95a4f09..5c6b06d00 100644
--- a/src/client/views/nodes/LinkMenu.tsx
+++ b/src/client/views/nodes/LinkMenu.tsx
@@ -1,17 +1,15 @@
-import { observable, computed, action } from "mobx";
-import React = require("react");
-import { SelectionManager } from "../../util/SelectionManager";
+import { action, observable } from "mobx";
 import { observer } from "mobx-react";
-import './LinkMenu.scss'
-import { KeyStore } from '../../../fields/KeyStore'
-import { props } from "bluebird";
-import { DocumentView } from "./DocumentView";
-import { LinkBox } from "./LinkBox"
 import { Document } from "../../../fields/Document";
-import { ListField } from "../../../fields/ListField";
-import { TextField } from "../../../fields/TextField";
 import { FieldWaiting } from "../../../fields/Field";
+import { Key } from "../../../fields/Key";
+import { KeyStore } from '../../../fields/KeyStore';
+import { ListField } from "../../../fields/ListField";
+import { DocumentView } from "./DocumentView";
+import { LinkBox } from "./LinkBox";
 import { LinkEditor } from "./LinkEditor";
+import './LinkMenu.scss';
+import React = require("react");
 
 interface Props {
     docView: DocumentView;
@@ -23,39 +21,27 @@ export class LinkMenu extends React.Component<Props> {
 
     @observable private _editingLink?: Document;
 
+    renderLinkItems(links: Document[], key: Key, type: string) {
+        return links.map(link => {
+            let doc = link.GetT(key, Document);
+            if (doc && doc != FieldWaiting) {
+                return <LinkBox key={doc.Id} linkDoc={link} linkName={link.Title} pairedDoc={doc} showEditor={action(() => this._editingLink = link)} type={type} />
+            }
+        })
+    }
+
     render() {
         //get list of links from document
         let linkFrom: Document[] = this.props.docView.props.Document.GetData(KeyStore.LinkedFromDocs, ListField, []);
         let linkTo: Document[] = this.props.docView.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []);
         if (this._editingLink === undefined) {
             return (
-
-                <div id="menu-container">
-                    <input id="search-bar" type="text" placeholder="Search..."></input>
-                    <div id="link-list">
-
-                        {linkTo.map(link => {
-                            let name = link.GetData(KeyStore.Title, TextField, new String);
-                            let doc = link.GetT(KeyStore.LinkedToDocs, Document);
-                            if (doc && doc != FieldWaiting) {
-                                return <LinkBox linkDoc={link} linkName={name} pairedDoc={doc} showEditor={action(() => this._editingLink = link)} type={"Destination: "} />
-                            } else {
-                                return <div></div>
-                            }
-
-                        })}
-
-                        {linkFrom.map(link => {
-                            let name = link.GetData(KeyStore.Title, TextField, new String);
-                            let doc = link.GetT(KeyStore.LinkedFromDocs, Document);
-                            if (doc && doc != FieldWaiting) {
-                                return <LinkBox linkDoc={link} linkName={name} pairedDoc={doc} showEditor={action(() => this._editingLink = link)} type={"Source: "} />
-                            } else {
-                                return <div></div>
-                            }
-                        })}
+                <div id="linkMenu-container">
+                    <input id="linkMenu-searchBar" type="text" placeholder="Search..."></input>
+                    <div id="linkMenu-list">
+                        {this.renderLinkItems(linkTo, KeyStore.LinkedToDocs, "Source: ")}
+                        {this.renderLinkItems(linkFrom, KeyStore.LinkedFromDocs, "Destination: ")}
                     </div>
-
                 </div>
             )
         } else {
-- 
cgit v1.2.3-70-g09d2


From 618e66a5a070f1aac9224bd3f44b76a5ac314bfa Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 11 Mar 2019 16:56:36 -0400
Subject: fixed dragging of link button.  made web views clips.  added delete
 on marquee.

---
 src/client/documents/Documents.ts                  | 14 ++---------
 src/client/util/DragManager.ts                     |  1 +
 src/client/views/DocumentDecorations.scss          | 28 +++++++++++++++-------
 src/client/views/DocumentDecorations.tsx           |  6 +++--
 .../views/collections/CollectionFreeFormView.tsx   | 21 +++++++++++++---
 src/client/views/nodes/WebBox.scss                 |  1 +
 6 files changed, 45 insertions(+), 26 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index b78762018..7b30dff98 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -152,20 +152,10 @@ export namespace Documents {
         return doc;
     }
     export function VideoDocument(url: string, options: DocumentOptions = {}) {
-        let doc = SetInstanceOptions(GetVideoPrototype(), { ...options, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] },
-            new URL(url), VideoField);
-        doc.SetText(KeyStore.Caption, "my caption...");
-        doc.SetText(KeyStore.BackgroundLayout, EmbeddedCaption());
-        doc.SetText(KeyStore.OverlayLayout, FixedCaption());
-        return doc;
+        return SetInstanceOptions(GetVideoPrototype(), options, new URL(url), VideoField);
     }
     export function AudioDocument(url: string, options: DocumentOptions = {}) {
-        let doc = SetInstanceOptions(GetAudioPrototype(), { ...options, layoutKeys: [KeyStore.Data, KeyStore.Annotations, KeyStore.Caption] },
-            new URL(url), AudioField);
-        doc.SetText(KeyStore.Caption, "my caption...");
-        doc.SetText(KeyStore.BackgroundLayout, EmbeddedCaption());
-        doc.SetText(KeyStore.OverlayLayout, FixedCaption());
-        return doc;
+        return SetInstanceOptions(GetAudioPrototype(), options, new URL(url), AudioField);
     }
     export function TextDocument(options: DocumentOptions = {}) {
         return SetInstanceOptions(GetTextPrototype(), options, "", RichTextField);
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 0dcaa9c77..4a61220a5 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -99,6 +99,7 @@ export namespace DragManager {
     export function StartDrag(ele: HTMLElement, dragData: { [id: string]: any }, options?: DragOptions) {
         if (!dragDiv) {
             dragDiv = document.createElement("div");
+            dragDiv.className = "dragManager-dragDiv"
             DragManager.Root().appendChild(dragDiv);
         }
         const w = ele.offsetWidth, h = ele.offsetHeight;
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index f88bf9c14..fb9091dfc 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -29,13 +29,23 @@
     #documentDecorations-rightResizer {
         cursor: ew-resize;
     }
-    #linkButton {
-        height: 20px;
-        width: 20px;
-        margin-top: 10px;
-        border-radius: 50%;
-        opacity: 0.6;
-        pointer-events: auto;
-        background-color: #2B6091;
-    }
+    
+}
+.linkButton-empty {
+    height: 20px;
+    width: 20px;
+    margin-top: 10px;
+    border-radius: 50%;
+    opacity: 0.6;
+    pointer-events: auto;
+    background-color: #2B6091;
+}
+.linkButton-nonempty {
+    height: 20px;
+    width: 20px;
+    margin-top: 10px;
+    border-radius: 50%;
+    opacity: 0.6;
+    pointer-events: auto;
+    background-color: rgb(35, 165, 42);
 }
\ No newline at end of file
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 8c3913232..dc62f97cf 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -8,6 +8,7 @@ import { NumberField } from "../../fields/NumberField";
 import { props } from "bluebird";
 import { DragManager } from "../util/DragManager";
 import { LinkMenu } from "./nodes/LinkMenu";
+import { ListField } from "../../fields/ListField";
 const higflyout = require("@hig/flyout");
 const { anchorPoints } = higflyout;
 const Flyout = higflyout.default;
@@ -204,13 +205,14 @@ export class DocumentDecorations extends React.Component {
 
         let linkButton = null;
         if (SelectionManager.SelectedDocuments().length > 0) {
+            let selFirst = SelectionManager.SelectedDocuments()[0];
             linkButton = (<Flyout
                 anchorPoint={anchorPoints.RIGHT_TOP}
                 content={
-                    <LinkMenu docView={SelectionManager.SelectedDocuments()[0]} changeFlyout={this.changeFlyoutContent}>
+                    <LinkMenu docView={selFirst} changeFlyout={this.changeFlyoutContent}>
                     </LinkMenu>
                 }>
-                <div id="linkButton" onPointerDown={this.onLinkButtonDown} ref={this._linkButton}></div>
+                <div className={"linkButton-" + (selFirst.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []).length ? "nonempty" : "empty")} onPointerDown={this.onLinkButtonDown} ref={this._linkButton} />
             </Flyout>);
         }
         return (
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index cd5f92623..b0cd7e017 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -100,7 +100,8 @@ export class CollectionFreeFormView extends CollectionViewBase {
             if (!e.shiftKey) {
                 SelectionManager.DeselectAll();
             }
-            this.marqueeSelect();
+            var selectedDocs = this.marqueeSelect();
+            selectedDocs.map(s => this.props.CollectionView.SelectedDocs.push(s.Id));
             this._marquee = false;
         }
         else if (!this._marquee && Math.abs(this._downX - e.clientX) < 3 && Math.abs(this._downY - e.clientY) < 3) {
@@ -122,7 +123,6 @@ export class CollectionFreeFormView extends CollectionViewBase {
             r2.bottom < r1.top);
     }
 
-    @action
     marqueeSelect() {
         this.props.CollectionView.SelectedDocs.length = 0;
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1);
@@ -132,6 +132,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
 
         var curPage = this.props.Document.GetNumber(KeyStore.CurPage, 1);
         const lvalue = this.props.Document.GetT<ListField<Document>>(this.props.fieldKey, ListField);
+        let selection: Document[] = [];
         if (lvalue && lvalue != FieldWaiting) {
             lvalue.Data.map(doc => {
                 var page = doc.GetNumber(KeyStore.Page, 0);
@@ -141,10 +142,11 @@ export class CollectionFreeFormView extends CollectionViewBase {
                     var w = doc.GetNumber(KeyStore.Width, 0);
                     var h = doc.GetNumber(KeyStore.Height, 0);
                     if (this.intersectRect({ left: x, top: y, right: x + w, bottom: y + h }, selRect))
-                        this.props.CollectionView.SelectedDocs.push(doc.Id)
+                        selection.push(doc)
                 }
             })
         }
+        return selection;
     }
 
     @action
@@ -152,7 +154,11 @@ export class CollectionFreeFormView extends CollectionViewBase {
         if (!e.cancelBubble && this.props.active()) {
             e.stopPropagation();
             e.preventDefault();
+            let wasMarquee = this._marquee;
             this._marquee = e.buttons != 2;
+            if (this._marquee && !wasMarquee) {
+                document.addEventListener("keydown", this.marqueeCommand);
+            }
 
             if (!this._marquee) {
                 let x = this.props.Document.GetNumber(KeyStore.PanX, 0);
@@ -166,6 +172,15 @@ export class CollectionFreeFormView extends CollectionViewBase {
         this._lastY = e.pageY;
     }
 
+    @action
+    marqueeCommand = (e: KeyboardEvent) => {
+        if (e.key == "Backspace") {
+            this.marqueeSelect().map(d => this.props.removeDocument(d));
+        }
+        if (e.key == "c") {
+        }
+    }
+
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
         e.stopPropagation();
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index e72b3c4da..a535b2638 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -4,6 +4,7 @@
     position: absolute;
     width: 100%;
     height: 100%;
+    overflow: scroll;
 }
 
 .webBox-button {
-- 
cgit v1.2.3-70-g09d2

