From c6a3faf616e68ede2d67580344e4337c3f0cfdc5 Mon Sep 17 00:00:00 2001
From: Jude <julie_wang1@brown.edu>
Date: Sat, 9 Mar 2019 17:14:42 -0500
Subject: added some flair to freeform views

---
 src/client/views/InkingControl.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/InkingControl.tsx')

diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 929fb42a1..fc6a266e4 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -49,7 +49,7 @@ export class InkingControl extends React.Component {
 
     selected = (tool: InkTool) => {
         if (this._selectedTool === tool) {
-            return { backgroundColor: "black", color: "white" }
+            return { backgroundColor: "#61aaa3", color: "white" }
         }
         return {}
     }
-- 
cgit v1.2.3-70-g09d2


From 06fb2bef46222c65d594b600bfeb72fb6a7f8212 Mon Sep 17 00:00:00 2001
From: Fawn <fangrui_tong@brown.edu>
Date: Sun, 10 Mar 2019 17:24:11 -0400
Subject: inking ui improvements

---
 src/client/views/InkingCanvas.scss | 121 +++++++++++++++++++++++++++++++++++--
 src/client/views/InkingControl.tsx |  59 ++++++++++++------
 src/client/views/Main.tsx          |   5 +-
 3 files changed, 158 insertions(+), 27 deletions(-)

(limited to 'src/client/views/InkingControl.tsx')

diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss
index f654b194b..71c7e9ce0 100644
--- a/src/client/views/InkingCanvas.scss
+++ b/src/client/views/InkingCanvas.scss
@@ -1,3 +1,4 @@
+@import "global_variables";
 .inking-canvas {
     position: fixed;
     top: -50000px;
@@ -13,20 +14,128 @@
 
 .inking-control {
     position: absolute;
-    right: 0;
-    bottom: 75px;
-    text-align: right;
+    left: 70px;
+    bottom: 70px;
+    margin: 0;
+    padding: 0;
+    display: flex;
+    label,
+    input,
+    option {
+        font-size: 12px;
+    }
+    input[type=range] {
+        -webkit-appearance: none;
+        background-color: transparent;
+        vertical-align: middle;
+        &:focus {
+            outline: none;
+        }
+        &::-webkit-slider-runnable-track {
+            width: 100%;
+            height: 3px;
+            border-radius: 1.5px;
+            cursor: pointer;
+            background: $light-color;
+        }
+        &::-webkit-slider-thumb {
+            height: 12px;
+            width: 12px;
+            border: 1px solid $intermediate-color;
+            border-radius: 6px;
+            background: $light-color;
+            cursor: pointer;
+            -webkit-appearance: none;
+            margin-top: -4px;
+        }
+        &::-moz-range-track {
+            width: 100%;
+            height: 3px;
+            border-radius: 1.5px;
+            cursor: pointer;
+            background: $light-color;
+        }
+        &::-moz-range-thumb {
+            height: 12px;
+            width: 12px;
+            border: 1px solid $intermediate-color;
+            border-radius: 6px;
+            background: $light-color;
+            cursor: pointer;
+            -webkit-appearance: none;
+            margin-top: -4px;
+        }
+    }
+    input[type=text] {
+        border: none;
+        padding: 0 3px;
+    }
     .ink-panel {
-        margin-top: 12px;
+        margin: 12px 18px 0 0;
+        height: 36px;
+        vertical-align: middle;
+        line-height: 36px;
+        padding: 0 10px;
+        background-color: $dark-color;
+        color: $light-color;
+        border-radius: 18px;
         &:first {
             margin-top: 0;
         }
     }
+    .ink-tools {
+        display: flex;
+        background-color: transparent;
+        border-radius: 0;
+        padding: 0;
+        button {
+            height: 36px;
+            border-radius: 18px;
+            margin-right: 6px;
+            padding: 0 16px;
+            font-size: 50%;
+            &:last-child {
+                margin-right: 0;
+            }
+        }
+    }
     .ink-size {
         display: flex;
         justify-content: space-between;
-        input {
-            width: 85%;
+        input[type=text] {
+            width: 42px;
+        }
+        >* {
+            margin-right: 6px;
+            &:last-child {
+                margin-right: 0;
+            }
+        }
+    }
+    .ink-color {
+        display: flex;
+        position: relative;
+        padding-right: 0;
+        .ink-color-display {
+            width: 60px;
+            height: 100%;
+            border-radius: 0 18px 18px 0;
+            margin-left: 6px;
+            cursor: pointer;
+            text-align: center;
+            span {
+                color: $light-color;
+                font-size: 8px;
+                user-select: none;
+            }
+        }
+        .ink-color-picker {
+            background-color: $dark-color;
+            border-radius: 5px;
+            padding: 6px;
+            position: absolute;
+            bottom: 42px;
+            left: 0;
         }
     }
 }
\ No newline at end of file
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index fc6a266e4..695b761c9 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -1,16 +1,18 @@
 import { observable, action, computed } from "mobx";
 import { CirclePicker, ColorResult } from 'react-color'
-import React = require("react");
-import "./InkingCanvas.scss"
 import { InkTool } from "../../fields/InkField";
 import { observer } from "mobx-react";
+import React = require("react");
+import "./InkingCanvas.scss"
 
 @observer
 export class InkingControl extends React.Component {
     static Instance: InkingControl = new InkingControl({});
     @observable private _selectedTool: InkTool = InkTool.None;
-    @observable private _selectedColor: string = "#f44336";
+    @observable private _selectedColor: string = "rgb(244, 67, 54)";
     @observable private _selectedWidth: string = "25";
+    @observable private _open: boolean = false;
+    @observable private _colorPickerDisplay: boolean = false;
 
     constructor(props: Readonly<{}>) {
         super(props);
@@ -54,24 +56,45 @@ export class InkingControl extends React.Component {
         return {}
     }
 
+    @action
+    toggleDisplay = () => {
+        this._open = !this._open;
+    }
+
+    @action
+    toggleColorPicker = () => {
+        this._colorPickerDisplay = !this._colorPickerDisplay;
+    }
+
     render() {
         return (
-            <div className="inking-control">
-                <div className="ink-tools ink-panel">
-                    <button onClick={() => this.switchTool(InkTool.Pen)} style={this.selected(InkTool.Pen)}>Pen</button>
-                    <button onClick={() => this.switchTool(InkTool.Highlighter)} style={this.selected(InkTool.Highlighter)}>Highlighter</button>
-                    <button onClick={() => this.switchTool(InkTool.Eraser)} style={this.selected(InkTool.Eraser)}>Eraser</button>
-                    <button onClick={() => this.switchTool(InkTool.None)} style={this.selected(InkTool.None)}> None</button>
-                </div>
-                <div className="ink-size ink-panel">
-                    <label htmlFor="stroke-width">Size</label>
-                    <input type="range" min="1" max="100" defaultValue="25" name="stroke-width"
+            <ul className="inking-control" style={this._open ? { display: "flex" } : { display: "none" }}>
+                <li className="ink-tools ink-panel">
+                    <div className="ink-tool-buttons">
+                        <button onClick={() => this.switchTool(InkTool.Pen)} style={this.selected(InkTool.Pen)}>Pen</button>
+                        <button onClick={() => this.switchTool(InkTool.Highlighter)} style={this.selected(InkTool.Highlighter)}>Highlighter</button>
+                        <button onClick={() => this.switchTool(InkTool.Eraser)} style={this.selected(InkTool.Eraser)}>Eraser</button>
+                        <button onClick={() => this.switchTool(InkTool.None)} style={this.selected(InkTool.None)}> None</button>
+                    </div>
+                </li>
+                <li className="ink-size ink-panel">
+                    <label htmlFor="stroke-width">Size: </label>
+                    <input type="text" min="1" max="100" value={this._selectedWidth} name="stroke-width"
+                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} />
+                    <input type="range" min="1" max="100" value={this._selectedWidth} name="stroke-width"
                         onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} />
-                </div>
-                <div className="ink-color ink-panel">
-                    <CirclePicker onChange={this.switchColor} />
-                </div>
-            </div>
+                </li>
+                <li className="ink-color ink-panel">
+                    <label>Color: </label>
+                    <div className="ink-color-display" style={{ backgroundColor: this._selectedColor }}
+                        onClick={() => this.toggleColorPicker()}>
+                        {this._colorPickerDisplay ? <span>&#9660;</span> : <span>&#9650;</span>}
+                    </div>
+                    <div className="ink-color-picker" style={this._colorPickerDisplay ? { display: "block" } : { display: "none" }}>
+                        <CirclePicker onChange={this.switchColor} />
+                    </div>
+                </li>
+            </ul >
         )
     }
 }
\ No newline at end of file
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index e4ef90d97..d0bfa1f21 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -124,8 +124,7 @@ Documents.initProtos(mainDocId, (res?: Document) => {
             < div id="toolbar" >
                 <button className="toolbar-button round-button" title="Undo" onClick={() => UndoManager.Undo()}><FontAwesomeIcon icon="undo-alt" size="sm" /></button>
                 <button className="toolbar-button round-button" title="Redo" onClick={() => UndoManager.Redo()}><FontAwesomeIcon icon="redo-alt" size="sm" /></button>
-                {/* @TODO do the ink thing */}
-                < button className="toolbar-button round-button" title="Ink" > <FontAwesomeIcon icon="pen-nib" size="sm" /></button >
+                <button className="toolbar-button round-button" title="Ink" onClick={() => InkingControl.Instance.toggleDisplay()}><FontAwesomeIcon icon="pen-nib" size="sm" /></button>
             </div >
 
             {/* for the expandable add nodes menu. Not included with the above because once it expands it expands the whole div with it, making canvas interactions limited. */}
@@ -164,7 +163,7 @@ Documents.initProtos(mainDocId, (res?: Document) => {
 
             </div >
 
-            {/* <InkingControl /> */}
+            <InkingControl />
         </div >),
         document.getElementById('root'));
 })
-- 
cgit v1.2.3-70-g09d2


From 99677c577a04aa289543ff5e97bd44e01b8fb4ab Mon Sep 17 00:00:00 2001
From: Jude <julie_wang1@brown.edu>
Date: Mon, 11 Mar 2019 16:21:30 -0400
Subject: inking controls changes

---
 src/client/views/InkingCanvas.scss | 260 +++++++++++++++++++------------------
 src/client/views/InkingControl.tsx |  33 +++--
 2 files changed, 152 insertions(+), 141 deletions(-)

(limited to 'src/client/views/InkingControl.tsx')

diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss
index 71c7e9ce0..d132504fc 100644
--- a/src/client/views/InkingCanvas.scss
+++ b/src/client/views/InkingCanvas.scss
@@ -1,141 +1,147 @@
 @import "global_variables";
 .inking-canvas {
-    position: fixed;
-    top: -50000px;
-    left: -50000px; // z-index: 99; //overlays ink on top of everything
-    svg {
-        width: 100000px;
-        height: 100000px;
-        .highlight {
-            mix-blend-mode: multiply;
-        }
+  position: fixed;
+  top: -50000px;
+  left: -50000px; // z-index: 99; //overlays ink on top of everything
+  svg {
+    width: 100000px;
+    height: 100000px;
+    .highlight {
+      mix-blend-mode: multiply;
     }
+  }
 }
 
 .inking-control {
-    position: absolute;
-    left: 70px;
-    bottom: 70px;
-    margin: 0;
-    padding: 0;
+  position: absolute;
+  left: 70px;
+  bottom: 70px;
+  margin: 0;
+  padding: 0;
+  display: flex;
+  label,
+  input,
+  option {
+    font-size: 12px;
+  }
+  input[type="range"] {
+    -webkit-appearance: none;
+    background-color: transparent;
+    vertical-align: middle;
+    margin-top: 8px;
+    &:focus {
+      outline: none;
+    }
+    &::-webkit-slider-runnable-track {
+      width: 100%;
+      height: 3px;
+      border-radius: 1.5px;
+      cursor: pointer;
+      background: $intermediate-color;
+    }
+    &::-webkit-slider-thumb {
+      height: 12px;
+      width: 12px;
+      border: 1px solid $intermediate-color;
+      border-radius: 6px;
+      background: $light-color;
+      cursor: pointer;
+      -webkit-appearance: none;
+      margin-top: -4px;
+    }
+    &::-moz-range-track {
+      width: 100%;
+      height: 3px;
+      border-radius: 1.5px;
+      cursor: pointer;
+      background: $light-color;
+    }
+    &::-moz-range-thumb {
+      height: 12px;
+      width: 12px;
+      border: 1px solid $intermediate-color;
+      border-radius: 6px;
+      background: $light-color;
+      cursor: pointer;
+      -webkit-appearance: none;
+      margin-top: -4px;
+    }
+  }
+  input[type="text"] {
+    border: none;
+    padding: 0 3px;
+    background: transparent;
+    color: $light-color;
+  }
+  .ink-panel {
+    margin: 6px 12px 6px 0;
+    height: 30px;
+    vertical-align: middle;
+    line-height: 36px;
+    padding: 0 10px;
+    color: $intermediate-color;
+    &:first {
+      margin-top: 0;
+    }
+  }
+  .ink-tools {
     display: flex;
-    label,
-    input,
-    option {
-        font-size: 12px;
+    background-color: transparent;
+    border-radius: 0;
+    padding: 0;
+    button {
+      height: 36px;
+      padding: 0px;
+      padding-bottom: 3px;
+      margin-left: 10px;
+      background-color: transparent;
+      color: $intermediate-color;
     }
-    input[type=range] {
-        -webkit-appearance: none;
-        background-color: transparent;
-        vertical-align: middle;
-        &:focus {
-            outline: none;
-        }
-        &::-webkit-slider-runnable-track {
-            width: 100%;
-            height: 3px;
-            border-radius: 1.5px;
-            cursor: pointer;
-            background: $light-color;
-        }
-        &::-webkit-slider-thumb {
-            height: 12px;
-            width: 12px;
-            border: 1px solid $intermediate-color;
-            border-radius: 6px;
-            background: $light-color;
-            cursor: pointer;
-            -webkit-appearance: none;
-            margin-top: -4px;
-        }
-        &::-moz-range-track {
-            width: 100%;
-            height: 3px;
-            border-radius: 1.5px;
-            cursor: pointer;
-            background: $light-color;
-        }
-        &::-moz-range-thumb {
-            height: 12px;
-            width: 12px;
-            border: 1px solid $intermediate-color;
-            border-radius: 6px;
-            background: $light-color;
-            cursor: pointer;
-            -webkit-appearance: none;
-            margin-top: -4px;
-        }
+    button:hover {
+      transform: scale(1.15);
     }
-    input[type=text] {
-        border: none;
-        padding: 0 3px;
+  }
+  .ink-size {
+    display: flex;
+    justify-content: space-between;
+    input[type="text"] {
+      width: 42px;
     }
-    .ink-panel {
-        margin: 12px 18px 0 0;
-        height: 36px;
-        vertical-align: middle;
-        line-height: 36px;
-        padding: 0 10px;
-        background-color: $dark-color;
-        color: $light-color;
-        border-radius: 18px;
-        &:first {
-            margin-top: 0;
-        }
+    > * {
+      margin-right: 6px;
+      &:last-child {
+        margin-right: 0;
+      }
     }
-    .ink-tools {
-        display: flex;
-        background-color: transparent;
-        border-radius: 0;
-        padding: 0;
-        button {
-            height: 36px;
-            border-radius: 18px;
-            margin-right: 6px;
-            padding: 0 16px;
-            font-size: 50%;
-            &:last-child {
-                margin-right: 0;
-            }
-        }
+  }
+  .ink-color {
+    display: flex;
+    position: relative;
+    padding-right: 0;
+    label {
+      margin-right: 6px;
     }
-    .ink-size {
-        display: flex;
-        justify-content: space-between;
-        input[type=text] {
-            width: 42px;
-        }
-        >* {
-            margin-right: 6px;
-            &:last-child {
-                margin-right: 0;
-            }
-        }
+    .ink-color-display {
+      border-radius: 11px;
+      width: 22px;
+      height: 22px;
+      margin-top: 6px;
+      cursor: pointer;
+      text-align: center;
+      //   span {
+      //     color: $light-color;
+      //     font-size: 8px;
+      //     user-select: none;
+      //   }
     }
-    .ink-color {
-        display: flex;
-        position: relative;
-        padding-right: 0;
-        .ink-color-display {
-            width: 60px;
-            height: 100%;
-            border-radius: 0 18px 18px 0;
-            margin-left: 6px;
-            cursor: pointer;
-            text-align: center;
-            span {
-                color: $light-color;
-                font-size: 8px;
-                user-select: none;
-            }
-        }
-        .ink-color-picker {
-            background-color: $dark-color;
-            border-radius: 5px;
-            padding: 6px;
-            position: absolute;
-            bottom: 42px;
-            left: 0;
-        }
+    .ink-color-picker {
+      background-color: $light-color;
+      border-radius: 5px;
+      padding: 12px;
+      position: absolute;
+      bottom: 36px;
+      left: -3px;
+      box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
     }
-}
\ No newline at end of file
+  }
+}
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 695b761c9..523971af4 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -4,6 +4,11 @@ import { InkTool } from "../../fields/InkField";
 import { observer } from "mobx-react";
 import React = require("react");
 import "./InkingCanvas.scss"
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-svg-icons';
+
+library.add(faPen, faHighlighter, faEraser, faBan);
 
 @observer
 export class InkingControl extends React.Component {
@@ -51,7 +56,7 @@ export class InkingControl extends React.Component {
 
     selected = (tool: InkTool) => {
         if (this._selectedTool === tool) {
-            return { backgroundColor: "#61aaa3", color: "white" }
+            return { color: "#61aaa3" }
         }
         return {}
     }
@@ -71,29 +76,29 @@ export class InkingControl extends React.Component {
             <ul className="inking-control" style={this._open ? { display: "flex" } : { display: "none" }}>
                 <li className="ink-tools ink-panel">
                     <div className="ink-tool-buttons">
-                        <button onClick={() => this.switchTool(InkTool.Pen)} style={this.selected(InkTool.Pen)}>Pen</button>
-                        <button onClick={() => this.switchTool(InkTool.Highlighter)} style={this.selected(InkTool.Highlighter)}>Highlighter</button>
-                        <button onClick={() => this.switchTool(InkTool.Eraser)} style={this.selected(InkTool.Eraser)}>Eraser</button>
-                        <button onClick={() => this.switchTool(InkTool.None)} style={this.selected(InkTool.None)}> None</button>
+                        <button onClick={() => this.switchTool(InkTool.Pen)} style={this.selected(InkTool.Pen)}><FontAwesomeIcon icon="pen" size="2x" /></button>
+                        <button onClick={() => this.switchTool(InkTool.Highlighter)} style={this.selected(InkTool.Highlighter)}><FontAwesomeIcon icon="highlighter" size="2x" /></button>
+                        <button onClick={() => this.switchTool(InkTool.Eraser)} style={this.selected(InkTool.Eraser)}><FontAwesomeIcon icon="eraser" size="2x" /></button>
+                        <button onClick={() => this.switchTool(InkTool.None)} style={this.selected(InkTool.None)}><FontAwesomeIcon icon="ban" size="2x" /></button>
                     </div>
                 </li>
-                <li className="ink-size ink-panel">
-                    <label htmlFor="stroke-width">Size: </label>
-                    <input type="text" min="1" max="100" value={this._selectedWidth} name="stroke-width"
-                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} />
-                    <input type="range" min="1" max="100" value={this._selectedWidth} name="stroke-width"
-                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} />
-                </li>
                 <li className="ink-color ink-panel">
                     <label>Color: </label>
                     <div className="ink-color-display" style={{ backgroundColor: this._selectedColor }}
                         onClick={() => this.toggleColorPicker()}>
-                        {this._colorPickerDisplay ? <span>&#9660;</span> : <span>&#9650;</span>}
+                        {/* {this._colorPickerDisplay ? <span>&#9660;</span> : <span>&#9650;</span>} */}
                     </div>
                     <div className="ink-color-picker" style={this._colorPickerDisplay ? { display: "block" } : { display: "none" }}>
-                        <CirclePicker onChange={this.switchColor} />
+                        <CirclePicker onChange={this.switchColor} circleSize={22} width={"220"} />
                     </div>
                 </li>
+                <li className="ink-size ink-panel">
+                    <label htmlFor="stroke-width">Size: </label>
+                    {/* <input type="text" min="1" max="100" value={this._selectedWidth} name="stroke-width"
+                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} /> */}
+                    <input type="range" min="1" max="100" value={this._selectedWidth} name="stroke-width"
+                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} />
+                </li>
             </ul >
         )
     }
-- 
cgit v1.2.3-70-g09d2


From 736e0bdc6fb2b98592889bc7ba0991abd56bda29 Mon Sep 17 00:00:00 2001
From: Hannah Chow <hannah_chow@brown.edu>
Date: Mon, 11 Mar 2019 17:35:54 -0400
Subject: linking kind of merged

---
 package-lock.json                         | 36 +++++++++++---
 src/client/views/DocumentDecorations.scss | 82 ++++++++++++++++---------------
 src/client/views/DocumentDecorations.tsx  |  4 +-
 src/client/views/InkingControl.tsx        |  6 +--
 src/client/views/Main.tsx                 | 12 +----
 src/client/views/nodes/DocumentView.tsx   |  6 ---
 6 files changed, 76 insertions(+), 70 deletions(-)

(limited to 'src/client/views/InkingControl.tsx')

diff --git a/package-lock.json b/package-lock.json
index 75c02628e..4830b4ac1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3574,14 +3574,18 @@
       },
       "dependencies": {
         "readable-stream": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz",
-          "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==",
+          "version": "2.3.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
           "dev": true,
           "requires": {
-            "inherits": "^2.0.3",
-            "string_decoder": "^1.1.1",
-            "util-deprecate": "^1.0.1"
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
           }
         }
       }
@@ -11929,6 +11933,26 @@
       "requires": {
         "is-fullwidth-code-point": "^2.0.0",
         "strip-ansi": "^4.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+        },
+        "is-fullwidth-code-point": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+        },
+        "strip-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+          "requires": {
+            "ansi-regex": "^3.0.0"
+          }
+        }
       }
     },
     "string_decoder": {
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index f39f31c3b..a29bf36fa 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -1,51 +1,18 @@
 @import "global_variables";
 #documentDecorations-container {
-<<<<<<< HEAD
-  position: absolute;
-  display: grid;
-  z-index: 1000;
-  grid-template-rows: 8px 1fr 8px;
-  grid-template-columns: 8px 1fr 8px;
-  pointer-events: none;
-  #documentDecorations-centerCont {
-    background: none;
-  }
-  .documentDecorations-resizer {
-    pointer-events: auto;
-    background: $alt-accent;
-    opacity: 0.8;
-  }
-  #documentDecorations-topLeftResizer,
-  #documentDecorations-bottomRightResizer {
-    cursor: nwse-resize;
-  }
-  #documentDecorations-topRightResizer,
-  #documentDecorations-bottomLeftResizer {
-    cursor: nesw-resize;
-  }
-  #documentDecorations-topResizer,
-  #documentDecorations-bottomResizer {
-    cursor: ns-resize;
-  }
-  #documentDecorations-leftResizer,
-  #documentDecorations-rightResizer {
-    cursor: ew-resize;
-  }
-}
-=======
     position: absolute;
     display: grid;
     z-index: 1000;
-    grid-template-rows: 20px 1fr 20px 0px;
-    grid-template-columns: 20px 1fr 20px;
+    grid-template-rows: 8px 1fr 8px 30px;
+    grid-template-columns: 8px 1fr 8px;
     pointer-events: none;
     #documentDecorations-centerCont {
         background: none;
     }
     .documentDecorations-resizer {
         pointer-events: auto;
-        background: lightblue;
-        opacity: 0.4;
+        background: $alt-accent;
+        opacity: 0.8;
     }
     #documentDecorations-topLeftResizer,
     #documentDecorations-bottomRightResizer {
@@ -63,8 +30,43 @@
     #documentDecorations-rightResizer {
         cursor: ew-resize;
     }
-    
 }
+
+//     position: absolute;
+//     display: grid;
+//     z-index: 1000;
+//     grid-template-rows: 20px 1fr 20px 0px;
+//     grid-template-columns: 20px 1fr 20px;
+//     pointer-events: none;
+//     #documentDecorations-centerCont {
+//         background: none;
+//     }
+//     .documentDecorations-resizer {
+//         pointer-events: auto;
+//         background: lightblue;
+//         opacity: 0.4;
+//     }
+//     #documentDecorations-topLeftResizer,
+//     #documentDecorations-bottomRightResizer {
+//         cursor: nwse-resize;
+//     }
+//     #documentDecorations-topRightResizer,
+//     #documentDecorations-bottomLeftResizer {
+//         cursor: nesw-resize;
+//     }
+//     #documentDecorations-topResizer,
+//     #documentDecorations-bottomResizer {
+//         cursor: ns-resize;
+//     }
+//     #documentDecorations-leftResizer,
+//     #documentDecorations-rightResizer {
+//         cursor: ew-resize;
+//     }
+// }
+.linkFlyout {
+    grid-column: 1/4
+}
+
 .linkButton-empty {
     height: 20px;
     width: 20px;
@@ -74,6 +76,7 @@
     pointer-events: auto;
     background-color: #2B6091;
 }
+
 .linkButton-nonempty {
     height: 20px;
     width: 20px;
@@ -82,5 +85,4 @@
     opacity: 0.6;
     pointer-events: auto;
     background-color: rgb(35, 165, 42);
-}
->>>>>>> 618e66a5a070f1aac9224bd3f44b76a5ac314bfa
+}
\ No newline at end of file
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index a644e4dbe..b75644ecd 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -220,7 +220,7 @@ export class DocumentDecorations extends React.Component {
         return (
             <div id="documentDecorations-container" style={{
                 width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
-                height: (bounds.b - bounds.y + this._resizeBorderWidth) + "px",
+                height: (bounds.b - bounds.y + this._resizeBorderWidth + 30) + "px",
                 left: bounds.x - this._resizeBorderWidth / 2,
                 top: bounds.y - this._resizeBorderWidth / 2,
             }}>
@@ -234,7 +234,7 @@ export class DocumentDecorations extends React.Component {
                 <div id="documentDecorations-bottomResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-bottomRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
 
-                {linkButton}
+                <div className="linkFlyout">{linkButton}</div>
 
             </div >
         )
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 96bf4d091..bf633b034 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -1,14 +1,10 @@
 import { observable, action, computed } from "mobx";
-<<<<<<< HEAD
+
 import { CirclePicker, ColorResult } from 'react-color'
-=======
-import { CirclePicker, ColorResult } from 'react-color';
 import React = require("react");
 import "./InkingCanvas.scss"
->>>>>>> 618e66a5a070f1aac9224bd3f44b76a5ac314bfa
 import { InkTool } from "../../fields/InkField";
 import { observer } from "mobx-react";
-import React = require("react");
 import "./InkingCanvas.scss"
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 1c0b9684e..687c765ec 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -82,7 +82,6 @@ Documents.initProtos(mainDocId, (res?: Document) => {
     let audiourl = "http://techslides.com/demos/samples/sample.mp3";
     let videourl = "http://techslides.com/demos/sample-videos/small.mp4";
     let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {}))
-<<<<<<< HEAD
     let addTextNode = action(() => Documents.TextDocument({ width: 230, height: 130, title: "a text note" }))
     let addColNode = action(() => Documents.FreeformDocument([], { width: 300, height: 300, title: "a freeform collection" }));
     let addSchemaNode = action(() => Documents.SchemaDocument([Documents.TextDocument()], { width: 450, height: 200, title: "a schema collection" }));
@@ -91,16 +90,7 @@ Documents.initProtos(mainDocId, (res?: Document) => {
     let addWebNode = action(() => Documents.WebDocument(weburl, { width: 300, height: 400, title: "a sample web page" }));
     let addVideoNode = action(() => Documents.VideoDocument(videourl, { width: 300, height: 250, title: "video node" }));
     let addAudioNode = action(() => Documents.AudioDocument(audiourl, { width: 250, height: 100, title: "audio node" }));
-=======
-    let addTextNode = action(() => Documents.TextDocument({ width: 200, height: 200, title: "a text note" }))
-    let addColNode = action(() => Documents.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" }));
-    let addSchemaNode = action(() => Documents.SchemaDocument([Documents.TextDocument()], { width: 200, height: 200, title: "a schema collection" }));
-    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 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" }))
->>>>>>> 618e66a5a070f1aac9224bd3f44b76a5ac314bfa
+
     let addClick = (creator: () => Document) => action(() =>
         mainfreeform.GetList<Document>(KeyStore.Data, []).push(creator())
     );
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 1db16aca6..dc793c16d 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -100,17 +100,11 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     onPointerDown = (e: React.PointerEvent): void => {
         this._downX = e.clientX;
         this._downY = e.clientY;
-<<<<<<< HEAD
-
-        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);
->>>>>>> 618e66a5a070f1aac9224bd3f44b76a5ac314bfa
             e.stopPropagation();
         } else {
             if (this.active && !e.isDefaultPrevented()) {
-- 
cgit v1.2.3-70-g09d2


From 3f7ff76768e0ff74e6a5d6e092f82e96661b3a2a Mon Sep 17 00:00:00 2001
From: Hannah Chow <hannah_chow@brown.edu>
Date: Mon, 11 Mar 2019 20:16:18 -0400
Subject: pen tools styling and tooltips

---
 src/client/views/DocumentDecorations.scss |   1 -
 src/client/views/InkingCanvas.scss        | 265 +++++++++++++++---------------
 src/client/views/InkingControl.tsx        |  16 +-
 3 files changed, 141 insertions(+), 141 deletions(-)

(limited to 'src/client/views/InkingControl.tsx')

diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index e77e22c5d..11595aa01 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -94,7 +94,6 @@
     transition: transform 0.2s;
     text-align: center;
     display: flex;
-    vertical-align: middle;
     justify-content: center;
     align-items: center;
 }
diff --git a/src/client/views/InkingCanvas.scss b/src/client/views/InkingCanvas.scss
index d132504fc..d76861be1 100644
--- a/src/client/views/InkingCanvas.scss
+++ b/src/client/views/InkingCanvas.scss
@@ -1,147 +1,148 @@
 @import "global_variables";
 .inking-canvas {
-  position: fixed;
-  top: -50000px;
-  left: -50000px; // z-index: 99; //overlays ink on top of everything
-  svg {
-    width: 100000px;
-    height: 100000px;
-    .highlight {
-      mix-blend-mode: multiply;
+    position: fixed;
+    top: -50000px;
+    left: -50000px; // z-index: 99; //overlays ink on top of everything
+    svg {
+        width: 100000px;
+        height: 100000px;
+        .highlight {
+            mix-blend-mode: multiply;
+        }
     }
-  }
 }
 
 .inking-control {
-  position: absolute;
-  left: 70px;
-  bottom: 70px;
-  margin: 0;
-  padding: 0;
-  display: flex;
-  label,
-  input,
-  option {
-    font-size: 12px;
-  }
-  input[type="range"] {
-    -webkit-appearance: none;
-    background-color: transparent;
-    vertical-align: middle;
-    margin-top: 8px;
-    &:focus {
-      outline: none;
-    }
-    &::-webkit-slider-runnable-track {
-      width: 100%;
-      height: 3px;
-      border-radius: 1.5px;
-      cursor: pointer;
-      background: $intermediate-color;
-    }
-    &::-webkit-slider-thumb {
-      height: 12px;
-      width: 12px;
-      border: 1px solid $intermediate-color;
-      border-radius: 6px;
-      background: $light-color;
-      cursor: pointer;
-      -webkit-appearance: none;
-      margin-top: -4px;
-    }
-    &::-moz-range-track {
-      width: 100%;
-      height: 3px;
-      border-radius: 1.5px;
-      cursor: pointer;
-      background: $light-color;
-    }
-    &::-moz-range-thumb {
-      height: 12px;
-      width: 12px;
-      border: 1px solid $intermediate-color;
-      border-radius: 6px;
-      background: $light-color;
-      cursor: pointer;
-      -webkit-appearance: none;
-      margin-top: -4px;
-    }
-  }
-  input[type="text"] {
-    border: none;
-    padding: 0 3px;
-    background: transparent;
-    color: $light-color;
-  }
-  .ink-panel {
-    margin: 6px 12px 6px 0;
-    height: 30px;
-    vertical-align: middle;
-    line-height: 36px;
-    padding: 0 10px;
-    color: $intermediate-color;
-    &:first {
-      margin-top: 0;
-    }
-  }
-  .ink-tools {
-    display: flex;
-    background-color: transparent;
-    border-radius: 0;
+    position: absolute;
+    left: 70px;
+    bottom: 70px;
+    margin: 0;
     padding: 0;
-    button {
-      height: 36px;
-      padding: 0px;
-      padding-bottom: 3px;
-      margin-left: 10px;
-      background-color: transparent;
-      color: $intermediate-color;
+    display: flex;
+    label,
+    input,
+    option {
+        font-size: 12px;
     }
-    button:hover {
-      transform: scale(1.15);
+    input[type="range"] {
+        -webkit-appearance: none;
+        background-color: transparent;
+        vertical-align: middle;
+        margin-top: 8px;
+        &:focus {
+            outline: none;
+        }
+        &::-webkit-slider-runnable-track {
+            width: 100%;
+            height: 3px;
+            border-radius: 1.5px;
+            cursor: pointer;
+            background: $intermediate-color;
+        }
+        &::-webkit-slider-thumb {
+            height: 12px;
+            width: 12px;
+            border: 1px solid $intermediate-color;
+            border-radius: 6px;
+            background: $light-color;
+            cursor: pointer;
+            -webkit-appearance: none;
+            margin-top: -4px;
+        }
+        &::-moz-range-track {
+            width: 100%;
+            height: 3px;
+            border-radius: 1.5px;
+            cursor: pointer;
+            background: $light-color;
+        }
+        &::-moz-range-thumb {
+            height: 12px;
+            width: 12px;
+            border: 1px solid $intermediate-color;
+            border-radius: 6px;
+            background: $light-color;
+            cursor: pointer;
+            -webkit-appearance: none;
+            margin-top: -4px;
+        }
     }
-  }
-  .ink-size {
-    display: flex;
-    justify-content: space-between;
     input[type="text"] {
-      width: 42px;
+        border: none;
+        padding: 0 0px;
+        background: transparent;
+        color: $dark-color;
+        font-size: 12px;
+        margin-top: 4px;
     }
-    > * {
-      margin-right: 6px;
-      &:last-child {
-        margin-right: 0;
-      }
+    .ink-panel {
+        margin: 6px 12px 6px 0;
+        height: 30px;
+        vertical-align: middle;
+        line-height: 36px;
+        padding: 0 10px;
+        color: $intermediate-color;
+        &:first {
+            margin-top: 0;
+        }
     }
-  }
-  .ink-color {
-    display: flex;
-    position: relative;
-    padding-right: 0;
-    label {
-      margin-right: 6px;
+    .ink-tools {
+        display: flex;
+        background-color: transparent;
+        border-radius: 0;
+        padding: 0;
+        button {
+            height: 36px;
+            padding: 0px;
+            padding-bottom: 3px;
+            margin-left: 10px;
+            background-color: transparent;
+            color: $intermediate-color;
+        }
+        button:hover {
+            transform: scale(1.15);
+        }
     }
-    .ink-color-display {
-      border-radius: 11px;
-      width: 22px;
-      height: 22px;
-      margin-top: 6px;
-      cursor: pointer;
-      text-align: center;
-      //   span {
-      //     color: $light-color;
-      //     font-size: 8px;
-      //     user-select: none;
-      //   }
+    .ink-size {
+        display: flex;
+        justify-content: space-between;
+        input[type="text"] {
+            width: 42px;
+        }
+        >* {
+            margin-right: 6px;
+            &:last-child {
+                margin-right: 0;
+            }
+        }
     }
-    .ink-color-picker {
-      background-color: $light-color;
-      border-radius: 5px;
-      padding: 12px;
-      position: absolute;
-      bottom: 36px;
-      left: -3px;
-      box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
+    .ink-color {
+        display: flex;
+        position: relative;
+        padding-right: 0;
+        label {
+            margin-right: 6px;
+        }
+        .ink-color-display {
+            border-radius: 11px;
+            width: 22px;
+            height: 22px;
+            margin-top: 6px;
+            cursor: pointer;
+            text-align: center; //   span {
+            //     color: $light-color;
+            //     font-size: 8px;
+            //     user-select: none;
+            //   }
+        }
+        .ink-color-picker {
+            background-color: $light-color;
+            border-radius: 5px;
+            padding: 12px;
+            position: absolute;
+            bottom: 36px;
+            left: -3px;
+            box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
+        }
     }
-  }
-}
+}
\ No newline at end of file
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index bf633b034..fb75ef2a5 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -78,14 +78,14 @@ export class InkingControl extends React.Component {
             <ul className="inking-control" style={this._open ? { display: "flex" } : { display: "none" }}>
                 <li className="ink-tools ink-panel">
                     <div className="ink-tool-buttons">
-                        <button onClick={() => this.switchTool(InkTool.Pen)} style={this.selected(InkTool.Pen)}><FontAwesomeIcon icon="pen" size="2x" /></button>
-                        <button onClick={() => this.switchTool(InkTool.Highlighter)} style={this.selected(InkTool.Highlighter)}><FontAwesomeIcon icon="highlighter" size="2x" /></button>
-                        <button onClick={() => this.switchTool(InkTool.Eraser)} style={this.selected(InkTool.Eraser)}><FontAwesomeIcon icon="eraser" size="2x" /></button>
-                        <button onClick={() => this.switchTool(InkTool.None)} style={this.selected(InkTool.None)}><FontAwesomeIcon icon="ban" size="2x" /></button>
+                        <button onClick={() => this.switchTool(InkTool.Pen)} style={this.selected(InkTool.Pen)}><FontAwesomeIcon icon="pen" size="lg" title="Pen" /></button>
+                        <button onClick={() => this.switchTool(InkTool.Highlighter)} style={this.selected(InkTool.Highlighter)}><FontAwesomeIcon icon="highlighter" size="lg" title="Highlighter" /></button>
+                        <button onClick={() => this.switchTool(InkTool.Eraser)} style={this.selected(InkTool.Eraser)}><FontAwesomeIcon icon="eraser" size="lg" title="Eraser" /></button>
+                        <button onClick={() => this.switchTool(InkTool.None)} style={this.selected(InkTool.None)}><FontAwesomeIcon icon="ban" size="lg" title="Pointer" /></button>
                     </div>
                 </li>
                 <li className="ink-color ink-panel">
-                    <label>Color: </label>
+                    <label>COLOR: </label>
                     <div className="ink-color-display" style={{ backgroundColor: this._selectedColor }}
                         onClick={() => this.toggleColorPicker()}>
                         {/* {this._colorPickerDisplay ? <span>&#9660;</span> : <span>&#9650;</span>} */}
@@ -95,9 +95,9 @@ export class InkingControl extends React.Component {
                     </div>
                 </li>
                 <li className="ink-size ink-panel">
-                    <label htmlFor="stroke-width">Size: </label>
-                    {/* <input type="text" min="1" max="100" value={this._selectedWidth} name="stroke-width"
-                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} /> */}
+                    <label htmlFor="stroke-width">SIZE: </label>
+                    <input type="text" min="1" max="100" value={this._selectedWidth} name="stroke-width"
+                        onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} />
                     <input type="range" min="1" max="100" value={this._selectedWidth} name="stroke-width"
                         onChange={(e: React.ChangeEvent<HTMLInputElement>) => this.switchWidth(e.target.value)} />
                 </li>
-- 
cgit v1.2.3-70-g09d2


From 1bf3a5a0108704a0204cedcbad6e6d52d19cf982 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sun, 17 Mar 2019 22:04:03 -0400
Subject: moved DocumentContents to DocumentContentsView

---
 src/client/views/InkingControl.tsx                 |  8 +++
 .../views/collections/CollectionFreeFormView.tsx   | 34 ++----------
 src/client/views/collections/MarqueeView.tsx       |  2 +-
 src/client/views/collections/PreviewCursor.tsx     | 10 ++--
 src/client/views/nodes/DocumentContentsView.tsx    | 60 +++++++++++++++-------
 src/client/views/nodes/DocumentView.tsx            | 55 ++------------------
 6 files changed, 62 insertions(+), 107 deletions(-)

(limited to 'src/client/views/InkingControl.tsx')

diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index fb75ef2a5..6616f68d8 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -9,6 +9,8 @@ import "./InkingCanvas.scss"
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-svg-icons';
+import { SelectionManager } from "../util/SelectionManager";
+import { KeyStore } from "../../fields/KeyStore";
 
 library.add(faPen, faHighlighter, faEraser, faBan);
 
@@ -34,6 +36,12 @@ export class InkingControl extends React.Component {
     @action
     switchColor = (color: ColorResult): void => {
         this._selectedColor = color.hex;
+        if (SelectionManager.SelectedDocuments().length == 1) {
+            var sdoc = SelectionManager.SelectedDocuments()[0];
+            if (sdoc.props.ContainingCollectionView && sdoc.props.ContainingCollectionView) {
+                sdoc.props.Document.SetText(KeyStore.BackgroundColor, color.hex);
+            }
+        }
     }
 
     @action
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 988c9941f..cca57912c 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -8,28 +8,16 @@ import { TextField } from "../../../fields/TextField";
 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 { CollectionVideoView } from "../collections/CollectionVideoView";
-import { CollectionView } from "../collections/CollectionView";
 import { InkingCanvas } from "../InkingCanvas";
-import { AudioBox } from "../nodes/AudioBox";
 import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
-import { DocumentView, DocumentViewProps, DocumentContents } from "../nodes/DocumentView";
-import { FormattedTextBox } from "../nodes/FormattedTextBox";
-import { ImageBox } from "../nodes/ImageBox";
-import { KeyValueBox } from "../nodes/KeyValueBox";
-import { PDFBox } from "../nodes/PDFBox";
-import { VideoBox } from "../nodes/VideoBox";
-import { WebBox } from "../nodes/WebBox";
+import { DocumentContentsView } from "../nodes/DocumentContentsView";
+import { DocumentView, DocumentViewProps } from "../nodes/DocumentView";
 import "./CollectionFreeFormView.scss";
 import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
 import { CollectionViewBase } from "./CollectionViewBase";
 import { MarqueeView } from "./MarqueeView";
 import { PreviewCursor } from "./PreviewCursor";
 import React = require("react");
-const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
 
 @observer
 export class CollectionFreeFormView extends CollectionViewBase {
@@ -283,28 +271,14 @@ export class CollectionFreeFormView extends CollectionViewBase {
     @computed
     get backgroundView() {
         return !this.backgroundLayout ? (null) :
-            (<DocumentContents {...this.getDocumentViewProps(this.props.Document)}
+            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
                 layoutKey={KeyStore.BackgroundLayout} isSelected={() => false} select={() => { }} />);
-        // (<JsxParser
-        //     components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox }}
-        //     bindings={this.props.bindings}
-        //     jsx={this.backgroundLayout}
-        //     showWarnings={true}
-        //     onError={(test: any) => console.log(test)}
-        // />);
     }
     @computed
     get overlayView() {
         return !this.overlayLayout ? (null) :
-            (<DocumentContents {...this.getDocumentViewProps(this.props.Document)}
+            (<DocumentContentsView {...this.getDocumentViewProps(this.props.Document)}
                 layoutKey={KeyStore.OverlayLayout} isSelected={() => false} select={() => { }} />);
-        // (<JsxParser
-        //     components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox }}
-        //     bindings={this.props.bindings}
-        //     jsx={this.overlayLayout}
-        //     showWarnings={true}
-        //     onError={(test: any) => console.log(test)}
-        // />);
     }
 
     getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform())
diff --git a/src/client/views/collections/MarqueeView.tsx b/src/client/views/collections/MarqueeView.tsx
index 65aaa837f..f5c83a934 100644
--- a/src/client/views/collections/MarqueeView.tsx
+++ b/src/client/views/collections/MarqueeView.tsx
@@ -121,7 +121,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
         let centerShiftX = 0 - (selRect.left + selRect.width / 2); // moves each point by the offset that shifts the selection's center to the origin.
         let centerShiftY = 0 - (selRect.top + selRect.height / 2);
         let ink = this.props.container.props.Document.GetT(KeyStore.Ink, InkField);
-        if (ink && ink != FieldWaiting) {
+        if (ink && ink != FieldWaiting && ink.Data) {
             let idata = new Map();
             ink.Data.forEach((value: StrokeData, key: string, map: any) => {
                 let inside = InkingCanvas.IntersectStrokeRect(value, selRect);
diff --git a/src/client/views/collections/PreviewCursor.tsx b/src/client/views/collections/PreviewCursor.tsx
index a1411250a..cbcfa568d 100644
--- a/src/client/views/collections/PreviewCursor.tsx
+++ b/src/client/views/collections/PreviewCursor.tsx
@@ -1,16 +1,12 @@
-import { trace } from "mobx";
-import "./PreviewCursor.scss";
-import React = require("react");
 import { action, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
 import { Document } from "../../../fields/Document";
-import { FieldWaiting, Opt } from "../../../fields/Field";
-import { KeyStore } from "../../../fields/KeyStore";
-import { ListField } from "../../../fields/ListField";
+import { Opt } from "../../../fields/Field";
 import { Documents } from "../../documents/Documents";
-import { SelectionManager } from "../../util/SelectionManager";
 import { Transform } from "../../util/Transform";
 import { CollectionFreeFormView } from "./CollectionFreeFormView";
+import "./PreviewCursor.scss";
+import React = require("react");
 
 
 export interface PreviewCursorProps {
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 55b4938a0..ce72ab64b 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -1,33 +1,55 @@
-import { Document } from "../../../fields/Document";
-import { CollectionFreeFormView } from "../collections/CollectionFreeFormView";
+import { computed } from "mobx";
+import { observer } from "mobx-react";
+import { FieldWaiting } from "../../../fields/Field";
+import { Key } from "../../../fields/Key";
+import { KeyStore } from "../../../fields/KeyStore";
+import { ListField } from "../../../fields/ListField";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
-import { CollectionSchemaView } from "../collections/CollectionSchemaView";
-import { CollectionView, CollectionViewType } from "../collections/CollectionView";
+import { CollectionFreeFormView } from "../collections/CollectionFreeFormView";
 import { CollectionPDFView } from "../collections/CollectionPDFView";
+import { CollectionSchemaView } from "../collections/CollectionSchemaView";
 import { CollectionVideoView } from "../collections/CollectionVideoView";
-import { FormattedTextBox } from "../nodes/FormattedTextBox";
-import { ImageBox } from "../nodes/ImageBox";
-import { VideoBox } from "../nodes/VideoBox";
-import { AudioBox } from "../nodes/AudioBox";
-import { KeyValueBox } from "./KeyValueBox"
-import { WebBox } from "../nodes/WebBox";
-import { PDFBox } from "../nodes/PDFBox";
+import { CollectionView } from "../collections/CollectionView";
+import { AudioBox } from "./AudioBox";
+import { DocumentViewProps, JsxBindings } from "./DocumentView";
 import "./DocumentView.scss";
+import { FormattedTextBox } from "./FormattedTextBox";
+import { ImageBox } from "./ImageBox";
+import { KeyValueBox } from "./KeyValueBox";
+import { PDFBox } from "./PDFBox";
+import { VideoBox } from "./VideoBox";
+import { WebBox } from "./WebBox";
 import React = require("react");
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
-interface JsxBindings {
-    Document: Document;
-    layout: string;
-    [prop: string]: any;
-}
 
-export class DocumentContentsView extends React.PureComponent<JsxBindings> {
+@observer
+export class DocumentContentsView extends React.Component<DocumentViewProps & {
+    isSelected: () => boolean,
+    select: (ctrl: boolean) => void,
+    layoutKey: Key
+}> {
+    @computed get layout(): string { return this.props.Document.GetText(this.props.layoutKey, "<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>()); }
+
+    CreateBindings(): JsxBindings {
+        let bindings: JsxBindings = { ...this.props, };
+        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
+        }
+        for (const key of this.layoutFields) {
+            let field = this.props.Document.Get(key);
+            bindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field;
+        }
+        return bindings;
+    }
+
     render() {
         return <JsxParser
             components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox }}
-            bindings={this.props}
-            jsx={this.props.layout}
+            bindings={this.CreateBindings()}
+            jsx={this.layout}
             showWarnings={true}
             onError={(test: any) => { console.log(test) }}
         />
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3e691ee6d..b36d47b8b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,11 +1,12 @@
 import { action, computed, IReactionDisposer, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { Document } from "../../../fields/Document";
-import { Field, FieldWaiting, Opt } from "../../../fields/Field";
+import { Field, Opt } from "../../../fields/Field";
 import { Key } from "../../../fields/Key";
 import { KeyStore } from "../../../fields/KeyStore";
 import { ListField } from "../../../fields/ListField";
 import { TextField } from "../../../fields/TextField";
+import { Utils } from "../../../Utils";
 import { Documents } from "../../documents/Documents";
 import { DocumentManager } from "../../util/DocumentManager";
 import { DragManager } from "../../util/DragManager";
@@ -14,22 +15,9 @@ import { Transform } from "../../util/Transform";
 import { CollectionDockingView } from "../collections/CollectionDockingView";
 import { CollectionView, CollectionViewType } from "../collections/CollectionView";
 import { ContextMenu } from "../ContextMenu";
+import { DocumentContentsView } from "./DocumentContentsView";
 import "./DocumentView.scss";
 import React = require("react");
-import { DocumentContentsView } from "./DocumentContentsView";
-import { Utils } from "../../../Utils";
-import { FormattedTextBox } from "./FormattedTextBox";
-import { ImageBox } from "./ImageBox";
-import { CollectionFreeFormView } from "../collections/CollectionFreeFormView";
-import { CollectionSchemaView } from "../collections/CollectionSchemaView";
-import { CollectionPDFView } from "../collections/CollectionPDFView";
-import { CollectionVideoView } from "../collections/CollectionVideoView";
-import { WebBox } from "./WebBox";
-import { KeyValueBox } from "./KeyValueBox";
-import { PDFBox } from "./PDFBox";
-import { VideoBox } from "./VideoBox";
-import { AudioBox } from "./AudioBox";
-const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 
 export interface DocumentViewProps {
@@ -87,7 +75,7 @@ export function FakeJsxArgs(keys: string[], fields: string[] = []): JsxArgs {
     return args;
 }
 
-interface JsxBindings {
+export interface JsxBindings {
     Document: Document;
     isSelected: () => boolean;
     select: (isCtrlPressed: boolean) => void;
@@ -96,40 +84,7 @@ interface JsxBindings {
     [prop: string]: any;
 }
 
-@observer
-export class DocumentContents extends React.Component<DocumentViewProps & {
-    isSelected: () => boolean,
-    select: (ctrl: boolean) => void,
-    layoutKey: Key
-}> {
-    @computed get layout(): string { return this.props.Document.GetText(this.props.layoutKey, "<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>()); }
-
-    CreateBindings(): JsxBindings {
-        let bindings: JsxBindings = {
-            ...this.props,
-        };
-        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
-        }
-        for (const key of this.layoutFields) {
-            let field = this.props.Document.Get(key);
-            bindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field;
-        }
-        return bindings;
-    }
 
-    render() {
-        return <JsxParser
-            components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox }}
-            bindings={this.CreateBindings()}
-            jsx={this.layout}
-            showWarnings={true}
-            onError={(test: any) => { console.log(test) }}
-        />
-    }
-}
 
 @observer
 export class DocumentView extends React.Component<DocumentViewProps> {
@@ -377,7 +332,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                 onDrop={this.onDrop}
                 onContextMenu={this.onContextMenu}
                 onPointerDown={this.onPointerDown} >
-                <DocumentContents {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={KeyStore.Layout} />
+                <DocumentContentsView {...this.props} isSelected={this.isSelected} select={this.select} layoutKey={KeyStore.Layout} />
             </div>
         )
     }
-- 
cgit v1.2.3-70-g09d2


From 8418b842b16da68150243e1750aa8b40eb8a8792 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 18 Mar 2019 11:48:24 -0400
Subject: fixed removing from schemas.  fixed dragging link button to move
 quickly. cleaned up drag/drop code a little

---
 src/client/util/DragManager.ts                     | 12 +++-----
 src/client/views/DocumentDecorations.tsx           | 14 ++++-----
 src/client/views/InkingControl.tsx                 |  3 +-
 .../views/collections/CollectionFreeFormView.tsx   |  4 +--
 src/client/views/collections/CollectionPDFView.tsx |  2 +-
 .../views/collections/CollectionSchemaView.tsx     |  4 +--
 .../views/collections/CollectionVideoView.tsx      |  2 +-
 src/client/views/collections/CollectionView.tsx    |  7 +++--
 .../views/collections/CollectionViewBase.tsx       | 36 ++++++++--------------
 src/client/views/collections/MarqueeView.tsx       | 15 +++++++--
 src/client/views/nodes/DocumentView.tsx            | 16 +++++-----
 11 files changed, 57 insertions(+), 58 deletions(-)

(limited to 'src/client/views/InkingControl.tsx')

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index c0abec407..54784f2d2 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -2,18 +2,18 @@ import { DocumentDecorations } from "../views/DocumentDecorations";
 import { CollectionDockingView } from "../views/collections/CollectionDockingView";
 import { Document } from "../../fields/Document"
 import { action } from "mobx";
-import { DocumentView } from "../views/nodes/DocumentView";
 import { ImageField } from "../../fields/ImageField";
 import { KeyStore } from "../../fields/KeyStore";
+import { CollectionView } from "../views/collections/CollectionView";
 
-export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Document) {
+export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: () => Document, removeFunc: (containingCollection: CollectionView) => void = () => { }) {
     let onRowMove = action((e: PointerEvent): void => {
         e.stopPropagation();
         e.preventDefault();
 
         document.removeEventListener("pointermove", onRowMove);
         document.removeEventListener('pointerup', onRowUp);
-        DragManager.StartDrag(_reference.current!, { document: docFunc() });
+        DragManager.StartDrag(_reference.current!, { draggedDocument: docFunc(), removeDocument: removeFunc });
     });
     let onRowUp = action((e: PointerEvent): void => {
         document.removeEventListener("pointermove", onRowMove);
@@ -122,9 +122,7 @@ export namespace DragManager {
         // bcz: PDFs don't show up if you clone them because they contain a canvas.
         //      however, PDF's have a thumbnail field that contains an image of their canvas.
         //      So we replace the pdf's canvas with the image thumbnail
-        const docView: DocumentView = dragData["documentView"];
-        const doc: Document = dragData["document"];
-
+        const doc: Document = dragData["draggedDocument"];
         if (doc) {
             var pdfBox = dragElement.getElementsByClassName("pdfBox-cont")[0] as HTMLElement;
             let thumbnail = doc.GetT(KeyStore.Thumbnail, ImageField);
@@ -138,7 +136,6 @@ export namespace DragManager {
             }
         }
 
-
         dragDiv.appendChild(dragElement);
 
         let hideSource = false;
@@ -191,6 +188,7 @@ export namespace DragManager {
         if (!target) {
             return;
         }
+        dragData["droppedDocument"] = dragData["aliasOnDrop"] ? (dragData["draggedDocument"] as Document).CreateAlias() : dragData["draggedDocument"];
         target.dispatchEvent(new CustomEvent<DropEvent>("dashOnDrop", {
             bubbles: true,
             detail: {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 3bdb7d5b3..1145fbe7f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -77,7 +77,6 @@ export class DocumentDecorations extends React.Component {
     }
 
     onLinkButtonUp = (e: PointerEvent): void => {
-        console.log("up");
         document.removeEventListener("pointermove", this.onLinkButtonMoved)
         document.removeEventListener("pointerup", this.onLinkButtonUp)
         e.stopPropagation();
@@ -85,10 +84,11 @@ export class DocumentDecorations extends React.Component {
 
 
     onLinkButtonMoved = (e: PointerEvent): void => {
-        console.log("moved");
-        let dragData: { [id: string]: any } = {};
-        dragData["linkSourceDoc"] = SelectionManager.SelectedDocuments()[0];
         if (this._linkButton.current != null) {
+            document.removeEventListener("pointermove", this.onLinkButtonMoved)
+            document.removeEventListener("pointerup", this.onLinkButtonUp)
+            let dragData: { [id: string]: any } = {};
+            dragData["linkSourceDoc"] = SelectionManager.SelectedDocuments()[0];
             DragManager.StartDrag(this._linkButton.current, dragData, {
                 handlers: {
                     dragComplete: action(() => { }),
@@ -96,8 +96,6 @@ export class DocumentDecorations extends React.Component {
                 hideSource: false
             })
         }
-        document.removeEventListener("pointermove", this.onLinkButtonMoved)
-        document.removeEventListener("pointerup", this.onLinkButtonUp)
         e.stopPropagation();
     }
 
@@ -217,7 +215,7 @@ export class DocumentDecorations extends React.Component {
                     <LinkMenu docView={selFirst} changeFlyout={this.changeFlyoutContent}>
                     </LinkMenu>
                 }>
-                <div className={"linkButton-" + (selFirst.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []).length ? "nonempty" : "empty")} onPointerDown={this.onLinkButtonDown} ref={this._linkButton}>{linkCount}</div>
+                <div className={"linkButton-" + (selFirst.props.Document.GetData(KeyStore.LinkedToDocs, ListField, []).length ? "nonempty" : "empty")} onPointerDown={this.onLinkButtonDown} >{linkCount}</div>
             </Flyout>);
         }
         return (
@@ -237,7 +235,7 @@ export class DocumentDecorations extends React.Component {
                 <div id="documentDecorations-bottomResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-bottomRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
 
-                <div title="View Links" className="linkFlyout">{linkButton}</div>
+                <div title="View Links" className="linkFlyout" ref={this._linkButton}>{linkButton}</div>
 
             </div >
         )
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 6616f68d8..ad6bbd476 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -11,6 +11,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-svg-icons';
 import { SelectionManager } from "../util/SelectionManager";
 import { KeyStore } from "../../fields/KeyStore";
+import { TextField } from "../../fields/TextField";
 
 library.add(faPen, faHighlighter, faEraser, faBan);
 
@@ -39,7 +40,7 @@ export class InkingControl extends React.Component {
         if (SelectionManager.SelectedDocuments().length == 1) {
             var sdoc = SelectionManager.SelectedDocuments()[0];
             if (sdoc.props.ContainingCollectionView && sdoc.props.ContainingCollectionView) {
-                sdoc.props.Document.SetText(KeyStore.BackgroundColor, color.hex);
+                sdoc.props.Document.SetOnPrototype(KeyStore.BackgroundColor, new TextField(color.hex));
             }
         }
     }
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 728076ef8..85ea2d121 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -28,7 +28,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
         // mark this collection so that when the text box is created we can send it the SelectOnLoad prop to focus itself
         this._selectOnLoaded = newBox.Id;
         //set text to be the typed key and get focus on text box
-        this.props.addDocument(newBox);
+        this.props.addDocument(newBox, false);
         //remove cursor from screen
         this.PreviewCursorVisible = false;
     }
@@ -79,7 +79,7 @@ export class CollectionFreeFormView extends CollectionViewBase {
         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);
-        let doc: Document = de.data["document"];
+        let doc: Document = de.data["droppedDocument"];
         if (doc) {
             doc.SetNumber(KeyStore.X, x);
             doc.SetNumber(KeyStore.Y, y);
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 124d82c8b..e64b4c945 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -38,7 +38,7 @@ export class CollectionPDFView extends React.Component<CollectionViewProps> {
     public SelectedDocs: FieldId[] = []
     public active: () => boolean = () => CollectionView.Active(this);
 
-    addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); }
+    addDocument = (doc: Document, allowDuplicates: boolean): void => { CollectionView.AddDocument(this.props, doc, allowDuplicates); }
     removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); }
 
     specificContextMenu = (e: React.MouseEvent): void => {
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index f88a62a0f..ced08a14e 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -14,7 +14,7 @@ import { EditableView } from "../EditableView";
 import { DocumentView } from "../nodes/DocumentView";
 import { FieldView, FieldViewProps } from "../nodes/FieldView";
 import "./CollectionSchemaView.scss";
-import { COLLECTION_BORDER_WIDTH } from "./CollectionView";
+import { COLLECTION_BORDER_WIDTH, CollectionView } from "./CollectionView";
 import { CollectionViewBase } from "./CollectionViewBase";
 import { setupDrag } from "../../util/DragManager";
 
@@ -47,7 +47,7 @@ export class CollectionSchemaView extends CollectionViewBase {
             <FieldView {...props} />
         )
         let reference = React.createRef<HTMLDivElement>();
-        let onItemDown = setupDrag(reference, () => props.doc);
+        let onItemDown = setupDrag(reference, () => props.doc, (containingCollection: CollectionView) => this.props.removeDocument(props.doc));
         return (
             <div className="collectionSchemaView-cellContents" onPointerDown={onItemDown} style={{ height: "36px" }} key={props.doc.Id} ref={reference}>
                 <EditableView contents={contents}
diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx
index 8fc1a1b4d..05f759967 100644
--- a/src/client/views/collections/CollectionVideoView.tsx
+++ b/src/client/views/collections/CollectionVideoView.tsx
@@ -44,7 +44,7 @@ export class CollectionVideoView extends React.Component<CollectionViewProps> {
     public SelectedDocs: FieldId[] = []
     public active: () => boolean = () => CollectionView.Active(this);
 
-    addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); }
+    addDocument = (doc: Document, allowDuplicates: boolean): void => { CollectionView.AddDocument(this.props, doc, allowDuplicates); }
     removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); }
 
     specificContextMenu = (e: React.MouseEvent): void => {
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 40acf466e..303099c16 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -36,7 +36,7 @@ export class CollectionView extends React.Component<CollectionViewProps> {
     @observable
     public SelectedDocs: FieldId[] = [];
     public active: () => boolean = () => CollectionView.Active(this);
-    addDocument = (doc: Document): void => { CollectionView.AddDocument(this.props, doc); }
+    addDocument = (doc: Document, allowDuplicates: boolean): void => { CollectionView.AddDocument(this.props, doc, allowDuplicates); }
     removeDocument = (doc: Document): boolean => { return CollectionView.RemoveDocument(this.props, doc); }
     get subView() { return CollectionView.SubView(this); }
 
@@ -48,12 +48,13 @@ export class CollectionView extends React.Component<CollectionViewProps> {
     }
 
     @action
-    public static AddDocument(props: CollectionViewProps, doc: Document) {
+    public static AddDocument(props: CollectionViewProps, doc: Document, allowDuplicates: boolean) {
         doc.SetNumber(KeyStore.Page, props.Document.GetNumber(KeyStore.CurPage, -1));
         if (props.Document.Get(props.fieldKey) instanceof Field) {
             //TODO This won't create the field if it doesn't already exist
             const value = props.Document.GetData(props.fieldKey, ListField, new Array<Document>())
-            value.push(doc);
+            if (!value.some(v => v.Id == doc.Id) || allowDuplicates)
+                value.push(doc);
         } else {
             props.Document.SetOnPrototype(props.fieldKey, new ListField([doc]));
         }
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index 3d1a76a07..0358b5907 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -27,7 +27,7 @@ export interface CollectionViewProps {
 }
 export interface SubCollectionViewProps extends CollectionViewProps {
     active: () => boolean;
-    addDocument: (doc: Document) => void;
+    addDocument: (doc: Document, allowDuplicates: boolean) => void;
     removeDocument: (doc: Document) => boolean;
     CollectionView: CollectionView;
 }
@@ -46,28 +46,16 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
     @undoBatch
     @action
     protected drop(e: Event, de: DragManager.DropEvent) {
-        let docToAlias = de.data["documentToAlias"];
-        let docView = de.data["documentView"];
-        let doc = docToAlias ? docToAlias.CreateAlias() : de.data["document"];
-        if (docToAlias) {
-            [KeyStore.Width, KeyStore.Height].map(key =>
-                docToAlias.GetTAsync(key, NumberField, (f: Opt<NumberField>) => {
-                    if (f) {
-                        doc.SetNumber(key, f.Data)
-                    }
-                })
-            );
-            de.data["document"] = doc;
-            this.props.addDocument(doc);
-        } else if (docView) {
-            if (doc && docView.props.RemoveDocument && docView.props.ContainingCollectionView !== this.props.CollectionView) {
-                docView.props.RemoveDocument(doc);
-                this.props.removeDocument(doc); // bcz: not good -- want to check if it's there and then add if it isn't
-                this.props.addDocument(doc);
+        let dropped = de.data["droppedDocument"];
+        if (dropped) {
+            if (de.data["aliasOnDrop"]) {
+                let dragged = de.data["draggedDocument"];
+                [KeyStore.Width, KeyStore.Height, KeyStore.CurPage].map(key =>
+                    dragged.GetTAsync(key, NumberField, (f: Opt<NumberField>) => f ? dropped.SetNumber(key, f.Data) : null));
+            } else if (de.data["removeDocument"]) {
+                de.data["removeDocument"](this.props.CollectionView);
             }
-        } else if (doc) {
-            this.props.removeDocument(doc); // bcz: not good -- want to check if it's there and then add if it isn't
-            this.props.addDocument(doc);
+            this.props.addDocument(dropped, false);
         }
         e.stopPropagation();
     }
@@ -89,7 +77,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
             console.log("not good");
             let htmlDoc = Documents.HtmlDocument(html, { ...options, width: 300, height: 300 });
             htmlDoc.SetText(KeyStore.DocumentText, text);
-            this.props.addDocument(htmlDoc);
+            this.props.addDocument(htmlDoc, false);
             return;
         }
 
@@ -99,7 +87,7 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps>
             const upload = window.location.origin + "/upload";
             let item = e.dataTransfer.items[i];
             if (item.kind === "string" && item.type.indexOf("uri") != -1) {
-                e.dataTransfer.items[i].getAsString(action((s: string) => this.props.addDocument(Documents.WebDocument(s, options))))
+                e.dataTransfer.items[i].getAsString(action((s: string) => this.props.addDocument(Documents.WebDocument(s, options), false)))
             }
             let type = item.type
             console.log(type)
diff --git a/src/client/views/collections/MarqueeView.tsx b/src/client/views/collections/MarqueeView.tsx
index f5c83a934..8c2f3443c 100644
--- a/src/client/views/collections/MarqueeView.tsx
+++ b/src/client/views/collections/MarqueeView.tsx
@@ -17,7 +17,7 @@ interface MarqueeViewProps {
     getMarqueeTransform: () => Transform;
     getTransform: () => Transform;
     container: CollectionFreeFormView;
-    addDocument: (doc: Document) => void;
+    addDocument: (doc: Document, allowDuplicates: false) => void;
     activeDocuments: () => Document[];
     selectDocuments: (docs: Document[]) => void;
     removeDocument: (doc: Document) => boolean;
@@ -111,7 +111,18 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             let liftedInk = this.marqueeInkSelect(true);
             this.props.container.props.Document.SetData(KeyStore.Ink, this.marqueeInkSelect(false), InkField);
             //setTimeout(() => {
-            this.props.addDocument(Documents.FreeformDocument(selected, { x: bounds.left, y: bounds.top, panx: 0, pany: 0, width: bounds.width, backgroundColor: "Transparent", height: bounds.height, ink: liftedInk, title: "a nested collection" }));
+            let newCollection = Documents.FreeformDocument(selected, {
+                x: bounds.left,
+                y: bounds.top,
+                panx: 0,
+                pany: 0,
+                width: bounds.width,
+                height: bounds.height,
+                backgroundColor: "Transparent",
+                ink: liftedInk,
+                title: "a nested collection"
+            });
+            this.props.addDocument(newCollection, false);
             // }, 100);
             this.cleanupInteractions();
         }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index fbd58ef7e..e98815fa6 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -23,7 +23,7 @@ import React = require("react");
 export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView>;
     Document: Document;
-    AddDocument?: (doc: Document) => void;
+    AddDocument?: (doc: Document, allowDuplicates: boolean) => void;
     RemoveDocument?: (doc: Document) => boolean;
     ScreenToLocalTransform: () => Transform;
     isTopMost: boolean;
@@ -164,12 +164,15 @@ export class DocumentView extends React.Component<DocumentViewProps> {
         if (this._mainCont.current) {
             const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
             let dragData: { [id: string]: any } = {};
-            dragData["documentView"] = this;
-            if (dropAliasOfDraggedDoc)
-                dragData["documentToAlias"] = this.props.Document;
-            dragData["document"] = this.props.Document;
+            dragData["aliasOnDrop"] = dropAliasOfDraggedDoc;
+            dragData["draggedDocument"] = this.props.Document;
             dragData["xOffset"] = x - left;
             dragData["yOffset"] = y - top;
+            dragData["removeDocument"] = (dropCollectionView: CollectionView) => {
+                if (this.props.RemoveDocument && this.props.ContainingCollectionView !== dropCollectionView) {
+                    this.props.RemoveDocument(this.props.Document);
+                }
+            }
             DragManager.StartDrag(this._mainCont.current, dragData, {
                 handlers: {
                     dragComplete: action(() => { }),
@@ -213,7 +216,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
 
     fieldsClicked = (e: React.MouseEvent): void => {
         if (this.props.AddDocument) {
-            this.props.AddDocument(Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }));
+            this.props.AddDocument(Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }), false);
         }
     }
     fullScreenClicked = (e: React.MouseEvent): void => {
@@ -232,7 +235,6 @@ export class DocumentView extends React.Component<DocumentViewProps> {
 
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
-        console.log("drop");
         const sourceDocView: DocumentView = de.data["linkSourceDoc"];
         if (!sourceDocView) {
             return;
-- 
cgit v1.2.3-70-g09d2

