From fd22f29e70e542b834884b01aac101190eb8c355 Mon Sep 17 00:00:00 2001
From: kimdahey <claire_kim1@brown.edu>
Date: Tue, 23 Jul 2019 13:15:03 -0400
Subject: title will not change after being given a custom title

---
 src/client/views/nodes/FormattedTextBox.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/client/views/nodes/FormattedTextBox.tsx')

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 0a79677e2..899b8d568 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -139,7 +139,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()));
             this._applyingChange = false;
             let title = StrCast(this.dataDoc.title);
-            if (title && title.startsWith("-") && this._editorView) {
+            if (title && title.startsWith("-") && this._editorView && !this.Document.customTitle) {
                 let str = this._editorView.state.doc.textContent;
                 let titlestr = str.substr(0, Math.min(40, str.length));
                 this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
@@ -422,7 +422,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         // stop propagation doesn't seem to stop propagation of native keyboard events.
         // so we set a flag on the native event that marks that the event's been handled.
         (e.nativeEvent as any).DASHFormattedTextBoxHandled = true;
-        if (StrCast(this.dataDoc.title).startsWith("-") && this._editorView) {
+        if (StrCast(this.dataDoc.title).startsWith("-") && this._editorView && !this.Document.customTitle) {
             let str = this._editorView.state.doc.textContent;
             let titlestr = str.substr(0, Math.min(40, str.length));
             this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
-- 
cgit v1.2.3-70-g09d2


From eb24b07405b902f34f9b335ef86f5ec2c6d7d062 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Fri, 26 Jul 2019 22:16:57 -0400
Subject: ui improvements

---
 src/client/views/ContextMenu.scss                  | 48 +++++++++++++++++-----
 src/client/views/ContextMenu.tsx                   |  4 +-
 src/client/views/ContextMenuItem.tsx               |  6 +--
 src/client/views/MainView.tsx                      |  2 +-
 .../views/collections/CollectionSchemaView.tsx     |  6 +--
 .../views/collections/CollectionTreeView.tsx       |  8 ++--
 src/client/views/collections/CollectionView.tsx    |  5 ++-
 src/client/views/nodes/DocumentView.tsx            | 23 +++++++----
 src/client/views/nodes/FormattedTextBox.tsx        |  6 +--
 src/client/views/nodes/IconBox.tsx                 | 10 +++--
 src/client/views/nodes/VideoBox.tsx                |  6 ++-
 src/client/views/search/SearchItem.tsx             |  7 ++--
 12 files changed, 85 insertions(+), 46 deletions(-)

(limited to 'src/client/views/nodes/FormattedTextBox.tsx')

diff --git a/src/client/views/ContextMenu.scss b/src/client/views/ContextMenu.scss
index 254163b53..195304b2c 100644
--- a/src/client/views/ContextMenu.scss
+++ b/src/client/views/ContextMenu.scss
@@ -6,6 +6,9 @@
     z-index: $contextMenu-zindex;
     box-shadow: $intermediate-color 0.2vw 0.2vw 0.4vw;
     flex-direction: column;
+    background: whitesmoke;
+    padding-bottom: 10px;
+    border-radius: 15px;
 }
 
 // .contextMenu-item:first-child {
@@ -33,7 +36,7 @@
 .contextMenu-item {
     // width: 11vw; //10vw
     height: 30px; //2vh
-    background: #DDDDDD;
+    background: whitesmoke;
     display: flex; //comment out to allow search icon to be inline with search text
     justify-content: left;
     align-items: center;
@@ -44,13 +47,22 @@
     -ms-user-select: none;
     user-select: none;
     transition: all .1s;
+    border-style: none;
+    // padding: 10px 0px 10px 0px;
+    white-space: nowrap;
+    font-size: 13px;
+    color: grey;
+    letter-spacing: 2px;
+    text-transform: uppercase;
+    padding-right: 10px;
+}
+
+.contextMenu-item:hover {
     border-width: .11px;
     border-style: none;
     border-color: $intermediate-color; //  rgb(187, 186, 186);
     border-bottom-style: solid;
-    // padding: 10px 0px 10px 0px;
-    white-space: nowrap;
-    font-size: 20px;
+    border-top-style: solid;
 }
 
 .contextMenu-itemSelected {
@@ -60,7 +72,7 @@
 .contextMenu-group {
     // width: 11vw; //10vw
     height: 30px; //2vh
-    background: rgb(200, 200, 200);
+    background: lightgoldenrodyellow;
     display: flex; //comment out to allow search icon to be inline with search text
     justify-content: left;
     align-items: center;
@@ -74,27 +86,41 @@
     border-width: .11px;
     border-style: none;
     border-color: $intermediate-color; //  rgb(187, 186, 186);
-    border-bottom-style: solid;
     // padding: 10px 0px 10px 0px;
     white-space: nowrap;
-    font-size: 20px;
+    font-size: 13px;
+    text-transform: uppercase;
+    letter-spacing: 2px;
+    padding-left: 5px;
 }
 
 .contextMenu-item:hover {
-    transition: all 0.1s;
+    transition: all 0.1s ease;
     background: $lighter-alt-accent;
 }
 
 .contextMenu-description {
-    font-size: 20px;
+    margin-left: 5px;
     text-align: left;
     display: inline; //need this?
 }
 
+.search-icon {
+    margin: 10px;
+}
+
+.search {
+    margin-left: 10px;
+    padding-left: 10px;
+    border: solid black 1px;
+    border-radius: 5px;
+}
+
 .icon-background {
     pointer-events: none;
-    background-color: #DDDDDD;
+    background-color: transparent;
     width: 35px;
     text-align: center;
-    font-size: 22px;
+    font-size: 20px;
+    margin-left: 5px;
 }
\ No newline at end of file
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index c163c56a0..5caf27327 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -165,11 +165,11 @@ export class ContextMenu extends React.Component {
 
         const contents = (
             <>
-                <span>
+                <span className={"search-icon"}>
                     <span className="icon-background">
                         <FontAwesomeIcon icon="search" size="lg" />
                     </span>
-                    <input className="contextMenu-item contextMenu-description" type="text" placeholder="Search . . ." value={this._searchString} onKeyDown={this.onKeyDown} onChange={this.onChange} autoFocus />
+                    <input className="contextMenu-item contextMenu-description search" type="text" placeholder="Search . . ." value={this._searchString} onKeyDown={this.onKeyDown} onChange={this.onChange} autoFocus />
                 </span>
                 {this.menuItems}
             </>
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 9bbb97d7e..4a7cd309d 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -10,14 +10,14 @@ library.add(faAngleRight);
 export interface OriginalMenuProps {
     description: string;
     event: () => void;
-    icon?: IconProp; //maybe should be optional (icon?)
+    icon: IconProp; //maybe should be optional (icon?)
     closeMenu?: () => void;
 }
 
 export interface SubmenuProps {
     description: string;
     subitems: ContextMenuProps[];
-    icon?: IconProp; //maybe should be optional (icon?)
+    icon: IconProp; //maybe should be optional (icon?)
     closeMenu?: () => void;
 }
 
@@ -94,7 +94,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
                     ) : null}
                     <div className="contextMenu-description">
                         {this.props.description}
-                        <FontAwesomeIcon icon={faAngleRight} size="lg" style={{ position: "absolute", right: "5px" }} />
+                        <FontAwesomeIcon icon={faAngleRight} size="lg" style={{ position: "absolute", right: "10px" }} />
                     </div>
                     {submenu}
                 </div>
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 61a013963..8606b52b3 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -390,7 +390,7 @@ export class MainView extends React.Component {
         ];
         if (!ClientUtils.RELEASE) btns.unshift([React.createRef<HTMLDivElement>(), "cat", "Add Cat Image", addImageNode]);
 
-        return < div id="add-nodes-menu" style={{ left: this.flyoutWidth + 5 }} >
+        return < div id="add-nodes-menu" style={{ left: this.flyoutWidth + 20, bottom: 20 }} >
             <input type="checkbox" id="add-menu-toggle" ref={this.addMenuToggle} />
             <label htmlFor="add-menu-toggle" style={{ marginTop: 2 }} title="Add Node"><p>+</p></label>
 
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 119aa7c19..91137f841 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -1,6 +1,6 @@
 import React = require("react");
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons';
+import { faCog, faPlus, faTable } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, trace, untracked } from "mobx";
 import { observer } from "mobx-react";
@@ -34,7 +34,7 @@ import { ComputedField } from "../../../new_fields/ScriptField";
 
 
 library.add(faCog);
-library.add(faPlus);
+library.add(faPlus, faTable);
 // bcz: need to add drag and drop of rows and columns.  This seems like it might work for rows: https://codesandbox.io/s/l94mn1q657
 
 
@@ -321,7 +321,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
 
     onContextMenu = (e: React.MouseEvent): void => {
         if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
-            ContextMenu.Instance.addItem({ description: "Make DB", event: this.makeDB });
+            ContextMenu.Instance.addItem({ description: "Make DB", event: this.makeDB, icon: "table" });
         }
     }
 
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index a1697f9b4..1c7fe4bee 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -1,5 +1,5 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faAngleRight, faCamera, faExpand, faTrash, faBell, faCaretDown, faCaretRight, faArrowsAltH, faCaretSquareDown, faCaretSquareRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
+import { faAngleRight, faCamera, faExpand, faTrash, faBell, faCaretDown, faCaretRight, faArrowsAltH, faCaretSquareDown, faCaretSquareRight, faTrashAlt, faPlus, faMinus } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, observable, trace, untracked } from "mobx";
 import { observer } from "mobx-react";
@@ -61,7 +61,7 @@ library.add(faCaretRight);
 library.add(faCaretSquareDown);
 library.add(faCaretSquareRight);
 library.add(faArrowsAltH);
-
+library.add(faPlus, faMinus);
 @observer
 /**
  * Component that takes in a document prop and a boolean whether it's collapsed or not.
@@ -520,8 +520,8 @@ export class CollectionTreeView extends CollectionSubView(Document) {
     onContextMenu = (e: React.MouseEvent): void => {
         // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout
         if (!e.isPropagationStopped() && this.props.Document.workspaceLibrary) { // excludeFromLibrary means this is the user document
-            ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => MainView.Instance.createNewWorkspace()) });
-            ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.remove(this.props.Document)) });
+            ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => MainView.Instance.createNewWorkspace()), icon: "plus" });
+            ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.remove(this.props.Document)), icon: "minus" });
             e.stopPropagation();
             e.preventDefault();
             ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15);
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 7781b26d9..0695029c7 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -17,6 +17,7 @@ import { CollectionStackingView } from './CollectionStackingView';
 import { CollectionTreeView } from "./CollectionTreeView";
 import { StrCast, PromiseValue } from '../../../new_fields/Types';
 import { DocumentType } from '../../documents/Documents';
+import { faEye } from '@fortawesome/free-regular-svg-icons';
 export const COLLECTION_BORDER_WIDTH = 2;
 
 library.add(faTh);
@@ -28,7 +29,7 @@ library.add(faThList);
 library.add(faFingerprint);
 library.add(faColumns);
 library.add(faEllipsisV);
-library.add(faImage);
+library.add(faImage, faEye);
 
 @observer
 export class CollectionView extends React.Component<FieldViewProps> {
@@ -68,7 +69,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
                     break;
                 }
             }
-            ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems });
+            ContextMenu.Instance.addItem({ description: "View Modes...", subitems: subItems, icon: "eye" });
             ContextMenu.Instance.addItem({ description: "Apply Template", event: undoBatch(() => this.props.addDocTab && this.props.addDocTab(Doc.ApplyTemplate(this.props.Document)!, undefined, "onRight")), icon: "project-diagram" });
         }
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index bae0b5b96..da72f212c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -39,6 +39,7 @@ import { OverlayView } from '../OverlayView';
 import { ScriptingRepl } from '../ScriptingRepl';
 import { ClientUtils } from '../../util/ClientUtils';
 import { EditableView } from '../EditableView';
+import { faHandPointer, faHandPointRight } from '@fortawesome/free-regular-svg-icons';
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 library.add(fa.faTrash);
@@ -60,7 +61,7 @@ library.add(fa.faCrosshairs);
 library.add(fa.faDesktop);
 library.add(fa.faUnlock);
 library.add(fa.faLock);
-library.add(fa.faLaptopCode);
+library.add(fa.faLaptopCode, fa.faMale, fa.faCopy, faHandPointRight);
 
 
 // const linkSchema = createSchema({
@@ -547,11 +548,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         subitems.push({ description: "Open Fields", event: this.fieldsClicked, icon: "layer-group" });
         cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" });
         cm.addItem({ description: BoolCast(this.props.Document.ignoreAspect, false) || !this.props.Document.nativeWidth || !this.props.Document.nativeHeight ? "Freeze" : "Unfreeze", event: this.freezeNativeDimensions, icon: "edit" });
-        cm.addItem({ description: "Pin to Pres", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" });
-        cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Pos" : "Lock Pos", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
-        cm.addItem({ description: "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
-        cm.addItem({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" });
-        cm.addItem({
+        cm.addItem({ description: "Pin to Presentation", event: () => PresentationView.Instance.PinDoc(this.props.Document), icon: "map-pin" });
+        cm.addItem({ description: BoolCast(this.props.Document.lockedPosition) ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
+        let makes: ContextMenuProps[] = [];
+        makes.push({ description: "Make Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
+        makes.push({ description: this.props.Document.isButton ? "Remove Button" : "Make Button", event: this.makeBtnClicked, icon: "concierge-bell" });
+        makes.push({
             description: "Make Portal", event: () => {
                 let portal = Docs.Create.FreeformDocument([], { width: this.props.Document[WidthSym]() + 10, height: this.props.Document[HeightSym](), title: this.props.Document.title + ".portal" });
                 Doc.GetProto(this.props.Document).subBulletDocs = new List<Doc>([portal]);
@@ -562,6 +564,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 this.props.removeDocument && this.props.removeDocument(this.props.Document);
             }, icon: "window-restore"
         });
+        cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" });
         // cm.addItem({
         //     description: "Find aliases", event: async () => {
         //         const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document);
@@ -575,8 +578,10 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" });
         cm.addItem({ description: "Zoom to Document", event: () => this.props.focus(this.props.Document, true), icon: "search" });
         if (!ClientUtils.RELEASE) {
-            cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" });
-            cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" });
+            let copies: ContextMenuProps[] = [];
+            copies.push({ description: "Copy URL", event: () => Utils.CopyText(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" });
+            copies.push({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" });
+            cm.addItem({ description: "Copy...", subitems: copies, icon: "copy" });
         }
         cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" });
         type User = { email: string, userDocumentId: string };
@@ -600,7 +605,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                             notifDoc.data = new List([sharedDoc]);
                         }
                     }
-                }
+                }, icon: "male"
             }));
         } catch {
 
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 0a79677e2..febb567e1 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -1,5 +1,5 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faEdit, faSmile } from '@fortawesome/free-solid-svg-icons';
+import { faEdit, faSmile, faTextHeight } from '@fortawesome/free-solid-svg-icons';
 import { action, IReactionDisposer, observable, reaction, runInAction, computed, trace } from "mobx";
 import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
@@ -38,7 +38,7 @@ import { thisExpression } from 'babel-types';
 import { Utils } from '../../../Utils';
 
 library.add(faEdit);
-library.add(faSmile);
+library.add(faSmile, faTextHeight);
 
 // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document
 //
@@ -462,7 +462,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             description: BoolCast(this.props.Document.autoHeight, false) ? "Manual Height" : "Auto Height",
             event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight, false)), icon: "expand-arrows-alt"
         });
-        ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems });
+        ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
     }
     render() {
         let self = this;
diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx
index d6ab2a34a..64d869ecf 100644
--- a/src/client/views/nodes/IconBox.tsx
+++ b/src/client/views/nodes/IconBox.tsx
@@ -1,6 +1,6 @@
 import React = require("react");
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons';
+import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTag, faTextHeight } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
@@ -18,7 +18,7 @@ library.add(faCaretUp);
 library.add(faObjectGroup);
 library.add(faStickyNote);
 library.add(faFilePdf);
-library.add(faFilm);
+library.add(faFilm, faTag, faTextHeight);
 
 @observer
 export class IconBox extends React.Component<FieldViewProps> {
@@ -47,13 +47,15 @@ export class IconBox extends React.Component<FieldViewProps> {
     specificContextMenu = (): void => {
         ContextMenu.Instance.addItem({
             description: BoolCast(this.props.Document.hideLabel) ? "Show label with icon" : "Remove label from icon",
-            event: this.setLabelField
+            event: this.setLabelField,
+            icon: "tag"
         });
         let maxDocs = DocListCast(this.props.Document.maximizedDocs);
         if (maxDocs.length === 1 && !BoolCast(this.props.Document.hideLabel)) {
             ContextMenu.Instance.addItem({
                 description: BoolCast(this.props.Document.useOwnTitle) ? "Use target title for label" : "Use own title label",
-                event: this.setUseOwnTitleField
+                event: this.setUseOwnTitleField,
+                icon: "text-height"
             });
         }
     }
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 30ad75000..34cb47b20 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -19,10 +19,14 @@ import { positionSchema } from "./DocumentView";
 import { FieldView, FieldViewProps } from './FieldView';
 import { pageSchema } from "./ImageBox";
 import "./VideoBox.scss";
+import { library } from "@fortawesome/fontawesome-svg-core";
+import { faVideo } from "@fortawesome/free-solid-svg-icons";
 
 type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const VideoDocument = makeInterface(positionSchema, pageSchema);
 
+library.add(faVideo);
+
 @observer
 export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoDocument) {
     private _reactionDisposer?: IReactionDisposer;
@@ -179,7 +183,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
                 },
                 icon: "expand-arrows-alt"
             });
-            ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems });
+            ContextMenu.Instance.addItem({ description: "Video Funcs...", subitems: subitems, icon: "video" });
         }
     }
 
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 5c2ced2eb..562594210 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -1,6 +1,6 @@
 import React = require("react");
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faChartBar, faFilePdf, faFilm, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons';
+import { faCaretUp, faChartBar, faFilePdf, faFilm, faGlobeAsia, faImage, faLink, faMusic, faObjectGroup, faStickyNote, faFingerprint } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, observable, runInAction } from "mobx";
 import { observer } from "mobx-react";
@@ -38,7 +38,7 @@ library.add(faFilm);
 library.add(faMusic);
 library.add(faLink);
 library.add(faChartBar);
-library.add(faGlobeAsia);
+library.add(faGlobeAsia, faFingerprint);
 
 @observer
 export class SelectorContextMenu extends React.Component<SearchItemProps> {
@@ -223,7 +223,8 @@ export class SearchItem extends React.Component<SearchItemProps> {
         ContextMenu.Instance.addItem({
             description: "Copy ID", event: () => {
                 Utils.CopyText(this.props.doc[Id]);
-            }
+            },
+            icon: "fingerprint"
         });
         ContextMenu.Instance.displayMenu(e.clientX, e.clientY);
     }
-- 
cgit v1.2.3-70-g09d2


From c360dc0adb468ae3aaa1c2d943606993d01a5a52 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 27 Jul 2019 11:08:44 -0400
Subject: fixed handling of keyboard events to avoid triggering global key
 events. made BoolCast default to false. fixed templating to deal with
 conflict between field fields and template fields

---
 src/client/util/DocumentManager.ts                 | 16 +++++++--------
 src/client/views/EditableView.tsx                  |  3 +++
 src/client/views/MainView.tsx                      |  1 -
 src/client/views/MetadataEntryMenu.tsx             |  1 +
 .../views/collections/CollectionSchemaView.tsx     |  2 +-
 .../views/collections/CollectionStackingView.tsx   |  3 ++-
 .../CollectionFreeFormLinkView.tsx                 |  8 ++++----
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  8 ++++----
 src/client/views/nodes/FormattedTextBox.tsx        |  4 ++--
 src/client/views/nodes/IconBox.tsx                 |  2 +-
 src/client/views/nodes/KeyValueBox.tsx             |  3 ++-
 src/client/views/nodes/LinkMenuItem.tsx            |  2 +-
 src/client/views/pdf/Page.tsx                      | 22 ++++++++------------
 .../views/presentationview/PresentationElement.tsx | 24 ++++++++++------------
 .../views/presentationview/PresentationView.tsx    |  2 +-
 src/new_fields/Doc.ts                              | 19 +++++++++--------
 src/new_fields/Types.ts                            |  2 +-
 18 files changed, 62 insertions(+), 62 deletions(-)

(limited to 'src/client/views/nodes/FormattedTextBox.tsx')

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 262194a40..32f728c71 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,16 +1,14 @@
-import { computed, observable, action } from 'mobx';
-import { DocumentView } from '../views/nodes/DocumentView';
-import { Doc, DocListCast, Opt } from '../../new_fields/Doc';
-import { FieldValue, Cast, NumCast, BoolCast, StrCast } from '../../new_fields/Types';
-import { listSpec } from '../../new_fields/Schema';
-import { undoBatch, UndoManager } from './UndoManager';
+import { action, computed, observable } from 'mobx';
+import { Doc } from '../../new_fields/Doc';
+import { Id } from '../../new_fields/FieldSymbols';
+import { BoolCast, Cast, NumCast } from '../../new_fields/Types';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
-import { CollectionView } from '../views/collections/CollectionView';
 import { CollectionPDFView } from '../views/collections/CollectionPDFView';
 import { CollectionVideoView } from '../views/collections/CollectionVideoView';
-import { Id } from '../../new_fields/FieldSymbols';
+import { CollectionView } from '../views/collections/CollectionView';
+import { DocumentView } from '../views/nodes/DocumentView';
 import { LinkManager } from './LinkManager';
-import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
+import { undoBatch, UndoManager } from './UndoManager';
 
 
 export class DocumentManager {
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index c66a92f48..7cabebddd 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -50,8 +50,10 @@ export class EditableView extends React.Component<EditableProps> {
     @action
     onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
         if (e.key === "Tab") {
+            e.stopPropagation();
             this.props.OnTab && this.props.OnTab();
         } else if (e.key === "Enter") {
+            e.stopPropagation();
             if (!e.ctrlKey) {
                 if (this.props.SetValue(e.currentTarget.value, e.shiftKey)) {
                     this._editing = false;
@@ -61,6 +63,7 @@ export class EditableView extends React.Component<EditableProps> {
                 this._editing = false;
             }
         } else if (e.key === "Escape") {
+            e.stopPropagation();
             this._editing = false;
         }
     }
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index bfb50bc75..8b7eb8856 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -7,7 +7,6 @@ import "normalize.css";
 import * as React from 'react';
 import { SketchPicker } from 'react-color';
 import Measure from 'react-measure';
-import * as request from 'request';
 import { Doc, DocListCast, Opt, HeightSym } from '../../new_fields/Doc';
 import { Id } from '../../new_fields/FieldSymbols';
 import { InkTool } from '../../new_fields/InkField';
diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx
index bd5a307b3..c50e02f0d 100644
--- a/src/client/views/MetadataEntryMenu.tsx
+++ b/src/client/views/MetadataEntryMenu.tsx
@@ -76,6 +76,7 @@ export class MetadataEntryMenu extends React.Component<MetadataEntryProps>{
 
     onValueKeyDown = async (e: React.KeyboardEvent) => {
         if (e.key === "Enter") {
+            e.stopPropagation();
             const script = KeyValueBox.CompileKVPScript(this._currentValue);
             if (!script) return;
             let doc = this.props.docs;
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 8ce3b40e5..0f67c47aa 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -11,7 +11,7 @@ import { Doc, DocListCast, DocListCastAsync, Field } from "../../../new_fields/D
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
-import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
+import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
 import { Docs } from "../../documents/Documents";
 import { Gateway } from "../../northstar/manager/Gateway";
 import { SetupDrag, DragManager } from "../../util/DragManager";
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 3da13bff5..d5a7b90da 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -53,7 +53,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                         let xhgt = height + this.getDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap);
                         return xhgt;
                     }, this.yMargin);
-                    this.layoutDoc.height = hgt * (this.props as any).ContentScaling();
+                    (this.props.DataDoc && this.props.DataDoc.layout === this.layoutDoc ? this.props.DataDoc : this.layoutDoc)
+                        .height = hgt * (this.props as any).ContentScaling();
                 }
             }, { fireImmediately: true });
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index b546d1b78..6af87b138 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -21,10 +21,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
         if (e.button === 0 && !InkingControl.Instance.selectedTool) {
             let a = this.props.A;
             let b = this.props.B;
-            let x1 = NumCast(a.x) + (BoolCast(a.isMinimized, false) ? 5 : a[WidthSym]() / 2);
-            let y1 = NumCast(a.y) + (BoolCast(a.isMinimized, false) ? 5 : a[HeightSym]() / 2);
-            let x2 = NumCast(b.x) + (BoolCast(b.isMinimized, false) ? 5 : b[WidthSym]() / 2);
-            let y2 = NumCast(b.y) + (BoolCast(b.isMinimized, false) ? 5 : b[HeightSym]() / 2);
+            let x1 = NumCast(a.x) + (BoolCast(a.isMinimized) ? 5 : a[WidthSym]() / 2);
+            let y1 = NumCast(a.y) + (BoolCast(a.isMinimized) ? 5 : a[HeightSym]() / 2);
+            let x2 = NumCast(b.x) + (BoolCast(b.isMinimized) ? 5 : b[WidthSym]() / 2);
+            let y2 = NumCast(b.y) + (BoolCast(b.isMinimized) ? 5 : b[HeightSym]() / 2);
             // this.props.LinkDocs.map(l => {
             //     let width = l[WidthSym]();
             //     l.x = (x1 + x2) / 2 - width / 2;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f83d02271..eaad43c10 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -471,7 +471,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             if (!(doc instanceof Doc)) return prev;
             var page = NumCast(doc.page, -1);
             if ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1) {
-                let minim = BoolCast(doc.isMinimized, false);
+                let minim = BoolCast(doc.isMinimized);
                 if (minim === undefined || !minim) {
                     const pos = script ? this.getCalculatedPositions(script, { doc, index: prev.length, collection: this.Document, docs, state }) : {};
                     state = pos.state === undefined ? state : pos.state;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3152d6a2a..bc2af2ae8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -275,7 +275,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 let iconAnimating = Cast(maximizedDoc.isIconAnimating, List);
                 if (!iconAnimating || (Date.now() - iconAnimating[2] > 1000)) {
                     if (isMinimized === undefined) {
-                        isMinimized = BoolCast(maximizedDoc.isMinimized, false);
+                        isMinimized = BoolCast(maximizedDoc.isMinimized);
                     }
                     maximizedDoc.willMaximize = isMinimized;
                     maximizedDoc.isMinimized = false;
@@ -308,7 +308,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
             SelectionManager.SelectDoc(this, e.ctrlKey);
             let isExpander = (e.target as any).id === "isExpander";
-            if (BoolCast(this.props.Document.isButton, false) || isExpander) {
+            if (BoolCast(this.props.Document.isButton) || isExpander) {
                 SelectionManager.DeselectAll();
                 let subBulletDocs = await DocListCastAsync(this.props.Document.subBulletDocs);
                 let maximizedDocs = await DocListCastAsync(this.props.Document.maximizedDocs);
@@ -326,7 +326,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                         maxLocation = this.props.Document.maximizeLocation = (ctrlKey ? maxLocation : (maxLocation === "inPlace" || !maxLocation ? "inTab" : "inPlace"));
                         if (!maxLocation || maxLocation === "inPlace") {
                             let hadView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView);
-                            let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized, false), false);
+                            let wasMinimized = !hadView && expandedDocs.reduce((min, d) => !min && !BoolCast(d.IsMinimized), false);
                             expandedDocs.forEach(maxDoc => Doc.GetProto(maxDoc).isMinimized = false);
                             let hasView = expandedDocs.length === 1 && DocumentManager.Instance.getDocumentView(expandedDocs[0], this.props.ContainingCollectionView);
                             if (!hasView) {
@@ -409,7 +409,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     @undoBatch
     makeBtnClicked = (): void => {
         let doc = Doc.GetProto(this.props.Document);
-        doc.isButton = !BoolCast(doc.isButton, false);
+        doc.isButton = !BoolCast(doc.isButton);
         if (doc.isButton) {
             if (!doc.nativeWidth) {
                 doc.nativeWidth = this.props.Document[WidthSym]();
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 0a79677e2..bd0fd8301 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -459,8 +459,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     specificContextMenu = (e: React.MouseEvent): void => {
         let subitems: ContextMenuProps[] = [];
         subitems.push({
-            description: BoolCast(this.props.Document.autoHeight, false) ? "Manual Height" : "Auto Height",
-            event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight, false)), icon: "expand-arrows-alt"
+            description: BoolCast(this.props.Document.autoHeight) ? "Manual Height" : "Auto Height",
+            event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
         });
         ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems });
     }
diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx
index d6ab2a34a..6f50033a4 100644
--- a/src/client/views/nodes/IconBox.tsx
+++ b/src/client/views/nodes/IconBox.tsx
@@ -64,7 +64,7 @@ export class IconBox extends React.Component<FieldViewProps> {
         let hideLabel = BoolCast(this.props.Document.hideLabel);
         let maxDocs = DocListCast(this.props.Document.maximizedDocs);
         let firstDoc = maxDocs.length ? maxDocs[0] : undefined;
-        let label = hideLabel ? "" : (firstDoc && labelField && !BoolCast(this.props.Document.useOwnTitle, false) ? firstDoc[labelField] : this.props.Document.title);
+        let label = hideLabel ? "" : (firstDoc && labelField && !BoolCast(this.props.Document.useOwnTitle) ? firstDoc[labelField] : this.props.Document.title);
         return (
             <div className="iconBox-container" onContextMenu={this.specificContextMenu}>
                 {this.minimizedIcon}
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 9fc0f2080..77824b4ff 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -46,6 +46,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
     @action
     onEnterKey = (e: React.KeyboardEvent): void => {
         if (e.key === 'Enter') {
+            e.stopPropagation();
             if (this._keyInput && this._valueInput && this.fieldDocToLayout) {
                 if (KeyValueBox.SetField(this.fieldDocToLayout, this._keyInput, this._valueInput)) {
                     this._keyInput = "";
@@ -153,7 +154,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
                     <input style={{ width: "100%" }} type="text" value={this._keyInput} placeholder="Key" onChange={this.keyChanged} />
                 </td>
                 <td className="keyValueBox-td-value" style={{ width: `${this.splitPercentage}%` }}>
-                    <input style={{ width: "100%" }} type="text" value={this._valueInput} placeholder="Value" onChange={this.valueChanged} onKeyPress={this.onEnterKey} />
+                    <input style={{ width: "100%" }} type="text" value={this._valueInput} placeholder="Value" onChange={this.valueChanged} onKeyDown={this.onEnterKey} />
                 </td>
             </tr>
         )
diff --git a/src/client/views/nodes/LinkMenuItem.tsx b/src/client/views/nodes/LinkMenuItem.tsx
index a0c37a719..d4c92c9f2 100644
--- a/src/client/views/nodes/LinkMenuItem.tsx
+++ b/src/client/views/nodes/LinkMenuItem.tsx
@@ -7,7 +7,7 @@ import { undoBatch } from "../../util/UndoManager";
 import './LinkMenu.scss';
 import React = require("react");
 import { Doc } from '../../../new_fields/Doc';
-import { StrCast, Cast, BoolCast, FieldValue, NumCast } from '../../../new_fields/Types';
+import { StrCast, Cast, FieldValue, NumCast } from '../../../new_fields/Types';
 import { observable, action } from 'mobx';
 import { LinkManager } from '../../util/LinkManager';
 import { DragLinkAsDocument } from '../../util/DragManager';
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index c9d442fe5..a6864e0f3 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -1,22 +1,18 @@
+import { action, IReactionDisposer, observable } from "mobx";
 import { observer } from "mobx-react";
-import React = require("react");
-import { observable, action, runInAction, IReactionDisposer, reaction } from "mobx";
 import * as Pdfjs from "pdfjs-dist";
-import { Opt, Doc, FieldResult, Field, DocListCast, WidthSym, HeightSym, DocListCastAsync } from "../../../new_fields/Doc";
-import "./PDFViewer.scss";
 import "pdfjs-dist/web/pdf_viewer.css";
-import { PDFBox } from "../nodes/PDFBox";
-import { DragManager } from "../../util/DragManager";
-import { Docs, DocUtils } from "../../documents/Documents";
+import { Doc, DocListCastAsync, Opt, WidthSym } from "../../../new_fields/Doc";
 import { List } from "../../../new_fields/List";
-import { emptyFunction } from "../../../Utils";
-import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
 import { listSpec } from "../../../new_fields/Schema";
-import { menuBar } from "prosemirror-menu";
-import { AnnotationTypes, PDFViewer, scale } from "./PDFViewer";
+import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { Docs, DocUtils } from "../../documents/Documents";
+import { DragManager } from "../../util/DragManager";
+import { PDFBox } from "../nodes/PDFBox";
 import PDFMenu from "./PDFMenu";
-import { UndoManager } from "../../util/UndoManager";
-import { copy } from "typescript-collections/dist/lib/arrays";
+import { scale } from "./PDFViewer";
+import "./PDFViewer.scss";
+import React = require("react");
 
 
 interface IPageProps {
diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx
index 329630875..36f1178f1 100644
--- a/src/client/views/presentationview/PresentationElement.tsx
+++ b/src/client/views/presentationview/PresentationElement.tsx
@@ -1,21 +1,19 @@
-import { observer } from "mobx-react";
-import React = require("react");
-import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc";
-import { NumCast, BoolCast, StrCast, Cast } from "../../../new_fields/Types";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { observable, action, computed, runInAction } from "mobx";
-import "./PresentationView.scss";
-import { Utils } from "../../../Utils";
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faFile as fileSolid, faFileDownload, faLocationArrow, faArrowUp, faSearch } from '@fortawesome/free-solid-svg-icons';
 import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons';
+import { faArrowUp, faFile as fileSolid, faFileDownload, faLocationArrow, faSearch } from '@fortawesome/free-solid-svg-icons';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { action, computed, observable, runInAction } from "mobx";
+import { observer } from "mobx-react";
+import { Doc } from "../../../new_fields/Doc";
+import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
-import { DragManager, SetupDrag, dropActionType } from "../../util/DragManager";
+import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { Utils } from "../../../Utils";
+import { DragManager, dropActionType, SetupDrag } from "../../util/DragManager";
 import { SelectionManager } from "../../util/SelectionManager";
-import { indexOf } from "typescript-collections/dist/lib/arrays";
-import { map } from "bluebird";
+import "./PresentationView.scss";
+import React = require("react");
 
 library.add(faArrowUp);
 library.add(fileSolid);
diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx
index f2fef7f16..e25725275 100644
--- a/src/client/views/presentationview/PresentationView.tsx
+++ b/src/client/views/presentationview/PresentationView.tsx
@@ -171,7 +171,7 @@ export class PresentationView extends React.Component<PresViewProps>  {
 
 
         //storing the presentation status,ie. whether it was stopped or playing
-        let presStatusBackUp = BoolCast(this.curPresentation.presStatus, null);
+        let presStatusBackUp = BoolCast(this.curPresentation.presStatus);
         runInAction(() => this.presStatus = presStatusBackUp);
     }
 
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index dbb0dc505..b5708e97b 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -455,7 +455,7 @@ export namespace Doc {
         return otherdoc;
     }
 
-    export function MakeTemplate(fieldTemplate: Doc, metaKey: string, proto: Doc) {
+    export function MakeTemplate(fieldTemplate: Doc, metaKey: string, templateDataDoc: Doc) {
         // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??)
         let backgroundLayout = StrCast(fieldTemplate.backgroundLayout);
         let fieldLayoutDoc = fieldTemplate;
@@ -466,21 +466,24 @@ export namespace Doc {
         if (backgroundLayout) {
             backgroundLayout = backgroundLayout.replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`);
         }
-        let nw = Cast(fieldTemplate.nativeWidth, "number");
-        let nh = Cast(fieldTemplate.nativeHeight, "number");
 
         let layoutDelegate = fieldTemplate.layout instanceof Doc ? fieldLayoutDoc : fieldTemplate;
         layoutDelegate.layout = layout;
 
-        fieldTemplate.title = metaKey;
         fieldTemplate.templateField = metaKey;
+        fieldTemplate.title = metaKey;
+        fieldTemplate.isTemplate = true;
         fieldTemplate.layout = layoutDelegate !== fieldTemplate ? layoutDelegate : layout;
         fieldTemplate.backgroundLayout = backgroundLayout;
-        fieldTemplate.nativeWidth = nw;
-        fieldTemplate.nativeHeight = nh;
-        fieldTemplate.isTemplate = true;
+        /* move certain layout properties from the original data doc to the template layout to avoid
+           inheriting them from the template's data doc which may also define these fields for its own use.
+        */
+        fieldTemplate.ignoreAspect = BoolCast(fieldTemplate.ignoreAspect);
+        fieldTemplate.singleColumn = BoolCast(fieldTemplate.singleColumn);
+        fieldTemplate.nativeWidth = Cast(fieldTemplate.nativeWidth, "number");
+        fieldTemplate.nativeHeight = Cast(fieldTemplate.nativeHeight, "number");
         fieldTemplate.showTitle = "title";
-        setTimeout(() => fieldTemplate.proto = proto);
+        setTimeout(() => fieldTemplate.proto = templateDataDoc);
     }
 
     export async function ToggleDetailLayout(d: Doc) {
diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts
index f8a4a30b4..565ae2ee3 100644
--- a/src/new_fields/Types.ts
+++ b/src/new_fields/Types.ts
@@ -78,7 +78,7 @@ export function StrCast(field: FieldResult, defaultVal: string | null = "") {
     return Cast(field, "string", defaultVal);
 }
 
-export function BoolCast(field: FieldResult, defaultVal: boolean | null = null) {
+export function BoolCast(field: FieldResult, defaultVal: boolean | null = false) {
     return Cast(field, "boolean", defaultVal);
 }
 export function DateCast(field: FieldResult) {
-- 
cgit v1.2.3-70-g09d2


From d53ad748d90ca1c863a7ef52d0835573ce967a54 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Sat, 27 Jul 2019 16:49:07 -0400
Subject: init

---
 src/client/util/TooltipTextMenu.tsx         |  6 +++++-
 src/client/views/GlobalKeyHandler.ts        |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx | 30 ++++++++++++++++++++++++++++-
 src/client/views/nodes/PDFBox.tsx           | 14 ++++++++++++++
 src/client/views/pdf/Page.tsx               | 11 ++++++++---
 5 files changed, 57 insertions(+), 6 deletions(-)

(limited to 'src/client/views/nodes/FormattedTextBox.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index a4c053de2..6214b568c 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -1,6 +1,6 @@
 import { action } from "mobx";
 import { Dropdown, MenuItem, icons, } from "prosemirror-menu"; //no import css
-import { EditorState, NodeSelection, TextSelection } from "prosemirror-state";
+import { EditorState, NodeSelection, TextSelection, Transaction } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { schema } from "./RichTextSchema";
 import { Schema, NodeType, MarkType, Mark, ResolvedPos } from "prosemirror-model";
@@ -321,6 +321,10 @@ export class TooltipTextMenu {
         }
     }
 
+    makeLinkWithState = (state: EditorState, target: string, location: string) => {
+        let link = state.schema.mark(state.schema.marks.link, { href: target, location: location });
+    }
+
     makeLink = (target: string, location: string) => {
         let node = this.view.state.selection.$from.nodeAfter;
         let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target, location: location });
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 7477c5b4f..6c80c7645 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -151,9 +151,9 @@ export default class KeyManager {
                 stopPropagation = false;
                 break;
             case "a":
-            case "c":
             case "v":
             case "x":
+            case "c":
                 stopPropagation = false;
                 preventDefault = false;
                 break;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 0a79677e2..cf913a4c7 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -6,7 +6,7 @@ import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
 import { NodeType } from 'prosemirror-model';
-import { EditorState, Plugin, Transaction } from "prosemirror-state";
+import { EditorState, Plugin, Transaction, Selection } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { Doc, Opt } from "../../../new_fields/Doc";
 import { Id, Copy } from '../../../new_fields/FieldSymbols';
@@ -123,12 +123,40 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         if (this.props.isOverlay) {
             DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined);
         }
+
+        document.addEventListener("paste", this.paste);
     }
 
     @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "dummy"); }
 
     @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
 
+    paste = (e: ClipboardEvent) => {
+        if (e.clipboardData && this._editorView) {
+            let pdfPasteText = `${Utils.GenerateDeterministicGuid("pdf paste")}`;
+            for (let i = 0; i < e.clipboardData.items.length; i++) {
+                let item = e.clipboardData.items.item(i);
+                if (item.type === "text/plain") {
+                    item.getAsString((text) => {
+                        let pdfPasteIndex = text.indexOf(pdfPasteText);
+                        if (pdfPasteIndex > -1) {
+                            let insertText = text.substr(0, pdfPasteIndex);
+                            const tx = this._editorView!.state.tr.insertText(insertText);
+                            // tx.setSelection(new Selection(tx.))
+                            const state = this._editorView!.state;
+                            this._editorView!.dispatch(tx);
+                            if (this._toolTipTextMenu) {
+                                // this._toolTipTextMenu.makeLinkWithState(state)
+                            }
+                            e.stopPropagation();
+                            e.preventDefault();
+                        }
+                    });
+                }
+            }
+        }
+    }
+
     dispatchTransaction = (tx: Transaction) => {
         if (this._editorView) {
             const state = this._editorView.state.apply(tx);
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 5a5e6e6dd..282312dca 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -24,6 +24,8 @@ import { Flyout, anchorPoints } from '../DocumentDecorations';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { ScriptField } from '../../../new_fields/ScriptField';
 import { KeyCodes } from '../../northstar/utils/KeyCodes';
+import { Utils } from '../../../Utils';
+import { Id } from '../../../new_fields/FieldSymbols';
 
 type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const PdfDocument = makeInterface(positionSchema, pageSchema);
@@ -32,6 +34,7 @@ export const handleBackspace = (e: React.KeyboardEvent) => { if (e.keyCode === K
 @observer
 export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocument) {
     public static LayoutString() { return FieldView.LayoutString(PDFBox); }
+    public selectionText: string = "";
 
     @observable private _alt = false;
     @observable private _scrollY: number = 0;
@@ -63,6 +66,8 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         this._keyRef = React.createRef();
         this._valueRef = React.createRef();
         this._scriptRef = React.createRef();
+
+        document.addEventListener("keydown", this.onKeyDown);
     }
 
     componentDidMount() {
@@ -73,6 +78,14 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         this._reactionDisposer && this._reactionDisposer();
     }
 
+    onKeyDown = (e: KeyboardEvent) => {
+        if (e.ctrlKey && e.keyCode === KeyCodes.C) {
+            let text = this.selectionText;
+            text += `${Utils.GenerateDeterministicGuid("pdf paste")}/${this.props.Document[Id]}`;
+            navigator.clipboard.writeText(text);
+        }
+    }
+
     public GetPage() {
         return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.pdfHeight)) + 1;
     }
@@ -241,6 +254,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         let classname = "pdfBox-cont" + (this.props.active() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
         return (
             <div className={classname}
+                onKeyDown={this.onKeyDown}
                 onScroll={this.onScroll}
                 style={{
                     marginTop: `${NumCast(this.props.ContainingCollectionView!.props.Document.panY)}px`
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index c9d442fe5..c6bdb2af6 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -357,7 +357,8 @@ export default class Page extends React.Component<IPageProps> {
         else {
             let sel = window.getSelection();
             if (sel && sel.type === "Range") {
-                this.createTextAnnotation(sel);
+                let selRange = sel.getRangeAt(0);
+                this.createTextAnnotation(sel, selRange);
                 PDFMenu.Instance.jumpTo(e.clientX, e.clientY);
             }
         }
@@ -375,8 +376,8 @@ export default class Page extends React.Component<IPageProps> {
     }
 
     @action
-    createTextAnnotation = (sel: Selection) => {
-        let clientRects = sel.getRangeAt(0).getClientRects();
+    createTextAnnotation = (sel: Selection, selRange: Range) => {
+        let clientRects = selRange.getClientRects();
         if (this._textLayer.current) {
             let boundingRect = this._textLayer.current.getBoundingClientRect();
             for (let i = 0; i < clientRects.length; i++) {
@@ -393,6 +394,10 @@ export default class Page extends React.Component<IPageProps> {
                 }
             }
         }
+        let text = selRange.extractContents().textContent;
+        if (text) {
+            this.props.parent.selectionText = text;
+        }
         // clear selection
         if (sel.empty) {  // Chrome
             sel.empty();
-- 
cgit v1.2.3-70-g09d2


From 3661d710d153f6c9fb4b11d45f3b72afb493a5a1 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Sat, 27 Jul 2019 18:31:52 -0400
Subject: Made copying out of formatted text work better

---
 src/client/views/nodes/FormattedTextBox.tsx | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

(limited to 'src/client/views/nodes/FormattedTextBox.tsx')

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 5ac4af0bb..180fc1e2b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -5,7 +5,7 @@ import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
-import { NodeType } from 'prosemirror-model';
+import { NodeType, Slice } from 'prosemirror-model';
 import { EditorState, Plugin, Transaction } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { Doc, Opt } from "../../../new_fields/Doc";
@@ -251,6 +251,23 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         this.setupEditor(config, this.dataDoc, this.props.fieldKey);
     }
 
+    clipboardTextSerializer = (slice: Slice): string => {
+        let text = "", separated = true;
+        const from = 0, to = slice.content.size;
+        slice.content.nodesBetween(from, to, (node, pos) => {
+            if (node.isText) {
+                text += node.text!.slice(Math.max(from, pos) - pos, to - pos);
+                separated = false;
+            } else if (!separated && node.isBlock) {
+                text += "\n";
+                separated = true;
+            } else if (node.type.name === "hard_break") {
+                text += "\n";
+            }
+        }, 0);
+        return text;
+    }
+
     private setupEditor(config: any, doc: Doc, fieldKey: string) {
         let field = doc ? Cast(doc[fieldKey], RichTextField) : undefined;
         let startup = StrCast(doc.documentText);
@@ -270,7 +287,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 nodeViews: {
                     image(node, view, getPos) { return new ImageResizeView(node, view, getPos); },
                     star(node, view, getPos) { return new SummarizedView(node, view, getPos); }
-                }
+                },
+                clipboardTextSerializer: this.clipboardTextSerializer
             });
             if (startup) {
                 Doc.GetProto(doc).documentText = undefined;
-- 
cgit v1.2.3-70-g09d2


From 1dd24847a8dc2940bb53af3e42f715edec5f43b2 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Sat, 27 Jul 2019 20:10:45 -0400
Subject: Added paste handler to prose mirror

---
 src/client/views/nodes/FormattedTextBox.tsx | 39 ++++++++++++++++++++++++++---
 1 file changed, 36 insertions(+), 3 deletions(-)

(limited to 'src/client/views/nodes/FormattedTextBox.tsx')

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 180fc1e2b..d5f539194 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -5,7 +5,7 @@ import { observer } from "mobx-react";
 import { baseKeymap } from "prosemirror-commands";
 import { history } from "prosemirror-history";
 import { keymap } from "prosemirror-keymap";
-import { NodeType, Slice } from 'prosemirror-model';
+import { NodeType, Slice, Node, Fragment } from 'prosemirror-model';
 import { EditorState, Plugin, Transaction } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { Doc, Opt } from "../../../new_fields/Doc";
@@ -34,7 +34,6 @@ import { FieldView, FieldViewProps } from "./FieldView";
 import "./FormattedTextBox.scss";
 import React = require("react");
 import { DateField } from '../../../new_fields/DateField';
-import { thisExpression } from 'babel-types';
 import { Utils } from '../../../Utils';
 
 library.add(faEdit);
@@ -268,6 +267,39 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         return text;
     }
 
+    sliceSingleNode(slice: Slice) {
+        return slice.openStart === 0 && slice.openEnd === 0 && slice.content.childCount === 1 ? slice.content.firstChild : null;
+    }
+
+    handlePaste = (view: EditorView, event: Event, slice: Slice): boolean => {
+        return false;
+        function addMarkToFrag(frag: Fragment) {
+            const nodes: Node[] = [];
+            frag.forEach(node => nodes.push(addLinkMark(node)));
+            return Fragment.fromArray(nodes);
+        }
+        function addLinkMark(node: Node) {
+            if (!node.isText) {
+                const content = addMarkToFrag(node.content);
+                return node.copy(content);
+            }
+            const marks = [...node.marks];
+            const linkIndex = marks.findIndex(mark => mark.type.name === "link");
+            const link = view.state.schema.mark(view.state.schema.marks.link, { href: "http://localhost:1050/doc/[link document id]", location: "onRight" });
+            if (linkIndex !== -1) {
+                marks.splice(linkIndex, 1, link);
+            } else {
+                marks.push(link);
+            }
+            return node.mark(marks);
+        }
+        let frag = addMarkToFrag(slice.content);
+        slice = new Slice(frag, slice.openStart, slice.openEnd);
+        var tr = view.state.tr.replaceSelection(slice);
+        view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
+        return true;
+    }
+
     private setupEditor(config: any, doc: Doc, fieldKey: string) {
         let field = doc ? Cast(doc[fieldKey], RichTextField) : undefined;
         let startup = StrCast(doc.documentText);
@@ -288,7 +320,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                     image(node, view, getPos) { return new ImageResizeView(node, view, getPos); },
                     star(node, view, getPos) { return new SummarizedView(node, view, getPos); }
                 },
-                clipboardTextSerializer: this.clipboardTextSerializer
+                clipboardTextSerializer: this.clipboardTextSerializer,
+                handlePaste: this.handlePaste,
             });
             if (startup) {
                 Doc.GetProto(doc).documentText = undefined;
-- 
cgit v1.2.3-70-g09d2


From 92b848b79eaf90235fed550bc96b6ca982bd07df Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Sat, 27 Jul 2019 21:23:12 -0400
Subject: asdfkjlsdafds

---
 src/client/documents/Documents.ts           |  6 ++---
 src/client/views/nodes/FormattedTextBox.tsx | 38 +++++++++++++++++++++++------
 src/client/views/nodes/PDFBox.tsx           | 18 ++++++++------
 src/client/views/pdf/PDFViewer.tsx          | 29 +++++++++++++++++++---
 4 files changed, 70 insertions(+), 21 deletions(-)

(limited to 'src/client/views/nodes/FormattedTextBox.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index e6fe1b8b3..ee1b9fd0d 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -582,12 +582,12 @@ export namespace Docs {
 export namespace DocUtils {
 
     export function MakeLink(source: Doc, target: Doc, targetContext?: Doc, title: string = "", description: string = "", tags: string = "Default", sourceContext?: Doc) {
-        if (LinkManager.Instance.doesLinkExist(source, target)) return;
+        if (LinkManager.Instance.doesLinkExist(source, target)) return undefined;
         let sv = DocumentManager.Instance.getDocumentView(source);
         if (sv && sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === target) return;
-        if (target === CurrentUserUtils.UserDocument) return;
+        if (target === CurrentUserUtils.UserDocument) return undefined;
 
-        let linkDoc;
+        let linkDoc: Doc | undefined;
         UndoManager.RunInBatch(() => {
             linkDoc = Docs.Create.TextDocument({ width: 100, height: 30, borderRounding: "100%" });
             linkDoc.type = DocumentType.LINK;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index e982cdfdd..364dc1c83 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -15,7 +15,7 @@ import { RichTextField } from "../../../new_fields/RichTextField";
 import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
 import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types";
 import { DocServer } from "../../DocServer";
-import { Docs } from '../../documents/Documents';
+import { Docs, DocUtils } from '../../documents/Documents';
 import { DocumentManager } from '../../util/DocumentManager';
 import { DragManager } from "../../util/DragManager";
 import buildKeymap from "../../util/ProsemirrorExampleTransfer";
@@ -300,7 +300,34 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
 
     handlePaste = (view: EditorView, event: Event, slice: Slice): boolean => {
-        return false;
+        let cbe = event as ClipboardEvent;
+        let docId: string;
+        if (!cbe.clipboardData) {
+            return false;
+        }
+        let linkId: string;
+        docId = cbe.clipboardData.getData("dash/pdfOrigin");
+        if (!docId) {
+            return false;
+        }
+
+        DocServer.GetRefField(docId).then(doc => {
+            if (!(doc instanceof Doc)) {
+                return;
+            }
+            let link = DocUtils.MakeLink(this.props.Document, doc);
+            if (link) {
+                cbe.clipboardData!.setData("dash/linkDoc", link[Id]);
+                linkId = link[Id];
+                let frag = addMarkToFrag(slice.content);
+                slice = new Slice(frag, slice.openStart, slice.openEnd);
+                var tr = view.state.tr.replaceSelection(slice);
+                view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
+            }
+        });
+
+        return true;
+
         function addMarkToFrag(frag: Fragment) {
             const nodes: Node[] = [];
             frag.forEach(node => nodes.push(addLinkMark(node)));
@@ -313,7 +340,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             }
             const marks = [...node.marks];
             const linkIndex = marks.findIndex(mark => mark.type.name === "link");
-            const link = view.state.schema.mark(view.state.schema.marks.link, { href: "http://localhost:1050/doc/[link document id]", location: "onRight" });
+            const link = view.state.schema.mark(view.state.schema.marks.link, { href: `http://localhost:1050/doc/${linkId}`, location: "onRight" });
             if (linkIndex !== -1) {
                 marks.splice(linkIndex, 1, link);
             } else {
@@ -321,11 +348,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             }
             return node.mark(marks);
         }
-        let frag = addMarkToFrag(slice.content);
-        slice = new Slice(frag, slice.openStart, slice.openEnd);
-        var tr = view.state.tr.replaceSelection(slice);
-        view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
-        return true;
     }
 
     private setupEditor(config: any, doc: Doc, fieldKey: string) {
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 282312dca..72d835fce 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -66,23 +66,28 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         this._keyRef = React.createRef();
         this._valueRef = React.createRef();
         this._scriptRef = React.createRef();
-
-        document.addEventListener("keydown", this.onKeyDown);
     }
 
     componentDidMount() {
         if (this.props.setPdfBox) this.props.setPdfBox(this);
+
+        document.removeEventListener("copy", this.copy);
+        document.addEventListener("copy", this.copy);
     }
 
     componentWillUnmount() {
         this._reactionDisposer && this._reactionDisposer();
+        document.removeEventListener("copy", this.copy);
     }
 
-    onKeyDown = (e: KeyboardEvent) => {
-        if (e.ctrlKey && e.keyCode === KeyCodes.C) {
+    private copy = (e: ClipboardEvent) => {
+        if (this.props.active()) {
             let text = this.selectionText;
-            text += `${Utils.GenerateDeterministicGuid("pdf paste")}/${this.props.Document[Id]}`;
-            navigator.clipboard.writeText(text);
+            if (e.clipboardData) {
+                e.clipboardData.setData("text/plain", text);
+                e.clipboardData.setData("dash/pdfOrigin", this.props.Document[Id]);
+                e.preventDefault();
+            }
         }
     }
 
@@ -254,7 +259,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         let classname = "pdfBox-cont" + (this.props.active() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
         return (
             <div className={classname}
-                onKeyDown={this.onKeyDown}
                 onScroll={this.onScroll}
                 style={{
                     marginTop: `${NumCast(this.props.ContainingCollectionView!.props.Document.panY)}px`
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index b7ded7e06..db2d49f0f 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -20,6 +20,7 @@ import { ScriptField } from "../../../new_fields/ScriptField";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import Annotation from "./Annotation";
 import { KeyCodes } from "../../northstar/utils/KeyCodes";
+import { DocServer } from "../../DocServer";
 const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
 
 export const scale = 2;
@@ -156,6 +157,9 @@ export class Viewer extends React.Component<IViewerProps> {
         if (this._mainCont.current) {
             this._dropDisposer = this._mainCont.current && DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } });
         }
+
+        document.removeEventListener("paste", this.paste);
+        document.addEventListener("paste", this.paste);
     }
 
     componentWillUnmount = () => {
@@ -163,6 +167,25 @@ export class Viewer extends React.Component<IViewerProps> {
         this._annotationReactionDisposer && this._annotationReactionDisposer();
         this._filterReactionDisposer && this._filterReactionDisposer();
         this._dropDisposer && this._dropDisposer();
+        document.removeEventListener("paste", this.paste);
+    }
+
+    paste = (e: ClipboardEvent) => {
+        if (e.clipboardData) {
+            if (e.clipboardData.getData("dash/pdfOrigin") === this.props.parent.props.Document[Id]) {
+                let linkDocId = e.clipboardData.getData("dash/linkDoc");
+                if (linkDocId) {
+                    DocServer.GetRefField(linkDocId).then(async (link) => {
+                        if (!(link instanceof Doc)) {
+                            return;
+                        }
+                        let proto = Doc.GetProto(link);
+                        let source = await Cast(proto.anchor1, Doc);
+                        proto.anchor2 = this.makeAnnotationDocument(source, 0, "#0390fc", false);
+                    });
+                }
+            }
+        }
     }
 
     scrollTo(y: number) {
@@ -213,7 +236,7 @@ export class Viewer extends React.Component<IViewerProps> {
     }
 
     @action
-    makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string): Doc => {
+    makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string, createLink: boolean = true): Doc => {
         let annoDocs: Doc[] = [];
         let mainAnnoDoc = Docs.Create.InstanceFromProto(new Doc(), "", {});
 
@@ -242,7 +265,7 @@ export class Viewer extends React.Component<IViewerProps> {
 
         mainAnnoDoc.y = Math.max(minY, 0);
         mainAnnoDoc.annotations = new List<Doc>(annoDocs);
-        if (sourceDoc) {
+        if (sourceDoc && createLink) {
             DocUtils.MakeLink(sourceDoc, mainAnnoDoc, undefined, `Annotation from ${StrCast(this.props.parent.Document.title)}`, "", StrCast(this.props.parent.Document.title));
         }
         this._savedAnnotations.clear();
@@ -611,7 +634,7 @@ export class Viewer extends React.Component<IViewerProps> {
                 <div className="viewer" style={this._searching ? { position: "absolute", top: 0 } : {}}>
                     {this._visibleElements}
                 </div>
-                <div className="pdfViewer-text" ref={this._viewer} style={{ transform: "scale(1.5)", transformOrigin: "top left" }} />
+                <div className="pdfViewer-text" ref={this._viewer} onCopy={() => console.log("gello world")} style={{ transform: "scale(1.5)", transformOrigin: "top left" }} />
                 <div className="pdfViewer-annotationLayer"
                     style={{
                         height: this.props.parent.Document.nativeHeight, width: `100%`,
-- 
cgit v1.2.3-70-g09d2


From 160ca6c2673b96b8cfe9dfd5bd887a3637a1a45f Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Sat, 27 Jul 2019 22:58:01 -0400
Subject: finisheddd

---
 src/client/views/nodes/FormattedTextBox.tsx | 42 +++++++++++++++++++----------
 src/client/views/nodes/PDFBox.tsx           |  2 --
 src/client/views/pdf/PDFViewer.tsx          | 30 ++++++++++++++++++---
 src/client/views/pdf/Page.tsx               |  3 ++-
 4 files changed, 56 insertions(+), 21 deletions(-)

(limited to 'src/client/views/nodes/FormattedTextBox.tsx')

diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 364dc1c83..f019868aa 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -8,7 +8,7 @@ import { keymap } from "prosemirror-keymap";
 import { EditorState, Plugin, Transaction, Selection } from "prosemirror-state";
 import { NodeType, Slice, Node, Fragment } from 'prosemirror-model';
 import { EditorView } from "prosemirror-view";
-import { Doc, Opt } from "../../../new_fields/Doc";
+import { Doc, Opt, DocListCast } from "../../../new_fields/Doc";
 import { Id, Copy } from '../../../new_fields/FieldSymbols';
 import { List } from '../../../new_fields/List';
 import { RichTextField } from "../../../new_fields/RichTextField";
@@ -302,28 +302,42 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     handlePaste = (view: EditorView, event: Event, slice: Slice): boolean => {
         let cbe = event as ClipboardEvent;
         let docId: string;
+        let regionId: string;
         if (!cbe.clipboardData) {
             return false;
         }
         let linkId: string;
         docId = cbe.clipboardData.getData("dash/pdfOrigin");
-        if (!docId) {
+        regionId = cbe.clipboardData.getData("dash/pdfRegion");
+        if (!docId || !regionId) {
             return false;
         }
 
         DocServer.GetRefField(docId).then(doc => {
-            if (!(doc instanceof Doc)) {
-                return;
-            }
-            let link = DocUtils.MakeLink(this.props.Document, doc);
-            if (link) {
-                cbe.clipboardData!.setData("dash/linkDoc", link[Id]);
-                linkId = link[Id];
-                let frag = addMarkToFrag(slice.content);
-                slice = new Slice(frag, slice.openStart, slice.openEnd);
-                var tr = view.state.tr.replaceSelection(slice);
-                view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
-            }
+            DocServer.GetRefField(regionId).then(region => {
+                if (!(doc instanceof Doc) || !(region instanceof Doc)) {
+                    return;
+                }
+
+                let annotations = DocListCast(region.annotations);
+                annotations.forEach(anno => anno.target = this.props.Document);
+                let fieldExtDoc = Doc.resolvedFieldDataDoc(doc, "data", "true");
+                let targetAnnotations = DocListCast(fieldExtDoc.annotations);
+                if (targetAnnotations) {
+                    targetAnnotations.push(region);
+                    fieldExtDoc.annotations = new List<Doc>(targetAnnotations);
+                }
+
+                let link = DocUtils.MakeLink(this.props.Document, region);
+                if (link) {
+                    cbe.clipboardData!.setData("dash/linkDoc", link[Id]);
+                    linkId = link[Id];
+                    let frag = addMarkToFrag(slice.content);
+                    slice = new Slice(frag, slice.openStart, slice.openEnd);
+                    var tr = view.state.tr.replaceSelection(slice);
+                    view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
+                }
+            });
         });
 
         return true;
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 72d835fce..f527c0595 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -34,7 +34,6 @@ export const handleBackspace = (e: React.KeyboardEvent) => { if (e.keyCode === K
 @observer
 export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocument) {
     public static LayoutString() { return FieldView.LayoutString(PDFBox); }
-    public selectionText: string = "";
 
     @observable private _alt = false;
     @observable private _scrollY: number = 0;
@@ -82,7 +81,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
 
     private copy = (e: ClipboardEvent) => {
         if (this.props.active()) {
-            let text = this.selectionText;
             if (e.clipboardData) {
                 e.clipboardData.setData("text/plain", text);
                 e.clipboardData.setData("dash/pdfOrigin", this.props.Document[Id]);
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index db2d49f0f..6fef8a4de 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -92,6 +92,7 @@ export class Viewer extends React.Component<IViewerProps> {
     // private _textContent: Pdfjs.TextContent[] = [];
     private _pdfFindController: any;
     private _searchString: string = "";
+    private _selectionText: string = "";
 
     constructor(props: IViewerProps) {
         super(props);
@@ -102,6 +103,10 @@ export class Viewer extends React.Component<IViewerProps> {
         this._mainCont = React.createRef();
     }
 
+    setSelectionText = (text: string) => {
+        this._selectionText = text;
+    }
+
     componentDidUpdate = (prevProps: IViewerProps) => {
         if (this.scrollY !== prevProps.scrollY) {
             this.renderPages();
@@ -158,8 +163,8 @@ export class Viewer extends React.Component<IViewerProps> {
             this._dropDisposer = this._mainCont.current && DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } });
         }
 
-        document.removeEventListener("paste", this.paste);
-        document.addEventListener("paste", this.paste);
+        document.removeEventListener("copy", this.copy);
+        document.addEventListener("copy", this.copy);
     }
 
     componentWillUnmount = () => {
@@ -167,7 +172,24 @@ export class Viewer extends React.Component<IViewerProps> {
         this._annotationReactionDisposer && this._annotationReactionDisposer();
         this._filterReactionDisposer && this._filterReactionDisposer();
         this._dropDisposer && this._dropDisposer();
-        document.removeEventListener("paste", this.paste);
+        document.removeEventListener("copy", this.copy);
+    }
+
+    private copy = (e: ClipboardEvent) => {
+        if (this.props.parent.props.active()) {
+            let text = this._selectionText;
+            if (e.clipboardData) {
+                e.clipboardData.setData("text/plain", text);
+                e.clipboardData.setData("dash/pdfOrigin", this.props.parent.props.Document[Id]);
+                let annoDoc = this.makeAnnotationDocument(undefined, 0, "#0390fc");
+                e.clipboardData.setData("dash/pdfRegion", annoDoc[Id]);
+                e.preventDefault();
+            }
+        }
+        // let targetAnnotations = DocListCast(this.props.parent.fieldExtensionDoc.annotations);
+        // if (targetAnnotations) {
+        //     targetAnnotations.push(destDoc);
+        // }
     }
 
     paste = (e: ClipboardEvent) => {
@@ -281,7 +303,6 @@ export class Viewer extends React.Component<IViewerProps> {
             let targetAnnotations = DocListCast(this.props.parent.fieldExtensionDoc.annotations);
             if (targetAnnotations) {
                 targetAnnotations.push(destDoc);
-                this.props.parent.fieldExtensionDoc.annotations = new List<Doc>(targetAnnotations);
             }
             else {
                 this.props.parent.fieldExtensionDoc.annotations = new List<Doc>([destDoc]);
@@ -315,6 +336,7 @@ export class Viewer extends React.Component<IViewerProps> {
             this._isPage[page] = "page";
             this._visibleElements[page] = (
                 <Page
+                    setSelectionText={this.setSelectionText}
                     size={this._pageSizes[page]}
                     pdf={this.props.pdf}
                     page={page}
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 989a53ec9..c205617b4 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -29,6 +29,7 @@ interface IPageProps {
     createAnnotation: (div: HTMLDivElement, page: number) => void;
     makeAnnotationDocuments: (doc: Doc | undefined, scale: number, color: string, linkTo: boolean) => Doc;
     getScrollFromPage: (page: number) => number;
+    setSelectionText: (text: string) => void;
 }
 
 @observer
@@ -392,7 +393,7 @@ export default class Page extends React.Component<IPageProps> {
         }
         let text = selRange.extractContents().textContent;
         if (text) {
-            this.props.parent.selectionText = text;
+            this.props.setSelectionText(text);
         }
         // clear selection
         if (sel.empty) {  // Chrome
-- 
cgit v1.2.3-70-g09d2

