From 0a6c03f109254e36556482e75fa5fb14491d1626 Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Thu, 13 Jun 2019 12:03:39 -0400
Subject: demo

---
 src/client/util/TooltipTextMenu.tsx | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index e12d4ed3c..7d4d5566c 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -234,19 +234,16 @@ export class TooltipTextMenu {
             this.linkEditor.appendChild(linkBtn);
             this.tooltip.appendChild(this.linkEditor);
 
+            // SUMMARIZE BUTTON
+
             let starButton = document.createElement("span");
-            // starButton.style.width = '10px';
-            // starButton.style.height = '10px';
-            starButton.style.marginLeft = '10px';
-            starButton.textContent = "Summarize";
-            starButton.style.color = 'black';
-            starButton.style.height = '20px';
-            starButton.style.backgroundColor = 'white';
-            starButton.style.textAlign = 'center';
+            starButton.className = "summarize";
+            starButton.textContent = "★";
+            starButton.title = 'Summarize';
             starButton.onclick = () => {
                 let state = this.view.state;
                 this.insertStar(state, this.view.dispatch);
-            }
+            };
 
             this.tooltip.appendChild(starButton);
         }
-- 
cgit v1.2.3-70-g09d2


From 552e7b558f6627d91471ca1ee33d3505a94a3a86 Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Thu, 13 Jun 2019 16:07:03 -0400
Subject: highlighting

---
 src/client/util/RichTextSchema.tsx   | 18 ++++++++++++++----
 src/client/util/TooltipTextMenu.scss |  8 ++++----
 src/client/util/TooltipTextMenu.tsx  |  6 +++---
 3 files changed, 21 insertions(+), 11 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index c0225f1f9..789f3e0cf 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -5,6 +5,7 @@ import { redo, undo } from 'prosemirror-history';
 import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list';
 import { EditorState, Transaction, NodeSelection, TextSelection, Selection, } from "prosemirror-state";
 import { EditorView, } from "prosemirror-view";
+import { View } from '@react-pdf/renderer';
 
 const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
     preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
@@ -254,11 +255,11 @@ export const marks: { [index: string]: MarkSpec } = {
         toDOM: () => ['sup']
     },
 
-    collapse: {
-        parseDOM: [{ style: 'color: blue' }],
+    highlight: {
+        parseDOM: [{ style: 'background: #9aa8a4' }],
         toDOM() {
             return ['span', {
-                style: 'color: blue'
+                style: 'background: #9aa8a4'
             }];
         }
     },
@@ -453,6 +454,7 @@ export class ImageResizeView {
 export class SummarizedView {
     // TODO: highlight text that is summarized. to find end of region, walk along mark
     _collapsed: HTMLElement;
+    _view: any;
     constructor(node: any, view: any, getPos: any) {
         this._collapsed = document.createElement("span");
         this._collapsed.textContent = "㊉";
@@ -462,6 +464,7 @@ export class SummarizedView {
         this._collapsed.style.width = "40px";
         this._collapsed.style.height = "20px";
         let self = this;
+        this._view = view;
         this._collapsed.onpointerdown = function (e: any) {
             console.log("star pressed!");
             if (node.attrs.visibility) {
@@ -471,17 +474,19 @@ export class SummarizedView {
                 view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1 + node.attrs.oldtextlen)));
                 view.dispatch(view.state.tr.deleteSelection(view.state, () => { }));
                 self._collapsed.textContent = "㊉";
+                self.updateSummarizedText();
             } else {
                 node.attrs.visibility = !node.attrs.visibility;
                 console.log("content is invisible");
                 let y = getPos();
                 console.log(y);
-                let mark = view.state.schema.mark(view.state.schema.marks.underline);
+                let mark = view.state.schema.mark(view.state.schema.marks.highlight);
                 console.log("PASTING " + node.attrs.oldtext.toString());
                 view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1)));
                 const from = view.state.selection.from;
                 view.dispatch(view.state.tr.replaceSelection(node.attrs.oldtext).addMark(from, from + node.attrs.oldtextlen, mark));
                 //view.dispatch(view.state.tr.setSelection(view.state.doc, from + node.attrs.oldtextlen + 1, from + node.attrs.oldtextlen + 1));
+                view.dispatch(view.state.tr.removeStoredMark(mark));
                 self._collapsed.textContent = "㊀";
             }
             e.preventDefault();
@@ -493,6 +498,11 @@ export class SummarizedView {
     selectNode() {
     }
 
+    updateSummarizedText(mark?: any) {
+        console.log(this._view.state.doc.marks);
+        console.log(this._view.state.doc.childCount);
+    }
+
     deselectNode() {
     }
 }
diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss
index af449071e..676411535 100644
--- a/src/client/util/TooltipTextMenu.scss
+++ b/src/client/util/TooltipTextMenu.scss
@@ -235,7 +235,7 @@
 .tooltipMenu {
     position: absolute;
     z-index: 50;
-    background: whitesmoke;
+    background: black;
     border: 1px solid silver;
     border-radius: 15px;
     padding: 2px 10px;
@@ -308,8 +308,8 @@
   }
   .summarize{
       margin-left: 15px;
-      color: black;
+      color: white;
       height: 20px;
-      background-color: white;
+    //   background-color: white;
       text-align: center;
-  }
+  }
\ No newline at end of file
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 7d4d5566c..f3f27335f 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -179,13 +179,13 @@ export class TooltipTextMenu {
             this.linkText.style.whiteSpace = "nowrap";
             this.linkText.style.width = "150px";
             this.linkText.style.overflow = "hidden";
-            this.linkText.style.color = "black";
+            this.linkText.style.color = "white";
             this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); };
             let linkBtn = document.createElement("div");
             linkBtn.textContent = ">>";
             linkBtn.style.width = "10px";
             linkBtn.style.height = "10px";
-            linkBtn.style.color = "black";
+            linkBtn.style.color = "white";
             linkBtn.style.cssFloat = "left";
             linkBtn.onpointerdown = (e: PointerEvent) => {
                 let node = this.view.state.selection.$from.nodeAfter;
@@ -382,7 +382,7 @@ export class TooltipTextMenu {
         span.className = name + " menuicon";
         span.title = title;
         span.textContent = text;
-        span.style.color = "black";
+        span.style.color = "white";
         return span;
     }
 
-- 
cgit v1.2.3-70-g09d2


From c22feda3d2df8f6814c0837ea18ad293975ae2e4 Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Fri, 14 Jun 2019 17:20:46 -0400
Subject: f this

---
 src/client/util/RichTextSchema.tsx   | 41 +++++++++++++++++++++++++-----------
 src/client/util/TooltipTextMenu.scss |  2 +-
 src/client/util/TooltipTextMenu.tsx  |  4 ++--
 3 files changed, 32 insertions(+), 15 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 789f3e0cf..8c56a32e8 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType, Slice } from "prosemirror-model";
+import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType, Slice, Mark } from "prosemirror-model";
 import { joinUp, lift, setBlockType, toggleMark, wrapIn, selectNodeForward, deleteSelection } from 'prosemirror-commands';
 import { redo, undo } from 'prosemirror-history';
 import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list';
@@ -90,7 +90,7 @@ export const nodes: { [index: string]: NodeSpec } = {
         inline: true,
         attrs: {
             visibility: { default: false },
-            oldtext: { default: undefined },
+            text: { default: undefined },
             oldtextslice: { default: undefined },
             oldtextlen: { default: 0 }
 
@@ -256,10 +256,10 @@ export const marks: { [index: string]: MarkSpec } = {
     },
 
     highlight: {
-        parseDOM: [{ style: 'background: #9aa8a4' }],
+        parseDOM: [{ style: 'background: #d9dbdd' }],
         toDOM() {
             return ['span', {
-                style: 'background: #9aa8a4'
+                style: 'background: #d9dbdd'
             }];
         }
     },
@@ -471,20 +471,23 @@ export class SummarizedView {
                 node.attrs.visibility = !node.attrs.visibility;
                 console.log("content is visible");
                 let y = getPos();
-                view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1 + node.attrs.oldtextlen)));
+                let { from, to } = self.updateSummarizedText(y + 1, view.state.schema.marks.highlight);
+                let length = to - from;
+                let newSelection = TextSelection.create(view.state.doc, y + 1, y + 1 + length);
+                node.attrs.text = newSelection.content();
+                view.dispatch(view.state.tr.setSelection(newSelection));
                 view.dispatch(view.state.tr.deleteSelection(view.state, () => { }));
                 self._collapsed.textContent = "㊉";
-                self.updateSummarizedText();
             } else {
                 node.attrs.visibility = !node.attrs.visibility;
                 console.log("content is invisible");
                 let y = getPos();
                 console.log(y);
                 let mark = view.state.schema.mark(view.state.schema.marks.highlight);
-                console.log("PASTING " + node.attrs.oldtext.toString());
+                console.log("PASTING " + node.attrs.text.toString());
                 view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1)));
                 const from = view.state.selection.from;
-                view.dispatch(view.state.tr.replaceSelection(node.attrs.oldtext).addMark(from, from + node.attrs.oldtextlen, mark));
+                view.dispatch(view.state.tr.replaceSelection(node.attrs.text).addMark(from, from + node.attrs.oldtextlen, mark));
                 //view.dispatch(view.state.tr.setSelection(view.state.doc, from + node.attrs.oldtextlen + 1, from + node.attrs.oldtextlen + 1));
                 view.dispatch(view.state.tr.removeStoredMark(mark));
                 self._collapsed.textContent = "㊀";
@@ -498,9 +501,23 @@ export class SummarizedView {
     selectNode() {
     }
 
-    updateSummarizedText(mark?: any) {
-        console.log(this._view.state.doc.marks);
-        console.log(this._view.state.doc.childCount);
+    updateSummarizedText(start?: any, mark?: any) {
+        let $start = this._view.state.doc.resolve(start);
+        let first_startPos = $start.start(), endPos = first_startPos;
+        while ($start.nodeAfter !== null) {
+            let startIndex = $start.index(), endIndex = $start.indexAfter();
+            while (startIndex > 0 && mark.isInSet($start.parent.child(startIndex - 1).marks)) startIndex--;
+            while (endIndex < $start.parent.childCount && mark.isInSet($start.parent.child(endIndex).marks)) endIndex++;
+            let startPos = $start.start(), endPos = startPos;
+            for (let i = 0; i < endIndex; i++) {
+                let size = $start.parent.child(i).nodeSize;
+                console.log($start.parent.child(i).childCount);
+                if (i < startIndex) startPos += size;
+                endPos += size;
+            }
+            $start = this._view.state.doc.resolve(start + (endPos - startPos) + 1);
+        }
+        return { from: first_startPos, to: endPos };
     }
 
     deselectNode() {
@@ -524,4 +541,4 @@ schema.nodeFromJSON = (json: any) => {
         node.attrs.oldtext = Slice.fromJSON(schema, node.attrs.oldtextslice);
     }
     return node;
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss
index 676411535..c10a61558 100644
--- a/src/client/util/TooltipTextMenu.scss
+++ b/src/client/util/TooltipTextMenu.scss
@@ -235,7 +235,7 @@
 .tooltipMenu {
     position: absolute;
     z-index: 50;
-    background: black;
+    background: #121721;
     border: 1px solid silver;
     border-radius: 15px;
     padding: 2px 10px;
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index f3f27335f..b8ca299dd 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -273,9 +273,9 @@ export class TooltipTextMenu {
 
     insertStar(state: EditorState<any>, dispatch: any) {
         console.log("creating star...");
-        let newNode = schema.nodes.star.create({ visibility: false, oldtext: state.selection.content(), oldtextslice: state.selection.content().toJSON(), oldtextlen: state.selection.to - state.selection.from });
+        let newNode = schema.nodes.star.create({ visibility: false, text: state.selection.content(), oldtextslice: state.selection.content().toJSON(), oldtextlen: state.selection.to - state.selection.from });
         if (dispatch) {
-            console.log(newNode.attrs.oldtext.toString());
+            console.log(newNode.attrs.text.toString());
             dispatch(state.tr.replaceSelectionWith(newNode));
         }
         return true;
-- 
cgit v1.2.3-70-g09d2


From 218c8b6476621ef0ffe151014f77bb1d506705a3 Mon Sep 17 00:00:00 2001
From: madelinegr <mgriswold99@gmail.com>
Date: Fri, 14 Jun 2019 18:24:01 -0400
Subject: Zooming added to presentation, and done

---
 src/client/util/DocumentManager.ts                 | 31 +++++++-
 src/client/util/TooltipTextMenu.tsx                |  2 +-
 src/client/views/MainOverlayTextBox.tsx            |  2 +-
 src/client/views/MainView.tsx                      |  5 +-
 src/client/views/SearchItem.tsx                    |  2 +-
 .../views/collections/CollectionDockingView.tsx    |  6 +-
 .../views/collections/CollectionSchemaView.tsx     |  4 +-
 .../views/collections/CollectionStackingView.tsx   |  2 +
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 31 +++++---
 src/client/views/nodes/DocumentView.tsx            | 10 ++-
 src/client/views/nodes/FieldView.tsx               |  5 +-
 .../views/presentationview/PresentationElement.tsx | 31 +++++++-
 .../views/presentationview/PresentationView.tsx    | 93 +++++++++++++++++++---
 14 files changed, 184 insertions(+), 42 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 65c4b9e4b..a613625cb 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,4 +1,4 @@
-import { computed, observable } from 'mobx';
+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 } from '../../new_fields/Types';
@@ -115,7 +115,7 @@ export class DocumentManager {
     }
 
     @undoBatch
-    public jumpToDocument = async (docDelegate: Doc, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void, linkPage?: number): Promise<void> => {
+    public jumpToDocument = async (docDelegate: Doc, willZoom: boolean, forceDockFunc: boolean = false, dockFunc?: (doc: Doc) => void, linkPage?: number): Promise<void> => {
         let doc = Doc.GetProto(docDelegate);
         const contextDoc = await Cast(doc.annotationOn, Doc);
         if (contextDoc) {
@@ -128,7 +128,7 @@ export class DocumentManager {
         if (!forceDockFunc && (docView = DocumentManager.Instance.getDocumentView(doc))) {
             docView.props.Document.libraryBrush = true;
             if (linkPage !== undefined) docView.props.Document.curPage = linkPage;
-            docView.props.focus(docView.props.Document);
+            docView.props.focus(docView.props.Document, willZoom);
         } else {
             if (!contextDoc) {
                 const actualDoc = Doc.MakeAlias(docDelegate);
@@ -140,11 +140,34 @@ export class DocumentManager {
                 docDelegate.libraryBrush = true;
                 if (!forceDockFunc && (contextView = DocumentManager.Instance.getDocumentView(contextDoc))) {
                     contextDoc.panTransformType = "Ease";
-                    contextView.props.focus(contextDoc);
+                    contextView.props.focus(contextDoc, willZoom);
                 } else {
                     (dockFunc || CollectionDockingView.Instance.AddRightSplit)(contextDoc);
                 }
             }
         }
     }
+
+    @action
+    zoomIntoScale = (docDelegate: Doc, scale: number) => {
+        let doc = Doc.GetProto(docDelegate);
+
+        let docView: DocumentView | null;
+        docView = DocumentManager.Instance.getDocumentView(doc);
+        if (docView) {
+            docView.props.zoomToScale(scale);
+        }
+    }
+
+    getScaleOfDocView = (docDelegate: Doc) => {
+        let doc = Doc.GetProto(docDelegate);
+
+        let docView: DocumentView | null;
+        docView = DocumentManager.Instance.getDocumentView(doc);
+        if (docView) {
+            return docView.props.getScale();
+        } else {
+            return 1;
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index f517f757a..34785446b 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -192,7 +192,7 @@ export class TooltipTextMenu {
                         DocServer.GetRefField(docid).then(action((f: Opt<Field>) => {
                             if (f instanceof Doc) {
                                 if (DocumentManager.Instance.getDocumentView(f)) {
-                                    DocumentManager.Instance.getDocumentView(f)!.props.focus(f);
+                                    DocumentManager.Instance.getDocumentView(f)!.props.focus(f, false);
                                 }
                                 else if (CollectionDockingView.Instance) CollectionDockingView.Instance.AddRightSplit(f);
                             }
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 24327b995..d1224febe 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -102,6 +102,6 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
                 </div>
             </ div>;
         }
-        else return (null); Z
+        else return (null);
     }
 }
\ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 3d772916e..f78879efe 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -199,7 +199,10 @@ export class MainView extends React.Component {
                 parentActive={returnTrue}
                 whenActiveChanged={emptyFunction}
                 bringToFront={emptyFunction}
-                ContainingCollectionView={undefined} />;
+                ContainingCollectionView={undefined}
+                zoomToScale={emptyFunction}
+                getScale={returnOne}
+            />;
         let castRes = mainCont ? FieldValue(Cast(mainCont.presentationView, Doc)) : undefined;
         console.log("GETTING mainContent()");
         console.log(castRes instanceof Promise);
diff --git a/src/client/views/SearchItem.tsx b/src/client/views/SearchItem.tsx
index 01c7316d6..101d893de 100644
--- a/src/client/views/SearchItem.tsx
+++ b/src/client/views/SearchItem.tsx
@@ -24,7 +24,7 @@ library.add(faFilm);
 export class SearchItem extends React.Component<SearchProps> {
 
     onClick = () => {
-        DocumentManager.Instance.jumpToDocument(this.props.doc);
+        DocumentManager.Instance.jumpToDocument(this.props.doc, false);
     }
 
     //needs help
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index dcc1bd95d..81f574a6c 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -9,7 +9,7 @@ import { Doc, Field, Opt, DocListCast } from "../../../new_fields/Doc";
 import { FieldId } from "../../../new_fields/RefField";
 import { listSpec } from "../../../new_fields/Schema";
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
-import { emptyFunction, returnTrue, Utils } from "../../../Utils";
+import { emptyFunction, returnTrue, Utils, returnOne } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { DragLinksAsDocuments, DragManager } from "../../util/DragManager";
 import { Transform } from '../../util/Transform';
@@ -483,7 +483,9 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
                     whenActiveChanged={emptyFunction}
                     focus={emptyFunction}
                     addDocTab={this.addDocTab}
-                    ContainingCollectionView={undefined} />
+                    ContainingCollectionView={undefined}
+                    zoomToScale={emptyFunction}
+                    getScale={returnOne} />
             </div >);
     }
 
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 11d71d023..715faafd0 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -7,7 +7,7 @@ import { observer } from "mobx-react";
 import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table";
 import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss';
 import "react-table/react-table.css";
-import { emptyFunction, returnFalse, returnZero } from "../../../Utils";
+import { emptyFunction, returnFalse, returnZero, returnOne } from "../../../Utils";
 import { SetupDrag } from "../../util/DragManager";
 import { CompileScript } from "../../util/Scripting";
 import { Transform } from "../../util/Transform";
@@ -451,6 +451,8 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
                         bringToFront={emptyFunction}
                         addDocTab={this.props.addDocTab}
                         collapseToPoint={this.collapseToPoint}
+                        zoomToScale={emptyFunction}
+                        getScale={returnOne}
                     />
                 </div>)}
             {input}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index da7ea50c6..e1453c658 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -146,6 +146,8 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                     bringToFront={emptyFunction}
                     whenActiveChanged={this.props.whenActiveChanged}
                     collapseToPoint={this.collapseToPoint}
+                    zoomToScale={emptyFunction}
+                    getScale={returnOne}
                 />
             </div>);
         })
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 2814c0502..c80bd8fce 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -147,7 +147,7 @@ class TreeView extends React.Component<TreeViewProps> {
                 ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, "inTab"), icon: "folder" });
                 ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, "onRight"), icon: "caret-square-right" });
                 if (DocumentManager.Instance.getDocumentViews(this.props.document).length) {
-                    ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.props.document).map(view => view.props.focus(this.props.document)) });
+                    ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.props.document).map(view => view.props.focus(this.props.document, false)) });
                 }
                 ContextMenu.Instance.addItem({ description: "Delete Item", event: undoBatch(() => this.props.deleteDoc(this.props.document)) });
             } else {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 5d26cb0c2..419d95b5f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -244,7 +244,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         doc.zIndex = docs.length + 1;
     }
 
-    focusDocument = (doc: Doc) => {
+    focusDocument = (doc: Doc, willZoom: boolean) => {
         const panX = this.Document.panX;
         const panY = this.Document.panY;
         const id = this.Document[Id];
@@ -271,9 +271,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         newState.initializers[id] = { panX: newPanX, panY: newPanY };
         HistoryUtil.pushState(newState);
         this.setPan(newPanX, newPanY);
+
         this.props.Document.panTransformType = "Ease";
         this.props.focus(this.props.Document);
-        //this.setScaleToZoom(doc);
+        if (willZoom) {
+            this.setScaleToZoom(doc);
+        }
 
     }
 
@@ -281,21 +284,29 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         let p = this.props;
         let PanelHeight = p.PanelHeight();
         let panelWidth = p.PanelWidth();
-        // let heightDif: number = PanelHeight - NumCast(doc.height);
-        // let widthDif: number = panelWidth - NumCast(doc.width);
+
         let docHeight = NumCast(doc.height);
         let docWidth = NumCast(doc.width);
-        let targetHeight = 0.8 * PanelHeight;
-        let targetWidth = 0.8 * panelWidth;
+        let targetHeight = 0.5 * PanelHeight;
+        let targetWidth = 0.5 * panelWidth;
 
         let maxScaleX: number = targetWidth / docWidth;
         let maxScaleY: number = targetHeight / docHeight;
-        // let maxScaleX: number = NumCast(doc.width) / (panelWidth - 10);
-        // let maxScaleY: number = NumCast(doc.height) / (PanelHeight - 10);
         let maxApplicableScale = Math.min(maxScaleX, maxScaleY);
         this.Document.scale = maxApplicableScale;
     }
 
+    zoomToScale = (scale: number) => {
+        this.Document.scale = scale;
+    }
+
+    getScale = () => {
+        if (this.Document.scale) {
+            return this.Document.scale;
+        }
+        return 1;
+    }
+
 
     getDocumentViewProps(document: Doc): DocumentViewProps {
         return {
@@ -315,6 +326,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             whenActiveChanged: this.props.whenActiveChanged,
             bringToFront: this.bringToFront,
             addDocTab: this.props.addDocTab,
+            zoomToScale: this.zoomToScale,
+            getScale: this.getScale
         };
     }
 
@@ -346,7 +359,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     private childViews = () => [
         <CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} />,
         ...this.views
-    ];
+    ]
     render() {
         const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         const easing = () => this.props.Document.panTransformType === "Ease";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 449fa76a7..fb7657b68 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -69,13 +69,15 @@ export interface DocumentViewProps {
     ContentScaling: () => number;
     PanelWidth: () => number;
     PanelHeight: () => number;
-    focus: (doc: Doc) => void;
+    focus: (doc: Doc, willZoom: boolean) => void;
     selectOnLoad: boolean;
     parentActive: () => boolean;
     whenActiveChanged: (isActive: boolean) => void;
     bringToFront: (doc: Doc) => void;
     addDocTab: (doc: Doc, where: string) => void;
     collapseToPoint?: (scrpt: number[], expandedDocs: Doc[] | undefined) => void;
+    zoomToScale: (scale: number) => void;
+    getScale: () => number;
 }
 
 const schema = createSchema({
@@ -302,8 +304,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this._lastTap = Date.now();
     }
 
-    deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); }
-    fieldsClicked = (): void => { this.props.addDocTab(Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight") };
+    deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); };
+    fieldsClicked = (): void => { this.props.addDocTab(Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight"); };
     makeBtnClicked = (): void => {
         let doc = Doc.GetProto(this.props.Document);
         doc.isButton = !BoolCast(doc.isButton, false);
@@ -422,7 +424,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 this.props.addDocTab && this.props.addDocTab(Docs.SchemaDocument(["title"], aliases, {}), "onRight");
             }, icon: "search"
         });
-        cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document), icon: "crosshairs" });
+        cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" });
         cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])), icon: "link" });
         cm.addItem({ description: "Copy ID", event: () => Utils.CopyText(this.props.Document[Id]), icon: "fingerprint" });
         cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" });
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 7b642b299..3047d55a3 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -103,7 +103,10 @@ export class FieldView extends React.Component<FieldViewProps> {
                     ContainingCollectionView={this.props.ContainingCollectionView}
                     parentActive={this.props.active}
                     whenActiveChanged={this.props.whenActiveChanged}
-                    bringToFront={emptyFunction} />
+                    bringToFront={emptyFunction}
+                    zoomToScale={emptyFunction}
+                    getScale={returnOne}
+                />
             );
         }
         else if (field instanceof List) {
diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx
index c58570798..00dc07921 100644
--- a/src/client/views/presentationview/PresentationElement.tsx
+++ b/src/client/views/presentationview/PresentationElement.tsx
@@ -12,6 +12,7 @@ import { faFile as fileSolid, faLocationArrow, faArrowUp, faSearch } from '@fort
 import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons';
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
+import { DocumentManager } from "../../util/DocumentManager";
 
 
 
@@ -27,7 +28,7 @@ interface PresentationElementProps {
     document: Doc;
     index: number;
     deleteDocument(index: number): void;
-    gotoDocument(index: number): void;
+    gotoDocument(index: number, fromDoc: number): Promise<void>;
     allListElements: Doc[];
     groupMappings: Map<String, Doc[]>;
     presStatus: boolean;
@@ -300,6 +301,9 @@ export default class PresentationElement extends React.Component<PresentationEle
             this.selectedButtons[buttonIndex.Navigate] = false;
 
         } else {
+            if (this.selectedButtons[buttonIndex.Show]) {
+                this.selectedButtons[buttonIndex.Show] = false;
+            }
             this.selectedButtons[buttonIndex.Navigate] = true;
         }
 
@@ -307,6 +311,27 @@ export default class PresentationElement extends React.Component<PresentationEle
 
     }
 
+    /**
+    * The function that is called on click to turn zoom option of docs on/off.
+    */
+    @action
+    onZoomDocumentClick = (e: React.MouseEvent) => {
+        e.stopPropagation();
+        if (this.selectedButtons[buttonIndex.Show]) {
+            this.selectedButtons[buttonIndex.Show] = false;
+            this.props.document.viewScale = 1;
+
+        } else {
+            if (this.selectedButtons[buttonIndex.Navigate]) {
+                this.selectedButtons[buttonIndex.Navigate] = false;
+            }
+            this.selectedButtons[buttonIndex.Show] = true;
+        }
+
+        this.autoSaveButtonChange(buttonIndex.Show);
+
+    }
+
 
     render() {
         let p = this.props;
@@ -330,13 +355,13 @@ export default class PresentationElement extends React.Component<PresentationEle
                     outlineStyle: "dashed",
                     outlineWidth: BoolCast(p.document.libraryBrush, false) || BoolCast(p.document.protoBrush, false) ? `1px` : "0px",
                 }}
-                onClick={e => { p.gotoDocument(p.index); e.stopPropagation(); }}>
+                onClick={e => { p.gotoDocument(p.index, NumCast(this.props.mainDocument.selectedDoc)); e.stopPropagation(); }}>
                 <strong className="presentationView-name">
                     {`${p.index + 1}. ${title}`}
                 </strong>
                 <button className="presentation-icon" onClick={e => { this.props.deleteDocument(p.index); e.stopPropagation(); }}>X</button>
                 <br></br>
-                <button title="Zoom" className={this.selectedButtons[buttonIndex.Show] ? "presentation-interaction-selected" : "presentation-interaction"}><FontAwesomeIcon icon={"search"} /></button>
+                <button title="Zoom" className={this.selectedButtons[buttonIndex.Show] ? "presentation-interaction-selected" : "presentation-interaction"} onClick={this.onZoomDocumentClick}><FontAwesomeIcon icon={"search"} /></button>
                 <button title="Navigate" className={this.selectedButtons[buttonIndex.Navigate] ? "presentation-interaction-selected" : "presentation-interaction"} onClick={this.onNavigateDocumentClick}><FontAwesomeIcon icon={"location-arrow"} /></button>
                 <button title="Hide Document Till Presented" className={this.selectedButtons[buttonIndex.HideTillPressed] ? "presentation-interaction-selected" : "presentation-interaction"} onClick={this.onHideDocumentUntilPressClick}><FontAwesomeIcon icon={fileSolid} /></button>
                 <button title="Fade Document After Presented" className={this.selectedButtons[buttonIndex.FadeAfter] ? "presentation-interaction-selected" : "presentation-interaction"} onClick={this.onFadeDocumentAfterPresentedClick}><FontAwesomeIcon icon={fileRegular} color={"gray"} /></button>
diff --git a/src/client/views/presentationview/PresentationView.tsx b/src/client/views/presentationview/PresentationView.tsx
index d3365725b..6cf5fad7e 100644
--- a/src/client/views/presentationview/PresentationView.tsx
+++ b/src/client/views/presentationview/PresentationView.tsx
@@ -26,7 +26,7 @@ export interface PresViewProps {
 
 interface PresListProps extends PresViewProps {
     deleteDocument(index: number): void;
-    gotoDocument(index: number): void;
+    gotoDocument(index: number, fromDoc: number): Promise<void>;
     groupMappings: Map<String, Doc[]>;
     presElementsMappings: Map<Doc, PresentationElement>;
     setChildrenDocs: (docList: Doc[]) => void;
@@ -71,9 +71,24 @@ class PresentationViewList extends React.Component<PresListProps> {
         });
     }
 
+    /**
+     * Initially every document starts with a viewScale 1, which means
+     * that they will be displayed in a canvas with scale 1.
+     */
+    @action
+    initializeScaleViews = (docList: Doc[]) => {
+        docList.forEach((doc: Doc) => {
+            let curScale = NumCast(doc.viewScale, null);
+            if (curScale === undefined) {
+                doc.viewScale = 1;
+            }
+        });
+    }
+
     render() {
         const children = DocListCast(this.props.Document.data);
         this.initializeGroupIds(children);
+        this.initializeScaleViews(children);
         this.props.setChildrenDocs(children);
         return (
 
@@ -102,7 +117,6 @@ export class PresentationView extends React.Component<PresViewProps>  {
     @observable presButtonBackUp: Doc = new Doc();
 
 
-
     componentDidMount() {
         //getting both backUp documents
         let castedGroupBackUp = Cast(this.props.Document.presGroupBackUp, Doc);
@@ -195,7 +209,7 @@ export class PresentationView extends React.Component<PresViewProps>  {
             if (nextSelected === current) nextSelected = current + 1;
         }
 
-        this.gotoDocument(nextSelected);
+        this.gotoDocument(nextSelected, current);
 
     }
     back = async () => {
@@ -209,6 +223,7 @@ export class PresentationView extends React.Component<PresViewProps>  {
         //asking for its presentation id.
         let curPresId = StrCast(docAtCurrent.presentId);
         let prevSelected = current - 1;
+        let zoomOut: boolean = false;
 
         //checking if this presentation id is mapped to a group, if so chosing the first element in group
         if (this.groupMappings.has(curPresId)) {
@@ -217,11 +232,29 @@ export class PresentationView extends React.Component<PresViewProps>  {
             //end of grup so go beyond
             if (prevSelected === current) prevSelected = current - 1;
 
+            //checking if any of the group members had used zooming in
+            currentsArray.forEach((doc: Doc) => {
+                if (this.presElementsMappings.get(doc)!.selected[buttonIndex.Show]) {
+                    zoomOut = true;
+                    return;
+                }
+            });
 
         }
 
+        // if a group set that flag to zero or a single element
+        //If so making sure to zoom out, which goes back to state before zooming action
+        if (zoomOut || this.presElementsMappings.get(docAtCurrent)!.selected[buttonIndex.Show]) {
+            let prevScale = NumCast(this.childrenDocs[prevSelected].viewScale, null);
+            let curScale = DocumentManager.Instance.getScaleOfDocView(this.childrenDocs[current]);
+            if (prevScale !== undefined) {
+                if (prevScale !== curScale) {
+                    DocumentManager.Instance.zoomIntoScale(docAtCurrent, prevScale);
+                }
+            }
+        }
+        this.gotoDocument(prevSelected, current);
 
-        this.gotoDocument(prevSelected);
     }
 
     /**
@@ -285,9 +318,10 @@ export class PresentationView extends React.Component<PresViewProps>  {
      * has the option open and last in the group. If not in the group, and it has
      * te option open, navigates to that element.
      */
-    navigateToElement = (curDoc: Doc) => {
+    navigateToElement = async (curDoc: Doc, fromDoc: number) => {
         let docToJump: Doc = curDoc;
         let curDocPresId = StrCast(curDoc.presentId, null);
+        let willZoom: boolean = false;
 
         //checking if in group
         if (curDocPresId !== undefined) {
@@ -297,6 +331,11 @@ export class PresentationView extends React.Component<PresViewProps>  {
                     let selectedButtons: boolean[] = this.presElementsMappings.get(doc)!.selected;
                     if (selectedButtons[buttonIndex.Navigate]) {
                         docToJump = doc;
+                        willZoom = false;
+                    }
+                    if (selectedButtons[buttonIndex.Show]) {
+                        docToJump = doc;
+                        willZoom = true;
                     }
                 });
             }
@@ -305,13 +344,35 @@ export class PresentationView extends React.Component<PresViewProps>  {
         //docToJump stayed same meaning, it was not in the group or was the last element in the group
         if (docToJump === curDoc) {
             //checking if curDoc has navigation open
-            if (this.presElementsMappings.get(curDoc)!.selected[buttonIndex.Navigate]) {
-                DocumentManager.Instance.jumpToDocument(curDoc);
-            } else {
-                return;
+            let curDocButtons = this.presElementsMappings.get(curDoc)!.selected;
+            if (curDocButtons[buttonIndex.Navigate]) {
+                DocumentManager.Instance.jumpToDocument(curDoc, false);
+            } else if (curDocButtons[buttonIndex.Show]) {
+                let curScale = DocumentManager.Instance.getScaleOfDocView(this.childrenDocs[fromDoc]);
+                //awaiting jump so that new scale can be found, since jumping is async
+                await DocumentManager.Instance.jumpToDocument(curDoc, true);
+                let newScale = DocumentManager.Instance.getScaleOfDocView(curDoc);
+                curDoc.viewScale = newScale;
+
+                //saving the scale user was on before zooming in
+                if (curScale !== 1) {
+                    this.childrenDocs[fromDoc].viewScale = curScale;
+                }
+
             }
+            return;
+        }
+        let curScale = DocumentManager.Instance.getScaleOfDocView(this.childrenDocs[fromDoc]);
+
+        //awaiting jump so that new scale can be found, since jumping is async
+        await DocumentManager.Instance.jumpToDocument(docToJump, willZoom);
+        let newScale = DocumentManager.Instance.getScaleOfDocView(curDoc);
+        curDoc.viewScale = newScale;
+        //saving the scale that user was on
+        if (curScale !== 1) {
+            this.childrenDocs[fromDoc].viewScale = curScale;
         }
-        DocumentManager.Instance.jumpToDocument(docToJump);
+
     }
 
     /**
@@ -340,7 +401,7 @@ export class PresentationView extends React.Component<PresViewProps>  {
         }
     }
     @action
-    public gotoDocument = async (index: number) => {
+    public gotoDocument = async (index: number, fromDoc: number) => {
         const list = FieldValue(Cast(this.props.Document.data, listSpec(Doc)));
         if (!list) {
             return;
@@ -357,7 +418,7 @@ export class PresentationView extends React.Component<PresViewProps>  {
 
         const doc = await list[index];
         if (this.presStatus) {
-            this.navigateToElement(doc);
+            this.navigateToElement(doc, fromDoc);
             this.hideIfNotPresented(index);
             this.showAfterPresented(index);
         }
@@ -407,7 +468,8 @@ export class PresentationView extends React.Component<PresViewProps>  {
         } else {
             this.presStatus = true;
             this.startPresentation(0);
-            this.gotoDocument(0);
+            const current = NumCast(this.props.Document.selectedDoc);
+            this.gotoDocument(0, current);
         }
         this.props.Document.presStatus = this.presStatus;
     }
@@ -423,6 +485,11 @@ export class PresentationView extends React.Component<PresViewProps>  {
             doc.opacity = 1;
         });
         this.props.Document.selectedDoc = 0;
+        if (this.childrenDocs.length === 0) {
+            return;
+        }
+        DocumentManager.Instance.zoomIntoScale(this.childrenDocs[0], 1);
+        this.childrenDocs[0].viewScale = 1;
 
     }
 
-- 
cgit v1.2.3-70-g09d2


From 90e8adc8578aa29a153cd41256b2f546a429a5bb Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Wed, 19 Jun 2019 12:03:13 -0400
Subject: ui changes

---
 src/client/util/TooltipTextMenu.scss        | 14 +++---
 src/client/util/TooltipTextMenu.tsx         | 72 ++++++++++++++++-------------
 src/client/views/nodes/FormattedTextBox.tsx |  4 +-
 3 files changed, 49 insertions(+), 41 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss
index c10a61558..1867a697a 100644
--- a/src/client/util/TooltipTextMenu.scss
+++ b/src/client/util/TooltipTextMenu.scss
@@ -233,19 +233,19 @@
   }
 
 .tooltipMenu {
-    position: absolute;
-    z-index: 50;
+    // position: absolute;
+    // z-index: 50;
     background: #121721;
     border: 1px solid silver;
     border-radius: 15px;
-    padding: 2px 10px;
+    //padding: 2px 10px;
     //margin-bottom: 100px;
     //-webkit-transform: translateX(-50%);
     //transform: translateX(-50%);
-    transform: translateY(-50%);
+    //transform: translateY(-50%);
     pointer-events: all;
-    height: 100;
-    width:250;
+    // height: 100;
+    // width:250;
     .ProseMirror-example-setup-style hr {
       padding: 2px 10px;
       border: none;
@@ -307,7 +307,7 @@
       padding-right: 0px;
   }
   .summarize{
-      margin-left: 15px;
+      //margin-left: 15px;
       color: white;
       height: 20px;
     //   background-color: white;
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index a19b6c1d8..06a916832 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -66,7 +66,7 @@ export class TooltipTextMenu {
         this.tooltip.className = "tooltipMenu";
 
         //add the div which is the tooltip
-        view.dom.parentNode!.parentNode!.appendChild(this.tooltip);
+        //view.dom.parentNode!.parentNode!.appendChild(this.tooltip);
 
         //add additional icons
         library.add(faListUl);
@@ -131,11 +131,17 @@ export class TooltipTextMenu {
         this.link = document.createElement("a");
         this.link.target = "_blank";
         this.link.style.color = "white";
-        this.tooltip.appendChild(this.link);
+        //this.tooltip.appendChild(this.link);
 
         this.tooltip.appendChild(this.createLink().render(this.view).dom);
 
+        this.tooltip.appendChild(this.createStar().render(this.view).dom);
+
         this.update(view, undefined);
+
+        if (view.dom.parentNode !== null) {
+            view.dom.parentNode.insertBefore(this.tooltip, view.dom);
+        }
     }
 
     //label of dropdown will change to given label
@@ -239,23 +245,10 @@ export class TooltipTextMenu {
                         hideSource: false
                     });
             };
-            this.linkEditor.appendChild(this.linkDrag);
-            this.linkEditor.appendChild(this.linkText);
-            this.linkEditor.appendChild(linkBtn);
-            this.tooltip.appendChild(this.linkEditor);
-
-            // SUMMARIZE BUTTON
-
-            let starButton = document.createElement("span");
-            starButton.className = "summarize";
-            starButton.textContent = "★";
-            starButton.title = 'Summarize';
-            starButton.onclick = () => {
-                let state = this.view.state;
-                this.insertStar(state, this.view.dispatch);
-            };
-
-            this.tooltip.appendChild(starButton);
+            // this.linkEditor.appendChild(this.linkDrag);
+            // this.linkEditor.appendChild(this.linkText);
+            // this.linkEditor.appendChild(linkBtn);
+            //this.tooltip.appendChild(this.linkEditor);
         }
 
         let node = this.view.state.selection.$from.nodeAfter;
@@ -370,6 +363,21 @@ export class TooltipTextMenu {
         });
     }
 
+    createStar() {
+        return new MenuItem({
+            title: "Summarize",
+            label: "Summarize",
+            icon: icons.join,
+            css: "color:white;",
+            class: "summarize",
+            execEvent: "",
+            run: (state, dispatch, view) => {
+                this.insertStar(state, dispatch);
+            }
+
+        });
+    }
+
     createLink() {
         let markType = schema.marks.link;
         return new MenuItem({
@@ -499,34 +507,34 @@ export class TooltipTextMenu {
 
         // Hide the tooltip if the selection is empty
         if (state.selection.empty) {
-            this.tooltip.style.display = "none";
-            return;
+            //this.tooltip.style.display = "none";
+            //return;
         }
 
         let linksInSelection = this.activeMarksOnSelection([schema.marks.link]);
-        if (linksInSelection.length > 0) {
-            let attributes = this.getMarksInSelection(this.view.state, [schema.marks.link])[0].attrs;
-            this.link.href = attributes.href;
-            this.link.textContent = attributes.title;
-            this.link.style.visibility = "visible";
-        } else this.link.style.visibility = "hidden";
+        // if (linksInSelection.length > 0) {
+        //     let attributes = this.getMarksInSelection(this.view.state, [schema.marks.link])[0].attrs;
+        //     this.link.href = attributes.href;
+        //     this.link.textContent = attributes.title;
+        //     this.link.style.visibility = "visible";
+        // } else this.link.style.visibility = "hidden";
 
         // Otherwise, reposition it and update its content
-        this.tooltip.style.display = "";
+        //this.tooltip.style.display = "";
         let { from, to } = state.selection;
         let start = view.coordsAtPos(from), end = view.coordsAtPos(to);
         // The box in which the tooltip is positioned, to use as base
-        let box = this.tooltip.offsetParent!.getBoundingClientRect();
+        //let box = this.tooltip.offsetParent!.getBoundingClientRect();
         // Find a center-ish x position from the selection endpoints (when
         // crossing lines, end may be more to the left)
         let left = Math.max((start.left + end.left) / 2, start.left + 3);
-        this.tooltip.style.left = (left - box.left) * this.editorProps.ScreenToLocalTransform().Scale + "px";
+        //this.tooltip.style.left = (left - box.left) * this.editorProps.ScreenToLocalTransform().Scale + "px";
         let width = Math.abs(start.left - end.left) / 2 * this.editorProps.ScreenToLocalTransform().Scale;
         let mid = Math.min(start.left, end.left) + width;
 
         //this.tooltip.style.width = 225 + "px";
-        this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px";
-        this.tooltip.style.top = "-100px";
+        // this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px";
+        // this.tooltip.style.top = "-100px";
         //this.tooltip.style.height = "100px";
 
         // let transform = this.editorProps.ScreenToLocalTransform();
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index df12f261b..223e6df0a 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -254,7 +254,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) {
             e.stopPropagation();
             if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) {
-                this._toolTipTextMenu.tooltip.style.opacity = "0";
+                //this._toolTipTextMenu.tooltip.style.opacity = "0";
             }
         }
         let ctrlKey = e.ctrlKey;
@@ -289,7 +289,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
     onPointerUp = (e: React.PointerEvent): void => {
         if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) {
-            this._toolTipTextMenu.tooltip.style.opacity = "1";
+            //this._toolTipTextMenu.tooltip.style.opacity = "1";
         }
         if (e.buttons === 1 && this.props.isSelected() && !e.altKey) {
             e.stopPropagation();
-- 
cgit v1.2.3-70-g09d2


From 47e125b9c7a8a61d820c013a5dd5f9cf654205af Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Wed, 19 Jun 2019 14:01:05 -0400
Subject: moved tooltip inside textbox

---
 src/client/util/TooltipTextMenu.tsx                             | 2 +-
 src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 06a916832..06862a79a 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -278,7 +278,7 @@ export class TooltipTextMenu {
         console.log("creating star...");
         let newNode = schema.nodes.star.create({ visibility: false, text: state.selection.content(), oldtextslice: state.selection.content().toJSON(), oldtextlen: state.selection.to - state.selection.from });
         if (dispatch) {
-            console.log(newNode.attrs.text.toString());
+            //console.log(newNode.attrs.text.toString());
             dispatch(state.tr.replaceSelectionWith(newNode));
         }
         return true;
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 05dc6f534..b8bcfcc89 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -50,7 +50,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             document.removeEventListener("pointerup", this.onPointerUp, true);
             document.removeEventListener("pointermove", this.onPointerMove, true);
         }
-        if (all) {
+        if (rem_keydown) {
             document.removeEventListener("keydown", this.marqueeCommand, true);
         }
         this._visible = false;
-- 
cgit v1.2.3-70-g09d2


From 6259738cf77c2749f556e6d57addae8dac1b32d2 Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Thu, 20 Jun 2019 11:17:22 -0400
Subject: moving div

---
 src/client/util/TooltipTextMenu.scss                            | 7 ++++---
 src/client/util/TooltipTextMenu.tsx                             | 6 +++---
 src/client/views/MainOverlayTextBox.scss                        | 2 +-
 src/client/views/MainOverlayTextBox.tsx                         | 7 +++++--
 src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 2 +-
 src/client/views/nodes/FormattedTextBox.scss                    | 2 +-
 src/client/views/nodes/FormattedTextBox.tsx                     | 2 ++
 7 files changed, 17 insertions(+), 11 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss
index 1867a697a..456953fb6 100644
--- a/src/client/util/TooltipTextMenu.scss
+++ b/src/client/util/TooltipTextMenu.scss
@@ -233,16 +233,17 @@
   }
 
 .tooltipMenu {
-    // position: absolute;
+    position: absolute;
     // z-index: 50;
     background: #121721;
     border: 1px solid silver;
     border-radius: 15px;
+    //height: 60px;
     //padding: 2px 10px;
-    //margin-bottom: 100px;
+    //margin-top: 100px;
     //-webkit-transform: translateX(-50%);
     //transform: translateX(-50%);
-    //transform: translateY(-50%);
+    transform: translateY(-85px);
     pointer-events: all;
     // height: 100;
     // width:250;
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 06862a79a..641514af9 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -139,9 +139,9 @@ export class TooltipTextMenu {
 
         this.update(view, undefined);
 
-        if (view.dom.parentNode !== null) {
-            view.dom.parentNode.insertBefore(this.tooltip, view.dom);
-        }
+        view.dom.parentNode!.parentNode!.insertBefore(this.tooltip, view.dom.parentNode);
+
+        //console.log("hi");
     }
 
     //label of dropdown will change to given label
diff --git a/src/client/views/MainOverlayTextBox.scss b/src/client/views/MainOverlayTextBox.scss
index f6a746e63..fd6ca3471 100644
--- a/src/client/views/MainOverlayTextBox.scss
+++ b/src/client/views/MainOverlayTextBox.scss
@@ -1,7 +1,7 @@
 @import "globalCssVariables";
 .mainOverlayTextBox-textInput {
     background-color: rgba(248, 6, 6, 0.001);
-    width: 200px;
+    width: 400px;
     height: 200px;
     position:absolute;
     overflow: visible;
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index b4ad5f4d7..f1c4b9708 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -24,6 +24,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
     private _textHideOnLeave?: boolean;
     private _textTargetDiv: HTMLDivElement | undefined;
     private _textProxyDiv: React.RefObject<HTMLDivElement>;
+    private _outerdiv: React.RefObject<HTMLDivElement>;
     private _textBottom: boolean | undefined;
     private _textAutoHeight: boolean | undefined;
     private _textBox: FormattedTextBox | undefined;
@@ -32,6 +33,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
     constructor(props: MainOverlayTextBoxProps) {
         super(props);
         this._textProxyDiv = React.createRef();
+        this._outerdiv = React.createRef();
         MainOverlayTextBox.Instance = this;
         reaction(() => FormattedTextBox.InputBoxOverlay,
             (box?: FormattedTextBox) => {
@@ -114,16 +116,17 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
             let s = this._textXf().Scale;
             let location = this._textBottom ? textRect.bottom : textRect.top;
             let hgt = this._textAutoHeight || this._textBottom ? "auto" : this._textTargetDiv.clientHeight;
-            return <div className="mainOverlayTextBox-textInput" style={{ transform: `translate(${textRect.left}px, ${location}px) scale(${1 / s},${1 / s})`, width: "auto", height: "0px" }} >
+            return <div ref={this._outerdiv} className="unscaled_div"><div className="mainOverlayTextBox-textInput" style={{ transform: `translate(${textRect.left}px, ${location}px) scale(${1 / s},${1 / s})`, width: "auto", height: "0px" }} >
                 <div className="mainOverlayTextBox-textInput" onPointerDown={this.textBoxDown} ref={this._textProxyDiv} onScroll={this.textScroll}
                     style={{ width: `${textRect.width * s}px`, height: "0px" }}>
                     <div style={{ height: hgt, width: "100%", position: "absolute", bottom: this._textBottom ? "0px" : undefined }}>
                         <FormattedTextBox color={`${this._textColor}`} fieldKey={this.TextFieldKey} hideOnLeave={this._textHideOnLeave} isOverlay={true} Document={FormattedTextBox.InputBoxOverlay.props.Document}
                             isSelected={returnTrue} select={emptyFunction} isTopMost={true} selectOnLoad={true}
                             ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue}
-                            ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} />
+                            ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} outer_div={this._outerdiv} />
                     </div>
                 </div>
+            </div>
             </ div>;
         }
         else return (null);
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index b8bcfcc89..b1e0e62ea 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -95,7 +95,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 }
             });
         } else if (!e.ctrlKey) {
-            let newBox = Docs.TextDocument({ width: 200, height: 30, x: x, y: y, title: "-typed text-" });
+            let newBox = Docs.TextDocument({ width: 200, height: 50, x: x, y: y, title: "-typed text-" });
             newBox.proto!.autoHeight = true;
             this.props.addLiveTextDocument(newBox);
         }
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index e3e40860c..d3045ae2f 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -1,7 +1,7 @@
 @import "../globalCssVariables";
 .ProseMirror {
   width: 100%;
-  height: 100;
+  height: 100%;
   min-height: 100%;
   font-family: $serif;
 }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 223e6df0a..370b24e95 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -45,6 +45,7 @@ export interface FormattedTextBoxProps {
     hideOnLeave?: boolean;
     height?: string;
     color?: string;
+    outer_div?: React.RefObject<HTMLDivElement>;
 }
 
 const richTextSchema = createSchema({
@@ -97,6 +98,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     constructor(props: FieldViewProps) {
         super(props);
+        this.props.outer_div ? console.log("smd") : console.log("bye");
 
         this._ref = React.createRef();
         if (this.props.isOverlay) {
-- 
cgit v1.2.3-70-g09d2


From 7ef1f39703a378df3f1116d046f9b57a4427d64d Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Thu, 20 Jun 2019 16:54:16 -0400
Subject: div moved, but z-index is fd

---
 src/client/util/TooltipTextMenu.scss        | 12 +++++++-----
 src/client/util/TooltipTextMenu.tsx         | 13 +++++++++----
 src/client/views/DocumentDecorations.tsx    |  2 +-
 src/client/views/MainOverlayTextBox.scss    |  4 ++++
 src/client/views/MainOverlayTextBox.tsx     |  8 ++++----
 src/client/views/nodes/FormattedTextBox.tsx |  8 ++++++--
 6 files changed, 31 insertions(+), 16 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss
index 456953fb6..d19ded68f 100644
--- a/src/client/util/TooltipTextMenu.scss
+++ b/src/client/util/TooltipTextMenu.scss
@@ -18,6 +18,7 @@
   .ProseMirror-menuitem {
     margin-right: 3px;
     display: inline-block;
+    z-index: 100000;
   }
   
   .ProseMirror-menuseparator {
@@ -67,7 +68,7 @@
   }
   
   .ProseMirror-menu-dropdown-menu {
-    z-index: 15;
+    z-index: 100000;
     min-width: 6em;
     background: white;
   }
@@ -80,6 +81,7 @@
     cursor: pointer;
     padding: 2px 8px 2px 4px;
     width: auto;
+    z-index: 100000;
   }
   
   .ProseMirror-menu-dropdown-item:hover {
@@ -233,8 +235,8 @@
   }
 
 .tooltipMenu {
-    position: absolute;
-    // z-index: 50;
+    position: relative;
+    z-index: 2000;
     background: #121721;
     border: 1px solid silver;
     border-radius: 15px;
@@ -245,8 +247,8 @@
     //transform: translateX(-50%);
     transform: translateY(-85px);
     pointer-events: all;
-    // height: 100;
-    // width:250;
+    height: 30px;
+    width:500px;
     .ProseMirror-example-setup-style hr {
       padding: 2px 10px;
       border: none;
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 641514af9..06c8bbc1a 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -29,6 +29,7 @@ import { CollectionDockingView } from "../views/collections/CollectionDockingVie
 import { DocumentManager } from "./DocumentManager";
 import { Id } from "../../new_fields/FieldSymbols";
 import { Utils } from "../../Utils";
+import { FormattedTextBoxProps } from "../views/nodes/FormattedTextBox";
 // import { wrap } from "module";
 
 const SVG = "http://www.w3.org/2000/svg";
@@ -42,7 +43,7 @@ export class TooltipTextMenu {
     private fontStyles: MarkType[];
     private fontSizes: MarkType[];
     private listTypes: NodeType[];
-    private editorProps: FieldViewProps;
+    private editorProps: FieldViewProps & FormattedTextBoxProps;
     private state: EditorState;
     private fontSizeToNum: Map<MarkType, number>;
     private fontStylesToName: Map<MarkType, string>;
@@ -58,7 +59,7 @@ export class TooltipTextMenu {
     private fontStyleDom?: Node;
     private listTypeBtnDom?: Node;
 
-    constructor(view: EditorView, editorProps: FieldViewProps) {
+    constructor(view: EditorView, editorProps: FieldViewProps & FormattedTextBoxProps) {
         this.view = view;
         this.state = view.state;
         this.editorProps = editorProps;
@@ -139,9 +140,13 @@ export class TooltipTextMenu {
 
         this.update(view, undefined);
 
-        view.dom.parentNode!.parentNode!.insertBefore(this.tooltip, view.dom.parentNode);
+        //view.dom.parentNode!.parentNode!.insertBefore(this.tooltip, view.dom.parentNode);
 
-        //console.log("hi");
+        // quick and dirty null check
+        const outer_div = this.editorProps.outer_div;
+        outer_div && outer_div(this.tooltip);
+
+        console.log("hi");
     }
 
     //label of dropdown will change to given label
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index d8642d675..3d802964a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -619,7 +619,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 left: bounds.x - this._resizeBorderWidth / 2,
                 top: bounds.y - this._resizeBorderWidth / 2,
                 pointerEvents: this.Interacting ? "none" : "all",
-                zIndex: SelectionManager.SelectedDocuments().length > 1 ? 1000 : 0,
+                zIndex: SelectionManager.SelectedDocuments().length > 1 ? 900 : 0,
             }} onPointerDown={this.onBackgroundDown} onContextMenu={(e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); }} >
             </div>
             <div className="documentDecorations-container" style={{
diff --git a/src/client/views/MainOverlayTextBox.scss b/src/client/views/MainOverlayTextBox.scss
index fd6ca3471..c294e1b35 100644
--- a/src/client/views/MainOverlayTextBox.scss
+++ b/src/client/views/MainOverlayTextBox.scss
@@ -17,4 +17,8 @@
         top: 0;
         left: 0;
     }
+}
+.unscaled_div{
+    width: 500px;
+    z-index: 10000;
 }
\ No newline at end of file
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index f1c4b9708..4488d1046 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -24,16 +24,16 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
     private _textHideOnLeave?: boolean;
     private _textTargetDiv: HTMLDivElement | undefined;
     private _textProxyDiv: React.RefObject<HTMLDivElement>;
-    private _outerdiv: React.RefObject<HTMLDivElement>;
+    private _outerdiv = (dominus: HTMLElement | null) => this._dominus && dominus && dominus.appendChild(this._dominus);
     private _textBottom: boolean | undefined;
     private _textAutoHeight: boolean | undefined;
     private _textBox: FormattedTextBox | undefined;
+    private _dominus?: HTMLElement;
     @observable public TextDoc?: Doc;
 
     constructor(props: MainOverlayTextBoxProps) {
         super(props);
         this._textProxyDiv = React.createRef();
-        this._outerdiv = React.createRef();
         MainOverlayTextBox.Instance = this;
         reaction(() => FormattedTextBox.InputBoxOverlay,
             (box?: FormattedTextBox) => {
@@ -116,14 +116,14 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
             let s = this._textXf().Scale;
             let location = this._textBottom ? textRect.bottom : textRect.top;
             let hgt = this._textAutoHeight || this._textBottom ? "auto" : this._textTargetDiv.clientHeight;
-            return <div ref={this._outerdiv} className="unscaled_div"><div className="mainOverlayTextBox-textInput" style={{ transform: `translate(${textRect.left}px, ${location}px) scale(${1 / s},${1 / s})`, width: "auto", height: "0px" }} >
+            return <div ref={this._outerdiv} className="unscaled_div" style={{ transform: `translate(${textRect.left}px, ${location}px)` }} ><div className="mainOverlayTextBox-textInput" style={{ transform: `scale(${1 / s},${1 / s})`, width: "auto", height: "0px" }} >
                 <div className="mainOverlayTextBox-textInput" onPointerDown={this.textBoxDown} ref={this._textProxyDiv} onScroll={this.textScroll}
                     style={{ width: `${textRect.width * s}px`, height: "0px" }}>
                     <div style={{ height: hgt, width: "100%", position: "absolute", bottom: this._textBottom ? "0px" : undefined }}>
                         <FormattedTextBox color={`${this._textColor}`} fieldKey={this.TextFieldKey} hideOnLeave={this._textHideOnLeave} isOverlay={true} Document={FormattedTextBox.InputBoxOverlay.props.Document}
                             isSelected={returnTrue} select={emptyFunction} isTopMost={true} selectOnLoad={true}
                             ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue}
-                            ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} outer_div={this._outerdiv} />
+                            ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} outer_div={(dominus: HTMLElement) => this._dominus = dominus} />
                     </div>
                 </div>
             </div>
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 370b24e95..421267b2a 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -45,7 +45,7 @@ export interface FormattedTextBoxProps {
     hideOnLeave?: boolean;
     height?: string;
     color?: string;
-    outer_div?: React.RefObject<HTMLDivElement>;
+    outer_div?: (domminus: HTMLElement) => void;
 }
 
 const richTextSchema = createSchema({
@@ -61,6 +61,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         return FieldView.LayoutString(FormattedTextBox, fieldStr);
     }
     private _ref: React.RefObject<HTMLDivElement>;
+    private _outerdiv?: (dominus: HTMLElement) => void;
     private _proseRef?: HTMLDivElement;
     private _editorView: Opt<EditorView>;
     private _toolTipTextMenu: TooltipTextMenu | undefined = undefined;
@@ -98,7 +99,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
 
     constructor(props: FieldViewProps) {
         super(props);
-        this.props.outer_div ? console.log("smd") : console.log("bye");
+        if (this.props.outer_div) {
+            this._outerdiv = this.props.outer_div;
+            console.log("yay");
+        }
 
         this._ref = React.createRef();
         if (this.props.isOverlay) {
-- 
cgit v1.2.3-70-g09d2


From 30fd6dc9431cd8121a6d761ffdfba5d0dae641a6 Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Fri, 21 Jun 2019 13:39:36 -0400
Subject: marks now reflect cursor position, not selection. Still need to
 consider when there is no nodeAfter

---
 src/client/util/TooltipTextMenu.scss     |  2 +-
 src/client/util/TooltipTextMenu.tsx      | 54 +++++++++++++++++++++++++-------
 src/client/views/MainOverlayTextBox.scss |  1 +
 3 files changed, 45 insertions(+), 12 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss
index d19ded68f..b10573b3e 100644
--- a/src/client/util/TooltipTextMenu.scss
+++ b/src/client/util/TooltipTextMenu.scss
@@ -60,7 +60,6 @@
   }
   
   .ProseMirror-menu-dropdown-menu, .ProseMirror-menu-submenu {
-    position: absolute;
     background: $dark-color;
     color:white;
     border: 1px solid rgb(223, 223, 223);
@@ -71,6 +70,7 @@
     z-index: 100000;
     min-width: 6em;
     background: white;
+    position: absolute;
   }
   
   .linking {
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 06c8bbc1a..c9216199b 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -7,6 +7,7 @@ import { EditorState, Transaction, NodeSelection, TextSelection } from "prosemir
 import { EditorView } from "prosemirror-view";
 import { schema } from "./RichTextSchema";
 import { Schema, NodeType, MarkType, Mark } from "prosemirror-model";
+import { Node as ProsNode } from "prosemirror-model"
 import React = require("react");
 import "./TooltipTextMenu.scss";
 const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands");
@@ -30,6 +31,7 @@ import { DocumentManager } from "./DocumentManager";
 import { Id } from "../../new_fields/FieldSymbols";
 import { Utils } from "../../Utils";
 import { FormattedTextBoxProps } from "../views/nodes/FormattedTextBox";
+import { text } from "body-parser";
 // import { wrap } from "module";
 
 const SVG = "http://www.w3.org/2000/svg";
@@ -290,7 +292,7 @@ export class TooltipTextMenu {
     }
 
     //will display a remove-list-type button if selection is in list, otherwise will show list type dropdown
-    updateListItemDropdown(label: string, listTypeBtn: Node) {
+    updateListItemDropdown(label: string, listTypeBtn: any) {
         //remove old btn
         if (listTypeBtn) { this.tooltip.removeChild(listTypeBtn); }
 
@@ -516,7 +518,7 @@ export class TooltipTextMenu {
             //return;
         }
 
-        let linksInSelection = this.activeMarksOnSelection([schema.marks.link]);
+        //let linksInSelection = this.activeMarksOnSelection([schema.marks.link]);
         // if (linksInSelection.length > 0) {
         //     let attributes = this.getMarksInSelection(this.view.state, [schema.marks.link])[0].attrs;
         //     this.link.href = attributes.href;
@@ -583,17 +585,47 @@ export class TooltipTextMenu {
         let { empty, $cursor, ranges } = this.view.state.selection as TextSelection;
         let state = this.view.state;
         let dispatch = this.view.dispatch;
-
-        let activeMarks = markGroup.filter(mark => {
-            if (dispatch) {
-                let has = false, tr = state.tr;
-                for (let i = 0; !has && i < ranges.length; i++) {
-                    let { $from, $to } = ranges[i];
-                    return state.doc.rangeHasMark($from.pos, $to.pos, mark);
+        let activeMarks: MarkType[];
+        if (!empty) {
+            activeMarks = markGroup.filter(mark => {
+                if (dispatch) {
+                    let has = false, tr = state.tr;
+                    for (let i = 0; !has && i < ranges.length; i++) {
+                        let { $from, $to } = ranges[i];
+                        return state.doc.rangeHasMark($from.pos, $to.pos, mark);
+                    }
                 }
+                return false;
+            });
+        }
+        else {
+            let pos = this.view.state.selection.$from;
+            let ref_node: ProsNode;
+            if (pos.nodeAfter !== null && pos.nodeAfter !== undefined) {
+                ref_node = pos.nodeAfter;
             }
-            return false;
-        });
+            else if (pos.nodeBefore !== null && pos.nodeBefore !== undefined) {
+                ref_node = pos.nodeBefore;
+            }
+            else {
+                return [];
+            }
+            let text_node_type: NodeType;
+            if (ref_node.isText) {
+                text_node_type = ref_node.type;
+            }
+            else {
+                return [];
+            }
+
+            activeMarks = markGroup.filter(mark_type => {
+                if (dispatch) {
+                    let mark = state.schema.mark(mark_type);
+                    return ref_node.marks.includes(mark);
+                }
+                return false;
+            });
+        }
         return activeMarks;
     }
 
diff --git a/src/client/views/MainOverlayTextBox.scss b/src/client/views/MainOverlayTextBox.scss
index c294e1b35..1093ff671 100644
--- a/src/client/views/MainOverlayTextBox.scss
+++ b/src/client/views/MainOverlayTextBox.scss
@@ -21,4 +21,5 @@
 .unscaled_div{
     width: 500px;
     z-index: 10000;
+    position: absolute;
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 6df09d7d646c16e6469b198e7d270b6a1e45b0c7 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 24 Jun 2019 13:23:28 -0400
Subject: fixes for templates with annotations and more.

---
 src/client/util/TooltipTextMenu.tsx                |   2 +-
 src/client/views/DocumentDecorations.tsx           |  55 +++++------
 src/client/views/InkingCanvas.tsx                  |   7 +-
 src/client/views/InkingControl.tsx                 |   3 +-
 src/client/views/MainView.tsx                      |   4 +-
 .../views/collections/CollectionBaseView.tsx       |   1 -
 .../views/collections/CollectionTreeView.tsx       | 106 +++++++++------------
 src/client/views/collections/CollectionView.tsx    |  17 +---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   5 +-
 src/client/views/pdf/PDFViewer.tsx                 |   1 +
 src/new_fields/Doc.ts                              |   2 +-
 11 files changed, 82 insertions(+), 121 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index c9216199b..048fb7133 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -222,7 +222,7 @@ export class TooltipTextMenu {
                                 if (DocumentManager.Instance.getDocumentView(f)) {
                                     DocumentManager.Instance.getDocumentView(f)!.props.focus(f);
                                 }
-                                else if (CollectionDockingView.Instance) CollectionDockingView.Instance.AddRightSplit(f);
+                                else if (CollectionDockingView.Instance) CollectionDockingView.Instance.AddRightSplit(f, f);
                             }
                         }));
                     }
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 0d5cca9f1..9be5c9cd6 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -24,9 +24,10 @@ import { LinkMenu } from "./nodes/LinkMenu";
 import { TemplateMenu } from "./TemplateMenu";
 import { Template, Templates } from "./Templates";
 import React = require("react");
-import { URLField } from '../../new_fields/URLField';
+import { URLField, ImageField } from '../../new_fields/URLField';
 import { templateLiteral } from 'babel-types';
 import { CollectionViewType } from './collections/CollectionBaseView';
+import { ImageBox } from './nodes/ImageBox';
 const higflyout = require("@hig/flyout");
 export const { anchorPoints } = higflyout;
 export const Flyout = higflyout.default;
@@ -75,41 +76,29 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
             if (text[0] === '#') {
                 this._fieldKey = text.slice(1, text.length);
                 this._title = this.selectionTitle;
-            } else if (text.startsWith(">>>")) {
-                let metaKey = text.slice(3, text.length);
-                let collection = SelectionManager.SelectedDocuments()[0].props.ContainingCollectionView!.props.Document;
-                Doc.GetProto(collection)[metaKey] = new List<Doc>([
-                    Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }),
-                    Docs.TextDocument({ documentText: "hello world!", width: 300, height: 300 }),
-                ]);
-                let template = Doc.MakeAlias(collection);
+            } else if (text.startsWith(">")) {
+                let metaKey = text.slice(text.startsWith(">>>") ? 3 : text.startsWith(">>") ? 2 : 1, text.length);
+                let field = SelectionManager.SelectedDocuments()[0];
+                let collectionKey = field.props.ContainingCollectionView!.props.fieldKey;
+                let collection = field.props.ContainingCollectionView!.props.Document;
+                let collectionKeyProp = `fieldKey={"${collectionKey}"}`;
+                let collectionAnnotationsKeyProp = `fieldKey={"annotations"}`;
+                let metaKeyProp = `fieldKey={"${metaKey}"}`;
+                let metaAnnotationsKeyProp = `fieldKey={"${metaKey}_annotations"}`;
+                let template = Doc.MakeAlias(field.props.Document);
+                template.proto = collection;
                 template.title = metaKey;
+                template.nativeWidth = Cast(field.nativeWidth, "number");
+                template.nativeHeight = Cast(field.nativeHeight, "number");
                 template.embed = true;
-                template.layout = CollectionView.LayoutString(metaKey);
-                template.viewType = CollectionViewType.Freeform;
-                template.x = 0;
-                template.y = 0;
-                template.width = 300;
-                template.height = 300;
                 template.isTemplate = true;
-                template.templates = new List<string>([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]);
-                Doc.AddDocToList(collection, "data", template);
-                SelectionManager.SelectedDocuments().map(dv => dv.props.removeDocument && dv.props.removeDocument(dv.props.Document));
-            } else if (text[0] === ">") {
-                let metaKey = text.slice(1, text.length);
-                let first = SelectionManager.SelectedDocuments()[0].props.Document!;
-                let collection = SelectionManager.SelectedDocuments()[0].props.ContainingCollectionView!.props.Document;
-                Doc.GetProto(collection)[metaKey] = "-empty field-";
-                let template = Doc.MakeAlias(collection);
-                template.title = metaKey;
-                template.layout = FormattedTextBox.LayoutString(metaKey);
-                template.isTemplate = true;
-                template.x = NumCast(first.x);
-                template.y = NumCast(first.y);
-                template.width = first[WidthSym]();
-                template.height = first[HeightSym]();
-                template.templates = new List<string>([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]);
-                Doc.AddDocToList(collection, "data", template);
+                template.templates = new List<string>([Templates.TitleBar(metaKey)]);
+                template.layout = StrCast(field.props.Document.layout).replace(collectionKeyProp, metaKeyProp);
+                if (field.props.Document.backgroundLayout) {
+                    template.layout = StrCast(field.props.Document.layout).replace(collectionAnnotationsKeyProp, metaAnnotationsKeyProp);
+                    template.backgroundLayout = StrCast(field.props.Document.backgroundLayout).replace(collectionKeyProp, metaKeyProp);
+                }
+                Doc.AddDocToList(collection, collectionKey, template);
                 SelectionManager.SelectedDocuments().map(dv => dv.props.removeDocument && dv.props.removeDocument(dv.props.Document));
             }
             else {
diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 5d4ea76cd..fd7e5b07d 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -14,6 +14,7 @@ import { Cast, PromiseValue, NumCast } from "../../new_fields/Types";
 interface InkCanvasProps {
     getScreenTransform: () => Transform;
     Document: Doc;
+    inkFieldKey: string;
     children: () => JSX.Element[];
 }
 
@@ -40,7 +41,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
     }
 
     componentDidMount() {
-        PromiseValue(Cast(this.props.Document.ink, InkField)).then(ink => runInAction(() => {
+        PromiseValue(Cast(this.props.Document[this.props.inkFieldKey], InkField)).then(ink => runInAction(() => {
             if (ink) {
                 let bounds = Array.from(ink.inkData).reduce(([mix, max, miy, may], [id, strokeData]) =>
                     strokeData.pathData.reduce(([mix, max, miy, may], p) =>
@@ -55,12 +56,12 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
 
     @computed
     get inkData(): Map<string, StrokeData> {
-        let map = Cast(this.props.Document.ink, InkField);
+        let map = Cast(this.props.Document[this.props.inkFieldKey], InkField);
         return !map ? new Map : new Map(map.inkData);
     }
 
     set inkData(value: Map<string, StrokeData>) {
-        Doc.GetProto(this.props.Document).ink = new InkField(value);
+        Doc.GetProto(this.props.Document)[this.props.inkFieldKey] = new InkField(value);
     }
 
     @action
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 0837e07a9..6cde73933 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -8,6 +8,7 @@ import { faPen, faHighlighter, faEraser, faBan } from '@fortawesome/free-solid-s
 import { SelectionManager } from "../util/SelectionManager";
 import { InkTool } from "../../new_fields/InkField";
 import { Doc } from "../../new_fields/Doc";
+import { InkingCanvas } from "./InkingCanvas";
 
 library.add(faPen, faHighlighter, faEraser, faBan);
 
@@ -39,7 +40,7 @@ export class InkingControl extends React.Component {
     @action
     switchColor = (color: ColorResult): void => {
         this._selectedColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff");
-        SelectionManager.SelectedDocuments().forEach(doc => Doc.GetProto(doc.props.Document).backgroundColor = this._selectedColor);
+        if (InkingControl.Instance.selectedTool === InkTool.None) SelectionManager.SelectedDocuments().forEach(doc => Doc.GetProto(doc.props.Document).backgroundColor = this._selectedColor);
     }
 
     @action
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 8198b88d2..a72f25b99 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -144,7 +144,7 @@ export class MainView extends React.Component {
         const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc));
         if (list) {
             let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, width: this.pwidth * .7, height: this.pheight, title: `WS collection ${list.length + 1}` });
-            var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(CurrentUserUtils.UserDocument, 150), CollectionDockingView.makeDocumentConfig(freeformDoc, 600)] }] };
+            var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(CurrentUserUtils.UserDocument, CurrentUserUtils.UserDocument, 150), CollectionDockingView.makeDocumentConfig(freeformDoc, freeformDoc, 600)] }] };
             let mainDoc = Docs.DockDocument([CurrentUserUtils.UserDocument, freeformDoc], JSON.stringify(dockingLayout), { title: `Workspace ${list.length + 1}` }, id);
             list.push(mainDoc);
             // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container)
@@ -177,7 +177,7 @@ export class MainView extends React.Component {
 
     openNotifsCol = () => {
         if (this._notifsCol && CollectionDockingView.Instance) {
-            CollectionDockingView.Instance.AddRightSplit(this._notifsCol);
+            CollectionDockingView.Instance.AddRightSplit(this._notifsCol, this._notifsCol);
         }
     }
 
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 75bdf755c..79a9f3be0 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -100,7 +100,6 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
         }
         return false;
     }
-    @computed get isAnnotationOverlay() { return this.props.fieldKey === "annotations"; }
 
     @action.bound
     addDocument(doc: Doc, allowDuplicates: boolean = false): boolean {
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index b3f1b1c88..f5f323269 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -28,7 +28,6 @@ import React = require("react");
 import { FormattedTextBox } from '../nodes/FormattedTextBox';
 import { ImageField } from '../../../new_fields/URLField';
 import { ImageBox } from '../nodes/ImageBox';
-import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
 import { CollectionView } from './CollectionView';
 
 
@@ -71,11 +70,23 @@ class TreeView extends React.Component<TreeViewProps> {
     @observable _collapsed: boolean = true;
 
     @computed get fieldKey() {
+        let keys = Array.from(Object.keys(this.dataDoc));
+        if (this.dataDoc.proto instanceof Doc) {
+            keys.push(...Array.from(Object.keys(this.dataDoc.proto)));
+            while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1);
+        }
+        let keyList: string[] = [];
+        keys.map(key => {
+            let docList = Cast(this.dataDoc[key], listSpec(Doc));
+            if (docList && docList.length > 0) {
+                keyList.push(key);
+            }
+        });
         let layout = StrCast(this.props.document.layout);
         if (layout.indexOf("fieldKey={\"") !== -1) {
             return layout.split("fieldKey={\"")[1].split("\"")[0];
         }
-        return "data";
+        return keyList.length ? keyList[0] : "data";
     }
 
     @computed get dataDoc() { return (BoolCast(this.props.document.isTemplate) ? this.props.dataDoc : this.props.document); }
@@ -163,63 +174,39 @@ class TreeView extends React.Component<TreeViewProps> {
         SetValue={(value: string) => {
             let res = (Doc.GetProto(this.dataDoc)[key] = value) ? true : true;
 
-            if (value.startsWith(">>>")) {
-                let metaKey = value.slice(3, value.length);
+            if (value.startsWith(">")) {
+                let metaKey = value.slice(value.startsWith(">>>") ? 3 : value.startsWith(">>") ? 2 : 1, value.length);
                 let collection = this.props.containingCollection;
-                Doc.GetProto(collection)[metaKey] = new List<Doc>([
-                    Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }),
-                    Docs.TextDocument({ documentText: "hello world!", width: 300, height: 300 }),
-                ]);
                 let template = Doc.MakeAlias(collection);
                 template.title = metaKey;
                 template.embed = true;
-                template.layout = CollectionView.LayoutString(metaKey);
-                template.viewType = CollectionViewType.Freeform;
                 template.x = 0;
                 template.y = 0;
                 template.width = 300;
                 template.height = 300;
                 template.isTemplate = true;
                 template.templates = new List<string>([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]);
-                Doc.AddDocToList(collection, "data", template);
-                this.delete();
-            } else
-                if (value.startsWith(">>")) {
-                    let metaKey = value.slice(2, value.length);
-                    let collection = this.props.containingCollection;
+                if (value.startsWith(">>>")) { // Collection
+                    Doc.GetProto(collection)[metaKey] = new List<Doc>([
+                        Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }),
+                        Docs.TextDocument({ documentText: "hello world!", width: 300, height: 300 }),
+                    ]);
+                    template.layout = CollectionView.LayoutString(metaKey);
+                    template.viewType = CollectionViewType.Freeform;
+                } else if (value.startsWith(">>")) { // Image
                     Doc.GetProto(collection)[metaKey] = new ImageField("http://www.cs.brown.edu/~bcz/face.gif");
-                    let template = Doc.MakeAlias(collection);
-                    template.title = metaKey;
-                    template.embed = true;
                     template.layout = ImageBox.LayoutString(metaKey);
-                    template.x = 0;
-                    template.y = 0;
                     template.nativeWidth = 300;
                     template.nativeHeight = 300;
-                    template.width = 300;
-                    template.height = 300;
-                    template.isTemplate = true;
-                    template.templates = new List<string>([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]);
-                    Doc.AddDocToList(collection, "data", template);
-                    this.delete();
-                } else
-                    if (value.startsWith(">")) {
-                        let metaKey = value.slice(1, value.length);
-                        let collection = this.props.containingCollection;
-                        Doc.GetProto(collection)[metaKey] = "-empty field-";
-                        let template = Doc.MakeAlias(collection);
-                        template.title = metaKey;
-                        template.embed = true;
-                        template.layout = FormattedTextBox.LayoutString(metaKey);
-                        template.x = 0;
-                        template.y = 0;
-                        template.width = 100;
-                        template.height = 50;
-                        template.isTemplate = true;
-                        template.templates = new List<string>([Templates.TitleBar(metaKey)]);//`{props.DataDoc.${metaKey}_text}`)]);
-                        Doc.AddDocToList(collection, "data", template);
-                        this.delete();
-                    }
+                } else if (value.startsWith(">")) {  // Text
+                    Doc.GetProto(collection)[metaKey] = "-empty field-";
+                    template.layout = FormattedTextBox.LayoutString(metaKey);
+                    template.width = 100;
+                    template.height = 50;
+                }
+                Doc.AddDocToList(collection, "data", template);
+                this.delete();
+            }
 
             return res;
         }}
@@ -238,14 +225,8 @@ class TreeView extends React.Component<TreeViewProps> {
             keys.push(...Array.from(Object.keys(this.dataDoc.proto)));
             while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1);
         }
-        let keyList: string[] = [];
-        keys.map(key => {
-            let docList = Cast(this.dataDoc[key], listSpec(Doc));
-            let doc = Cast(this.dataDoc[key], Doc);
-            if (doc instanceof Doc || docList) {
-                keyList.push(key);
-            }
-        });
+        let keyList: string[] = keys.reduce((l, key) => Cast(this.dataDoc[key], listSpec(Doc)) ? [...l, key] : l, [] as string[]);
+        keys.map(key => Cast(this.dataDoc[key], Doc) instanceof Doc && keyList.push(key));
         if (keyList.indexOf(this.fieldKey) !== -1) {
             keyList.splice(keyList.indexOf(this.fieldKey), 1);
         }
@@ -291,16 +272,16 @@ class TreeView extends React.Component<TreeViewProps> {
     onWorkspaceContextMenu = (e: React.MouseEvent): void => {
         if (!e.isPropagationStopped()) { // 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: "Open as Workspace", event: undoBatch(() => MainView.Instance.openWorkspace(this.dataDoc)) });
-            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.KVPDocument(this.dataDoc, { width: 300, height: 300 }); this.props.addDocTab(kvp, kvp, "onRight"); }, icon: "layer-group" });
+            ContextMenu.Instance.addItem({ description: "Open Fields", event: () => { let kvp = Docs.KVPDocument(this.props.document, { width: 300, height: 300 }); this.props.addDocTab(kvp, kvp, "onRight"); }, icon: "layer-group" });
             if (NumCast(this.props.document.viewType) !== CollectionViewType.Docking) {
-                ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.props.document, "inTab"), icon: "folder" });
-                ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.props.document, "onRight"), icon: "caret-square-right" });
+                ContextMenu.Instance.addItem({ description: "Open Tab", event: () => this.props.addDocTab(this.props.document, this.dataDoc, "inTab"), icon: "folder" });
+                ContextMenu.Instance.addItem({ description: "Open Right", event: () => this.props.addDocTab(this.props.document, this.dataDoc, "onRight"), icon: "caret-square-right" });
                 if (DocumentManager.Instance.getDocumentViews(this.dataDoc).length) {
                     ContextMenu.Instance.addItem({ description: "Focus", event: () => DocumentManager.Instance.getDocumentViews(this.dataDoc).map(view => view.props.focus(this.props.document)) });
                 }
-                ContextMenu.Instance.addItem({ description: "Delete Item", event: undoBatch(() => this.props.deleteDoc(this.dataDoc)) });
+                ContextMenu.Instance.addItem({ description: "Delete Item", event: undoBatch(() => this.props.deleteDoc(this.props.document)) });
             } else {
-                ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.props.deleteDoc(this.dataDoc)) });
+                ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.props.deleteDoc(this.props.document)) });
             }
             ContextMenu.Instance.displayMenu(e.pageX > 156 ? e.pageX - 156 : 0, e.pageY - 15);
             e.stopPropagation();
@@ -349,14 +330,14 @@ class TreeView extends React.Component<TreeViewProps> {
         if (!this._collapsed) {
             if (!this.props.document.embed) {
                 contentElement = <ul key={this._chosenKey + "more"}>
-                    {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.props.dataDoc, this._chosenKey, addDoc, remDoc, this.move,
+                    {TreeView.GetChildElements(doc instanceof Doc ? [doc] : DocListCast(docList), this.props.treeViewId, this.props.document, this.dataDoc, this._chosenKey, addDoc, remDoc, this.move,
                         this.props.dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.props.outerXf, this.props.active, this.props.panelWidth)}
                 </ul >;
             } else {
                 contentElement = <div ref={this._dref} style={{ display: "inline-block", height: this.props.panelHeight() }} key={this.props.document[Id]}>
                     <CollectionSchemaPreview
                         Document={this.props.document}
-                        DataDocument={this.props.dataDoc}
+                        DataDocument={this.dataDoc}
                         width={docWidth}
                         height={this.props.panelHeight}
                         getTransform={this.docTransform}
@@ -400,7 +381,7 @@ class TreeView extends React.Component<TreeViewProps> {
         active: () => boolean,
         panelWidth: () => number,
     ) {
-        let docList = docs.filter(child => !child.excludeFromLibrary && (key !== this.fieldKey || !child.isMinimized));
+        let docList = docs.filter(child => !child.excludeFromLibrary);
         let rowWidth = () => panelWidth() - 20;
         return docList.map((child, i) => {
             let indent = i === 0 ? undefined : () => {
@@ -475,6 +456,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
 
     outerXf = () => Utils.GetScreenTransform(this._mainEle!);
     onTreeDrop = (e: React.DragEvent) => this.onDrop(e, {});
+    @computed get dataDoc() { return (BoolCast(this.props.DataDoc.isTemplate) ? this.props.DataDoc : this.props.Document); }
 
     render() {
         let dropAction = StrCast(this.props.Document.dropAction) as dropActionType;
@@ -502,7 +484,7 @@ export class CollectionTreeView extends CollectionSubView(Document) {
                     }} />
                 <ul className="no-indent" style={{ width: "max-content" }} >
                     {
-                        TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove,
+                        TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.dataDoc, this.props.fieldKey, addDoc, this.remove,
                             moveDoc, dropAction, this.props.addDocTab, this.props.ScreenToLocalTransform, this.outerXf, this.props.active, this.props.PanelWidth)
                     }
                 </ul>
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 872cb3f1c..cc097f371 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -2,8 +2,10 @@ import { library } from '@fortawesome/fontawesome-svg-core';
 import { faProjectDiagram, faSignature, faSquare, faTh, faThList, faTree } from '@fortawesome/free-solid-svg-icons';
 import { observer } from "mobx-react";
 import * as React from 'react';
+import { Doc } from '../../../new_fields/Doc';
 import { Id } from '../../../new_fields/FieldSymbols';
 import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
+import { Docs } from '../../documents/Documents';
 import { undoBatch } from '../../util/UndoManager';
 import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from '../ContextMenuItem';
@@ -14,11 +16,6 @@ import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormV
 import { CollectionSchemaView } from "./CollectionSchemaView";
 import { CollectionStackingView } from './CollectionStackingView';
 import { CollectionTreeView } from "./CollectionTreeView";
-import { Doc } from '../../../new_fields/Doc';
-import { FormattedTextBox } from '../nodes/FormattedTextBox';
-import { Docs } from '../../documents/Documents';
-import { List } from '../../../new_fields/List';
-import { ImageField } from '../../../new_fields/URLField';
 export const COLLECTION_BORDER_WIDTH = 2;
 
 library.add(faTh);
@@ -62,17 +59,7 @@ export class CollectionView extends React.Component<FieldViewProps> {
             ContextMenu.Instance.addItem({
                 description: "Apply Template", event: undoBatch(() => {
                     let otherdoc = Docs.TextDocument({ width: 100, height: 50, title: "applied template" });
-                    Doc.GetProto(otherdoc).description = "THIS DESCRIPTION IS REALLY IMPORTANT!";
-                    Doc.GetProto(otherdoc).summary = "THIS SUMMARY IS MEANINGFUL!";
-                    Doc.GetProto(otherdoc).photo = new ImageField("http://www.cs.brown.edu/~bcz/snowbeast.JPG");
                     Doc.GetProto(otherdoc).layout = Doc.MakeDelegate(this.props.Document);
-                    Doc.GetProto(otherdoc).publication = new List<Doc>([
-                        Docs.TextDocument({ documentText: "hello world!", width: 300, height: 300 }),
-                        Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }),
-                        Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }),
-                        Docs.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { width: 300, height: 300 }),
-                        Docs.TextDocument({ documentText: "hello world!", width: 300, height: 300 }),
-                    ]);
                     this.props.addDocTab && this.props.addDocTab(otherdoc, otherdoc, "onRight");
                 }), icon: "project-diagram"
             });
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 71964ef82..c6f003a81 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -370,7 +370,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     }
 
     private childViews = () => [
-        <CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} />,
+        <CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} DataDoc={this.props.DataDoc} />,
         ...this.views
     ]
     render() {
@@ -387,7 +387,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                         easing={easing} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
 
                         <CollectionFreeFormLinksView {...this.props} key="freeformLinks">
-                            <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} >
+                            <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.DataDoc} inkFieldKey={this.props.fieldKey + "_ink"} >
                                 {this.childViews}
                             </InkingCanvas>
                         </CollectionFreeFormLinksView>
@@ -414,6 +414,7 @@ class CollectionFreeFormOverlayView extends React.Component<DocumentViewProps &
 @observer
 class CollectionFreeFormBackgroundView extends React.Component<DocumentViewProps & { isSelected: () => boolean }> {
     @computed get backgroundView() {
+        let props = this.props;
         return (<DocumentContentsView {...this.props} layoutKey={"backgroundLayout"}
             isTopMost={this.props.isTopMost} isSelected={this.props.isSelected} select={emptyFunction} />);
     }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 7000352e7..6adead626 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -203,6 +203,7 @@ class Viewer extends React.Component<IViewerProps> {
             this._isPage[page] = "page";
             this._visibleElements[page] = (
                 <Page
+                    size={this._pageSizes[page]}
                     pdf={this.props.pdf}
                     page={page}
                     numPages={this.props.pdf.numPages}
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 27b3473f8..0a1964dea 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -215,7 +215,7 @@ export namespace Doc {
 
     // gets the document's prototype or returns the document if it is a prototype
     export function GetProto(doc: Doc) {
-        return Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc);
+        return Doc.GetT(doc, "isPrototype", "boolean", true) || doc.isTemplate ? doc : (doc.proto || doc);
     }
 
     export function allKeys(doc: Doc): string[] {
-- 
cgit v1.2.3-70-g09d2


From 4270bd26e1b28f429ca11e43504b1a39a0a77baa Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Mon, 24 Jun 2019 16:11:29 -0400
Subject: idrk

---
 src/client/util/RichTextSchema.tsx  |  33 ++-----
 src/client/util/TooltipTextMenu.tsx | 168 ++++++++++++++++++++++--------------
 2 files changed, 110 insertions(+), 91 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index f3f6655af..936dcbfd6 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -91,8 +91,8 @@ export const nodes: { [index: string]: NodeSpec } = {
         attrs: {
             visibility: { default: false },
             text: { default: undefined },
-            oldtextslice: { default: undefined },
-            oldtextlen: { default: 0 }
+            textslice: { default: undefined },
+            textlen: { default: 0 }
 
         },
         group: "inline",
@@ -495,31 +495,26 @@ export class SummarizedView {
         this._collapsed = document.createElement("span");
         this._collapsed.textContent = "㊉";
         this._collapsed.style.opacity = "0.5";
-        // this._collapsed.style.background = "yellow";
         this._collapsed.style.position = "relative";
         this._collapsed.style.width = "40px";
         this._collapsed.style.height = "20px";
         let self = this;
         this._view = view;
         this._collapsed.onpointerdown = function (e: any) {
-            console.log("star pressed!");
             if (node.attrs.visibility) {
                 node.attrs.visibility = !node.attrs.visibility;
-                console.log("content is visible");
                 let y = getPos();
                 let { from, to } = self.updateSummarizedText(y + 1, view.state.schema.marks.highlight);
                 let length = to - from;
                 let newSelection = TextSelection.create(view.state.doc, y + 1, y + 1 + length);
+                // update attrs of node
                 node.attrs.text = newSelection.content();
                 view.dispatch(view.state.tr.setSelection(newSelection).deleteSelection(view.state, () => { }));
                 self._collapsed.textContent = "㊉";
             } else {
                 node.attrs.visibility = !node.attrs.visibility;
-                console.log("content is invisible");
                 let y = getPos();
-                console.log(y);
                 let mark = view.state.schema.mark(view.state.schema.marks.highlight);
-                console.log("PASTING " + node.attrs.text.toString());
                 view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, y + 1, y + 1)));
                 const from = view.state.selection.from;
                 let size = node.attrs.text.size;
@@ -538,39 +533,21 @@ export class SummarizedView {
     updateSummarizedText(start?: any, mark?: any) {
         let $start = this._view.state.doc.resolve(start);
         let endPos = start;
-        //let first_startPos = $start.start(), endPos = first_startPos;
-        // let startIndex = $start.index(), endIndex = $start.indexAfter();
-        // let nodeAfter = $start.nodeAfter;
-        // while (startIndex > 0 && mark.isInSet($start.parent.child(startIndex - 1).marks)) startIndex--;
-        // while (endIndex < $start.parent.childCount && mark.isInSet($start.parent.child(endIndex).marks)) endIndex++;
-        // let startPos = $start.start(), endPos = startPos;
-        // for (let i = 0; i < endIndex; i++) {
-        //     let size = $start.parent.child(i).nodeSize;
-        //     console.log($start.parent.child(i).childCount);
-        //     if (i < startIndex) startPos += size;
-        //     endPos += size;
-        // }
+
         let _mark = this._view.state.schema.mark(this._view.state.schema.marks.highlight);
-        // first_startPos = start;
-        // endPos = first_startPos;
         let visited = new Set();
         for (let i: number = start + 1; i < this._view.state.doc.nodeSize - 1; i++) {
-            console.log("ITER:", i);
             let skip = false;
             this._view.state.doc.nodesBetween(start, i, (node: Node, pos: number, parent: Node, index: number) => {
                 if (node.isLeaf && !visited.has(node) && !skip) {
                     if (node.marks.includes(_mark)) {
                         visited.add(node);
-                        //endPos += node.nodeSize + 1;
                         endPos = i + node.nodeSize - 1;
-                        console.log("node contains mark!");
                     }
                     else skip = true;
                 }
             });
         }
-        console.log(start);
-        console.log(endPos);
         return { from: start, to: endPos };
     }
 
@@ -592,7 +569,7 @@ const fromJson = schema.nodeFromJSON;
 schema.nodeFromJSON = (json: any) => {
     let node = fromJson(json);
     if (json.type === "star") {
-        node.attrs.oldtext = Slice.fromJSON(schema, node.attrs.oldtextslice);
+        node.attrs.text = Slice.fromJSON(schema, node.attrs.textslice);
     }
     return node;
 };
\ No newline at end of file
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index c9216199b..c42d5fab8 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -6,7 +6,7 @@ import { keymap } from "prosemirror-keymap";
 import { EditorState, Transaction, NodeSelection, TextSelection } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { schema } from "./RichTextSchema";
-import { Schema, NodeType, MarkType, Mark } from "prosemirror-model";
+import { Schema, NodeType, MarkType, Mark, ResolvedPos } from "prosemirror-model";
 import { Node as ProsNode } from "prosemirror-model"
 import React = require("react");
 import "./TooltipTextMenu.scss";
@@ -32,6 +32,7 @@ import { Id } from "../../new_fields/FieldSymbols";
 import { Utils } from "../../Utils";
 import { FormattedTextBoxProps } from "../views/nodes/FormattedTextBox";
 import { text } from "body-parser";
+import { type } from "os";
 // import { wrap } from "module";
 
 const SVG = "http://www.w3.org/2000/svg";
@@ -61,6 +62,8 @@ export class TooltipTextMenu {
     private fontStyleDom?: Node;
     private listTypeBtnDom?: Node;
 
+    private _activeMarks: Mark[] = [];
+
     constructor(view: EditorView, editorProps: FieldViewProps & FormattedTextBoxProps) {
         this.view = view;
         this.state = view.state;
@@ -123,6 +126,7 @@ export class TooltipTextMenu {
         this.fontSizeToNum.set(schema.marks.p32, 32);
         this.fontSizeToNum.set(schema.marks.p48, 48);
         this.fontSizeToNum.set(schema.marks.p72, 72);
+        //this.fontSizeToNum.set(schema.marks.pFontSize,schema.marks.pFontSize.)
         this.fontSizes = Array.from(this.fontSizeToNum.keys());
 
         //list types
@@ -282,8 +286,20 @@ export class TooltipTextMenu {
     }
 
     insertStar(state: EditorState<any>, dispatch: any) {
-        console.log("creating star...");
-        let newNode = schema.nodes.star.create({ visibility: false, text: state.selection.content(), oldtextslice: state.selection.content().toJSON(), oldtextlen: state.selection.to - state.selection.from });
+        if (state.selection.empty) {
+            let mark = state.schema.mark(state.schema.marks.highlight)
+            if (this._activeMarks.includes(mark)) {
+                const ind = this._activeMarks.indexOf(mark);
+                this._activeMarks.splice(ind, 1);
+            }
+            else {
+                this._activeMarks.push(mark);
+            }
+            dispatch(state.tr.insertText(" ").setStoredMarks(this._activeMarks));
+            //dispatch(state.tr.setStoredMarks(this._activeMarks));
+            return true;
+        }
+        let newNode = schema.nodes.star.create({ visibility: false, text: state.selection.content(), textslice: state.selection.content().toJSON(), textlen: state.selection.to - state.selection.from });
         if (dispatch) {
             //console.log(newNode.attrs.text.toString());
             dispatch(state.tr.replaceSelectionWith(newNode));
@@ -315,7 +331,7 @@ export class TooltipTextMenu {
     }
 
     //for a specific grouping of marks (passed in), remove all and apply the passed-in one to the selected text
-    changeToMarkInGroup(markType: MarkType, view: EditorView, fontMarks: MarkType[]) {
+    changeToMarkInGroup = (markType: MarkType, view: EditorView, fontMarks: MarkType[]) => {
         let { empty, $cursor, ranges } = view.state.selection as TextSelection;
         let state = view.state;
         let dispatch = view.dispatch;
@@ -341,7 +357,18 @@ export class TooltipTextMenu {
                     }
                 }
             }
-        }); //actually apply font
+        });
+        // fontsize
+        // if (markType.name[0] === 'p') {
+        //     let size = this.fontSizeToNum.get(markType);
+        //     if (size) { this.updateFontSizeDropdown(String(size) + " pt"); }
+        // }
+        // else {
+        //     let fontName = this.fontStylesToName.get(markType);
+        //     if (fontName) { this.updateFontStyleDropdown(fontName); }
+        // }
+        //this.update(view, undefined);
+        //actually apply font
         return toggleMark(markType)(view.state, view.dispatch, view);
     }
 
@@ -529,53 +556,46 @@ export class TooltipTextMenu {
         // Otherwise, reposition it and update its content
         //this.tooltip.style.display = "";
         let { from, to } = state.selection;
-        let start = view.coordsAtPos(from), end = view.coordsAtPos(to);
-        // The box in which the tooltip is positioned, to use as base
-        //let box = this.tooltip.offsetParent!.getBoundingClientRect();
-        // Find a center-ish x position from the selection endpoints (when
-        // crossing lines, end may be more to the left)
-        let left = Math.max((start.left + end.left) / 2, start.left + 3);
-        //this.tooltip.style.left = (left - box.left) * this.editorProps.ScreenToLocalTransform().Scale + "px";
-        let width = Math.abs(start.left - end.left) / 2 * this.editorProps.ScreenToLocalTransform().Scale;
-        let mid = Math.min(start.left, end.left) + width;
-
-        //this.tooltip.style.width = 225 + "px";
-        // this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px";
-        // this.tooltip.style.top = "-100px";
-        //this.tooltip.style.height = "100px";
-
-        // let transform = this.editorProps.ScreenToLocalTransform();
-        // this.tooltip.style.width = `${225 / transform.Scale}px`;
-        // Utils
 
         //UPDATE LIST ITEM DROPDOWN
         this.listTypeBtnDom = this.updateListItemDropdown(":", this.listTypeBtnDom!);
+        //this._activeMarks = [];
 
         //UPDATE FONT STYLE DROPDOWN
         let activeStyles = this.activeMarksOnSelection(this.fontStyles);
-        if (activeStyles.length === 1) {
-            // if we want to update something somewhere with active font name
-            let fontName = this.fontStylesToName.get(activeStyles[0]);
-            if (fontName) { this.updateFontStyleDropdown(fontName); }
-        } else if (activeStyles.length === 0) {
-            //crimson on default
-            this.updateFontStyleDropdown("Crimson Text");
-        } else {
-            this.updateFontStyleDropdown("Various");
+        if (activeStyles !== undefined) {
+            // activeStyles.forEach((markType) => {
+            //     this._activeMarks.push(this.view.state.schema.mark(markType));
+            // });
+            if (activeStyles.length === 1) {
+                // if we want to update something somewhere with active font name
+                let fontName = this.fontStylesToName.get(activeStyles[0]);
+                if (fontName) { this.updateFontStyleDropdown(fontName); }
+            } else if (activeStyles.length === 0) {
+                //crimson on default
+                this.updateFontStyleDropdown("Crimson Text");
+            } else {
+                this.updateFontStyleDropdown("Various");
+            }
         }
 
         //UPDATE FONT SIZE DROPDOWN
         let activeSizes = this.activeMarksOnSelection(this.fontSizes);
-        if (activeSizes.length === 1) { //if there's only one active font size
-            let size = this.fontSizeToNum.get(activeSizes[0]);
-            if (size) { this.updateFontSizeDropdown(String(size) + " pt"); }
-        } else if (activeSizes.length === 0) {
-            //should be 14 on default  
-            this.updateFontSizeDropdown("14 pt");
-        } else { //multiple font sizes selected
-            this.updateFontSizeDropdown("Various");
+        if (activeSizes !== undefined) {
+            if (activeSizes.length === 1) { //if there's only one active font size
+                // activeSizes.forEach((markType) => {
+                //     this._activeMarks.push(this.view.state.schema.mark(markType));
+                // });
+                let size = this.fontSizeToNum.get(activeSizes[0]);
+                if (size) { this.updateFontSizeDropdown(String(size) + " pt"); }
+            } else if (activeSizes.length === 0) {
+                //should be 14 on default  
+                this.updateFontSizeDropdown("14 pt");
+            } else { //multiple font sizes selected
+                this.updateFontSizeDropdown("Various");
+            }
         }
-
+        this.view.dispatch(this.view.state.tr.setStoredMarks(this._activeMarks));
         this.updateLinkMenu();
     }
 
@@ -599,34 +619,56 @@ export class TooltipTextMenu {
             });
         }
         else {
-            let pos = this.view.state.selection.$from;
-            let ref_node: ProsNode;
-            if (pos.nodeAfter !== null && pos.nodeAfter !== undefined) {
-                ref_node = pos.nodeAfter;
-            }
-            else if (pos.nodeBefore !== null && pos.nodeBefore !== undefined) {
-                ref_node = pos.nodeBefore;
-            }
-            else {
-                return [];
-            }
-            let text_node_type: NodeType;
-            if (ref_node.isText) {
-                text_node_type = ref_node.type;
+            const pos = this.view.state.selection.$from;
+            const ref_node: ProsNode = this.reference_node(pos);
+            if (ref_node !== null && ref_node !== this.view.state.doc) {
+                let text_node_type: NodeType;
+                if (ref_node.isText) {
+                    text_node_type = ref_node.type;
+                }
+                else {
+                    return [];
+                }
+
+                this._activeMarks = ref_node.marks;
+
+                activeMarks = markGroup.filter(mark_type => {
+                    if (dispatch) {
+                        let mark = state.schema.mark(mark_type);
+                        return ref_node.marks.includes(mark);
+                    }
+                    return false;
+                });
+                return activeMarks;
             }
             else {
                 return [];
             }
 
-            activeMarks = markGroup.filter(mark_type => {
-                if (dispatch) {
-                    let mark = state.schema.mark(mark_type);
-                    return ref_node.marks.includes(mark);
-                }
-                return false;
-            });
         }
-        return activeMarks;
+    }
+
+    reference_node(pos: ResolvedPos<any>): ProsNode {
+        let ref_node: ProsNode = this.view.state.doc;
+        if (pos.nodeAfter !== null && pos.nodeAfter !== undefined) {
+            ref_node = pos.nodeAfter;
+        }
+        else if (pos.nodeBefore !== null && pos.nodeBefore !== undefined) {
+            ref_node = pos.nodeBefore;
+        }
+        else if (pos.pos > 0) {
+            let skip = false;
+            for (let i: number = pos.pos - 1; i > 0; i--) {
+                this.view.state.doc.nodesBetween(i, pos.pos, (node: ProsNode, pos: number, parent: ProsNode, index: number) => {
+                    if (node.isLeaf && !skip) {
+                        ref_node = node;
+                        skip = true;
+                    }
+
+                });
+            }
+        }
+        return ref_node;
     }
 
     destroy() { this.tooltip.remove(); }
-- 
cgit v1.2.3-70-g09d2


From c2c04325e0f29c01cd5ab0617d17a62183a53611 Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Tue, 25 Jun 2019 14:00:42 -0400
Subject: fixed most stuff, still the zooming and focus bugs

---
 src/client/util/RichTextSchema.tsx                 |  1 +
 src/client/util/TooltipTextMenu.tsx                | 54 ++++++++++------------
 .../collections/collectionFreeForm/MarqueeView.tsx |  2 +-
 3 files changed, 26 insertions(+), 31 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 936dcbfd6..63c879d67 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -509,6 +509,7 @@ export class SummarizedView {
                 let newSelection = TextSelection.create(view.state.doc, y + 1, y + 1 + length);
                 // update attrs of node
                 node.attrs.text = newSelection.content();
+                node.attrs.textslice = newSelection.content().toJSON();
                 view.dispatch(view.state.tr.setSelection(newSelection).deleteSelection(view.state, () => { }));
                 self._collapsed.textContent = "㊉";
             } else {
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index c42d5fab8..d08048e21 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -84,7 +84,7 @@ export class TooltipTextMenu {
             { command: toggleMark(schema.marks.strikethrough), dom: this.icon("S", "strikethrough", "Strikethrough") },
             { command: toggleMark(schema.marks.superscript), dom: this.icon("s", "superscript", "Superscript") },
             { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript", "Subscript") },
-            { command: deleteSelection, dom: this.icon("C", 'collapse', 'Collapse') }
+            { command: toggleMark(schema.marks.highlight), dom: this.icon("H", 'blue', 'Blue') }
             // { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") },
             // { command: wrapInList(schema.nodes.ordered_list), dom: this.icon("1)", "bullets") },
             // { command: lift, dom: this.icon("<", "lift") },
@@ -144,6 +144,8 @@ export class TooltipTextMenu {
 
         this.tooltip.appendChild(this.createStar().render(this.view).dom);
 
+        this.updateListItemDropdown(":", this.listTypeBtnDom);
+
         this.update(view, undefined);
 
         //view.dom.parentNode!.parentNode!.insertBefore(this.tooltip, view.dom.parentNode);
@@ -166,12 +168,15 @@ export class TooltipTextMenu {
             fontSizeBtns.push(this.dropdownMarkBtn(String(number), "color: black; width: 50px;", mark, this.view, this.changeToMarkInGroup, this.fontSizes));
         });
 
-        if (this.fontSizeDom) { this.tooltip.removeChild(this.fontSizeDom); }
-        this.fontSizeDom = (new Dropdown(cut(fontSizeBtns), {
+        let newfontSizeDom = (new Dropdown(cut(fontSizeBtns), {
             label: label,
             css: "color:black; min-width: 60px; padding-left: 5px; margin-right: 0;"
         }) as MenuItem).render(this.view).dom;
-        this.tooltip.appendChild(this.fontSizeDom);
+        if (this.fontSizeDom) { this.tooltip.replaceChild(newfontSizeDom, this.fontSizeDom); }
+        else {
+            this.tooltip.appendChild(newfontSizeDom);
+        }
+        this.fontSizeDom = newfontSizeDom;
     }
 
     //label of dropdown will change to given label
@@ -185,13 +190,16 @@ export class TooltipTextMenu {
             fontBtns.push(this.dropdownMarkBtn(name, "color: black; font-family: " + name + ", sans-serif; width: 125px;", mark, this.view, this.changeToMarkInGroup, this.fontStyles));
         });
 
-        if (this.fontStyleDom) { this.tooltip.removeChild(this.fontStyleDom); }
-        this.fontStyleDom = (new Dropdown(cut(fontBtns), {
+        let newfontStyleDom = (new Dropdown(cut(fontBtns), {
             label: label,
             css: "color:black; width: 125px; margin-left: -3px; padding-left: 2px;"
         }) as MenuItem).render(this.view).dom;
+        if (this.fontStyleDom) { this.tooltip.replaceChild(newfontStyleDom, this.fontStyleDom); }
+        else {
+            this.tooltip.appendChild(newfontStyleDom);
+        }
+        this.fontStyleDom = newfontStyleDom;
 
-        this.tooltip.appendChild(this.fontStyleDom);
     }
 
     updateLinkMenu() {
@@ -286,19 +294,6 @@ export class TooltipTextMenu {
     }
 
     insertStar(state: EditorState<any>, dispatch: any) {
-        if (state.selection.empty) {
-            let mark = state.schema.mark(state.schema.marks.highlight)
-            if (this._activeMarks.includes(mark)) {
-                const ind = this._activeMarks.indexOf(mark);
-                this._activeMarks.splice(ind, 1);
-            }
-            else {
-                this._activeMarks.push(mark);
-            }
-            dispatch(state.tr.insertText(" ").setStoredMarks(this._activeMarks));
-            //dispatch(state.tr.setStoredMarks(this._activeMarks));
-            return true;
-        }
         let newNode = schema.nodes.star.create({ visibility: false, text: state.selection.content(), textslice: state.selection.content().toJSON(), textlen: state.selection.to - state.selection.from });
         if (dispatch) {
             //console.log(newNode.attrs.text.toString());
@@ -359,15 +354,14 @@ export class TooltipTextMenu {
             }
         });
         // fontsize
-        // if (markType.name[0] === 'p') {
-        //     let size = this.fontSizeToNum.get(markType);
-        //     if (size) { this.updateFontSizeDropdown(String(size) + " pt"); }
-        // }
-        // else {
-        //     let fontName = this.fontStylesToName.get(markType);
-        //     if (fontName) { this.updateFontStyleDropdown(fontName); }
-        // }
-        //this.update(view, undefined);
+        if (markType.name[0] === 'p') {
+            let size = this.fontSizeToNum.get(markType);
+            if (size) { this.updateFontSizeDropdown(String(size) + " pt"); }
+        }
+        else {
+            let fontName = this.fontStylesToName.get(markType);
+            if (fontName) { this.updateFontStyleDropdown(fontName); }
+        }
         //actually apply font
         return toggleMark(markType)(view.state, view.dispatch, view);
     }
@@ -558,7 +552,7 @@ export class TooltipTextMenu {
         let { from, to } = state.selection;
 
         //UPDATE LIST ITEM DROPDOWN
-        this.listTypeBtnDom = this.updateListItemDropdown(":", this.listTypeBtnDom!);
+        //this.listTypeBtnDom = this.updateListItemDropdown(":", this.listTypeBtnDom!);
         //this._activeMarks = [];
 
         //UPDATE FONT STYLE DROPDOWN
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 796ff029c..d2a6ceafa 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -95,7 +95,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 }
             });
         } else if (!e.ctrlKey) {
-            let newBox = Docs.TextDocument({ width: 200, height: 50, x: x, y: y, title: "-typed text-" });
+            let newBox = Docs.TextDocument({ width: 200, height: 100, x: x, y: y, title: "-typed text-" });
             newBox.proto!.autoHeight = true;
             this.props.addLiveTextDocument(newBox);
         }
-- 
cgit v1.2.3-70-g09d2


From 76e444f3016fa2d550f664520ee27ead3eb39837 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 25 Jun 2019 14:45:46 -0400
Subject: fixed tooltip appearing.

---
 src/client/util/TooltipTextMenu.tsx     |  4 +++-
 src/client/views/MainOverlayTextBox.tsx | 13 +++++++++----
 2 files changed, 12 insertions(+), 5 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index c42d5fab8..5ff244b5f 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -671,5 +671,7 @@ export class TooltipTextMenu {
         return ref_node;
     }
 
-    destroy() { this.tooltip.remove(); }
+    destroy() {
+        this.tooltip.remove();
+    }
 }
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 4488d1046..58946845c 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -24,13 +24,18 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
     private _textHideOnLeave?: boolean;
     private _textTargetDiv: HTMLDivElement | undefined;
     private _textProxyDiv: React.RefObject<HTMLDivElement>;
-    private _outerdiv = (dominus: HTMLElement | null) => this._dominus && dominus && dominus.appendChild(this._dominus);
     private _textBottom: boolean | undefined;
     private _textAutoHeight: boolean | undefined;
+    private _setouterdiv = (outerdiv: HTMLElement | null) => { this._outerdiv = outerdiv; this.updateTooltip(); }
+    private _outerdiv: HTMLElement | null = null;
     private _textBox: FormattedTextBox | undefined;
-    private _dominus?: HTMLElement;
+    private _tooltip?: HTMLElement;
     @observable public TextDoc?: Doc;
 
+    updateTooltip = () => {
+        this._outerdiv && this._tooltip && !this._outerdiv.contains(this._tooltip) && this._outerdiv.appendChild(this._tooltip)
+    }
+
     constructor(props: MainOverlayTextBoxProps) {
         super(props);
         this._textProxyDiv = React.createRef();
@@ -116,14 +121,14 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
             let s = this._textXf().Scale;
             let location = this._textBottom ? textRect.bottom : textRect.top;
             let hgt = this._textAutoHeight || this._textBottom ? "auto" : this._textTargetDiv.clientHeight;
-            return <div ref={this._outerdiv} className="unscaled_div" style={{ transform: `translate(${textRect.left}px, ${location}px)` }} ><div className="mainOverlayTextBox-textInput" style={{ transform: `scale(${1 / s},${1 / s})`, width: "auto", height: "0px" }} >
+            return <div ref={this._setouterdiv} className="unscaled_div" style={{ transform: `translate(${textRect.left}px, ${location}px)` }} ><div className="mainOverlayTextBox-textInput" style={{ transform: `scale(${1 / s},${1 / s})`, width: "auto", height: "0px" }} >
                 <div className="mainOverlayTextBox-textInput" onPointerDown={this.textBoxDown} ref={this._textProxyDiv} onScroll={this.textScroll}
                     style={{ width: `${textRect.width * s}px`, height: "0px" }}>
                     <div style={{ height: hgt, width: "100%", position: "absolute", bottom: this._textBottom ? "0px" : undefined }}>
                         <FormattedTextBox color={`${this._textColor}`} fieldKey={this.TextFieldKey} hideOnLeave={this._textHideOnLeave} isOverlay={true} Document={FormattedTextBox.InputBoxOverlay.props.Document}
                             isSelected={returnTrue} select={emptyFunction} isTopMost={true} selectOnLoad={true}
                             ContainingCollectionView={undefined} whenActiveChanged={emptyFunction} active={returnTrue}
-                            ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} outer_div={(dominus: HTMLElement) => this._dominus = dominus} />
+                            ScreenToLocalTransform={this._textXf} PanelWidth={returnZero} PanelHeight={returnZero} focus={emptyFunction} addDocTab={this.addDocTab} outer_div={(tooltip: HTMLElement) => { this._tooltip = tooltip; this.updateTooltip(); }} />
                     </div>
                 </div>
             </div>
-- 
cgit v1.2.3-70-g09d2


From 4b69ee75fbc98d81eac1bbad0749cf266ccd4c3c Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Wed, 26 Jun 2019 13:12:39 -0400
Subject: idk

---
 src/client/util/TooltipTextMenu.tsx         | 7 ++-----
 src/client/views/nodes/FormattedTextBox.tsx | 1 -
 2 files changed, 2 insertions(+), 6 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index d08048e21..c42a29806 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -153,8 +153,6 @@ export class TooltipTextMenu {
         // quick and dirty null check
         const outer_div = this.editorProps.outer_div;
         outer_div && outer_div(this.tooltip);
-
-        console.log("hi");
     }
 
     //label of dropdown will change to given label
@@ -552,8 +550,6 @@ export class TooltipTextMenu {
         let { from, to } = state.selection;
 
         //UPDATE LIST ITEM DROPDOWN
-        //this.listTypeBtnDom = this.updateListItemDropdown(":", this.listTypeBtnDom!);
-        //this._activeMarks = [];
 
         //UPDATE FONT STYLE DROPDOWN
         let activeStyles = this.activeMarksOnSelection(this.fontStyles);
@@ -606,6 +602,7 @@ export class TooltipTextMenu {
                     let has = false, tr = state.tr;
                     for (let i = 0; !has && i < ranges.length; i++) {
                         let { $from, $to } = ranges[i];
+                        let hasmark: boolean = state.doc.rangeHasMark($from.pos, $to.pos, mark);
                         return state.doc.rangeHasMark($from.pos, $to.pos, mark);
                     }
                 }
@@ -633,13 +630,13 @@ export class TooltipTextMenu {
                     }
                     return false;
                 });
-                return activeMarks;
             }
             else {
                 return [];
             }
 
         }
+        return activeMarks;
     }
 
     reference_node(pos: ResolvedPos<any>): ProsNode {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 391e42b57..ca2a58cfe 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -101,7 +101,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         super(props);
         if (this.props.outer_div) {
             this._outerdiv = this.props.outer_div;
-            console.log("yay");
         }
 
         this._ref = React.createRef();
-- 
cgit v1.2.3-70-g09d2


From cad1871a1a8860b67eec61df225b7abf99900029 Mon Sep 17 00:00:00 2001
From: ab <abdullah_ahmed@brown.edu>
Date: Thu, 27 Jun 2019 12:37:04 -0400
Subject: keyboard shortcut for summarize

---
 src/client/util/ProsemirrorExampleTransfer.ts      |  4 ++
 src/client/util/TooltipTextMenu.tsx                | 53 +++++++++++++++++++++-
 src/client/views/MainOverlayTextBox.scss           |  2 +-
 src/client/views/MainOverlayTextBox.tsx            |  4 +-
 .../collections/collectionFreeForm/MarqueeView.tsx |  6 +--
 5 files changed, 61 insertions(+), 8 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts
index 091926d0a..fa9e2e5af 100644
--- a/src/client/util/ProsemirrorExampleTransfer.ts
+++ b/src/client/util/ProsemirrorExampleTransfer.ts
@@ -7,6 +7,8 @@ import { wrapInList, splitListItem, liftListItem, sinkListItem } from "prosemirr
 import { undo, redo } from "prosemirror-history";
 import { undoInputRule } from "prosemirror-inputrules";
 import { Transaction, EditorState } from "prosemirror-state";
+import { TooltipTextMenu } from "./TooltipTextMenu";
+import { Statement } from "../northstar/model/idea/idea";
 
 const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false;
 
@@ -96,5 +98,7 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?:
         });
     }
 
+    bind("Mod-s", TooltipTextMenu.insertStar);
+
     return keys;
 }
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 385c9a2a9..3a72a1ede 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -64,6 +64,8 @@ export class TooltipTextMenu {
 
     private _activeMarks: Mark[] = [];
 
+    private _collapseBtn?: MenuItem;
+
     constructor(view: EditorView, editorProps: FieldViewProps & FormattedTextBoxProps) {
         this.view = view;
         this.state = view.state;
@@ -71,6 +73,10 @@ export class TooltipTextMenu {
         this.tooltip = document.createElement("div");
         this.tooltip.className = "tooltipMenu";
 
+        // this.createCollapse();
+        // if (this._collapseBtn) {
+        //     this.tooltip.appendChild(this._collapseBtn.render(this.view).dom);
+        // }
         //add the div which is the tooltip
         //view.dom.parentNode!.parentNode!.appendChild(this.tooltip);
 
@@ -144,6 +150,8 @@ export class TooltipTextMenu {
 
         this.tooltip.appendChild(this.createStar().render(this.view).dom);
 
+
+
         this.updateListItemDropdown(":", this.listTypeBtnDom);
 
         this.update(view, undefined);
@@ -291,7 +299,7 @@ export class TooltipTextMenu {
         link = node && node.marks.find(m => m.type.name === "link");
     }
 
-    insertStar(state: EditorState<any>, dispatch: any) {
+    public static insertStar(state: EditorState<any>, dispatch: any) {
         let newNode = schema.nodes.star.create({ visibility: false, text: state.selection.content(), textslice: state.selection.content().toJSON(), textlen: state.selection.to - state.selection.from });
         if (dispatch) {
             //console.log(newNode.attrs.text.toString());
@@ -398,12 +406,53 @@ export class TooltipTextMenu {
             class: "summarize",
             execEvent: "",
             run: (state, dispatch, view) => {
-                this.insertStar(state, dispatch);
+                TooltipTextMenu.insertStar(state, dispatch);
             }
 
         });
     }
 
+    createCollapse() {
+        this._collapseBtn = new MenuItem({
+            title: "Collapse",
+            //label: "Collapse",
+            icon: icons.join,
+            execEvent: "",
+            css: "color:white;",
+            class: "summarize",
+            run: (state, dispatch, view) => {
+                this.collapseToolTip();
+            }
+        });
+    }
+
+    collapseToolTip() {
+        if (this._collapseBtn) {
+            if (this._collapseBtn.spec.title === "Collapse") {
+                // const newcollapseBtn = new MenuItem({
+                //     title: "Expand",
+                //     icon: icons.join,
+                //     execEvent: "",
+                //     css: "color:white;",
+                //     class: "summarize",
+                //     run: (state, dispatch, view) => {
+                //         this.collapseToolTip();
+                //     }
+                // });
+                // this.tooltip.replaceChild(newcollapseBtn.render(this.view).dom, this._collapseBtn.render(this.view).dom);
+                // this._collapseBtn = newcollapseBtn;
+                this.tooltip.style.width = "30px";
+                this._collapseBtn.spec.title = "Expand";
+                this._collapseBtn.render(this.view);
+            }
+            else {
+                this._collapseBtn.spec.title = "Collapse";
+                this.tooltip.style.width = "550px";
+                this._collapseBtn.render(this.view);
+            }
+        }
+    }
+
     createLink() {
         let markType = schema.marks.link;
         return new MenuItem({
diff --git a/src/client/views/MainOverlayTextBox.scss b/src/client/views/MainOverlayTextBox.scss
index 1093ff671..5381a63b3 100644
--- a/src/client/views/MainOverlayTextBox.scss
+++ b/src/client/views/MainOverlayTextBox.scss
@@ -19,7 +19,7 @@
     }
 }
 .unscaled_div{
-    width: 500px;
+    // width: 500px;
     z-index: 10000;
     position: absolute;
 }
\ No newline at end of file
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 58946845c..479713fbd 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -26,14 +26,14 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
     private _textProxyDiv: React.RefObject<HTMLDivElement>;
     private _textBottom: boolean | undefined;
     private _textAutoHeight: boolean | undefined;
-    private _setouterdiv = (outerdiv: HTMLElement | null) => { this._outerdiv = outerdiv; this.updateTooltip(); }
+    private _setouterdiv = (outerdiv: HTMLElement | null) => { this._outerdiv = outerdiv; this.updateTooltip(); };
     private _outerdiv: HTMLElement | null = null;
     private _textBox: FormattedTextBox | undefined;
     private _tooltip?: HTMLElement;
     @observable public TextDoc?: Doc;
 
     updateTooltip = () => {
-        this._outerdiv && this._tooltip && !this._outerdiv.contains(this._tooltip) && this._outerdiv.appendChild(this._tooltip)
+        this._outerdiv && this._tooltip && !this._outerdiv.contains(this._tooltip) && this._outerdiv.appendChild(this._tooltip);
     }
 
     constructor(props: MainOverlayTextBoxProps) {
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index d2a6ceafa..5a25a4f9a 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -184,9 +184,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
 
     @action
     onPointerUp = (e: PointerEvent): void => {
-        console.log("pointer up!");
+        // console.log("pointer up!");
         if (this._visible) {
-            console.log("visible");
+            // console.log("visible");
             let mselect = this.marqueeSelect();
             if (!e.shiftKey) {
                 SelectionManager.DeselectAll(mselect.length ? undefined : this.props.container.props.Document);
@@ -195,7 +195,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             mselect.length ? this.cleanupInteractions(true, false) : this.cleanupInteractions(true);
         }
         else {
-            console.log("invisible");
+            //console.log("invisible");
             this.cleanupInteractions(true);
         }
 
-- 
cgit v1.2.3-70-g09d2


From d3c36913fa0252103d12f062a69cb6126098a3e5 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Sat, 29 Jun 2019 10:10:24 -0400
Subject: more datadoc fixes

---
 src/client/util/DocumentManager.ts      | 11 +++++------
 src/client/util/TooltipTextMenu.tsx     |  2 +-
 src/client/views/MainView.tsx           |  2 +-
 src/client/views/nodes/DocumentView.tsx |  4 ++--
 4 files changed, 9 insertions(+), 10 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index d0014dbf3..acd8dcef7 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -44,15 +44,14 @@ export class DocumentManager {
             DocumentManager.Instance.DocumentViews.map(view => {
                 let doc = view.props.Document.proto;
                 if (doc && doc[Id]) {
-                    if(doc[Id] === id)
-                    {toReturn.push(view);}
+                    if (doc[Id] === id) { toReturn.push(view); }
                 }
             });
         }
         return toReturn;
     }
 
-    public getAllDocumentViews(doc: Doc){
+    public getAllDocumentViews(doc: Doc) {
         return this.getDocumentViewsById(doc[Id]);
     }
 
@@ -150,7 +149,7 @@ export class DocumentManager {
                         docContext.panTransformType = "Ease";
                         targetContextView.props.focus(docDelegate, willZoom);
                     } else {
-                        (dockFunc || CollectionDockingView.Instance.AddRightSplit)(docContext, docContext);
+                        (dockFunc || CollectionDockingView.Instance.AddRightSplit)(docContext, undefined);
                         setTimeout(() => {
                             this.jumpToDocument(docDelegate, willZoom, forceDockFunc, dockFunc, linkPage);
                         }, 10);
@@ -159,7 +158,7 @@ export class DocumentManager {
                     const actualDoc = Doc.MakeAlias(docDelegate);
                     actualDoc.libraryBrush = true;
                     if (linkPage !== undefined) actualDoc.curPage = linkPage;
-                    (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc, actualDoc);
+                    (dockFunc || CollectionDockingView.Instance.AddRightSplit)(actualDoc, undefined);
                 }
             } else {
                 let contextView: DocumentView | null;
@@ -168,7 +167,7 @@ export class DocumentManager {
                     contextDoc.panTransformType = "Ease";
                     contextView.props.focus(docDelegate, willZoom);
                 } else {
-                    (dockFunc || CollectionDockingView.Instance.AddRightSplit)(contextDoc, contextDoc);
+                    (dockFunc || CollectionDockingView.Instance.AddRightSplit)(contextDoc, undefined);
                     setTimeout(() => {
                         this.jumpToDocument(docDelegate, willZoom, forceDockFunc, dockFunc, linkPage);
                     }, 10);
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index a96615488..390bb2f44 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -240,7 +240,7 @@ export class TooltipTextMenu {
                                 if (DocumentManager.Instance.getDocumentView(f)) {
                                     DocumentManager.Instance.getDocumentView(f)!.props.focus(f, false);
                                 }
-                                else if (CollectionDockingView.Instance) CollectionDockingView.Instance.AddRightSplit(f, f);
+                                else if (CollectionDockingView.Instance) CollectionDockingView.Instance.AddRightSplit(f, undefined);
                             }
                         }));
                     }
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 629827f11..fe3ff2392 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -203,7 +203,7 @@ export class MainView extends React.Component {
 
     openNotifsCol = () => {
         if (this._notifsCol && CollectionDockingView.Instance) {
-            CollectionDockingView.Instance.AddRightSplit(this._notifsCol, this._notifsCol);
+            CollectionDockingView.Instance.AddRightSplit(this._notifsCol, undefined);
         }
     }
 
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 525ca52a6..1d03fa04d 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -333,7 +333,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     let linkedPages = [linkedDocs.length ? NumCast(linkedDocs[0].anchor1Page, undefined) : NumCast(linkedDocs[0].anchor2Page, undefined),
                     linkedDocs.length ? NumCast(linkedDocs[0].anchor2Page, undefined) : NumCast(linkedDocs[0].anchor1Page, undefined)];
                     let maxLocation = StrCast(linkedDoc.maximizeLocation, "inTab");
-                    DocumentManager.Instance.jumpToDocument(linkedDoc, ctrlKey, false, document => this.props.addDocTab(document, document, maxLocation), linkedPages[altKey ? 1 : 0]);
+                    DocumentManager.Instance.jumpToDocument(linkedDoc, ctrlKey, false, document => this.props.addDocTab(document, undefined, maxLocation), linkedPages[altKey ? 1 : 0]);
 
                     // else if (linkedToDocs.length || linkedFromDocs.length) {
                     //     let linkedFwdDocs = [
@@ -503,7 +503,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         cm.addItem({
             description: "Find aliases", event: async () => {
                 const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document);
-                this.props.addDocTab && this.props.addDocTab(Docs.SchemaDocument(["title"], aliases, {}), Docs.SchemaDocument(["title"], aliases, {}), "onRight"); // bcz: dataDoc?
+                this.props.addDocTab && this.props.addDocTab(Docs.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc?
             }, icon: "search"
         });
         cm.addItem({ description: "Center View", event: () => this.props.focus(this.props.Document, false), icon: "crosshairs" });
-- 
cgit v1.2.3-70-g09d2


From 13fcbc4c500fec36e69cac4fc3c0ca6822322809 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Sun, 30 Jun 2019 16:04:52 -0400
Subject: Fixed errors and linter warnings

---
 src/client/util/TooltipTextMenu.tsx                | 70 ++++++----------------
 .../views/collections/CollectionStackingView.tsx   |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  3 +-
 src/client/views/pdf/Annotation.tsx                |  6 +-
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 .../views/presentationview/PresentationElement.tsx |  3 +-
 src/client/views/search/FilterBox.tsx              |  7 ++-
 src/client/views/search/SearchItem.tsx             | 15 +++--
 src/new_fields/Doc.ts                              |  3 +-
 9 files changed, 37 insertions(+), 74 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 390bb2f44..9f8d0b2f6 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -1,57 +1,37 @@
-import { action, IReactionDisposer, reaction } from "mobx";
-import { Dropdown, DropdownSubmenu, MenuItem, MenuItemSpec, renderGrouped, icons, } from "prosemirror-menu"; //no import css
-import { baseKeymap, lift, deleteSelection } from "prosemirror-commands";
-import { history, redo, undo } from "prosemirror-history";
-import { keymap } from "prosemirror-keymap";
-import { EditorState, Transaction, NodeSelection, TextSelection } from "prosemirror-state";
+import { action } from "mobx";
+import { Dropdown, MenuItem, icons, } from "prosemirror-menu"; //no import css
+import { EditorState, NodeSelection, TextSelection } from "prosemirror-state";
 import { EditorView } from "prosemirror-view";
 import { schema } from "./RichTextSchema";
 import { Schema, NodeType, MarkType, Mark, ResolvedPos } from "prosemirror-model";
-import { Node as ProsNode } from "prosemirror-model"
-import React = require("react");
+import { Node as ProsNode } from "prosemirror-model";
 import "./TooltipTextMenu.scss";
-const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands");
+const { toggleMark, setBlockType } = require("prosemirror-commands");
 import { library } from '@fortawesome/fontawesome-svg-core';
-import { wrapInList, bulletList, liftListItem, listItem, } from 'prosemirror-schema-list';
-import { liftTarget, RemoveMarkStep, AddMarkStep } from 'prosemirror-transform';
-import {
-    faListUl, faGrinTongueSquint,
-} from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { wrapInList, liftListItem, } from 'prosemirror-schema-list';
+import { faListUl } from '@fortawesome/free-solid-svg-icons';
 import { FieldViewProps } from "../views/nodes/FieldView";
-import { throwStatement } from "babel-types";
 const { openPrompt, TextField } = require("./ProsemirrorCopy/prompt.js");
-import { View } from "@react-pdf/renderer";
 import { DragManager } from "./DragManager";
 import { Doc, Opt, Field } from "../../new_fields/Doc";
 import { DocServer } from "../DocServer";
-import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView";
 import { CollectionDockingView } from "../views/collections/CollectionDockingView";
 import { DocumentManager } from "./DocumentManager";
 import { Id } from "../../new_fields/FieldSymbols";
-import { Utils } from "../../Utils";
 import { FormattedTextBoxProps } from "../views/nodes/FormattedTextBox";
-import { text } from "body-parser";
-import { type } from "os";
-// import { wrap } from "module";
-
-const SVG = "http://www.w3.org/2000/svg";
 
 //appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc.
 export class TooltipTextMenu {
 
     public tooltip: HTMLElement;
-    private num_icons = 0;
     private view: EditorView;
     private fontStyles: MarkType[];
     private fontSizes: MarkType[];
     private listTypes: NodeType[];
     private editorProps: FieldViewProps & FormattedTextBoxProps;
-    private state: EditorState;
     private fontSizeToNum: Map<MarkType, number>;
     private fontStylesToName: Map<MarkType, string>;
     private listTypeToIcon: Map<NodeType, string>;
-    private fontSizeIndicator: HTMLSpanElement = document.createElement("span");
     private link: HTMLAnchorElement;
 
     private linkEditor?: HTMLDivElement;
@@ -68,7 +48,6 @@ export class TooltipTextMenu {
 
     constructor(view: EditorView, editorProps: FieldViewProps & FormattedTextBoxProps) {
         this.view = view;
-        this.state = view.state;
         this.editorProps = editorProps;
         this.tooltip = document.createElement("div");
         this.tooltip.className = "tooltipMenu";
@@ -333,7 +312,7 @@ export class TooltipTextMenu {
 
     //for a specific grouping of marks (passed in), remove all and apply the passed-in one to the selected text
     changeToMarkInGroup = (markType: MarkType, view: EditorView, fontMarks: MarkType[]) => {
-        let { empty, $cursor, ranges } = view.state.selection as TextSelection;
+        let { $cursor, ranges } = view.state.selection as TextSelection;
         let state = view.state;
         let dispatch = view.dispatch;
 
@@ -345,13 +324,12 @@ export class TooltipTextMenu {
                         dispatch(state.tr.removeStoredMark(type));
                     }
                 } else {
-                    let has = false, tr = state.tr;
+                    let has = false;
                     for (let i = 0; !has && i < ranges.length; i++) {
                         let { $from, $to } = ranges[i];
                         has = state.doc.rangeHasMark($from.pos, $to.pos, type);
                     }
                     for (let i of ranges) {
-                        let { $from, $to } = i;
                         if (has) {
                             toggleMark(type)(view.state, view.dispatch, view);
                         }
@@ -373,7 +351,7 @@ export class TooltipTextMenu {
     }
 
     //remove all node typeand apply the passed-in one to the selected text
-    changeToNodeType(nodeType: NodeType | undefined, view: EditorView, allNodes: NodeType[]) {
+    changeToNodeType(nodeType: NodeType | undefined, view: EditorView) {
         //remove old
         liftListItem(schema.nodes.list_item)(view.state, view.dispatch);
         if (nodeType) { //add new
@@ -390,7 +368,7 @@ export class TooltipTextMenu {
             execEvent: "",
             class: "menuicon",
             css: css,
-            enable(state) { return true; },
+            enable() { return true; },
             run() {
                 changeToMarkInGroup(markType, view, groupMarks);
             }
@@ -405,7 +383,7 @@ export class TooltipTextMenu {
             css: "color:white;",
             class: "summarize",
             execEvent: "",
-            run: (state, dispatch, view) => {
+            run: (state, dispatch) => {
                 TooltipTextMenu.insertStar(state, dispatch);
             }
 
@@ -420,7 +398,7 @@ export class TooltipTextMenu {
             execEvent: "",
             css: "color:white;",
             class: "summarize",
-            run: (state, dispatch, view) => {
+            run: () => {
                 this.collapseToolTip();
             }
         });
@@ -499,7 +477,7 @@ export class TooltipTextMenu {
             execEvent: "",
             class: "menuicon",
             css: css,
-            enable(state) { return true; },
+            enable() { return true; },
             run() {
                 changeToNodeInGroup(nodeType, view, groupNodes);
             }
@@ -586,17 +564,6 @@ export class TooltipTextMenu {
             //return;
         }
 
-        //let linksInSelection = this.activeMarksOnSelection([schema.marks.link]);
-        // if (linksInSelection.length > 0) {
-        //     let attributes = this.getMarksInSelection(this.view.state, [schema.marks.link])[0].attrs;
-        //     this.link.href = attributes.href;
-        //     this.link.textContent = attributes.title;
-        //     this.link.style.visibility = "visible";
-        // } else this.link.style.visibility = "hidden";
-
-        // Otherwise, reposition it and update its content
-        //this.tooltip.style.display = "";
-        let { from, to } = state.selection;
 
         //UPDATE LIST ITEM DROPDOWN
 
@@ -641,17 +608,16 @@ export class TooltipTextMenu {
     //finds all active marks on selection in given group
     activeMarksOnSelection(markGroup: MarkType[]) {
         //current selection
-        let { empty, $cursor, ranges } = this.view.state.selection as TextSelection;
+        let { empty, ranges } = this.view.state.selection as TextSelection;
         let state = this.view.state;
         let dispatch = this.view.dispatch;
         let activeMarks: MarkType[];
         if (!empty) {
             activeMarks = markGroup.filter(mark => {
                 if (dispatch) {
-                    let has = false, tr = state.tr;
+                    let has = false;
                     for (let i = 0; !has && i < ranges.length; i++) {
                         let { $from, $to } = ranges[i];
-                        let hasmark: boolean = state.doc.rangeHasMark($from.pos, $to.pos, mark);
                         return state.doc.rangeHasMark($from.pos, $to.pos, mark);
                     }
                 }
@@ -662,9 +628,7 @@ export class TooltipTextMenu {
             const pos = this.view.state.selection.$from;
             const ref_node: ProsNode = this.reference_node(pos);
             if (ref_node !== null && ref_node !== this.view.state.doc) {
-                let text_node_type: NodeType;
                 if (ref_node.isText) {
-                    text_node_type = ref_node.type;
                 }
                 else {
                     return [];
@@ -699,7 +663,7 @@ export class TooltipTextMenu {
         else if (pos.pos > 0) {
             let skip = false;
             for (let i: number = pos.pos - 1; i > 0; i--) {
-                this.view.state.doc.nodesBetween(i, pos.pos, (node: ProsNode, pos: number, parent: ProsNode, index: number) => {
+                this.view.state.doc.nodesBetween(i, pos.pos, (node: ProsNode) => {
                     if (node.isLeaf && !skip) {
                         ref_node = node;
                         skip = true;
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 088a9bae8..b10907937 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -78,7 +78,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                 style={{ width: width(), height: height() }} >
                 <CollectionSchemaPreview
                     Document={layoutDoc}
-                    DataDocument={d != this.props.DataDoc ? this.props.DataDoc : undefined}
+                    DataDocument={d !== this.props.DataDoc ? this.props.DataDoc : undefined}
                     renderDepth={this.props.renderDepth}
                     width={width}
                     height={height}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index dd165e90c..927aa363f 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -186,8 +186,7 @@ class TreeView extends React.Component<TreeViewProps> {
         }
         let keyList: string[] = keys.reduce((l, key) => {
             let listspec = DocListCast(this.resolvedDataDoc[key]);
-            if (listspec && listspec.length)
-                return [...l, key];
+            if (listspec && listspec.length) return [...l, key];
             return l;
         }, [] as string[]);
         keys.map(key => Cast(this.resolvedDataDoc[key], Doc) instanceof Doc && keyList.push(key));
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 74f4be51a..73fca229b 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -10,9 +10,9 @@ import PDFMenu from "./PDFMenu";
 import { DocumentManager } from "../../util/DocumentManager";
 
 interface IAnnotationProps {
-    anno: Doc,
-    index: number,
-    parent: Viewer
+    anno: Doc;
+    index: number;
+    parent: Viewer;
 }
 
 export default class Annotation extends React.Component<IAnnotationProps> {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 6fab390d4..bb148e738 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -426,7 +426,7 @@ export class Viewer extends React.Component<IViewerProps> {
     }
 
     renderAnnotation = (anno: Doc, index: number): JSX.Element => {
-        return <Annotation anno={anno} index={index} parent={this} />
+        return <Annotation anno={anno} index={index} parent={this} />;
     }
 
     @action
diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx
index 4afc0210f..d63c0b066 100644
--- a/src/client/views/presentationview/PresentationElement.tsx
+++ b/src/client/views/presentationview/PresentationElement.tsx
@@ -13,12 +13,11 @@ import { faFile as fileRegular } from '@fortawesome/free-regular-svg-icons';
 import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
 
-
 library.add(faArrowUp);
 library.add(fileSolid);
 library.add(faLocationArrow);
+library.add(fileRegular as any);
 library.add(faSearch);
-library.add(fileRegular);
 
 interface PresentationElementProps {
     mainDocument: Doc;
diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx
index c39ec1145..8bbbf3012 100644
--- a/src/client/views/search/FilterBox.tsx
+++ b/src/client/views/search/FilterBox.tsx
@@ -65,9 +65,9 @@ export class FilterBox extends React.Component {
 
     setupAccordion() {
         $('document').ready(function () {
-            var acc = document.getElementsByClassName('filter-header');
-
-            for (var i = 0; i < acc.length; i++) {
+            const acc = document.getElementsByClassName('filter-header');
+            // tslint:disable-next-line: prefer-for-of
+            for (let i = 0; i < acc.length; i++) {
                 acc[i].addEventListener("click", function (this: HTMLElement) {
                     this.classList.toggle("active");
 
@@ -96,6 +96,7 @@ export class FilterBox extends React.Component {
         $('document').ready(function () {
             var acc = document.getElementsByClassName('filter-header');
 
+            // tslint:disable-next-line: prefer-for-of
             for (var i = 0; i < acc.length; i++) {
                 let classList = acc[i].classList;
                 if (classList.contains("active")) {
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index b72f8c814..f8a0c7b16 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -83,9 +83,8 @@ export class SelectorContextMenu extends React.Component<SearchItemProps> {
                             <FontAwesomeIcon icon={faStickyNote} />
                         </div>
                         <a className="title" onClick={this.getOnClick(doc)}>{doc.col.title}</a>
-                    </div>
-                }
-                )}
+                    </div>;
+                })}
             </div>
         );
     }
@@ -111,7 +110,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
             if (layoutresult.indexOf(DocTypes.COL) !== -1) {
                 renderDoc = Doc.MakeDelegate(renderDoc);
                 let bounds = DocListCast(renderDoc.data).reduce((bounds, doc) => {
-                    var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)]
+                    var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)];
                     let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()];
                     return {
                         x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y),
@@ -124,7 +123,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
             let returnYDimension = () => this._displayDim;
             let scale = () => returnXDimension() / NumCast(renderDoc.nativeWidth, returnXDimension());
             return <div
-                onPointerDown={action(() => { this._useIcons = !this._useIcons; this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE) })}
+                onPointerDown={action(() => { this._useIcons = !this._useIcons; this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE); })}
                 onPointerEnter={action(() => this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE))}
                 onPointerLeave={action(() => this._displayDim = 50)} >
                 <DocumentView
@@ -147,7 +146,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
                     ContainingCollectionView={undefined}
                     ContentScaling={scale}
                 />
-            </div>
+            </div>;
         }
 
         let button = layoutresult.indexOf(DocTypes.PDF) !== -1 ? faFilePdf :
@@ -160,7 +159,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
                                     layoutresult.indexOf(DocTypes.HIST) !== -1 ? faChartBar :
                                         layoutresult.indexOf(DocTypes.WEB) !== -1 ? faGlobeAsia :
                                             faCaretUp;
-        return <div onPointerDown={action(() => { this._useIcons = false; this._displayDim = Number(SEARCH_THUMBNAIL_SIZE) })} >
+        return <div onPointerDown={action(() => { this._useIcons = false; this._displayDim = Number(SEARCH_THUMBNAIL_SIZE); })} >
             <FontAwesomeIcon icon={button} size="2x" />
         </div>;
     }
@@ -189,7 +188,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
     }
 
     @action
-    pointerDown = (e: React.PointerEvent) => SearchBox.Instance.openSearch(e);
+    pointerDown = (e: React.PointerEvent) => SearchBox.Instance.openSearch(e)
 
     highlightDoc = (e: React.PointerEvent) => {
         if (this.props.doc.type === DocTypes.LINK) {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index e76e94d63..734a90731 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -293,11 +293,12 @@ export namespace Doc {
         if (expandedTemplateLayout instanceof Doc) {
             return expandedTemplateLayout;
         }
-        if (expandedTemplateLayout === undefined)
+        if (expandedTemplateLayout === undefined) {
             setTimeout(() => {
                 templateLayoutDoc["_expanded_" + dataDoc[Id]] = Doc.MakeDelegate(templateLayoutDoc);
                 (templateLayoutDoc["_expanded_" + dataDoc[Id]] as Doc).title = templateLayoutDoc.title + " applied to " + dataDoc.title;
             }, 0);
+        }
         return templateLayoutDoc;
     }
 
-- 
cgit v1.2.3-70-g09d2


From d479f5e6bcdb7d1a0edb2f8cf366549abe2a910b Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 4 Jul 2019 14:08:00 -0400
Subject: added text font color setting.   adding interactive border radius.
 moved main toolbar.

---
 src/client/documents/Documents.ts                  |  4 +--
 src/client/util/DragManager.ts                     |  1 +
 src/client/util/RichTextSchema.tsx                 | 11 ++++++++
 src/client/util/TooltipTextMenu.tsx                |  3 +-
 src/client/views/DocumentDecorations.scss          | 22 +++++++++++++++
 src/client/views/DocumentDecorations.tsx           | 32 ++++++++++++++++++++++
 src/client/views/InkingControl.tsx                 |  3 ++
 src/client/views/Main.scss                         |  2 +-
 src/client/views/MainOverlayTextBox.tsx            |  5 ++++
 src/client/views/MainView.tsx                      |  2 +-
 .../collections/collectionFreeForm/MarqueeView.tsx | 16 ++++-------
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 15 ++++++----
 src/client/views/nodes/DocumentView.tsx            |  4 +--
 src/client/views/nodes/FormattedTextBox.tsx        | 11 +++++++-
 14 files changed, 106 insertions(+), 25 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 7a976e7d7..2bddf053a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -77,7 +77,7 @@ export interface DocumentOptions {
     backgroundLayout?: string;
     curPage?: number;
     documentText?: string;
-    borderRounding?: number;
+    borderRounding?: string;
     schemaColumns?: List<string>;
     dockingConfig?: string;
     dbDoc?: Doc;
@@ -93,7 +93,7 @@ export namespace DocUtils {
         if (target === CurrentUserUtils.UserDocument) return;
 
         UndoManager.RunInBatch(() => {
-            let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 });
+            let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: "100%" });
             linkDoc.type = DocTypes.LINK;
             let linkDocProto = Doc.GetProto(linkDoc);
 
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 7dc48fb78..d4b1bc8f4 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -315,6 +315,7 @@ export namespace DragManager {
             scaleYs.push(scaleY);
             let dragElement = ele.cloneNode(true) as HTMLElement;
             dragElement.style.opacity = "0.7";
+            dragElement.style.borderRadius = getComputedStyle(ele).borderRadius;
             dragElement.style.position = "absolute";
             dragElement.style.margin = "0";
             dragElement.style.top = "0";
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 63c879d67..2a57180d3 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -348,6 +348,17 @@ export const marks: { [index: string]: MarkSpec } = {
         }]
     },
 
+    pFontColor: {
+        attrs: {
+            color: { default: "yellow" }
+        },
+        parseDOM: [{ style: 'background: #d9dbdd' }],
+        toDOM: (node) => {
+            return ['span', {
+                style: `color: ${node.attrs.color}`
+            }];
+        }
+    },
 
     /** FONT SIZES */
     pFontSize: {
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 9f8d0b2f6..e3e26d1f4 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -111,7 +111,8 @@ export class TooltipTextMenu {
         this.fontSizeToNum.set(schema.marks.p32, 32);
         this.fontSizeToNum.set(schema.marks.p48, 48);
         this.fontSizeToNum.set(schema.marks.p72, 72);
-        //this.fontSizeToNum.set(schema.marks.pFontSize,schema.marks.pFontSize.)
+        this.fontSizeToNum.set(schema.marks.pFontSize, 10);
+        this.fontSizeToNum.set(schema.marks.pFontSize, 10);
         this.fontSizes = Array.from(this.fontSizeToNum.keys());
 
         //list types
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index ba9f32d7d..2d430512b 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -26,6 +26,14 @@ $linkGap : 3px;
         opacity: 0.8;
     }
 
+    .documentDecorations-radius {
+        pointer-events: auto;
+        background: black;
+        opacity: 0.8;
+        transform: translate(10px, 10px);
+        grid-row: 4;
+    }
+
     #documentDecorations-topLeftResizer,
     #documentDecorations-leftResizer,
     #documentDecorations-bottomLeftResizer {
@@ -44,11 +52,25 @@ $linkGap : 3px;
         grid-column-start: 5;
         grid-column-end: 7;
     }
+    
+    #documentDecorations-borderRadius{
+        grid-column-start: 5;
+        grid-column-end: 7;
+        border-radius: 100%;
+        .borderRadiusTooltip{
+            width:10px;
+            height:10px;
+            position:absolute;
+        }
+    }
 
     #documentDecorations-topLeftResizer,
     #documentDecorations-bottomRightResizer {
         cursor: nwse-resize;
     }
+    #documentDecorations-bottomRightResizer {
+        grid-row:4;
+    }
 
     #documentDecorations-topRightResizer,
     #documentDecorations-bottomLeftResizer {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 3df520428..c7990647a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -341,6 +341,37 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         iconDoc.y = where[1] + NumCast(selView.props.Document.y);
     }
 
+    _radiusDown = [0, 0];
+    @action
+    onRadiusDown = (e: React.PointerEvent): void => {
+        e.stopPropagation();
+        if (e.button === 0) {
+            this._radiusDown = [e.clientX, e.clientY];
+            this._isPointerDown = true;
+            this._resizeUndo = UndoManager.StartBatch("DocDecs set radius");
+            document.removeEventListener("pointermove", this.onRadiusMove);
+            document.removeEventListener("pointerup", this.onRadiusUp);
+            document.addEventListener("pointermove", this.onRadiusMove);
+            document.addEventListener("pointerup", this.onRadiusUp);
+        }
+    }
+
+    onRadiusMove = (e: PointerEvent): void => {
+        let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1]));
+        SelectionManager.SelectedDocuments().map(dv => Doc.GetProto(dv.props.Document).borderRounding = `${Math.min(100, dist)}%`);
+        e.stopPropagation();
+        e.preventDefault();
+    }
+
+    onRadiusUp = (e: PointerEvent): void => {
+        e.stopPropagation();
+        e.preventDefault();
+        this._isPointerDown = false;
+        this._resizeUndo && this._resizeUndo.end();
+        document.removeEventListener("pointermove", this.onRadiusMove);
+        document.removeEventListener("pointerup", this.onRadiusUp);
+    }
+
     @action
     onPointerDown = (e: React.PointerEvent): void => {
         e.stopPropagation();
@@ -705,6 +736,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 <div id="documentDecorations-bottomLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <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 id="documentDecorations-borderRadius" className="documentDecorations-radius" onPointerDown={this.onRadiusDown} onContextMenu={(e) => e.preventDefault()}><span className="borderRadiusTooltip" title="Drag Corner Radius"></span></div>
                 <div className="link-button-container">
                     <div className="linkButtonWrapper">
                         <div title="View Links" className="linkFlyout" ref={this._linkButton}> {linkButton}  </div>
diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx
index 0461d7299..c7f7bdb66 100644
--- a/src/client/views/InkingControl.tsx
+++ b/src/client/views/InkingControl.tsx
@@ -10,6 +10,8 @@ import { InkTool } from "../../new_fields/InkField";
 import { Doc } from "../../new_fields/Doc";
 import { undoBatch, UndoManager } from "../util/UndoManager";
 import { StrCast } from "../../new_fields/Types";
+import { FormattedTextBox } from "./nodes/FormattedTextBox";
+import { MainOverlayTextBox } from "./MainOverlayTextBox";
 
 library.add(faPen, faHighlighter, faEraser, faBan);
 
@@ -42,6 +44,7 @@ export class InkingControl extends React.Component {
     switchColor = action((color: ColorResult): void => {
         this._selectedColor = color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff");
         if (InkingControl.Instance.selectedTool === InkTool.None) {
+            if (MainOverlayTextBox.Instance.SetColor(color.hex)) return;
             let selected = SelectionManager.SelectedDocuments();
             let oldColors = selected.map(view => {
                 let targetDoc = view.props.Document.isTemplate ? view.props.Document : Doc.GetProto(view.props.Document);
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index 44c1cb9fc..b85a8040a 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -144,7 +144,7 @@ button:hover {
 #add-nodes-menu {
     position: absolute;
     bottom: 22px;
-    left: 24px;
+    left: 250px;
 
     > label {
         background: $dark-color;
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 7d15702a2..d8aaea259 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -36,6 +36,11 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
         this._outerdiv && this._tooltip && !this._outerdiv.contains(this._tooltip) && this._outerdiv.appendChild(this._tooltip);
     }
 
+    public SetColor(color: string) {
+        return this._textBox && this._textBox.setFontColor(color);
+    }
+
+
     constructor(props: MainOverlayTextBoxProps) {
         super(props);
         this._textProxyDiv = React.createRef();
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 1542fedef..61ccf4c1d 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -354,7 +354,7 @@ export class MainView extends React.Component {
             [React.createRef<HTMLDivElement>(), "tree", "Add Tree", addTreeNode],
         ];
 
-        return < div id="add-nodes-menu" >
+        return < div id="add-nodes-menu" style={{ left: this.flyoutWidth + 5 }} >
             <input type="checkbox" id="add-menu-toggle" ref={this.addMenuToggle} />
             <label htmlFor="add-menu-toggle" title="Add Node"><p>+</p></label>
 
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 31c0fe499..4850c6218 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -44,14 +44,12 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
     _commandExecuted = false;
 
     @action
-    cleanupInteractions = (all: boolean = false, rem_keydown: boolean = true) => {
+    cleanupInteractions = (all: boolean = false) => {
         if (all) {
             document.removeEventListener("pointerup", this.onPointerUp, true);
             document.removeEventListener("pointermove", this.onPointerMove, true);
         }
-        if (rem_keydown) {
-            document.removeEventListener("keydown", this.marqueeCommand, true);
-        }
+        document.removeEventListener("keydown", this.marqueeCommand, true);
         this._visible = false;
     }
 
@@ -191,12 +189,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                 SelectionManager.DeselectAll(mselect.length ? undefined : this.props.container.props.Document);
             }
             this.props.selectDocuments(mselect.length ? mselect : [this.props.container.props.Document]);
-            mselect.length ? this.cleanupInteractions(true, false) : this.cleanupInteractions(true);
-        }
-        else {
-            //console.log("invisible");
-            this.cleanupInteractions(true);
         }
+        //console.log("invisible");
+        this.cleanupInteractions(true);
 
         if (e.altKey) {
             e.preventDefault();
@@ -266,13 +261,12 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
             }
             let ink = Cast(this.props.container.props.Document.ink, InkField);
             let inkData = ink ? ink.inkData : undefined;
-            let zoomBasis = NumCast(this.props.container.props.Document.scale, 1);
             let newCollection = Docs.FreeformDocument(selected, {
                 x: bounds.left,
                 y: bounds.top,
                 panX: 0,
                 panY: 0,
-                borderRounding: e.key === "e" ? -1 : undefined,
+                borderRounding: e.key === "e" ? "100%" : undefined,
                 backgroundColor: this.props.container.isAnnotationOverlay ? undefined : "white",
                 width: bounds.width,
                 height: bounds.height,
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 30cf74f3e..1c00687ed 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -70,11 +70,14 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     }
 
     borderRounding = () => {
-        let br = NumCast(this.props.Document.borderRounding);
-        return br >= 0 ? br :
-            NumCast(this.props.Document.nativeWidth) === 0 ?
-                Math.min(this.props.PanelWidth(), this.props.PanelHeight())
-                : Math.min(this.Document.nativeWidth || 0, this.Document.nativeHeight || 0);
+        let br = StrCast(this.props.Document.borderRounding);
+        if (br.endsWith("%")) {
+            let percent = Number(br.substr(0, br.length - 1)) / 100;
+            let nativeDim = Math.min(NumCast(this.props.Document.nativeWidth), NumCast(this.props.Document.nativeHeight));
+            let minDim = percent * (nativeDim ? nativeDim : Math.min(this.props.PanelWidth(), this.props.PanelHeight()));
+            return minDim;
+        }
+        return undefined;
     }
 
     render() {
@@ -84,7 +87,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                     transformOrigin: "left top",
                     position: "absolute",
                     backgroundColor: "transparent",
-                    borderRadius: `${this.borderRounding()}px`,
+                    borderRadius: this.borderRounding(),
                     transform: this.transform,
                     transition: StrCast(this.props.Document.transition),
                     width: this.width,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f751a45fe..a84cac37f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -589,9 +589,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 style={{
                     outlineColor: "maroon",
                     outlineStyle: "dashed",
-                    outlineWidth: BoolCast(this.props.Document.libraryBrush) && !NumCast(this.props.Document.borderRounding) ?
+                    outlineWidth: BoolCast(this.props.Document.libraryBrush) && !StrCast(this.props.Document.borderRounding) ?
                         `${this.props.ScreenToLocalTransform().Scale}px` : "0px",
-                    border: BoolCast(this.props.Document.libraryBrush) && NumCast(this.props.Document.borderRounding) ?
+                    border: BoolCast(this.props.Document.libraryBrush) && StrCast(this.props.Document.borderRounding) ?
                         `dashed maroon ${this.props.ScreenToLocalTransform().Scale}px` : undefined,
                     borderRadius: "inherit",
                     background: backgroundColor,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 1eeb04755..bf6f4c764 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -97,6 +97,15 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         return "";
     }
 
+    @undoBatch
+    public setFontColor(color: string) {
+        if (this._editorView!.state.selection.from === this._editorView!.state.selection.to) return false;
+        let colorMark = this._editorView!.state.schema.mark(this._editorView!.state.schema.marks.pFontColor, { color: color });
+        this._editorView!.dispatch(this._editorView!.state.tr.addMark(this._editorView!.state.selection.from,
+            this._editorView!.state.selection.to, colorMark));
+        return true;
+    }
+
     constructor(props: FieldViewProps) {
         super(props);
         if (this.props.outer_div) {
@@ -418,7 +427,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
     }
     render() {
         let style = this.props.isOverlay ? "scroll" : "hidden";
-        let rounded = NumCast(this.props.Document.borderRounding) < 0 ? "-rounded" : "";
+        let rounded = StrCast(this.props.Document.borderRounding) === "100%" ? "-rounded" : "";
         let interactive = InkingControl.Instance.selectedTool ? "" : "interactive";
         return (
             <div className={`formattedTextBox-cont-${style}`} ref={this._ref}
-- 
cgit v1.2.3-70-g09d2


From 149fdb6c172a84c8ec2fbb170bbdd5625c1ac0fa Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 5 Jul 2019 00:34:00 -0400
Subject: restored dragging hyperlink from menu for formattedText boxes

---
 src/client/util/TooltipTextMenu.scss |  2 +-
 src/client/util/TooltipTextMenu.tsx  | 32 ++++++++++++++++++--------------
 2 files changed, 19 insertions(+), 15 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss
index b10573b3e..40ac3abb9 100644
--- a/src/client/util/TooltipTextMenu.scss
+++ b/src/client/util/TooltipTextMenu.scss
@@ -248,7 +248,7 @@
     transform: translateY(-85px);
     pointer-events: all;
     height: 30px;
-    width:500px;
+    width:550px;
     .ProseMirror-example-setup-style hr {
       padding: 2px 10px;
       border: none;
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index e3e26d1f4..cb7ed976a 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -32,7 +32,6 @@ export class TooltipTextMenu {
     private fontSizeToNum: Map<MarkType, number>;
     private fontStylesToName: Map<MarkType, string>;
     private listTypeToIcon: Map<NodeType, string>;
-    private link: HTMLAnchorElement;
 
     private linkEditor?: HTMLDivElement;
     private linkText?: HTMLDivElement;
@@ -89,6 +88,7 @@ export class TooltipTextMenu {
             });
 
         });
+        this.updateLinkMenu();
 
         //list of font styles
         this.fontStylesToName = new Map();
@@ -121,11 +121,6 @@ export class TooltipTextMenu {
         this.listTypeToIcon.set(schema.nodes.ordered_list, "1)");
         this.listTypes = Array.from(this.listTypeToIcon.keys());
 
-        this.link = document.createElement("a");
-        this.link.target = "_blank";
-        this.link.style.color = "white";
-        //this.tooltip.appendChild(this.link);
-
         this.tooltip.appendChild(this.createLink().render(this.view).dom);
 
         this.tooltip.appendChild(this.createStar().render(this.view).dom);
@@ -191,6 +186,7 @@ export class TooltipTextMenu {
     updateLinkMenu() {
         if (!this.linkEditor || !this.linkText) {
             this.linkEditor = document.createElement("div");
+            this.linkEditor.className = "ProseMirror-icon menuicon";
             this.linkEditor.style.color = "black";
             this.linkText = document.createElement("div");
             this.linkText.style.cssFloat = "left";
@@ -231,8 +227,9 @@ export class TooltipTextMenu {
             };
             this.linkDrag = document.createElement("img");
             this.linkDrag.src = "https://seogurusnyc.com/wp-content/uploads/2016/12/link-1.png";
-            this.linkDrag.style.width = "20px";
-            this.linkDrag.style.height = "20px";
+            this.linkDrag.style.width = "15px";
+            this.linkDrag.style.height = "15px";
+            this.linkDrag.title = "Drag to create link";
             this.linkDrag.style.color = "black";
             this.linkDrag.style.background = "black";
             this.linkDrag.style.cssFloat = "left";
@@ -250,10 +247,10 @@ export class TooltipTextMenu {
                         hideSource: false
                     });
             };
-            // this.linkEditor.appendChild(this.linkDrag);
+            this.linkEditor.appendChild(this.linkDrag);
             // this.linkEditor.appendChild(this.linkText);
             // this.linkEditor.appendChild(linkBtn);
-            //this.tooltip.appendChild(this.linkEditor);
+            this.tooltip.appendChild(this.linkEditor);
         }
 
         let node = this.view.state.selection.$from.nodeAfter;
@@ -444,16 +441,24 @@ export class TooltipTextMenu {
             enable(state) { return !state.selection.empty; },
             run: (state, dispatch, view) => {
                 // to remove link
+                let curLink = "";
                 if (this.markActive(state, markType)) {
-                    toggleMark(markType)(state, dispatch);
-                    return true;
+
+                    let { from, $from, to, empty } = state.selection;
+                    let node = state.doc.nodeAt(from);
+                    node && node.marks.map(m => {
+                        m.type === markType && (curLink = m.attrs.href);
+                    })
+                    //toggleMark(markType)(state, dispatch);
+                    //return true;
                 }
                 // to create link
                 openPrompt({
                     title: "Create a link",
                     fields: {
                         href: new TextField({
-                            label: "Link target",
+                            value: curLink,
+                            label: "Link Target",
                             required: true
                         }),
                         title: new TextField({ label: "Title" })
@@ -603,7 +608,6 @@ export class TooltipTextMenu {
             }
         }
         this.view.dispatch(this.view.state.tr.setStoredMarks(this._activeMarks));
-        this.updateLinkMenu();
     }
 
     //finds all active marks on selection in given group
-- 
cgit v1.2.3-70-g09d2


From 0058f56fda4e9e6a70ec7c23e1c141927715f9c1 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 11 Jul 2019 00:38:37 -0400
Subject: trying to make everything work the same way

---
 src/client/documents/Documents.ts                  |  8 +++---
 src/client/util/LinkManager.ts                     |  4 +--
 src/client/util/TooltipTextMenu.tsx                |  2 +-
 .../views/collections/CollectionBaseView.tsx       | 19 ++++++++++---
 src/client/views/collections/CollectionPDFView.tsx |  4 +--
 .../views/collections/CollectionStackingView.tsx   | 10 +++----
 src/client/views/collections/CollectionSubView.tsx | 10 ++++---
 .../views/collections/CollectionTreeView.tsx       |  2 +-
 .../views/collections/CollectionVideoView.tsx      |  4 +--
 src/client/views/collections/CollectionView.tsx    |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.scss |  4 +--
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 33 +++++++++++-----------
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 src/client/views/nodes/FieldView.tsx               |  4 +--
 src/client/views/nodes/FormattedTextBox.tsx        |  3 +-
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 src/new_fields/Doc.ts                              |  2 +-
 17 files changed, 64 insertions(+), 51 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index d1c9feb32..46255b5d5 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -174,7 +174,7 @@ export namespace Docs {
     }
 
     function CreateImagePrototype(): Doc {
-        let imageProto = setupPrototypeOptions(imageProtoId, "IMAGE_PROTO", CollectionView.LayoutString("annotations"),
+        let imageProto = setupPrototypeOptions(imageProtoId, "IMAGE_PROTO", CollectionView.LayoutString("data", "annotations"),
             { x: 0, y: 0, nativeWidth: 600, width: 300, backgroundLayout: ImageBox.LayoutString(), curPage: 0, type: DocTypes.IMG });
         return imageProto;
     }
@@ -185,7 +185,7 @@ export namespace Docs {
     }
 
     function CreateHistogramPrototype(): Doc {
-        let histoProto = setupPrototypeOptions(histoProtoId, "HISTO PROTO", CollectionView.LayoutString("annotations"),
+        let histoProto = setupPrototypeOptions(histoProtoId, "HISTO PROTO", CollectionView.LayoutString("data"),
             { x: 0, y: 0, width: 300, height: 300, backgroundColor: "black", backgroundLayout: HistogramBox.LayoutString(), type: DocTypes.HIST });
         return histoProto;
     }
@@ -200,7 +200,7 @@ export namespace Docs {
         return textProto;
     }
     function CreatePdfPrototype(): Doc {
-        let pdfProto = setupPrototypeOptions(pdfProtoId, "PDF_PROTO", CollectionPDFView.LayoutString("annotations"),
+        let pdfProto = setupPrototypeOptions(pdfProtoId, "PDF_PROTO", CollectionPDFView.LayoutString("data", "annotations"),
             { x: 0, y: 0, width: 300, height: 300, backgroundLayout: PDFBox.LayoutString(), curPage: 1, type: DocTypes.PDF });
         return pdfProto;
     }
@@ -221,7 +221,7 @@ export namespace Docs {
         return kvpProto;
     }
     function CreateVideoPrototype(): Doc {
-        let videoProto = setupPrototypeOptions(videoProtoId, "VIDEO_PROTO", CollectionVideoView.LayoutString("annotations"),
+        let videoProto = setupPrototypeOptions(videoProtoId, "VIDEO_PROTO", CollectionVideoView.LayoutString("data", "annotations"),
             { x: 0, y: 0, nativeWidth: 600, width: 300, backgroundLayout: VideoBox.LayoutString(), curPage: 0, type: DocTypes.VID });
         return videoProto;
     }
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 944bc532f..d6ea6013b 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -234,9 +234,9 @@ export class LinkManager {
     //TODO This should also await the return value of the anchor so we don't filter out promises
     public getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc {
         if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, null))) {
-            return Cast(linkDoc.anchor2, Doc, null)!;
+            return Cast(linkDoc.anchor2, Doc, null);
         } else {
-            return Cast(linkDoc.anchor1, Doc, null)!;
+            return Cast(linkDoc.anchor1, Doc, null);
         }
     }
 }
\ No newline at end of file
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index cb7ed976a..4fcc16ddd 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -448,7 +448,7 @@ export class TooltipTextMenu {
                     let node = state.doc.nodeAt(from);
                     node && node.marks.map(m => {
                         m.type === markType && (curLink = m.attrs.href);
-                    })
+                    });
                     //toggleMark(markType)(state, dispatch);
                     //return true;
                 }
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index e4f9b5058..079a44b88 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -74,21 +74,27 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
         this.props.whenActiveChanged(isActive);
     }
 
+    public get isAnnotationOverlay() { return this.props.fieldKey === "annotations" || this.props.fieldExt === "annotations"; }
+    @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.isAnnotationOverlay ? "dummy" : ""); }
+
     @action.bound
     addDocument(doc: Doc, allowDuplicates: boolean = false): boolean {
+        let self = this;
         var curPage = NumCast(this.props.Document.curPage, -1);
         Doc.GetProto(doc).page = curPage;
         if (curPage >= 0) {
             Doc.GetProto(doc).annotationOn = this.props.Document;
         }
         allowDuplicates = true;
-        const value = Cast(this.dataDoc[this.dataField], listSpec(Doc));
+        let targetDataDoc = this.props.fieldExt || this.props.Document.isTemplate ? this.extensionDoc : this.props.Document;
+        let targetField = (this.props.fieldExt || this.props.Document.isTemplate) && this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey;
+        const value = Cast(targetDataDoc[targetField], listSpec(Doc));
         if (value !== undefined) {
             if (allowDuplicates || !value.some(v => v instanceof Doc && v[Id] === doc[Id])) {
                 value.push(doc);
             }
         } else {
-            Doc.GetProto(this.dataDoc)[this.dataField] = new List([doc]);
+            Doc.GetProto(targetDataDoc)[targetField] = new List([doc]);
         }
         return true;
     }
@@ -98,7 +104,9 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
         let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView);
         docView && SelectionManager.DeselectDoc(docView);
         //TODO This won't create the field if it doesn't already exist
-        const value = Cast(this.dataDoc[this.dataField], listSpec(Doc), []);
+        let targetDataDoc = this.props.fieldExt || this.props.Document.isTemplate ? this.extensionDoc : this.props.Document;
+        let targetField = (this.props.fieldExt || this.props.Document.isTemplate) && this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey;
+        let value = Cast(targetDataDoc[targetField], listSpec(Doc), []);
         let index = value.reduce((p, v, i) => (v instanceof Doc && v[Id] === doc[Id]) ? i : p, -1);
         PromiseValue(Cast(doc.annotationOn, Doc)).then(annotationOn =>
             annotationOn === this.dataDoc.Document && (doc.annotationOn = undefined)
@@ -116,7 +124,10 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
 
     @action.bound
     moveDocument(doc: Doc, targetCollection: Doc, addDocument: (doc: Doc) => boolean): boolean {
-        if (Doc.AreProtosEqual(this.dataDoc, targetCollection)) {
+        let self = this;
+        let targetDataDoc = this.props.fieldExt || this.props.Document.isTemplate ? this.extensionDoc : this.props.Document;
+        if (Doc.AreProtosEqual(targetDataDoc, targetCollection)) {
+            //if (Doc.AreProtosEqual(this.extensionDoc, targetCollection)) {
             return true;
         }
         if (this.removeDocument(doc)) {
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 31a73ab36..c97443785 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -47,8 +47,8 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
         this._reactionDisposer && this._reactionDisposer();
     }
 
-    public static LayoutString(fieldKey: string = "data") {
-        return FieldView.LayoutString(CollectionPDFView, fieldKey);
+    public static LayoutString(fieldKey: string = "data", fieldExt: string = "annotations") {
+        return FieldView.LayoutString(CollectionPDFView, fieldKey, fieldExt);
     }
     @observable _inThumb = false;
 
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 372891923..9266fc8fd 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -50,11 +50,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
     }
 
     overlays = (doc: Doc) => {
-        return doc.type === DocTypes.IMG ? { title: "title", caption: "caption" } : {}
+        return doc.type === DocTypes.IMG ? { title: "title", caption: "caption" } : {};
     }
 
     getDisplayDoc(layoutDoc: Doc, d: Doc, dxf: () => Transform) {
-        let dataDoc = d !== this.props.DataDoc ? this.props.DataDoc : undefined
+        let dataDoc = d !== this.props.DataDoc ? this.props.DataDoc : undefined;
         let width = () => d.nativeWidth ? Math.min(layoutDoc[WidthSym](), this.columnWidth) : this.columnWidth;
         let height = () => this.getDocHeight(layoutDoc);
         let finalDxf = () => dxf().scale(this.columnWidth / layoutDoc[WidthSym]());
@@ -75,7 +75,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             addDocTab={this.props.addDocTab}
             setPreviewScript={emptyFunction}
             previewScript={undefined}>
-        </CollectionSchemaPreview>
+        </CollectionSchemaPreview>;
     }
     getDocHeight(d: Doc) {
         let nw = NumCast(d.nativeWidth);
@@ -176,7 +176,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                 if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) {
                     targInd = i;
                 }
-            })
+            });
         }
         if (super.drop(e, de)) {
             let newDoc = de.data.droppedDocuments[0];
@@ -202,7 +202,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             if (where[0] > pos[0] && where[0] < pos1[0] && where[1] > pos[1] && where[1] < pos1[1]) {
                 targInd = i;
             }
-        })
+        });
         super.onDrop(e, {}, () => {
             if (targInd !== -1) {
                 let newDoc = this.childDocs[this.childDocs.length - 1];
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 496f7e461..e72e69330 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -46,18 +46,20 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
             this.createDropTarget(ele);
         }
 
-        @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.props.fieldExt); }
+        public get isAnnotationOverlay() { return this.props.fieldKey === "annotations" || this.props.fieldExt === "annotations"; }
+        @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.isAnnotationOverlay ? "dummy" : ""); }
+
 
         get childDocs() {
             let self = this;
             //TODO tfs: This might not be what we want?
             //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue)
-            return DocListCast((BoolCast(this.props.Document.isTemplate) ? this.extensionDoc : this.props.Document)[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey]);
+            return DocListCast(this.extensionDoc[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey]);
         }
         get childDocList() {
             //TODO tfs: This might not be what we want?
             //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue)
-            return Cast((BoolCast(this.props.Document.isTemplate) ? this.extensionDoc : this.props.Document)[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey], listSpec(Doc));
+            return Cast(this.extensionDoc[this.props.fieldExt ? this.props.fieldExt : this.props.fieldKey], listSpec(Doc));
         }
 
         @action
@@ -102,7 +104,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                 } else if (de.data.moveDocument) {
                     let movedDocs = de.data.options === this.props.Document[Id] ? de.data.draggedDocuments : de.data.droppedDocuments;
                     added = movedDocs.reduce((added: boolean, d) =>
-                        de.data.moveDocument(d, this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.addDocument) || added, false);
+                        de.data.moveDocument(d, /*this.props.DataDoc ? this.props.DataDoc :*/ this.props.Document, this.props.addDocument) || added, false);
                 } else {
                     added = de.data.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
                 }
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 3674a743a..1280d515c 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -75,7 +75,7 @@ class TreeView extends React.Component<TreeViewProps> {
     @computed get fieldKey() {
         let keys = Array.from(Object.keys(this.resolvedDataDoc));  // bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set
         if (this.resolvedDataDoc.proto instanceof Doc) {
-            let arr = Array.from(Object.keys(this.resolvedDataDoc.proto!));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set
+            let arr = Array.from(Object.keys(this.resolvedDataDoc.proto));// bcz: Argh -- make untracked to avoid this rerunning whenever 'libraryBrush' is set
             keys.push(...arr);
             while (keys.indexOf("proto") !== -1) keys.splice(keys.indexOf("proto"), 1);
         }
diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx
index 1984965ba..16287a658 100644
--- a/src/client/views/collections/CollectionVideoView.tsx
+++ b/src/client/views/collections/CollectionVideoView.tsx
@@ -21,8 +21,8 @@ import { Docs, DocUtils } from "../../documents/Documents";
 export class CollectionVideoView extends React.Component<FieldViewProps> {
     private _videoBox?: VideoBox;
 
-    public static LayoutString(fieldKey: string = "data") {
-        return FieldView.LayoutString(CollectionVideoView, fieldKey);
+    public static LayoutString(fieldKey: string = "data", fieldExt: string = "annotations") {
+        return FieldView.LayoutString(CollectionVideoView, fieldKey, fieldExt);
     }
     private get uIButtons() {
         let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().Scale);
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index e500e5c70..e69696390 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -27,7 +27,7 @@ library.add(faThList);
 
 @observer
 export class CollectionView extends React.Component<FieldViewProps> {
-    public static LayoutString(fieldStr: string = "data") { return FieldView.LayoutString(CollectionView, fieldStr); }
+    public static LayoutString(fieldStr: string = "data", fieldExt: string = "") { return FieldView.LayoutString(CollectionView, fieldStr, fieldExt); }
 
     private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => {
         let props = { ...this.props, ...renderProps };
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index ccf261c95..51cfa77b1 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -38,7 +38,7 @@
     // }
     box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
     border: 0px solid $light-color-secondary;
-    border-radius: $border-radius;
+    border-radius: inherit;
     box-sizing: border-box;
     position: absolute;
 
@@ -71,7 +71,7 @@
 
     opacity: 0.99;
     border: 0px solid transparent;
-    border-radius: $border-radius;
+    border-radius: inherit;
     box-sizing: border-box;
     position:absolute;
     z-index: -1;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 2c9b6b6a9..c931c74bc 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -54,7 +54,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
     @computed get nativeWidth() { return this.Document.nativeWidth || 0; }
     @computed get nativeHeight() { return this.Document.nativeHeight || 0; }
-    public get isAnnotationOverlay() { return this.props.fieldKey === "annotations" || this.props.fieldExt === "annotations"; }
+    public get isAnnotationOverlay() { return this.props.fieldExt === "annotations"; }
     private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
     private panX = () => this.props.fitToBox ? this.props.fitToBox()[0] : this.Document.panX || 0;
     private panY = () => this.props.fitToBox ? this.props.fitToBox()[1] : this.Document.panY || 0;
@@ -86,6 +86,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         });
     }
 
+    @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.isAnnotationOverlay ? "dummy" : ""); }
+
+
     @undoBatch
     @action
     drop = (e: Event, de: DragManager.DropEvent) => {
@@ -93,10 +96,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             if (de.data instanceof DragManager.DocumentDragData) {
                 if (de.data.droppedDocuments.length) {
                     let dragDoc = de.data.droppedDocuments[0];
-                    let zoom = NumCast(dragDoc.zoomBasis, 1);
                     let [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
-                    let x = xp - de.data.xOffset / zoom;
-                    let y = yp - de.data.yOffset / zoom;
+                    let x = xp - de.data.xOffset;
+                    let y = yp - de.data.yOffset;
                     let dropX = NumCast(de.data.droppedDocuments[0].x);
                     let dropY = NumCast(de.data.droppedDocuments[0].y);
                     de.data.droppedDocuments.forEach(d => {
@@ -117,10 +119,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             else if (de.data instanceof DragManager.AnnotationDragData) {
                 if (de.data.dropDocument) {
                     let dragDoc = de.data.dropDocument;
-                    let zoom = NumCast(dragDoc.zoomBasis, 1);
                     let [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
-                    let x = xp - de.data.xOffset / zoom;
-                    let y = yp - de.data.yOffset / zoom;
+                    let x = xp - de.data.xOffset;
+                    let y = yp - de.data.yOffset;
                     let dropX = NumCast(de.data.dropDocument.x);
                     let dropY = NumCast(de.data.dropDocument.y);
                     dragDoc.x = x + NumCast(dragDoc.x) - dropX;
@@ -159,14 +160,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             if (!this.isAnnotationOverlay) {
                 PDFMenu.Instance.fadeOut(true);
                 let minx = docs.length ? NumCast(docs[0].x) : 0;
-                let maxx = docs.length ? NumCast(docs[0].width) / NumCast(docs[0].zoomBasis, 1) + minx : minx;
+                let maxx = docs.length ? NumCast(docs[0].width) + minx : minx;
                 let miny = docs.length ? NumCast(docs[0].y) : 0;
-                let maxy = docs.length ? NumCast(docs[0].height) / NumCast(docs[0].zoomBasis, 1) + miny : miny;
+                let maxy = docs.length ? NumCast(docs[0].height) + miny : miny;
                 let ranges = docs.filter(doc => doc).reduce((range, doc) => {
                     let x = NumCast(doc.x);
-                    let xe = x + NumCast(doc.width) / NumCast(doc.zoomBasis, 1);
+                    let xe = x + NumCast(doc.width);
                     let y = NumCast(doc.y);
-                    let ye = y + NumCast(doc.height) / NumCast(doc.zoomBasis, 1);
+                    let ye = y + NumCast(doc.height);
                     return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
                     [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
                 }, [[minx, maxx], [miny, maxy]]);
@@ -299,8 +300,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             }
         }
         SelectionManager.DeselectAll();
-        const newPanX = NumCast(doc.x) + NumCast(doc.width) / NumCast(doc.zoomBasis, 1) / 2;
-        const newPanY = NumCast(doc.y) + NumCast(doc.height) / NumCast(doc.zoomBasis, 1) / 2;
+        const newPanX = NumCast(doc.x) + NumCast(doc.width) / 2;
+        const newPanY = NumCast(doc.y) + NumCast(doc.height) / 2;
         const newState = HistoryUtil.getState();
         newState.initializers[id] = { panX: newPanX, panY: newPanY };
         HistoryUtil.pushState(newState);
@@ -501,19 +502,17 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         const easing = () => this.props.Document.panTransformType === "Ease";
 
-        if (this.props.fieldExt) Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
+        Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
         return (
             <div className={containerName} ref={this.createDropTarget} onWheel={this.onPointerWheel}
-                style={{ borderRadius: "inherit" }}
                 onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onDrop.bind(this)} onDragOver={this.onDragOver} onContextMenu={this.onContextMenu}>
                 <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} isSelected={this.props.isSelected}
                     addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox}
                     getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}>
                     <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY}
                         easing={easing} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
-
                         <CollectionFreeFormLinksView {...this.props} key="freeformLinks">
-                            <InkingCanvas getScreenTransform={this.getTransform} Document={this.extensionDoc} inkFieldKey={this.props.fieldExt ? "ink" : this.props.fieldKey + "_ink"} >
+                            <InkingCanvas getScreenTransform={this.getTransform} Document={this.extensionDoc} inkFieldKey={"ink"} >
                                 {this.childViews}
                             </InkingCanvas>
                         </CollectionFreeFormLinksView>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6f3adb6b5..613cbf98e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -530,7 +530,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 this.props.addDocument && this.props.addDocument(coll);
                 this.props.removeDocument && this.props.removeDocument(this.props.Document);
             }, icon: "window-restore"
-        })
+        });
         cm.addItem({
             description: "Find aliases", event: async () => {
                 const aliases = await SearchUtil.GetAliasesOfDocument(this.props.Document);
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index c5fc6c65a..abd0d9e12 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -55,8 +55,8 @@ export interface FieldViewProps {
 
 @observer
 export class FieldView extends React.Component<FieldViewProps> {
-    public static LayoutString(fieldType: { name: string }, fieldStr: string = "data") {
-        return `<${fieldType.name} {...props} fieldKey={"${fieldStr}"} />`;
+    public static LayoutString(fieldType: { name: string }, fieldStr: string = "data", fieldExt: string = "") {
+        return `<${fieldType.name} {...props} fieldKey={"${fieldStr}"} fieldExt={"${fieldExt}"} />`;
     }
 
     @computed
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 5475aa2b2..084fd4c96 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -232,9 +232,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 return field ? field.Data : `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`;
             },
             field2 => {
-                if (StrCast(this.props.Document.layout).indexOf("\"" + this.props.fieldKey + "\"") !== -1) // bcz: UGH!  why is this needed... something is happening out of order.  test with making a collection, then adding a text note and converting that to a template field.
+                if (StrCast(this.props.Document.layout).indexOf("\"" + this.props.fieldKey + "\"") !== -1) { // bcz: UGH!  why is this needed... something is happening out of order.  test with making a collection, then adding a text note and converting that to a template field.
                     this._editorView && !this._applyingChange &&
                         this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2)));
+                }
             }
         );
 
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 8af29110f..8bba05850 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -588,7 +588,7 @@ export class Viewer extends React.Component<IViewerProps> {
             }
             return true;
         });
-        this.Index = Math.min(this.Index + 1, filtered.length - 1)
+        this.Index = Math.min(this.Index + 1, filtered.length - 1);
     }
 
     nextResult = () => {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 3d46243e0..cc0dc71dd 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -372,7 +372,7 @@ export namespace Doc {
         }
         let layout = StrCast(fieldLayoutDoc.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`);
         if (backgroundLayout) {
-            layout = StrCast(fieldLayoutDoc.layout).replace(/fieldKey={"annotations"}/, `fieldKey={"${metaKey}"} fieldExt={"annotations"}`);
+            layout = StrCast(fieldLayoutDoc.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"} fieldExt={"annotations"}`);
             backgroundLayout = backgroundLayout.replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`);
         }
         let nw = Cast(fieldTemplate.nativeWidth, "number");
-- 
cgit v1.2.3-70-g09d2


From a69a43015ec414bd1a9577c03fbeb5c3b27fb55f Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Thu, 11 Jul 2019 12:36:34 -0400
Subject: fixes

---
 src/client/util/DocumentManager.ts                 |  8 +++--
 src/client/util/DragManager.ts                     | 35 ++++++++++++--------
 src/client/util/LinkManager.ts                     |  6 ++--
 src/client/util/RichTextSchema.tsx                 | 14 ++++++++
 src/client/util/TooltipTextMenu.tsx                |  2 ++
 src/client/views/MainView.tsx                      |  6 ++--
 .../views/collections/CollectionTreeView.tsx       |  9 +++++-
 src/client/views/nodes/LinkEditor.tsx              | 37 +++++++++++++---------
 src/client/views/nodes/LinkMenuGroup.tsx           | 16 ++++++++--
 src/client/views/nodes/PDFBox.tsx                  |  8 +++--
 src/client/views/pdf/PDFMenu.tsx                   |  5 +--
 src/client/views/pdf/PDFViewer.tsx                 |  4 +--
 12 files changed, 102 insertions(+), 48 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 8fa460bca..bb1345044 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -111,9 +111,11 @@ export class DocumentManager {
             pairs.push(...linksList.reduce((pairs, link) => {
                 if (link) {
                     let linkToDoc = LinkManager.Instance.getOppositeAnchor(link, dv.props.Document);
-                    DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => {
-                        pairs.push({ a: dv, b: docView1, l: link });
-                    });
+                    if (linkToDoc) {
+                        DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => {
+                            pairs.push({ a: dv, b: docView1, l: link });
+                        });
+                    }
                 }
                 return pairs;
             }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]));
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index cb71db2c5..8e44631a3 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -61,16 +61,18 @@ export function SetupDrag(
 export async function DragLinkAsDocument(dragEle: HTMLElement, x: number, y: number, linkDoc: Doc, sourceDoc: Doc) {
     let draggeddoc = LinkManager.Instance.getOppositeAnchor(linkDoc, sourceDoc);
 
-    let moddrag = await Cast(draggeddoc.annotationOn, Doc);
-    let dragdocs = moddrag ? [moddrag] : [draggeddoc];
-    let dragData = new DragManager.DocumentDragData(dragdocs, dragdocs);
-    dragData.dropAction = "alias" as dropActionType;
-    DragManager.StartLinkedDocumentDrag([dragEle], sourceDoc, dragData, x, y, {
-        handlers: {
-            dragComplete: action(emptyFunction),
-        },
-        hideSource: false
-    });
+    if (draggeddoc) {
+        let moddrag = await Cast(draggeddoc.annotationOn, Doc);
+        let dragdocs = moddrag ? [moddrag] : [draggeddoc];
+        let dragData = new DragManager.DocumentDragData(dragdocs, dragdocs);
+        dragData.dropAction = "alias" as dropActionType;
+        DragManager.StartLinkedDocumentDrag([dragEle], sourceDoc, dragData, x, y, {
+            handlers: {
+                dragComplete: action(emptyFunction),
+            },
+            hideSource: false
+        });
+    }
 }
 
 export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Doc) {
@@ -80,9 +82,16 @@ export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: n
     if (srcTarg) {
         let linkDocs = LinkManager.Instance.getAllRelatedLinks(srcTarg);
         if (linkDocs) {
-            draggedDocs = linkDocs.map(link => {
-                return LinkManager.Instance.getOppositeAnchor(link, sourceDoc);
-            });
+            linkDocs.forEach((doc) => {
+                let opp = LinkManager.Instance.getOppositeAnchor(doc, sourceDoc);
+                if (opp) {
+                    draggedDocs.push(opp);
+                }
+            }
+            )
+            // draggedDocs = linkDocs.map(link => {
+            //     return LinkManager.Instance.getOppositeAnchor(link, sourceDoc);
+            // });
         }
     }
     if (draggedDocs.length) {
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index 944bc532f..1ed040aa4 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -232,11 +232,11 @@ export class LinkManager {
     // finds the opposite anchor of a given anchor in a link
     //TODO This should probably return undefined if there isn't an opposite anchor
     //TODO This should also await the return value of the anchor so we don't filter out promises
-    public getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc {
+    public getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined {
         if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, null))) {
-            return Cast(linkDoc.anchor2, Doc, null)!;
+            return Cast(linkDoc.anchor2, Doc, null);
         } else {
-            return Cast(linkDoc.anchor1, Doc, null)!;
+            return Cast(linkDoc.anchor1, Doc, null);
         }
     }
 }
\ No newline at end of file
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 2a57180d3..b6402da13 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -400,6 +400,20 @@ export const marks: { [index: string]: MarkSpec } = {
         }]
     },
 
+    p18: {
+        parseDOM: [{ style: 'font-size: 18px;' }],
+        toDOM: () => ['span', {
+            style: 'font-size: 18px;'
+        }]
+    },
+
+    p20: {
+        parseDOM: [{ style: 'font-size: 20px;' }],
+        toDOM: () => ['span', {
+            style: 'font-size: 20px;'
+        }]
+    },
+
     p24: {
         parseDOM: [{ style: 'font-size: 24px;' }],
         toDOM: () => ['span', {
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index cb7ed976a..81a966923 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -107,6 +107,8 @@ export class TooltipTextMenu {
         this.fontSizeToNum.set(schema.marks.p12, 12);
         this.fontSizeToNum.set(schema.marks.p14, 14);
         this.fontSizeToNum.set(schema.marks.p16, 16);
+        this.fontSizeToNum.set(schema.marks.p18, 18);
+        this.fontSizeToNum.set(schema.marks.p20, 20);
         this.fontSizeToNum.set(schema.marks.p24, 24);
         this.fontSizeToNum.set(schema.marks.p32, 32);
         this.fontSizeToNum.set(schema.marks.p48, 48);
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index bf4ee84d6..df5c2020a 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -394,9 +394,9 @@ export class MainView extends React.Component {
                         </div></li>)}
                     <li key="undoTest"><button className="add-button round-button" onClick={() => UndoManager.PrintBatches()}><FontAwesomeIcon icon="exclamation" size="sm" /></button></li>
                     <li key="ink" style={{ paddingRight: "6px" }}><button className="toolbar-button round-button" title="Ink" onClick={() => InkingControl.Instance.toggleDisplay()}><FontAwesomeIcon icon="pen-nib" size="sm" /> </button></li>
-                    <li key="pen"><button onClick={() => InkingControl.Instance.switchTool(InkTool.Pen)} style={this.selected(InkTool.Pen)}><FontAwesomeIcon icon="pen" size="lg" title="Pen" /></button></li>
-                    <li key="marker"><button onClick={() => InkingControl.Instance.switchTool(InkTool.Highlighter)} style={this.selected(InkTool.Highlighter)}><FontAwesomeIcon icon="highlighter" size="lg" title="Pen" /></button></li>
-                    <li key="eraser"><button onClick={() => InkingControl.Instance.switchTool(InkTool.Eraser)} style={this.selected(InkTool.Eraser)}><FontAwesomeIcon icon="eraser" size="lg" title="Pen" /></button></li>
+                    <li key="pen"><button onClick={() => InkingControl.Instance.switchTool(InkTool.Pen)} title="Pen" style={this.selected(InkTool.Pen)}><FontAwesomeIcon icon="pen" size="lg" /></button></li>
+                    <li key="marker"><button onClick={() => InkingControl.Instance.switchTool(InkTool.Highlighter)} title="Highlighter" style={this.selected(InkTool.Highlighter)}><FontAwesomeIcon icon="highlighter" size="lg" /></button></li>
+                    <li key="eraser"><button onClick={() => InkingControl.Instance.switchTool(InkTool.Eraser)} title="Eraser" style={this.selected(InkTool.Eraser)}><FontAwesomeIcon icon="eraser" size="lg" /></button></li>
                     <li key="inkControls"><InkingControl /></li>
                 </ul>
             </div>
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 3674a743a..f8e5f72e4 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -301,7 +301,14 @@ class TreeView extends React.Component<TreeViewProps> {
         let addDoc = (doc: Doc, addBefore?: Doc, before?: boolean) => Doc.AddDocToList(this.props.document, this._chosenKey, doc, addBefore, before);
         let groups = LinkManager.Instance.getRelatedGroupedLinks(this.props.document);
         groups.forEach((groupLinkDocs, groupType) => {
-            let destLinks = groupLinkDocs.map(d => LinkManager.Instance.getOppositeAnchor(d, this.props.document));
+            // let destLinks = groupLinkDocs.map(d => LinkManager.Instance.getOppositeAnchor(d, this.props.document));
+            let destLinks: Doc[] = [];
+            groupLinkDocs.forEach((doc) => {
+                let opp = LinkManager.Instance.getOppositeAnchor(doc, this.props.document);
+                if (opp) {
+                    destLinks.push(opp);
+                }
+            });
             ele.push(
                 <div key={"treeviewlink-" + groupType + "subtitle"}>
                     <div className="collectionTreeView-subtitle">{groupType}:</div>
diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx
index a97ec8831..df56a19d0 100644
--- a/src/client/views/nodes/LinkEditor.tsx
+++ b/src/client/views/nodes/LinkEditor.tsx
@@ -200,7 +200,9 @@ export class LinkGroupEditor extends React.Component<LinkGroupEditorProps> {
         destGroupDoc.type = groupType;
         destGroupDoc.metadata = destMdDoc;
 
-        LinkManager.Instance.addGroupToAnchor(this.props.linkDoc, destDoc, destGroupDoc, true);
+        if (destDoc) {
+            LinkManager.Instance.addGroupToAnchor(this.props.linkDoc, destDoc, destGroupDoc, true);
+        }
     }
 
     @action
@@ -308,7 +310,10 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
         // create new metadata document for group
         let mdDoc = new Doc();
         mdDoc.anchor1 = this.props.sourceDoc.title;
-        mdDoc.anchor2 = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc).title;
+        let opp = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc);
+        if (opp) {
+            mdDoc.anchor2 = opp.title;
+        }
 
         // create new group document
         let groupDoc = new Doc();
@@ -326,20 +331,22 @@ export class LinkEditor extends React.Component<LinkEditorProps> {
             return <LinkGroupEditor key={"gred-" + StrCast(groupDoc.type)} linkDoc={this.props.linkDoc} sourceDoc={this.props.sourceDoc} groupDoc={groupDoc} />;
         });
 
-        return (
-            <div className="linkEditor">
-                <button className="linkEditor-back" onPointerDown={() => this.props.showLinks()}><FontAwesomeIcon icon="arrow-left" size="sm" /></button>
-                <div className="linkEditor-info">
-                    <p className="linkEditor-linkedTo">editing link to: <b>{destination.proto!.title}</b></p>
-                    <button className="linkEditor-button" onPointerDown={() => this.deleteLink()} title="Delete link"><FontAwesomeIcon icon="trash" size="sm" /></button>
-                </div>
-                <div className="linkEditor-groupsLabel">
-                    <b>Relationships:</b>
-                    <button className="linkEditor-button" onClick={() => this.addGroup()} title=" Add Group"><FontAwesomeIcon icon="plus" size="sm" /></button>
+        if (destination) {
+            return (
+                <div className="linkEditor">
+                    <button className="linkEditor-back" onPointerDown={() => this.props.showLinks()}><FontAwesomeIcon icon="arrow-left" size="sm" /></button>
+                    <div className="linkEditor-info">
+                        <p className="linkEditor-linkedTo">editing link to: <b>{destination.proto!.title}</b></p>
+                        <button className="linkEditor-button" onPointerDown={() => this.deleteLink()} title="Delete link"><FontAwesomeIcon icon="trash" size="sm" /></button>
+                    </div>
+                    <div className="linkEditor-groupsLabel">
+                        <b>Relationships:</b>
+                        <button className="linkEditor-button" onClick={() => this.addGroup()} title=" Add Group"><FontAwesomeIcon icon="plus" size="sm" /></button>
+                    </div>
+                    {groups.length > 0 ? groups : <div className="linkEditor-group">There are currently no relationships associated with this link.</div>}
                 </div>
-                {groups.length > 0 ? groups : <div className="linkEditor-group">There are currently no relationships associated with this link.</div>}
-            </div>
 
-        );
+            );
+        }
     }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/LinkMenuGroup.tsx b/src/client/views/nodes/LinkMenuGroup.tsx
index e4cf56d20..97f2e13ae 100644
--- a/src/client/views/nodes/LinkMenuGroup.tsx
+++ b/src/client/views/nodes/LinkMenuGroup.tsx
@@ -45,7 +45,15 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
             document.removeEventListener("pointermove", this.onLinkButtonMoved);
             document.removeEventListener("pointerup", this.onLinkButtonUp);
 
-            let draggedDocs = this.props.group.map(linkDoc => LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc));
+            let draggedDocs: Doc[] = [];
+            this.props.group.forEach(
+                (doc: Doc) => {
+                    let opp = LinkManager.Instance.getOppositeAnchor(doc, this.props.sourceDoc);
+                    if (opp) {
+                        draggedDocs.push(opp);
+                    }
+                }
+            )
             let dragData = new DragManager.DocumentDragData(draggedDocs, draggedDocs.map(d => undefined));
 
             DragManager.StartLinkedDocumentDrag([this._drag.current], this.props.sourceDoc, dragData, e.x, e.y, {
@@ -72,8 +80,10 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
     render() {
         let groupItems = this.props.group.map(linkDoc => {
             let destination = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc);
-            return <LinkMenuItem key={destination[Id] + this.props.sourceDoc[Id]} groupType={this.props.groupType}
-                linkDoc={linkDoc} sourceDoc={this.props.sourceDoc} destinationDoc={destination} showEditor={this.props.showEditor} />;
+            if (destination) {
+                return <LinkMenuItem key={destination[Id] + this.props.sourceDoc[Id]} groupType={this.props.groupType}
+                    linkDoc={linkDoc} sourceDoc={this.props.sourceDoc} destinationDoc={destination} showEditor={this.props.showEditor} />;
+            }
         });
 
         return (
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index cc02bb282..2ff5c089f 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -23,9 +23,11 @@ import { CompileScript } from '../../util/Scripting';
 import { Flyout, anchorPoints } from '../DocumentDecorations';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { ScriptField } from '../../../new_fields/ScriptField';
+import { KeyCodes } from '../../northstar/utils/KeyCodes';
 
 type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const PdfDocument = makeInterface(positionSchema, pageSchema);
+export const handleBackspace = (e: React.KeyboardEvent) => { if (e.keyCode === KeyCodes.BACKSPACE) e.stopPropagation() }
 
 @observer
 export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocument) {
@@ -175,13 +177,13 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
                             Annotation View Settings
                         </div>
                         <div className="pdfBox-settingsFlyout-kvpInput">
-                            <input placeholder="Key" className="pdfBox-settingsFlyout-input" onChange={this.newKeyChange}
+                            <input placeholder="Key" className="pdfBox-settingsFlyout-input" onKeyDown={handleBackspace} onChange={this.newKeyChange}
                                 style={{ gridColumn: 1 }} ref={this._keyRef} />
-                            <input placeholder="Value" className="pdfBox-settingsFlyout-input" onChange={this.newValueChange}
+                            <input placeholder="Value" className="pdfBox-settingsFlyout-input" onKeyDown={handleBackspace} onChange={this.newValueChange}
                                 style={{ gridColumn: 3 }} ref={this._valueRef} />
                         </div>
                         <div className="pdfBox-settingsFlyout-kvpInput">
-                            <input placeholder="Custom Script" onChange={this.newScriptChange} style={{ gridColumn: "1 / 4" }} ref={this._scriptRef} />
+                            <input placeholder="Custom Script" onChange={this.newScriptChange} onKeyDown={handleBackspace} style={{ gridColumn: "1 / 4" }} ref={this._scriptRef} />
                         </div>
                         <div className="pdfBox-settingsFlyout-kvpInput">
                             <button style={{ gridColumn: 1 }} onClick={this.resetFilters}>
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index d6970e7f4..feaa1f652 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -5,6 +5,7 @@ import { observer } from "mobx-react";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { emptyFunction, returnFalse } from "../../../Utils";
 import { Doc } from "../../../new_fields/Doc";
+import { handleBackspace } from "../nodes/PDFBox";
 
 @observer
 export default class PDFMenu extends React.Component {
@@ -251,8 +252,8 @@ export default class PDFMenu extends React.Component {
                 <button className="pdfMenu-button" title="Delete Anchor" onPointerDown={this.deleteClicked}><FontAwesomeIcon icon="trash-alt" size="lg" key="1" /></button>,
                 <button className="pdfMenu-button" title="Pin to Presentation" onPointerDown={this.PinToPres}><FontAwesomeIcon icon="map-pin" size="lg" key="2" /></button>,
                 <div className="pdfMenu-addTag" key="3">
-                    <input onChange={this.keyChanged} placeholder="Key" style={{ gridColumn: 1 }} />
-                    <input onChange={this.valueChanged} placeholder="Value" style={{ gridColumn: 3 }} />
+                    <input onKeyDown={handleBackspace} onChange={this.keyChanged} placeholder="Key" style={{ gridColumn: 1 }} />
+                    <input onKeyDown={handleBackspace} onChange={this.valueChanged} placeholder="Value" style={{ gridColumn: 3 }} />
                 </div>,
                 <button className="pdfMenu-button" title={`Add tag: ${this._keyValue} with value: ${this._valueValue}`} onPointerDown={this.addTag}><FontAwesomeIcon style={{ transition: "all .2s" }} color={this._added ? "#42f560" : "white"} icon="check" size="lg" key="4" /></button>,
             ];
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 8af29110f..761db7922 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -14,7 +14,7 @@ import { Docs, DocUtils, DocumentOptions } from "../../documents/Documents";
 import { DocumentManager } from "../../util/DocumentManager";
 import { DragManager } from "../../util/DragManager";
 import { DocumentView } from "../nodes/DocumentView";
-import { PDFBox } from "../nodes/PDFBox";
+import { PDFBox, handleBackspace } from "../nodes/PDFBox";
 import Page from "./Page";
 import "./PDFViewer.scss";
 import React = require("react");
@@ -648,7 +648,7 @@ export class Viewer extends React.Component<IViewerProps> {
                     <button className="pdfViewer-overlayButton" title="Open Search Bar"></button>
                     {/* <button title="Previous Result" onClick={() => this.search(this._searchString)}><FontAwesomeIcon icon="arrow-up" size="3x" color="white" /></button>
                     <button title="Next Result" onClick={this.nextResult}><FontAwesomeIcon icon="arrow-down" size="3x" color="white" /></button> */}
-                    <input placeholder="Search" className="pdfViewer-overlaySearchBar" onChange={this.searchStringChanged} />
+                    <input onKeyDown={handleBackspace} placeholder="Search" className="pdfViewer-overlaySearchBar" onChange={this.searchStringChanged} />
                     <button title="Search" onClick={() => this.search(this._searchString)}><FontAwesomeIcon icon="search" size="3x" color="white" /></button>
                 </div>
                 <button className="pdfViewer-overlayButton" onClick={this.prevAnnotation} title="Previous Annotation"
-- 
cgit v1.2.3-70-g09d2


From 59d32987f4f220c97a3b3cd4886ba47f3e8c4341 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Fri, 12 Jul 2019 20:18:24 -0400
Subject: second link icon commented out in rich text bar

---
 src/client/util/TooltipTextMenu.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 930379c65..d287ff9b1 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -252,7 +252,7 @@ export class TooltipTextMenu {
             this.linkEditor.appendChild(this.linkDrag);
             // this.linkEditor.appendChild(this.linkText);
             // this.linkEditor.appendChild(linkBtn);
-            this.tooltip.appendChild(this.linkEditor);
+            // this.tooltip.appendChild(this.linkEditor);
         }
 
         let node = this.view.state.selection.$from.nodeAfter;
@@ -266,7 +266,7 @@ export class TooltipTextMenu {
                 e.preventDefault();
             }
         };
-        this.tooltip.appendChild(this.linkEditor);
+        // this.tooltip.appendChild(this.linkEditor);
     }
 
     makeLink = (target: string) => {
-- 
cgit v1.2.3-70-g09d2


From 81d23dbd7b918fd1812b770960687bc8a12a0a34 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Sat, 13 Jul 2019 17:49:18 -0400
Subject: wrong link button hidden

---
 src/client/util/TooltipTextMenu.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index d287ff9b1..0d3adef2e 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -123,7 +123,7 @@ export class TooltipTextMenu {
         this.listTypeToIcon.set(schema.nodes.ordered_list, "1)");
         this.listTypes = Array.from(this.listTypeToIcon.keys());
 
-        this.tooltip.appendChild(this.createLink().render(this.view).dom);
+        // this.tooltip.appendChild(this.createLink().render(this.view).dom);
 
         this.tooltip.appendChild(this.createStar().render(this.view).dom);
 
@@ -252,7 +252,7 @@ export class TooltipTextMenu {
             this.linkEditor.appendChild(this.linkDrag);
             // this.linkEditor.appendChild(this.linkText);
             // this.linkEditor.appendChild(linkBtn);
-            // this.tooltip.appendChild(this.linkEditor);
+            this.tooltip.appendChild(this.linkEditor);
         }
 
         let node = this.view.state.selection.$from.nodeAfter;
-- 
cgit v1.2.3-70-g09d2


From c9bf8852a77298e1e958cfc72559418b6cb5981a Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Mon, 15 Jul 2019 11:57:23 -0400
Subject: tweaks

---
 src/client/util/TooltipTextMenu.tsx                    | 2 +-
 src/client/views/collections/CollectionDockingView.tsx | 1 +
 src/server/Search.ts                                   | 2 +-
 3 files changed, 3 insertions(+), 2 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 0d3adef2e..9ba339285 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -243,7 +243,7 @@ export class TooltipTextMenu {
                         handlers: {
                             dragComplete: action(() => {
                                 let m = dragData.droppedDocuments;
-                                this.makeLink(DocServer.prepend("/doc/" + m[0][Id]));
+                                m.length && this.makeLink(DocServer.prepend("/doc/" + m[0][Id]));
                             }),
                         },
                         hideSource: false
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 781bafec0..1069ebbdb 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -260,6 +260,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                         // Because this is in a set timeout, if this component unmounts right after mounting,
                         // we will leak a GoldenLayout, because we try to destroy it before we ever create it
                         setTimeout(() => this.setupGoldenLayout(), 1);
+                        DocListCast((CurrentUserUtils.UserDocument.workspaces as Doc).data).map(d => d.workspaceBrush = false);
                         this.props.Document.workspaceBrush = true;
                     }
                     this._ignoreStateChange = "";
diff --git a/src/server/Search.ts b/src/server/Search.ts
index 98f421937..11092c5be 100644
--- a/src/server/Search.ts
+++ b/src/server/Search.ts
@@ -26,7 +26,7 @@ export class Search {
             });
             return res;
         } catch (e) {
-            // console.warn("Search error: " + e + document);
+            // console.warn("Search error: ", e, documents);
         }
     }
 
-- 
cgit v1.2.3-70-g09d2


From 89e0d0d3edd5385cab8859b1d0784251b4aac15b Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Mon, 15 Jul 2019 12:56:12 -0400
Subject: Added AB's tooltip dragging code

---
 src/client/util/TooltipTextMenu.tsx | 42 +++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 0d3adef2e..add6f902c 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -51,6 +51,7 @@ export class TooltipTextMenu {
         this.tooltip = document.createElement("div");
         this.tooltip.className = "tooltipMenu";
 
+        this.dragElement(this.tooltip);
         // this.createCollapse();
         // if (this._collapseBtn) {
         //     this.tooltip.appendChild(this._collapseBtn.render(this.view).dom);
@@ -269,6 +270,47 @@ export class TooltipTextMenu {
         // this.tooltip.appendChild(this.linkEditor);
     }
 
+    dragElement(elmnt: HTMLElement) {
+        var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
+        if (elmnt) {
+            // if present, the header is where you move the DIV from:
+            elmnt.onpointerdown = dragMouseDown;
+        }
+        const self = this;
+
+        function dragMouseDown(e: PointerEvent) {
+            e = e || window.event;
+            //e.preventDefault();
+            // get the mouse cursor position at startup:
+            pos3 = e.clientX;
+            pos4 = e.clientY;
+            document.onpointerup = closeDragElement;
+            // call a function whenever the cursor moves:
+            document.onpointermove = elementDrag;
+        }
+
+        function elementDrag(e: PointerEvent) {
+            e = e || window.event;
+            //e.preventDefault();
+            // calculate the new cursor position:
+            pos1 = pos3 - e.clientX;
+            pos2 = pos4 - e.clientY;
+            pos3 = e.clientX;
+            pos4 = e.clientY;
+            // set the element's new position:
+            elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
+            elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
+        }
+
+        function closeDragElement() {
+            // stop moving when mouse button is released:
+            document.onpointerup = null;
+            document.onpointermove = null;
+            //self.highlightSearchTerms(self.state, ["hello"]);
+            //FormattedTextBox.Instance.unhighlightSearchTerms();
+        }
+    }
+
     makeLink = (target: string) => {
         let node = this.view.state.selection.$from.nodeAfter;
         let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target });
-- 
cgit v1.2.3-70-g09d2


From 78faa73f1d4a315a3d76613bdcbb894e2428ee10 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Tue, 16 Jul 2019 12:06:31 -0400
Subject: rich text bar link dragging fixed

---
 src/client/util/TooltipTextMenu.tsx | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 9ba339285..ba3543b72 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -238,6 +238,7 @@ export class TooltipTextMenu {
             this.linkDrag.onpointerdown = (e: PointerEvent) => {
                 let dragData = new DragManager.LinkDragData(this.editorProps.Document);
                 dragData.dontClearTextBox = true;
+                e.stopPropagation();
                 DragManager.StartLinkDrag(this.linkDrag!, dragData, e.clientX, e.clientY,
                     {
                         handlers: {
-- 
cgit v1.2.3-70-g09d2


From 7a4310f95da38cf5de55e487030284157acc58d8 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Tue, 16 Jul 2019 17:48:11 -0400
Subject: link ctrl makes link show in context

---
 .vscode/launch.json                         |  2 +-
 src/client/documents/Documents.ts           | 10 ++++++----
 src/client/util/RichTextSchema.tsx          |  3 ++-
 src/client/util/TooltipTextMenu.tsx         | 12 +++++++-----
 src/client/views/nodes/DocumentView.tsx     |  6 ++++--
 src/client/views/nodes/FormattedTextBox.tsx | 12 ++++++++++--
 src/server/index.ts                         |  1 +
 7 files changed, 31 insertions(+), 15 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/.vscode/launch.json b/.vscode/launch.json
index 3b6549767..e4196600e 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -38,7 +38,7 @@
             "protocol": "inspector",
             "port": 9229,
             "localRoot": "${workspaceFolder}",
-            "remoteRoot": "."
+            "remoteRoot": "${workspaceFolder}"
         },
         {
             "type": "node",
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 177810444..85fc721da 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -483,18 +483,20 @@ export namespace Docs {
 
 export namespace DocUtils {
 
-    export function MakeLink(source: Doc, target: Doc, targetContext?: Doc, title: string = "", description: string = "", tags: string = "Default") {
+    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;
         let sv = DocumentManager.Instance.getDocumentView(source);
         if (sv && sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === target) return;
         if (target === CurrentUserUtils.UserDocument) return;
 
+        let linkDoc;
         UndoManager.RunInBatch(() => {
-            let linkDoc = Docs.Create.TextDocument({ width: 100, height: 30, borderRounding: "100%" });
+            linkDoc = Docs.Create.TextDocument({ width: 100, height: 30, borderRounding: "100%" });
             linkDoc.type = DocumentType.LINK;
             let linkDocProto = Doc.GetProto(linkDoc);
 
-            linkDocProto.context = targetContext;
+            linkDocProto.targetContext = targetContext;
+            linkDocProto.sourceContext = sourceContext;
             linkDocProto.title = title === "" ? source.title + " to " + target.title : title;
             linkDocProto.linkDescription = description;
             linkDocProto.linkTags = tags;
@@ -509,8 +511,8 @@ export namespace DocUtils {
 
             LinkManager.Instance.addLink(linkDoc);
 
-            return linkDoc;
         }, "make link");
+        return linkDoc;
     }
 
 }
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index e0ff3074b..269de0f42 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -215,12 +215,13 @@ export const marks: { [index: string]: MarkSpec } = {
     link: {
         attrs: {
             href: {},
+            location: { default: null },
             title: { default: null }
         },
         inclusive: false,
         parseDOM: [{
             tag: "a[href]", getAttrs(dom: any) {
-                return { href: dom.getAttribute("href"), title: dom.getAttribute("title") };
+                return { href: dom.getAttribute("href"), location: dom.getAttribute("location"), title: dom.getAttribute("title") };
             }
         }],
         toDOM(node: any) { return ["a", node.attrs, 0]; }
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 3e804651c..f4579fc51 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -240,12 +240,14 @@ export class TooltipTextMenu {
                 let dragData = new DragManager.LinkDragData(this.editorProps.Document);
                 dragData.dontClearTextBox = true;
                 e.stopPropagation();
+                let ctrlKey = e.ctrlKey;
                 DragManager.StartLinkDrag(this.linkDrag!, dragData, e.clientX, e.clientY,
                     {
                         handlers: {
                             dragComplete: action(() => {
-                                let m = dragData.droppedDocuments;
-                                m.length && this.makeLink(DocServer.prepend("/doc/" + m[0][Id]));
+                                // let m = dragData.droppedDocuments;
+                                let linkDoc = dragData.linkDocument;
+                                linkDoc instanceof Doc && this.makeLink(DocServer.prepend("/doc/" + linkDoc[Id]), ctrlKey ? "onRight" : "inTab");
                             }),
                         },
                         hideSource: false
@@ -263,7 +265,7 @@ export class TooltipTextMenu {
 
         this.linkText.onkeydown = (e: KeyboardEvent) => {
             if (e.key === "Enter") {
-                this.makeLink(this.linkText!.textContent!);
+                // this.makeLink(this.linkText!.textContent!);
                 e.stopPropagation();
                 e.preventDefault();
             }
@@ -312,9 +314,9 @@ export class TooltipTextMenu {
         }
     }
 
-    makeLink = (target: string) => {
+    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 });
+        let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target, location: location });
         this.view.dispatch(this.view.state.tr.removeMark(this.view.state.selection.from, this.view.state.selection.to, this.view.state.schema.marks.link));
         this.view.dispatch(this.view.state.tr.addMark(this.view.state.selection.from, this.view.state.selection.to, link));
         node = this.view.state.selection.$from.nodeAfter;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f7a33466e..970ef24d8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -344,7 +344,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     let first = linkedDocs.filter(d => Doc.AreProtosEqual(d.anchor1 as Doc, this.props.Document));
                     let linkedFwdDocs = first.length ? [first[0].anchor2 as Doc, first[0].anchor1 as Doc] : [expandedDocs[0], expandedDocs[0]];
 
-                    let linkedFwdContextDocs = [first.length ? await (first[0].context) as Doc : undefined, undefined];
+                    // @TODO: shouldn't always follow target context
+                    let linkedFwdContextDocs = [first.length ? await (first[0].targetContext) as Doc : undefined, undefined];
 
                     let linkedFwdPage = [first.length ? NumCast(first[0].linkedToPage, undefined) : undefined, undefined];
 
@@ -454,8 +455,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             else {
                 // const docs = await SearchUtil.Search(`data_l:"${destDoc[Id]}"`, true);
                 // const views = docs.map(d => DocumentManager.Instance.getDocumentView(d)).filter(d => d).map(d => d as DocumentView);
-                DocUtils.MakeLink(sourceDoc, destDoc, this.props.ContainingCollectionView ? this.props.ContainingCollectionView.props.Document : undefined);
+                let linkDoc = DocUtils.MakeLink(sourceDoc, destDoc, this.props.ContainingCollectionView ? this.props.ContainingCollectionView.props.Document : undefined);
                 de.data.droppedDocuments.push(destDoc);
+                de.data.linkDocument = linkDoc;
             }
         }
     }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 82c2cef26..45e7171d2 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -303,15 +303,23 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         let ctrlKey = e.ctrlKey;
         if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey && e.target) {
             let href = (e.target as any).href;
+            let location = (e.target as any).attributes.location.value;
             for (let parent = (e.target as any).parentNode; !href && parent; parent = parent.parentNode) {
                 href = parent.childNodes[0].href ? parent.childNodes[0].href : parent.href;
             }
             if (href) {
+                ``
                 if (href.indexOf(DocServer.prepend("/doc/")) === 0) {
                     this._linkClicked = href.replace(DocServer.prepend("/doc/"), "").split("?")[0];
                     if (this._linkClicked) {
-                        DocServer.GetRefField(this._linkClicked).then(f => {
-                            (f instanceof Doc) && DocumentManager.Instance.jumpToDocument(f, ctrlKey, false, document => this.props.addDocTab(document, undefined, "inTab"));
+                        DocServer.GetRefField(this._linkClicked).then(async linkDoc => {
+                            if (linkDoc instanceof Doc) {
+                                let proto = Doc.GetProto(linkDoc);
+                                let targetContext = await Cast(proto.targetContext, Doc);
+                                if (targetContext) {
+                                    DocumentManager.Instance.jumpToDocument(targetContext, ctrlKey, false, document => this.props.addDocTab(document, undefined, location ? location : "inTab"));
+                                }
+                            }
                         });
                         e.stopPropagation();
                         e.preventDefault();
diff --git a/src/server/index.ts b/src/server/index.ts
index 06f8358e1..37eabf4c8 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -190,6 +190,7 @@ app.get("/thumbnail/:filename", (req, res) => {
             probe(input, (err: any, result: any) => {
                 if (err) {
                     console.log(err);
+                    console.log(filename);
                     return;
                 }
                 res.send({ path: "/files/" + filename, width: result.width, height: result.height });
-- 
cgit v1.2.3-70-g09d2


From fd003a789941d2008d895a5e047cdd224540156a Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Tue, 16 Jul 2019 22:27:17 -0400
Subject: fixed backlinking

---
 src/client/util/TooltipTextMenu.tsx     |  7 +++++++
 src/client/views/nodes/LinkMenuItem.tsx | 14 ++++++++++----
 2 files changed, 17 insertions(+), 4 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index f4579fc51..309d19016 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -19,6 +19,7 @@ import { CollectionDockingView } from "../views/collections/CollectionDockingVie
 import { DocumentManager } from "./DocumentManager";
 import { Id } from "../../new_fields/FieldSymbols";
 import { FormattedTextBoxProps } from "../views/nodes/FormattedTextBox";
+import { SelectionManager } from "./SelectionManager";
 
 //appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc.
 export class TooltipTextMenu {
@@ -239,6 +240,8 @@ export class TooltipTextMenu {
             this.linkDrag.onpointerdown = (e: PointerEvent) => {
                 let dragData = new DragManager.LinkDragData(this.editorProps.Document);
                 dragData.dontClearTextBox = true;
+                // hack to get source context -sy
+                let docView = DocumentManager.Instance.getDocumentView(this.editorProps.Document);
                 e.stopPropagation();
                 let ctrlKey = e.ctrlKey;
                 DragManager.StartLinkDrag(this.linkDrag!, dragData, e.clientX, e.clientY,
@@ -247,6 +250,10 @@ export class TooltipTextMenu {
                             dragComplete: action(() => {
                                 // let m = dragData.droppedDocuments;
                                 let linkDoc = dragData.linkDocument;
+                                let proto = Doc.GetProto(linkDoc);
+                                if (docView && docView.props.ContainingCollectionView) {
+                                    proto.sourceContext = docView.props.ContainingCollectionView.props.Document;
+                                }
                                 linkDoc instanceof Doc && this.makeLink(DocServer.prepend("/doc/" + linkDoc[Id]), ctrlKey ? "onRight" : "inTab");
                             }),
                         },
diff --git a/src/client/views/nodes/LinkMenuItem.tsx b/src/client/views/nodes/LinkMenuItem.tsx
index 99ea16094..23758a1c0 100644
--- a/src/client/views/nodes/LinkMenuItem.tsx
+++ b/src/client/views/nodes/LinkMenuItem.tsx
@@ -40,14 +40,20 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
         }
         let proto = Doc.GetProto(this.props.linkDoc);
         let targetContext = await Cast(proto.targetContext, Doc);
+        let sourceContext = await Cast(proto.sourceContext, Doc);
+        let self = this;
         if (DocumentManager.Instance.getDocumentView(jumpToDoc)) {
-            let self = this;
             DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, undefined, undefined, NumCast((this.props.destinationDoc === self.props.linkDoc.anchor2 ? self.props.linkDoc.anchor2Page : self.props.linkDoc.anchor1Page)));
         }
-        else if (targetContext) {
-            DocumentManager.Instance.jumpToDocument(targetContext, e.altKey, false, document => CollectionDockingView.Instance.AddRightSplit(document, undefined));
-        } else {
+        else if (!((this.props.destinationDoc === self.props.linkDoc.anchor2 && targetContext) || (this.props.destinationDoc === self.props.linkDoc.anchor1 && sourceContext))) {
             CollectionDockingView.Instance.AddRightSplit(jumpToDoc, undefined);
+        } else {
+            if (this.props.destinationDoc === self.props.linkDoc.anchor2 && targetContext) {
+                DocumentManager.Instance.jumpToDocument(targetContext, e.altKey, false, document => CollectionDockingView.Instance.AddRightSplit(document, undefined));
+            }
+            else if (this.props.destinationDoc === self.props.linkDoc.anchor1 && sourceContext) {
+                DocumentManager.Instance.jumpToDocument(sourceContext, e.altKey, false, document => CollectionDockingView.Instance.AddRightSplit(document, undefined));
+            }
         }
     }
 
-- 
cgit v1.2.3-70-g09d2


From 5aa6bcdd4e23bb9e9d05181d0dc6b638e45e397b Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Wed, 17 Jul 2019 20:48:14 -0400
Subject: Moved DocServer.prepend and changed how corsProxy works

---
 src/Utils.ts                                       | 13 +++++
 src/client/DocServer.ts                            |  8 ----
 src/client/util/History.ts                         |  2 +-
 .../util/Import & Export/DirectoryImportBox.tsx    |  4 +-
 src/client/util/SearchUtil.ts                      |  3 +-
 src/client/util/TooltipTextMenu.tsx                |  8 ++--
 src/client/views/MainView.tsx                      |  4 +-
 src/client/views/SearchBox.tsx                     |  3 +-
 .../views/collections/CollectionDockingView.tsx    |  2 +-
 src/client/views/collections/CollectionSubView.tsx |  7 +--
 src/client/views/nodes/DocumentView.tsx            |  4 +-
 src/client/views/nodes/FormattedTextBox.tsx        |  5 +-
 src/client/views/nodes/ImageBox.tsx                |  6 +--
 src/client/views/nodes/VideoBox.tsx                |  4 +-
 src/client/views/pdf/PDFViewer.tsx                 | 55 +++++-----------------
 src/client/views/search/SearchBox.tsx              |  6 +--
 src/mobile/ImageUpload.tsx                         |  5 +-
 .../authentication/models/current_user_utils.ts    |  5 +-
 src/server/index.ts                                |  2 +-
 19 files changed, 65 insertions(+), 81 deletions(-)

(limited to 'src/client/util/TooltipTextMenu.tsx')

diff --git a/src/Utils.ts b/src/Utils.ts
index e8a80bdc3..ac6d127cc 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -2,6 +2,7 @@ import v4 = require('uuid/v4');
 import v5 = require("uuid/v5");
 import { Socket } from 'socket.io';
 import { Message } from './server/Message';
+import { RouteStore } from './server/RouteStore';
 
 export class Utils {
 
@@ -27,6 +28,18 @@ export class Utils {
         return { scale, translateX, translateY };
     }
 
+    /**
+     * A convenience method. Prepends the full path (i.e. http://localhost:1050) to the
+     * requested extension
+     * @param extension the specified sub-path to append to the window origin
+     */
+    public static prepend(extension: string): string {
+        return window.location.origin + extension;
+    }
+    public static CorsProxy(url: string): string {
+        return this.prepend(RouteStore.corsProxy + "/") + encodeURIComponent(url);
+    }
+
     public static CopyText(text: string) {
         var textArea = document.createElement("textarea");
         textArea.value = text;
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 6737657c8..8c64d2b2f 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -47,14 +47,6 @@ export namespace DocServer {
         Utils.AddServerHandler(_socket, MessageStore.DeleteField, respondToDelete);
         Utils.AddServerHandler(_socket, MessageStore.DeleteFields, respondToDelete);
     }
-    /**
-     * A convenience method. Prepends the full path (i.e. http://localhost:1050) to the
-     * requested extension
-     * @param extension the specified sub-path to append to the window origin
-     */
-    export function prepend(extension: string): string {
-        return window.location.origin + extension;
-    }
 
     function errorFunc(): never {
         throw new Error("Can't use DocServer without calling init first");
diff --git a/src/client/util/History.ts b/src/client/util/History.ts
index cbf5b3fc8..e9ff21b22 100644
--- a/src/client/util/History.ts
+++ b/src/client/util/History.ts
@@ -129,7 +129,7 @@ export namespace HistoryUtil {
 
     function addStringifier(type: string, keys: string[], customStringifier?: (state: ParsedUrl, current: string) => string) {
         stringifiers[type] = state => {
-            let path = DocServer.prepend(`/${type}`);
+            let path = Utils.prepend(`/${type}`);
             if (customStringifier) {
                 path = customStringifier(state, path);
             }
diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx
index c096e9ceb..75b0b52a7 100644
--- a/src/client/util/Import & Export/DirectoryImportBox.tsx	
+++ b/src/client/util/Import & Export/DirectoryImportBox.tsx	
@@ -98,12 +98,12 @@ export default class DirectoryImportBox extends React.Component<FieldViewProps>
 
             runInAction(() => this.remaining++);
 
-            let prom = fetch(DocServer.prepend(RouteStore.upload), {
+            let prom = fetch(Utils.prepend(RouteStore.upload), {
                 method: 'POST',
                 body: formData
             }).then(async (res: Response) => {
                 (await res.json()).map(action((file: any) => {
-                    let docPromise = Docs.Get.DocumentFromType(type, DocServer.prepend(file), { nativeWidth: 300, width: 300, title: dropFileName });
+                    let docPromise = Docs.Get.DocumentFromType(type, Utils.prepend(file), { nativeWidth: 300, width: 300, title: dropFileName });
                     docPromise.then(doc => {
                         doc && docs.push(doc) && runInAction(() => this.remaining--);
                     });
diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts
index abf1a7c32..ee5a83710 100644
--- a/src/client/util/SearchUtil.ts
+++ b/src/client/util/SearchUtil.ts
@@ -2,6 +2,7 @@ import * as rp from 'request-promise';
 import { DocServer } from '../DocServer';
 import { Doc } from '../../new_fields/Doc';
 import { Id } from '../../new_fields/FieldSymbols';
+import { Utils } from '../../Utils';
 
 export namespace SearchUtil {
     export type HighlightingResult = { [id: string]: { [key: string]: string[] } };
@@ -29,7 +30,7 @@ export namespace SearchUtil {
     export function Search(query: string, returnDocs: false, options?: SearchParams): Promise<IdSearchResult>;
     export async function Search(query: string, returnDocs: boolean, options: SearchParams = {}) {
         query = query || "*"; //If we just have a filter query, search for * as the query
-        const result: IdSearchResult = JSON.parse(await rp.get(DocServer.prepend("/search"), {
+        const result: IdSearchResult = JSON.parse(await rp.get(Utils.prepend("/search"), {
             qs: { ...options, q: query },
         }));
         if (!returnDocs) {
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 309d19016..a4c053de2 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -19,7 +19,7 @@ import { CollectionDockingView } from "../views/collections/CollectionDockingVie
 import { DocumentManager } from "./DocumentManager";
 import { Id } from "../../new_fields/FieldSymbols";
 import { FormattedTextBoxProps } from "../views/nodes/FormattedTextBox";
-import { SelectionManager } from "./SelectionManager";
+import { Utils } from "../../Utils";
 
 //appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc.
 export class TooltipTextMenu {
@@ -213,8 +213,8 @@ export class TooltipTextMenu {
                 let link = node && node.marks.find(m => m.type.name === "link");
                 if (link) {
                     let href: string = link.attrs.href;
-                    if (href.indexOf(DocServer.prepend("/doc/")) === 0) {
-                        let docid = href.replace(DocServer.prepend("/doc/"), "");
+                    if (href.indexOf(Utils.prepend("/doc/")) === 0) {
+                        let docid = href.replace(Utils.prepend("/doc/"), "");
                         DocServer.GetRefField(docid).then(action((f: Opt<Field>) => {
                             if (f instanceof Doc) {
                                 if (DocumentManager.Instance.getDocumentView(f)) {
@@ -254,7 +254,7 @@ export class TooltipTextMenu {
                                 if (docView && docView.props.ContainingCollectionView) {
                                     proto.sourceContext = docView.props.ContainingCollectionView.props.Document;
                                 }
-                                linkDoc instanceof Doc && this.makeLink(DocServer.prepend("/doc/" + linkDoc[Id]), ctrlKey ? "onRight" : "inTab");
+                                linkDoc instanceof Doc && this.makeLink(Utils.prepend("/doc/" + linkDoc[Id]), ctrlKey ? "onRight" : "inTab");
                             }),
                         },
                         hideSource: false
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index ce7369220..94a4835a1 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -16,7 +16,7 @@ import { listSpec } from '../../new_fields/Schema';
 import { Cast, FieldValue, NumCast, BoolCast, StrCast } from '../../new_fields/Types';
 import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
 import { RouteStore } from '../../server/RouteStore';
-import { emptyFunction, returnOne, returnTrue } from '../../Utils';
+import { emptyFunction, returnOne, returnTrue, Utils } from '../../Utils';
 import { DocServer } from '../DocServer';
 import { Docs } from '../documents/Documents';
 import { SetupDrag } from '../util/DragManager';
@@ -433,7 +433,7 @@ export class MainView extends React.Component {
         return [
             this.isSearchVisible ? <div className="main-searchDiv" key="search" style={{ top: '34px', right: '1px', position: 'absolute' }} > <FilterBox /> </div> : null,
             <div className="main-buttonDiv" key="logout" style={{ bottom: '0px', right: '1px', position: 'absolute' }} ref={logoutRef}>
-                <button onClick={() => window.location.assign(DocServer.prepend(RouteStore.logout))}>Log Out</button></div>
+                <button onClick={() => window.location.assign(Utils.prepend(RouteStore.logout))}>Log Out</button></div>
         ];
 
     }
diff --git a/src/client/views/SearchBox.tsx b/src/client/views/SearchBox.tsx
index 1b9be841f..33cb63df5 100644
--- a/src/client/views/SearchBox.tsx
+++ b/src/client/views/SearchBox.tsx
@@ -13,6 +13,7 @@ import { Docs } from '../documents/Documents';
 import { SetupDrag } from '../util/DragManager';
 import { SearchItem } from './search/SearchItem';
 import "./SearchBox.scss";
+import { Utils } from '../../Utils';
 
 library.add(faSearch);
 library.add(faObjectGroup);
@@ -47,7 +48,7 @@ export class SearchBox extends React.Component {
 
     @action
     getResults = async (query: string) => {
-        let response = await rp.get(DocServer.prepend('/search'), {
+        let response = await rp.get(Utils.prepend('/search'), {
             qs: {
                 query
             }
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index a193ff677..ba7903419 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -465,7 +465,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
             .off('click') //unbind the current click handler
             .click(action(function () {
                 stack.config.fixed = !stack.config.fixed;
-                // var url = DocServer.prepend("/doc/" + stack.contentItems[0].tab.contentItem.config.props.documentId);
+                // var url = Utils.prepend("/doc/" + stack.contentItems[0].tab.contentItem.config.props.documentId);
                 // let win = window.open(url, stack.contentItems[0].tab.title, "width=300,height=400");
             }));
     }
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 5d5189336..2ddefb3c0 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -20,6 +20,7 @@ import { CollectionVideoView } from "./CollectionVideoView";
 import { CollectionView } from "./CollectionView";
 import React = require("react");
 import { MainView } from "../MainView";
+import { Utils } from "../../../Utils";
 
 export interface CollectionViewProps extends FieldViewProps {
     addDocument: (document: Doc, allowDuplicates?: boolean) => boolean;
@@ -164,7 +165,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                 } else {
                     let path = window.location.origin + "/doc/";
                     if (text.startsWith(path)) {
-                        let docid = text.replace(DocServer.prepend("/doc/"), "").split("?")[0];
+                        let docid = text.replace(Utils.prepend("/doc/"), "").split("?")[0];
                         DocServer.GetRefField(docid).then(f => {
                             if (f instanceof Doc) {
                                 if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
@@ -193,7 +194,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                 if (item.kind === "string" && item.type.indexOf("uri") !== -1) {
                     let str: string;
                     let prom = new Promise<string>(resolve => e.dataTransfer.items[i].getAsString(resolve))
-                        .then(action((s: string) => rp.head(DocServer.prepend(RouteStore.corsProxy + "/" + (str = s)))))
+                        .then(action((s: string) => rp.head(Utils.CorsProxy(str = s))))
                         .then(result => {
                             let type = result["content-type"];
                             if (type) {
@@ -219,7 +220,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                     }).then(async (res: Response) => {
                         (await res.json()).map(action((file: any) => {
                             let full = { ...options, nativeWidth: type.indexOf("video") !== -1 ? 600 : 300, width: 300, title: dropFileName };
-                            let path = DocServer.prepend(file);
+                            let path = Utils.prepend(file);
                             Docs.Get.DocumentFromType(type, path, full).then(doc => doc && this.props.addDocument(doc));
                         }));
                     });
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 245dd319d..af1cc079b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -557,13 +557,13 @@ 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" });
-        cm.addItem({ description: "Copy URL", event: () => Utils.CopyText(DocServer.prepend("/doc/" + this.props.Document[Id])), icon: "link" });
+        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" });
         cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" });
         type User = { email: string, userDocumentId: string };
         let usersMenu: ContextMenuProps[] = [];
         try {
-            let stuff = await rp.get(DocServer.prepend(RouteStore.getUsers));
+            let stuff = await rp.get(Utils.prepend(RouteStore.getUsers));
             const users: User[] = JSON.parse(stuff);
             usersMenu = users.filter(({ email }) => email !== CurrentUserUtils.email).map(({ email, userDocumentId }) => ({
                 description: email, event: async () => {
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 066cc40e2..99801ecff 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -35,6 +35,7 @@ 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);
 library.add(faSmile);
@@ -311,8 +312,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 href = parent.childNodes[0].href ? parent.childNodes[0].href : parent.href;
             }
             if (href) {
-                if (href.indexOf(DocServer.prepend("/doc/")) === 0) {
-                    this._linkClicked = href.replace(DocServer.prepend("/doc/"), "").split("?")[0];
+                if (href.indexOf(Utils.prepend("/doc/")) === 0) {
+                    this._linkClicked = href.replace(Utils.prepend("/doc/"), "").split("?")[0];
                     if (this._linkClicked) {
                         DocServer.GetRefField(this._linkClicked).then(async linkDoc => {
                             if (linkDoc instanceof Doc) {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index ebe3732e6..4ffd265d7 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -165,12 +165,12 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
             recorder.ondataavailable = async function (e: any) {
                 const formData = new FormData();
                 formData.append("file", e.data);
-                const res = await fetch(DocServer.prepend(RouteStore.upload), {
+                const res = await fetch(Utils.prepend(RouteStore.upload), {
                     method: 'POST',
                     body: formData
                 });
                 const files = await res.json();
-                const url = DocServer.prepend(files[0]);
+                const url = Utils.prepend(files[0]);
                 // upload to server with known URL 
                 let audioDoc = Docs.Create.AudioDocument(url, { title: "audio test", x: NumCast(self.props.Document.x), y: NumCast(self.props.Document.y), width: 200, height: 32 });
                 audioDoc.embed = true;
@@ -327,7 +327,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
         let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx
         let nativeWidth = FieldValue(this.Document.nativeWidth, pw);
         let nativeHeight = FieldValue(this.Document.nativeHeight, 0);
-        let paths: string[] = [window.origin + RouteStore.corsProxy + "/" + "http://www.cs.brown.edu/~bcz/noImage.png"];
+        let paths: string[] = [Utils.CorsProxy("http://www.cs.brown.edu/~bcz/noImage.png")];
         // this._curSuffix = "";
         // if (w > 20) {
         Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey);
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 8b8e500c4..0f2d18f6b 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -122,7 +122,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
 
     public static async convertDataUri(imageUri: string, returnedFilename: string) {
         try {
-            let posting = DocServer.prepend(RouteStore.dataUriToImage);
+            let posting = Utils.prepend(RouteStore.dataUriToImage);
             const returnedUri = await rp.post(posting, {
                 body: {
                     uri: imageUri,
@@ -164,7 +164,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
                     let filename = encodeURIComponent("snapshot" + this.props.Document.title + "_" + this.props.Document.curPage).replace(/\./g, "");
                     VideoBox.convertDataUri(dataUrl, filename).then(returnedFilename => {
                         if (returnedFilename) {
-                            let url = DocServer.prepend(returnedFilename);
+                            let url = Utils.prepend(returnedFilename);
                             let imageSummary = Docs.Create.ImageDocument(url, {
                                 x: NumCast(this.props.Document.x) + width, y: NumCast(this.props.Document.y),
                                 width: 150, height: height / width * 150, title: "--snapshot" + NumCast(this.props.Document.curPage) + " image-"
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 699a1ffd7..b7ded7e06 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -4,23 +4,18 @@ import * as Pdfjs from "pdfjs-dist";
 import "pdfjs-dist/web/pdf_viewer.css";
 import * as rp from "request-promise";
 import { Dictionary } from "typescript-collections";
-import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Opt } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
-import { BoolCast, Cast, NumCast, StrCast, FieldValue } from "../../../new_fields/Types";
-import { emptyFunction } from "../../../Utils";
-import { DocServer } from "../../DocServer";
-import { Docs, DocUtils, DocumentOptions } from "../../documents/Documents";
-import { DocumentManager } from "../../util/DocumentManager";
+import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { emptyFunction, Utils } from "../../../Utils";
+import { Docs, DocUtils } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
-import { DocumentView } from "../nodes/DocumentView";
-import { PDFBox, handleBackspace } from "../nodes/PDFBox";
+import { PDFBox } from "../nodes/PDFBox";
 import Page from "./Page";
 import "./PDFViewer.scss";
 import React = require("react");
-import PDFMenu from "./PDFMenu";
-import { UndoManager } from "../../util/UndoManager";
-import { CompileScript, CompiledScript, CompileResult } from "../../util/Scripting";
+import { CompileScript, CompileResult } from "../../util/Scripting";
 import { ScriptField } from "../../../new_fields/ScriptField";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import Annotation from "./Annotation";
@@ -90,16 +85,12 @@ export class Viewer extends React.Component<IViewerProps> {
     private _annotationReactionDisposer?: IReactionDisposer;
     private _dropDisposer?: DragManager.DragDropDisposer;
     private _filterReactionDisposer?: IReactionDisposer;
-    private _activeReactionDisposer?: IReactionDisposer;
     private _viewer: React.RefObject<HTMLDivElement>;
     private _mainCont: React.RefObject<HTMLDivElement>;
     private _pdfViewer: any;
     // private _textContent: Pdfjs.TextContent[] = [];
     private _pdfFindController: any;
     private _searchString: string = "";
-    private _rendered: boolean = false;
-    private _pageIndex: number = -1;
-    private _matchIndex: number = 0;
 
     constructor(props: IViewerProps) {
         super(props);
@@ -135,23 +126,6 @@ export class Viewer extends React.Component<IViewerProps> {
             },
             { fireImmediately: true });
 
-        this._activeReactionDisposer = reaction(
-            () => this.props.parent.props.active(),
-            () => {
-                runInAction(() => {
-                    if (!this.props.parent.props.active()) {
-                        this._searching = false;
-                        this._pdfFindController = null;
-                        if (this._viewer.current) {
-                            let cns = this._viewer.current.childNodes;
-                            for (let i = cns.length - 1; i >= 0; i--) {
-                                cns.item(i).remove();
-                            }
-                        }
-                    }
-                });
-            }
-        );
 
         if (this.props.parent.props.ContainingCollectionView) {
             this._filterReactionDisposer = reaction(
@@ -346,7 +320,7 @@ export class Viewer extends React.Component<IViewerProps> {
             this._isPage[page] = "image";
             const address = this.props.url;
             try {
-                let res = JSON.parse(await rp.get(DocServer.prepend(`/thumbnail${address.substring("files/".length, address.length - ".pdf".length)}-${page + 1}.PNG`)));
+                let res = JSON.parse(await rp.get(Utils.prepend(`/thumbnail${address.substring("files/".length, address.length - ".pdf".length)}-${page + 1}.PNG`)));
                 runInAction(() => this._visibleElements[page] =
                     <img key={res.path} src={res.path} onError={handleError}
                         style={{ width: `${parseInt(res.width) * scale}px`, height: `${parseInt(res.height) * scale}px` }} />);
@@ -476,7 +450,6 @@ export class Viewer extends React.Component<IViewerProps> {
                             phraseSearch: true,
                             query: searchString
                         });
-                    this._rendered = true;
                 });
                 container.addEventListener("pagerendered", () => {
                     console.log("rendered");
@@ -488,7 +461,6 @@ export class Viewer extends React.Component<IViewerProps> {
                             phraseSearch: true,
                             query: searchString
                         });
-                    this._rendered = true;
                 });
             }
         }
@@ -563,7 +535,6 @@ export class Viewer extends React.Component<IViewerProps> {
                     });
                     container.addEventListener("pagerendered", () => {
                         console.log("rendered");
-                        this._rendered = true;
                     });
                     this._pdfViewer.setDocument(this.props.pdf);
                     this._pdfFindController = new PDFJSViewer.PDFFindController(this._pdfViewer);
@@ -703,17 +674,17 @@ class SimpleLinkService {
     externalLinkRel: any = null;
     pdf: any = null;
 
-    navigateTo(dest: any) { }
+    navigateTo() { }
 
-    getDestinationHash(dest: any) { return "#"; }
+    getDestinationHash() { return "#"; }
 
-    getAnchorUrl(hash: any) { return "#"; }
+    getAnchorUrl() { return "#"; }
 
-    setHash(hash: any) { }
+    setHash() { }
 
-    executeNamedAction(action: any) { }
+    executeNamedAction() { }
 
-    cachePageRef(pageNum: any, pageRef: any) { }
+    cachePageRef() { }
 
     get pagesCount() {
         return this.pdf ? this.pdf.numPages : 0;
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 16c44225a..2214ac8af 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -9,12 +9,12 @@ import { Docs } from '../../documents/Documents';
 import { NumCast, Cast } from '../../../new_fields/Types';
 import { Doc } from '../../../new_fields/Doc';
 import { SearchItem } from './SearchItem';
-import { DocServer } from '../../DocServer';
 import * as rp from 'request-promise';
 import { Id } from '../../../new_fields/FieldSymbols';
 import { SearchUtil } from '../../util/SearchUtil';
 import { RouteStore } from '../../../server/RouteStore';
 import { FilterBox } from './FilterBox';
+import { Utils } from '../../../Utils';
 
 
 @observer
@@ -74,7 +74,7 @@ export class SearchBox extends React.Component {
 
     public static async convertDataUri(imageUri: string, returnedFilename: string) {
         try {
-            let posting = DocServer.prepend(RouteStore.dataUriToImage);
+            let posting = Utils.prepend(RouteStore.dataUriToImage);
             const returnedUri = await rp.post(posting, {
                 body: {
                     uri: imageUri,
@@ -154,7 +154,7 @@ export class SearchBox extends React.Component {
                         filteredDocs.forEach(doc => {
                             const index = this._resultsSet.get(doc);
                             const highlight = highlights[doc[Id]];
-                            const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)) : []
+                            const hlights = highlight ? Object.keys(highlight).map(key => key.substring(0, key.length - 2)) : [];
                             if (index === undefined) {
                                 this._resultsSet.set(doc, this._results.length);
                                 this._results.push([doc, hlights]);
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index a8f94b746..33a615cbf 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -11,6 +11,7 @@ import { listSpec } from '../new_fields/Schema';
 import { List } from '../new_fields/List';
 import { observer } from 'mobx-react';
 import { observable } from 'mobx';
+import { Utils } from '../Utils';
 
 
 
@@ -57,7 +58,7 @@ class Uploader extends React.Component {
 
                         this.status = "getting user document";
 
-                        const res = await rp.get(DocServer.prepend(RouteStore.getUserDocumentId));
+                        const res = await rp.get(Utils.prepend(RouteStore.getUserDocumentId));
                         if (!res) {
                             throw new Error("No user id returned");
                         }
@@ -104,6 +105,8 @@ class Uploader extends React.Component {
 }
 
 
+DocServer.init(window.location.protocol, window.location.hostname, 4321, "image upload");
+
 ReactDOM.render((
     <Uploader />
 ),
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index e796ccb43..1c52a3f11 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -12,6 +12,7 @@ import { List } from "../../../new_fields/List";
 import { listSpec } from "../../../new_fields/Schema";
 import { Cast, FieldValue, StrCast } from "../../../new_fields/Types";
 import { RouteStore } from "../../RouteStore";
+import { Utils } from "../../../Utils";
 
 export class CurrentUserUtils {
     private static curr_email: string;
@@ -74,7 +75,7 @@ export class CurrentUserUtils {
     }
 
     public static loadCurrentUser() {
-        return rp.get(DocServer.prepend(RouteStore.getCurrUser)).then(response => {
+        return rp.get(Utils.prepend(RouteStore.getCurrUser)).then(response => {
             if (response) {
                 const result: { id: string, email: string } = JSON.parse(response);
                 return result;
@@ -87,7 +88,7 @@ export class CurrentUserUtils {
     public static async loadUserDocument({ id, email }: { id: string, email: string }) {
         this.curr_id = id;
         this.curr_email = email;
-        await rp.get(DocServer.prepend(RouteStore.getUserDocumentId)).then(id => {
+        await rp.get(Utils.prepend(RouteStore.getUserDocumentId)).then(id => {
             if (id) {
                 return DocServer.GetRefField(id).then(async field => {
                     if (field instanceof Doc) {
diff --git a/src/server/index.ts b/src/server/index.ts
index b3859aa4f..6b4e59bfc 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -417,7 +417,7 @@ app.get(RouteStore.reset, getReset);
 app.post(RouteStore.reset, postReset);
 
 app.use(RouteStore.corsProxy, (req, res) =>
-    req.pipe(request(req.url.substring(1))).pipe(res));
+    req.pipe(request(decodeURIComponent(req.url.substring(1)))).pipe(res));
 
 app.get(RouteStore.delete, (req, res) => {
     if (release) {
-- 
cgit v1.2.3-70-g09d2

