From de0304b2966ebdede9d9db8c510e19020046115c Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samuel_wilkins@brown.edu>
Date: Mon, 17 Jun 2019 13:38:15 -0400
Subject: peripheral renaming fixes

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 9d19df540..cd613e6ab 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -235,8 +235,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             e.preventDefault();
             let start = html.indexOf(window.location.origin);
             let path = html.substr(start, html.length - start);
-            let docid = path.substr(0, path.indexOf("\">")).replace(DocServer.prepend("/doc/"), "").split("?")[0];
-            DocServer.GetRefField(docid).then(f => {
+            let docid = path.substr(0, path.indexOf("\">")).replace(DocServer.Util.prepend("/doc/"), "").split("?")[0];
+            DocServer.getRefField(docid).then(f => {
                 if (f instanceof Doc) {
                     f.x = pt[0];
                     f.y = pt[1];
-- 
cgit v1.2.3-70-g09d2


From 1864c73573cd7129c8e6994842ad4d442d959c46 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 10 Jul 2019 18:51:44 -0400
Subject: fixed some field extension and templating things so that text
 templates can be used within templates.

---
 src/client/views/DocumentDecorations.tsx           | 13 +++++++++---
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 src/client/views/nodes/FormattedTextBox.tsx        | 24 ++++++++++------------
 src/client/views/nodes/ImageBox.tsx                |  2 +-
 5 files changed, 24 insertions(+), 19 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 059500627..07ecc6b0f 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -87,16 +87,23 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
 
                 // move data doc fields to layout doc as needed (nativeWidth/nativeHeight, data, ??)
                 let backgroundLayout = StrCast(fieldTemplate.backgroundLayout);
-                let layout = StrCast(fieldTemplate.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`);
+                let fieldLayoutDoc = fieldTemplate;
+                if (fieldTemplate.layout instanceof Doc) {
+                    fieldLayoutDoc = Doc.MakeDelegate(fieldTemplate.layout);
+                }
+                let layout = StrCast(fieldLayoutDoc.layout).replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`);
                 if (backgroundLayout) {
-                    layout = StrCast(fieldTemplate.layout).replace(/fieldKey={"annotations"}/, `fieldKey={"${metaKey}"} fieldExt={"annotations"}`);
+                    layout = StrCast(fieldLayoutDoc.layout).replace(/fieldKey={"annotations"}/, `fieldKey={"${metaKey}"} fieldExt={"annotations"}`);
                     backgroundLayout = backgroundLayout.replace(/fieldKey={"[^"]*"}/, `fieldKey={"${metaKey}"}`);
                 }
                 let nw = Cast(fieldTemplate.nativeWidth, "number");
                 let nh = Cast(fieldTemplate.nativeHeight, "number");
 
+                let layoutDelegate = fieldTemplate.layout instanceof Doc ? fieldLayoutDoc : fieldTemplate;
+                layoutDelegate.layout = layout;
+
                 fieldTemplate.title = metaKey;
-                fieldTemplate.layout = layout;
+                fieldTemplate.layout = layoutDelegate !== fieldTemplate ? layoutDelegate : layout;
                 fieldTemplate.backgroundLayout = backgroundLayout;
                 fieldTemplate.nativeWidth = nw;
                 fieldTemplate.nativeHeight = nh;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index cb55a0d5d..2c9b6b6a9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -501,7 +501,7 @@ 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.extensionDoc, this.props.fieldKey);
+        if (this.props.fieldExt) 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" }}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b8e8e7afe..0da6ed02e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -605,7 +605,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 if (str.indexOf("fieldKey={\"caption\"}") !== -1) showCaption = "caption";
             });
         }
-        let showTextTitle = showTitle && StrCast(this.props.Document.layout).startsWith("<FormattedTextBox") ? showTitle : undefined;
+        let showTextTitle = showTitle && StrCast(this.props.Document.layout).startsWith("<FormattedTextBox") || (this.props.Document.layout instanceof Doc && StrCast(this.props.Document.layout.layout).startsWith("<FormattedTextBox")) ? showTitle : undefined;
         return (
             <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
                 ref={this._mainCont}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 864d5f809..d84ad0918 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -121,23 +121,23 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         }
     }
 
-    @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; }
+    @computed get extensionDoc() { return Doc.resolvedFieldDataDoc(this.dataDoc, this.props.fieldKey, "dummy"); }
+
+    @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
 
     dispatchTransaction = (tx: Transaction) => {
         if (this._editorView) {
             const state = this._editorView.state.apply(tx);
             this._editorView.updateState(state);
             this._applyingChange = true;
-            Doc.GetProto(this.dataDoc)[this.props.fieldKey + "_text"] = state.doc.textBetween(0, state.doc.content.size, "\n\n");
-
-            Doc.GetProto(this.dataDoc)[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()));
+            if (this.extensionDoc) this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n");
+            this.dataDoc[this.props.fieldKey] = new RichTextField(JSON.stringify(state.toJSON()));
             this._applyingChange = false;
             let title = StrCast(this.dataDoc.title);
             if (title && title.startsWith("-") && this._editorView) {
                 let str = this._editorView.state.doc.textContent;
                 let titlestr = str.substr(0, Math.min(40, str.length));
-                let target = this.dataDoc.proto ? this.dataDoc.proto : this.dataDoc;
-                target.title = "-" + titlestr + (str.length > 40 ? "..." : "");
+                this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
             }
         }
     }
@@ -227,10 +227,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined;
                 return field ? field.Data : `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`;
             },
-            () => {
-                const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined;
-                const field2 = field ? field.Data : `{"doc":{"type":"doc","content":[]},"selection":{"type":"text","anchor":0,"head":0}}`;
-                if (StrCast(this.props.Document.layout).indexOf("\"" + this.props.fieldKey + "\"") !== -1)
+            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.
                     this._editorView && !this._applyingChange &&
                         this._editorView.updateState(EditorState.fromJSON(config, JSON.parse(field2)));
             }
@@ -398,8 +396,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         if (StrCast(this.dataDoc.title).startsWith("-") && this._editorView) {
             let str = this._editorView.state.doc.textContent;
             let titlestr = str.substr(0, Math.min(40, str.length));
-            let target = this.dataDoc.proto ? this.dataDoc.proto : this.dataDoc;
-            target.title = "-" + titlestr + (str.length > 40 ? "..." : "");
+            this.dataDoc.title = "-" + titlestr + (str.length > 40 ? "..." : "");
         }
         if (!this._undoTyping) {
             this._undoTyping = UndoManager.StartBatch("undoTyping");
@@ -417,7 +414,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
             let dh = NumCast(this.props.Document.height, 0);
             let sh = scrBounds.height;
             this.props.Document.height = nh ? dh / nh * sh : sh;
-            Doc.GetProto(this.dataDoc).nativeHeight = nh ? sh : undefined;
+            this.dataDoc.nativeHeight = nh ? sh : undefined;
         }
     }
 
@@ -443,6 +440,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
         let style = this.props.isOverlay ? "scroll" : "hidden";
         let rounded = StrCast(this.props.Document.borderRounding) === "100%" ? "-rounded" : "";
         let interactive = InkingControl.Instance.selectedTool ? "" : "interactive";
+        Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey);
         return (
             <div className={`formattedTextBox-cont-${style}`} ref={this._ref}
                 style={{
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 4181625c6..77e44b807 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -236,7 +236,7 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
         let paths: string[] = ["http://www.cs.brown.edu/~bcz/noImage.png"];
         // this._curSuffix = "";
         // if (w > 20) {
-        Doc.UpdateDocumentExtensionForField(this.extensionDoc, this.props.fieldKey);
+        Doc.UpdateDocumentExtensionForField(this.dataDoc, this.props.fieldKey);
         let alts = DocListCast(this.extensionDoc.Alternates);
         let altpaths: string[] = alts.filter(doc => doc.data instanceof ImageField).map(doc => this.choosePath((doc.data as ImageField).url));
         let field = this.dataDoc[this.props.fieldKey];
-- 
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/views/collections/collectionFreeForm/CollectionFreeFormView.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 7b10d90d7e20a8a5f4572387c085fafcc2fd56f3 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 11 Jul 2019 02:02:52 -0400
Subject: fixing template details.

---
 src/client/views/InkingCanvas.tsx                             |  2 +-
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx | 11 ++++++-----
 2 files changed, 7 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index fd7e5b07d..2c54054a5 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -61,7 +61,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
     }
 
     set inkData(value: Map<string, StrokeData>) {
-        Doc.GetProto(this.props.Document)[this.props.inkFieldKey] = new InkField(value);
+        this.props.Document[this.props.inkFieldKey] = new InkField(value);
     }
 
     @action
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index c931c74bc..23572a823 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.fieldExt === "annotations"; }
+    public get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } // fieldExt will be "" or "annotation". should maybe generalize this, or make it more specific (ie, 'annotation' instead of 'fieldExt')
     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,7 +86,7 @@ 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" : ""); }
+    @computed get annoExtensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc && (!this.props.Document.isTemplate || this.isAnnotationOverlay) ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.isAnnotationOverlay ? "dummy" : ""); }
 
 
     @undoBatch
@@ -171,7 +171,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
                     [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
                 }, [[minx, maxx], [miny, maxy]]);
-                let ink = Cast(this.extensionDoc.ink, InkField);
+                let ink = Cast(this.annoExtensionDoc.ink, InkField);
                 if (ink && ink.inkData) {
                     ink.inkData.forEach((value: StrokeData, key: string) => {
                         let bounds = InkingCanvas.StrokeRect(value);
@@ -344,7 +344,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
 
 
     getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps {
-        let resolvedDataDoc = this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined;
+        let self = this;
+        let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined;
         let layoutDoc = Doc.expandTemplateLayout(childDocLayout, resolvedDataDoc);
         return {
             DataDoc: resolvedDataDoc !== layoutDoc && resolvedDataDoc ? resolvedDataDoc : undefined,
@@ -512,7 +513,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     <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={"ink"} >
+                            <InkingCanvas getScreenTransform={this.getTransform} Document={this.annoExtensionDoc} inkFieldKey={"ink"} >
                                 {this.childViews}
                             </InkingCanvas>
                         </CollectionFreeFormLinksView>
-- 
cgit v1.2.3-70-g09d2


From 35f581ce1beef665265688551f50ca4cd51fd62a Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Thu, 11 Jul 2019 02:35:24 -0400
Subject: mostly working now.

---
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx     | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 23572a823..1363e1ceb 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -86,7 +86,9 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         });
     }
 
-    @computed get annoExtensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc && (!this.props.Document.isTemplate || this.isAnnotationOverlay) ? this.props.DataDoc : this.props.Document, this.props.fieldKey, this.isAnnotationOverlay ? "dummy" : ""); }
+    @computed get fieldExtensionDoc() {
+        return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true");
+    }
 
 
     @undoBatch
@@ -171,7 +173,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     return [[range[0][0] > x ? x : range[0][0], range[0][1] < xe ? xe : range[0][1]],
                     [range[1][0] > y ? y : range[1][0], range[1][1] < ye ? ye : range[1][1]]];
                 }, [[minx, maxx], [miny, maxy]]);
-                let ink = Cast(this.annoExtensionDoc.ink, InkField);
+                let ink = Cast(this.fieldExtensionDoc.ink, InkField);
                 if (ink && ink.inkData) {
                     ink.inkData.forEach((value: StrokeData, key: string) => {
                         let bounds = InkingCanvas.StrokeRect(value);
@@ -513,7 +515,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     <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.annoExtensionDoc} inkFieldKey={"ink"} >
+                            <InkingCanvas getScreenTransform={this.getTransform} Document={this.fieldExtensionDoc} inkFieldKey={"ink"} >
                                 {this.childViews}
                             </InkingCanvas>
                         </CollectionFreeFormLinksView>
-- 
cgit v1.2.3-70-g09d2


From a9ecaef0c7d870136401dfbb687afdb9dd2843f4 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 11 Jul 2019 11:00:09 -0400
Subject: fixed fitToBox stuff.

---
 .../views/collections/CollectionSchemaView.tsx     |  2 +-
 .../views/collections/CollectionTreeView.tsx       | 12 +++----
 .../collectionFreeForm/CollectionFreeFormView.scss | 41 +---------------------
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 18 +++++++---
 src/client/views/nodes/DocumentView.tsx            |  2 +-
 src/client/views/nodes/FieldView.tsx               |  2 +-
 src/client/views/search/SearchItem.tsx             |  6 +---
 src/new_fields/Doc.ts                              |  7 ++--
 8 files changed, 27 insertions(+), 63 deletions(-)

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

diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 21a2a7dd0..a55549280 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -401,8 +401,8 @@ interface CollectionSchemaPreviewProps {
     Document?: Doc;
     DataDocument?: Doc;
     childDocs?: Doc[];
-    fitToBox?: () => number[];
     renderDepth: number;
+    fitToBox?: boolean;
     width: () => number;
     height: () => number;
     showOverlays?: (doc: Doc) => { title?: string, caption?: string };
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 1280d515c..4685e774d 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -315,10 +315,10 @@ class TreeView extends React.Component<TreeViewProps> {
         return ele;
     }
 
-    @computed get docBounds() {
+    @computed get boundsOfCollectionDocument() {
         if (StrCast(this.props.document.type).indexOf(DocTypes.COL) === -1) return undefined;
         let layoutDoc = Doc.expandTemplateLayout(this.props.document, this.props.dataDoc);
-        return Doc.ComputeContentBounds(layoutDoc);
+        return Doc.ComputeContentBounds(DocListCast(layoutDoc.data));
     }
     docWidth = () => {
         let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth);
@@ -326,7 +326,7 @@ class TreeView extends React.Component<TreeViewProps> {
         return NumCast(this.props.document.nativeWidth) ? Math.min(this.props.document[WidthSym](), this.props.panelWidth() - 5) : this.props.panelWidth() - 5;
     }
     docHeight = () => {
-        let bounds = this.docBounds;
+        let bounds = this.boundsOfCollectionDocument;
         return Math.min(this.MAX_EMBED_HEIGHT, (() => {
             let aspect = NumCast(this.props.document.nativeHeight) / NumCast(this.props.document.nativeWidth);
             if (aspect) return this.docWidth() * aspect;
@@ -334,10 +334,6 @@ class TreeView extends React.Component<TreeViewProps> {
             return NumCast(this.props.document.height) ? NumCast(this.props.document.height) : 50;
         })());
     }
-    fitToBox = () => {
-        let bounds = this.docBounds!;
-        return [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Math.min(this.docHeight() / (bounds.b - bounds.y), this.docWidth() / (bounds.r - bounds.x))];
-    }
 
     render() {
         let contentElement: (JSX.Element | null) = null;
@@ -360,7 +356,7 @@ class TreeView extends React.Component<TreeViewProps> {
                         Document={layoutDoc}
                         DataDocument={this.resolvedDataDoc}
                         renderDepth={this.props.renderDepth}
-                        fitToBox={this.docBounds && !NumCast(this.props.document.nativeWidth) ? this.fitToBox : undefined}
+                        fitToBox={this.boundsOfCollectionDocument !== undefined}
                         width={this.docWidth}
                         height={this.docHeight}
                         getTransform={this.docTransform}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 51cfa77b1..ec0e446e9 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -37,6 +37,7 @@
     // background-size: 30px 30px;
     // }
     box-shadow: $intermediate-color 0.2vw 0.2vw 0.8vw;
+    opacity: 0.99;
     border: 0px solid $light-color-secondary;
     border-radius: inherit;
     box-sizing: border-box;
@@ -52,46 +53,6 @@
     height: 100%;
 }
 
-
-.collectionfreeformview-overlay {
-    .collectionfreeformview>.jsx-parser {
-        position: inherit;
-        height: 100%;
-    }
-
-    >.jsx-parser {
-        position: absolute;
-        z-index: 0;
-    }
-
-    .formattedTextBox-cont {
-        background: $light-color-secondary;
-        overflow: visible;
-    }
-
-    opacity: 0.99;
-    border: 0px solid transparent;
-    border-radius: inherit;
-    box-sizing: border-box;
-    position:absolute;
-    z-index: -1;
-
-    .marqueeView {
-        overflow: hidden;
-    }
-
-    top: 0;
-    left: 0;
-    width: 100%;
-    height: 100%;
-
-    .collectionfreeformview {
-        .formattedTextBox-cont {
-            background: yellow;
-        }
-    }
-}
-
 // selection border...?
 .border {
     border-style: solid;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 1363e1ceb..1d1db8de3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -52,13 +52,22 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     private get _pwidth() { return this.props.PanelWidth(); }
     private get _pheight() { return this.props.PanelHeight(); }
 
+    @computed get contentBounds() {
+        let bounds = this.props.fitToBox && !NumCast(this.nativeWidth) ? Doc.ComputeContentBounds(DocListCast(this.props.Document.data)) : undefined;
+        return {
+            panX: bounds ? (bounds.x + bounds.r) / 2 : this.Document.panX || 0,
+            panY: bounds ? (bounds.y + bounds.b) / 2 : this.Document.panY || 0,
+            scale: bounds ? Math.min(this.props.PanelHeight() / (bounds.b - bounds.y), this.props.PanelWidth() / (bounds.r - bounds.x)) : this.Document.scale || 1
+        };
+    }
+
     @computed get nativeWidth() { return this.Document.nativeWidth || 0; }
     @computed get nativeHeight() { return this.Document.nativeHeight || 0; }
     public get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } // fieldExt will be "" or "annotation". should maybe generalize this, or make it more specific (ie, 'annotation' instead of 'fieldExt')
     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;
-    private zoomScaling = () => this.props.fitToBox ? this.props.fitToBox()[2] : this.Document.scale || 1;
+    private panX = () => this.contentBounds.panX;
+    private panY = () => this.contentBounds.panY;
+    private zoomScaling = () => this.contentBounds.scale;
     private centeringShiftX = () => !this.nativeWidth ? this._pwidth / 2 : 0;  // shift so pan position is at center of window for non-overlay collections
     private centeringShiftY = () => !this.nativeHeight ? this._pheight / 2 : 0;// shift so pan position is at center of window for non-overlay collections
     private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
@@ -502,12 +511,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         ...this.views
     ]
     render() {
-        const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         const easing = () => this.props.Document.panTransformType === "Ease";
 
         Doc.UpdateDocumentExtensionForField(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey);
         return (
-            <div className={containerName} ref={this.createDropTarget} onWheel={this.onPointerWheel}
+            <div className={"collectionfreeformview-container"} ref={this.createDropTarget} onWheel={this.onPointerWheel}
                 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}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 613cbf98e..184f5dca2 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -73,7 +73,7 @@ export interface DocumentViewProps {
     ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
     Document: Doc;
     DataDoc?: Doc;
-    fitToBox?: () => number[];
+    fitToBox?: boolean;
     addDocument?: (doc: Doc, allowDuplicates?: boolean) => boolean;
     removeDocument?: (doc: Doc) => boolean;
     moveDocument?: (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean) => boolean;
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index abd0d9e12..0c084035a 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -31,7 +31,7 @@ export interface FieldViewProps {
     fieldKey: string;
     fieldExt: string;
     leaveNativeSize?: boolean;
-    fitToBox?: () => number[];
+    fitToBox?: boolean;
     ContainingCollectionView: Opt<CollectionView | CollectionPDFView | CollectionVideoView>;
     Document: Doc;
     DataDoc?: Doc;
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 87cae5487..c34e4febd 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -104,10 +104,6 @@ export class SearchItem extends React.Component<SearchItemProps> {
     @observable _useIcons = true;
     @observable _displayDim = 50;
 
-    fitToBox = () => {
-        let bounds = Doc.ComputeContentBounds(this.props.doc);
-        return [(bounds.x + bounds.r) / 2, (bounds.y + bounds.b) / 2, Number(SEARCH_THUMBNAIL_SIZE) / Math.max((bounds.b - bounds.y), (bounds.r - bounds.x)), this._displayDim];
-    }
     @computed
     public get DocumentIcon() {
         if (!this._useIcons) {
@@ -119,7 +115,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
                 onPointerEnter={action(() => this._displayDim = this._useIcons ? 50 : Number(SEARCH_THUMBNAIL_SIZE))}
                 onPointerLeave={action(() => this._displayDim = 50)} >
                 <DocumentView
-                    fitToBox={StrCast(this.props.doc.type).indexOf(DocTypes.COL) !== -1 ? this.fitToBox : undefined}
+                    fitToBox={StrCast(this.props.doc.type).indexOf(DocTypes.COL) !== -1}
                     Document={this.props.doc}
                     addDocument={returnFalse}
                     removeDocument={returnFalse}
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index cc0dc71dd..d28a29e40 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -264,8 +264,11 @@ export namespace Doc {
         return true;
     }
 
-    export function ComputeContentBounds(doc: Doc) {
-        let bounds = DocListCast(doc.data).reduce((bounds, doc) => {
+    //
+    // Computes the bounds of the contents of a set of documents.
+    //
+    export function ComputeContentBounds(docList: Doc[]) {
+        let bounds = docList.reduce((bounds, doc) => {
             var [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)];
             let [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()];
             return {
-- 
cgit v1.2.3-70-g09d2


From 145bc737a6f234821c941a14e0a859a5c5eac307 Mon Sep 17 00:00:00 2001
From: Sam Wilkins <samwilkins333@gmail.com>
Date: Thu, 11 Jul 2019 12:48:57 -0400
Subject: fixed image issue and added undo redo opacity changes

---
 src/client/documents/Documents.ts                                  | 5 +++--
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx      | 7 ++++---
 2 files changed, 7 insertions(+), 5 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index cda116570..62ec2f8bc 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -104,7 +104,7 @@ export namespace Docs {
                 background: HistogramBox.LayoutString()
             }],
             [DocumentType.IMG, {
-                options: { height: 300, backgroundColor: "black" },
+                options: { nativeWidth: 600, curPage: 0 },
                 primary: CollectionView.LayoutString("annotations"),
                 background: ImageBox.LayoutString()
             }],
@@ -202,7 +202,8 @@ export namespace Docs {
             let primary = template.primary;
             let background = template.background;
             let upper = Suffix.toUpperCase();
-            let options = { ...defaultOptions, ...(template.options || {}), title: prototypeId.toUpperCase().replace(upper, `_${upper}`) };
+            let title = prototypeId.toUpperCase().replace(upper, `_${upper}`);
+            let options = { title: title, type: type, ...defaultOptions, ...(template.options || {}) };
             background && (options = { ...options, backgroundLayout: background, });
             return Doc.assign(new Doc(prototypeId, true), { ...options, layout: primary, baseLayout: primary });
         }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 1867938a7..12240451b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -283,12 +283,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         const panY = this.Document.panY;
         const id = this.Document[Id];
         const state = HistoryUtil.getState();
+        state.initializers = state.initializers || {};
         // TODO This technically isn't correct if type !== "doc", as 
         // currently nothing is done, but we should probably push a new state
         if (state.type === "doc" && panX !== undefined && panY !== undefined) {
-            const init = state.initializers![id];
+            const init = state.initializers[id];
             if (!init) {
-                state.initializers![id] = {
+                state.initializers[id] = {
                     panX, panY
                 };
                 HistoryUtil.pushState(state);
@@ -302,7 +303,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         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 newState = HistoryUtil.getState();
-        newState.initializers![id] = { panX: newPanX, panY: newPanY };
+        (newState.initializers || (newState.initializers = {}))[id] = { panX: newPanX, panY: newPanY };
         HistoryUtil.pushState(newState);
         this.setPan(newPanX, newPanY);
 
-- 
cgit v1.2.3-70-g09d2


From d5acf6672b5b7cedf7b6d65293d671faf9bf4a4f Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 11 Jul 2019 15:10:39 -0400
Subject: fixed text links

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx    | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 1d1db8de3..2b6317541 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -295,6 +295,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         const panY = this.Document.panY;
         const id = this.Document[Id];
         const state = HistoryUtil.getState();
+        state.initializers = state.initializers || {};
         // TODO This technically isn't correct if type !== "doc", as 
         // currently nothing is done, but we should probably push a new state
         if (state.type === "doc" && panX !== undefined && panY !== undefined) {
@@ -314,7 +315,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         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 };
+        (newState.initializers || (newState.initializers = {}))[id] = { panX: newPanX, panY: newPanY };
         HistoryUtil.pushState(newState);
         this.setPan(newPanX, newPanY);
 
-- 
cgit v1.2.3-70-g09d2


From 6a477918f2f16bdc023c76d6a145bb6435e918a6 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 12 Jul 2019 16:06:15 -0400
Subject: fixed annotations on video timecodes.  added start of youtube
 support.

---
 src/client/views/InkingCanvas.tsx                  |  7 +-
 src/client/views/MainView.tsx                      |  5 ++
 src/client/views/collections/CollectionSubView.tsx |  4 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 src/client/views/nodes/VideoBox.tsx                | 98 +++++++++++-----------
 5 files changed, 61 insertions(+), 55 deletions(-)

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

diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 2c54054a5..37a6bbab7 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -13,6 +13,7 @@ import { Cast, PromiseValue, NumCast } from "../../new_fields/Types";
 
 interface InkCanvasProps {
     getScreenTransform: () => Transform;
+    AnnotationDocument: Doc;
     Document: Doc;
     inkFieldKey: string;
     children: () => JSX.Element[];
@@ -41,7 +42,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
     }
 
     componentDidMount() {
-        PromiseValue(Cast(this.props.Document[this.props.inkFieldKey], InkField)).then(ink => runInAction(() => {
+        PromiseValue(Cast(this.props.AnnotationDocument[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) =>
@@ -56,12 +57,12 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
 
     @computed
     get inkData(): Map<string, StrokeData> {
-        let map = Cast(this.props.Document[this.props.inkFieldKey], InkField);
+        let map = Cast(this.props.AnnotationDocument[this.props.inkFieldKey], InkField);
         return !map ? new Map : new Map(map.inkData);
     }
 
     set inkData(value: Map<string, StrokeData>) {
-        this.props.Document[this.props.inkFieldKey] = new InkField(value);
+        this.props.AnnotationDocument[this.props.inkFieldKey] = new InkField(value);
     }
 
     @action
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index ec5ec6e8b..f0e11a480 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -64,6 +64,11 @@ export class MainView extends React.Component {
     }
 
     componentWillMount() {
+        var tag = document.createElement('script');
+
+        tag.src = "https://www.youtube.com/iframe_api";
+        var firstScriptTag = document.getElementsByTagName('script')[0];
+        firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag);
         window.removeEventListener("keydown", KeyManager.Instance.handle);
         window.addEventListener("keydown", KeyManager.Instance.handle);
 
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 7ac8aee4c..b2c3fb7d0 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -179,8 +179,8 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
                 }
             }
             if (text && text.indexOf("www.youtube.com/watch") !== -1) {
-                const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");
-                this.props.addDocument(Docs.Create.WebDocument(url, { ...options, width: 300, height: 300 }));
+                const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");// + "?enablejsapi=1";
+                this.props.addDocument(Docs.Create.VideoDocument(url, { ...options, width: 400, height: 315 }));
                 return;
             }
 
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f4e5c4384..e35546fec 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -524,7 +524,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     <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.fieldExtensionDoc} inkFieldKey={"ink"} >
+                            <InkingCanvas getScreenTransform={this.getTransform} Document={this.props.Document} AnnotationDocument={this.fieldExtensionDoc} inkFieldKey={"ink"} >
                                 {this.childViews}
                             </InkingCanvas>
                         </CollectionFreeFormLinksView>
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 895d9a422..9ee4d7942 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -3,7 +3,7 @@ import { action, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
 import * as rp from "request-promise";
 import { makeInterface } from "../../../new_fields/Schema";
-import { Cast, FieldValue } from "../../../new_fields/Types";
+import { Cast, FieldValue, NumCast } from "../../../new_fields/Types";
 import { VideoField } from "../../../new_fields/URLField";
 import { RouteStore } from "../../../server/RouteStore";
 import { DocServer } from "../../DocServer";
@@ -15,6 +15,7 @@ import "./VideoBox.scss";
 import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from "../ContextMenuItem";
 import { InkingControl } from "../InkingControl";
+import * as $ from "jquery";
 
 type VideoDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const VideoDocument = makeInterface(positionSchema, pageSchema);
@@ -22,6 +23,7 @@ const VideoDocument = makeInterface(positionSchema, pageSchema);
 @observer
 export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoDocument) {
     private _reactionDisposer?: IReactionDisposer;
+    private _youtubePlayer: any = undefined;
     private _videoRef: HTMLVideoElement | null = null;
     @observable _playTimer?: NodeJS.Timeout = undefined;
     @observable _fullScreen = false;
@@ -67,12 +69,16 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
     updateTimecode = () => {
         this.player && (this.props.Document.curPage = this.player.currentTime);
     }
-
+    @action
+    updateYoutubeTimecode = () => {
+        this._youtubePlayer && (this.props.Document.curPage = this._youtubePlayer.getCurrentTime());
+    }
     componentDidMount() {
         if (this.props.setVideoBox) this.props.setVideoBox(this);
 
         let field = Cast(this.Document[this.props.fieldKey], VideoField);
-        if (field && field.url.href.indexOf("youtube") !== -1) {
+        let videoid = field && field.url.href.indexOf("youtube") !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : "";
+        if (videoid) {
             let youtubeaspect = 400 / 315;
             var nativeWidth = FieldValue(this.Document.nativeWidth, 0);
             var nativeHeight = FieldValue(this.Document.nativeHeight, 0);
@@ -81,7 +87,42 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
                 this.Document.nativeHeight = this.Document.nativeWidth / youtubeaspect;
                 this.Document.height = FieldValue(this.Document.width, 0) / youtubeaspect;
             }
+            this._youtubePlayer = new YT.Player(`${videoid}-player`, {
+                height: `${NumCast(this.props.Document.height)}`,
+                width: `${NumCast(this.props.Document.width)}`,
+                videoId: videoid.toString(),
+                playerVars: { 'controls': 0 },
+                events: {
+                    //'onReady': this.onPlayerReady,
+                }
+            });
+            // let iframe = $(document.getElementById(`${videoid}-player`)!);
+            // iframe.on("load", function () {
+            //     iframe.contents().find("head")
+            //         .append($("<style type='text/css'>  .ytp-pause-overlay, .ytp-scroll-min { opacity : 0 !important; }  </style>"));
+            // });
+            reaction(() => this.props.isSelected(), (sel) => {
+                if (sel) {
+                    this._youtubePlayer.playVideo();
+                    if (!this._playTimer) this._playTimer = setInterval(this.updateYoutubeTimecode, 1000);
+                } else {
+                    let iframe = $(document.getElementById(`${videoid}-player`)!);
+                    //  .ytp-pause-overlay, .ytp-scroll-min { opacity : 0 !important; }
+                    //     $('iframe').load( function() {
+                    //     $('iframe').contents().find("head")
+                    //       .append($("<style type='text/css'>  .my-class{display:none;}  </style>"));
+                    // });
+                    //this._youtubePlayer.cueVideoById(videoid, this._youtubePlayer.getCurrentTime());
+                    this._youtubePlayer.pauseVideo();
+                    if (this._playTimer) {
+                        clearInterval(this._playTimer);
+                        this._playTimer = undefined;
+                    }
+                }
+            });
         }
+
+
     }
     componentWillUnmount() {
         this.Pause();
@@ -100,39 +141,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
         }
     }
 
-    getMp4ForVideo(videoId: string = "JN5beCVArMs") {
-        return new Promise(async (resolve, reject) => {
-            const videoInfoRequestConfig = {
-                headers: {
-                    connection: 'keep-alive',
-                    "user-agent": 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/46.0',
-                },
-            };
-            try {
-                let responseSchema: any = {};
-                const videoInfoResponse = await rp.get(DocServer.prepend(RouteStore.corsProxy + "/" + `https://www.youtube.com/watch?v=${videoId}`), videoInfoRequestConfig);
-                const dataHtml = videoInfoResponse;
-                const start = dataHtml.indexOf('ytplayer.config = ') + 18;
-                const end = dataHtml.indexOf(';ytplayer.load');
-                const subString = dataHtml.substring(start, end);
-                const subJson = JSON.parse(subString);
-                const stringSub = subJson.args.player_response;
-                const stringSubJson = JSON.parse(stringSub);
-                const adaptiveFormats = stringSubJson.streamingData.adaptiveFormats;
-                const videoDetails = stringSubJson.videoDetails;
-                responseSchema.adaptiveFormats = adaptiveFormats;
-                responseSchema.videoDetails = videoDetails;
-                resolve(responseSchema);
-            }
-            catch (err) {
-                console.log(`
-                --- Youtube ---
-                Function: getMp4ForVideo
-                Error: `, err);
-                reject(err);
-            }
-        });
-    }
+
     onPointerDown = (e: React.PointerEvent) => {
     }
 
@@ -149,22 +158,13 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
 
     render() {
         let field = Cast(this.Document[this.props.fieldKey], VideoField);
-
-        // this.getMp4ForVideo().then((mp4) => {
-        //     console.log(mp4);
-        // }).catch(e => {
-        //     console.log("")
-        // });
-        // //
-
         let interactive = InkingControl.Instance.selectedTool || !this.props.isSelected() ? "" : "-interactive";
         let style = "videoBox-cont" + (this._fullScreen ? "-fullScreen" : interactive);
-        let videoid = field ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : "";
+        let videoid = field && field.url.href.indexOf("youtube") !== -1 ? ((arr: string[]) => arr[arr.length - 1])(field.url.href.split("/")) : "";
+
         return !field ? <div>Loading</div> :
-            field.url.href.indexOf("youtube") !== -1 ?
-                <embed className={`${style}`} onLoad={this.videoLoad} id="video" onPointerDown={this.onPointerDown} onContextMenu={this.specificContextMenu}
-                    src={`https://www.youtube.com/v/${videoid}`} type="application/x-shockwave-flash" style={{ height: "100%" }} title="Adobe Flash Player">
-                </embed> :
+            videoid ?
+                <div id={`${videoid}-player`} className={`${style}`} style={{ height: "100%" }} /> :
                 <video className={`${style}`} ref={this.setVideoRef} onCanPlay={this.videoLoad} onPointerDown={this.onPointerDown} onContextMenu={this.specificContextMenu} controls={VideoBox._showControls}>
                     <source src={field.url.href} type="video/mp4" />
                     Not supported.
-- 
cgit v1.2.3-70-g09d2


From c97119fd445d107568f74d4667eafe7e67bb8706 Mon Sep 17 00:00:00 2001
From: _stanleyyip <33562077+yipstanley@users.noreply.github.com>
Date: Sun, 14 Jul 2019 13:07:52 -0400
Subject: added undo for arrange contents in a grid

---
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 36 ++++++++++++----------
 1 file changed, 19 insertions(+), 17 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index e35546fec..b75cf7d5e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -11,7 +11,7 @@ import { DragManager } from "../../../util/DragManager";
 import { HistoryUtil } from "../../../util/History";
 import { SelectionManager } from "../../../util/SelectionManager";
 import { Transform } from "../../../util/Transform";
-import { undoBatch } from "../../../util/UndoManager";
+import { undoBatch, UndoManager } from "../../../util/UndoManager";
 import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss";
 import { ContextMenu } from "../../ContextMenu";
 import { InkingCanvas } from "../../InkingCanvas";
@@ -455,24 +455,26 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             description: "Arrange contents in grid",
             event: async () => {
                 const docs = await DocListCastAsync(this.Document[this.props.fieldKey]);
-                if (docs) {
-                    let startX = this.Document.panX || 0;
-                    let x = startX;
-                    let y = this.Document.panY || 0;
-                    let i = 0;
-                    const width = Math.max(...docs.map(doc => NumCast(doc.width)));
-                    const height = Math.max(...docs.map(doc => NumCast(doc.height)));
-                    for (const doc of docs) {
-                        doc.x = x;
-                        doc.y = y;
-                        x += width + 20;
-                        if (++i === 6) {
-                            i = 0;
-                            x = startX;
-                            y += height + 20;
+                UndoManager.RunInBatch(() => {
+                    if (docs) {
+                        let startX = this.Document.panX || 0;
+                        let x = startX;
+                        let y = this.Document.panY || 0;
+                        let i = 0;
+                        const width = Math.max(...docs.map(doc => NumCast(doc.width)));
+                        const height = Math.max(...docs.map(doc => NumCast(doc.height)));
+                        for (const doc of docs) {
+                            doc.x = x;
+                            doc.y = y;
+                            x += width + 20;
+                            if (++i === 6) {
+                                i = 0;
+                                x = startX;
+                                y += height + 20;
+                            }
                         }
                     }
-                }
+                }, "arrange contents");
             }
         });
         ContextMenu.Instance.addItem({
-- 
cgit v1.2.3-70-g09d2


From 68c135f23c54cc44a84fb17223bc49e3b7bff1a8 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Sun, 14 Jul 2019 19:20:03 -0400
Subject: Fixed a couple issues

---
 src/client/views/MetadataEntryMenu.scss                                | 2 ++
 src/client/views/MetadataEntryMenu.tsx                                 | 1 +
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx    | 3 ++-
 3 files changed, 5 insertions(+), 1 deletion(-)

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

diff --git a/src/client/views/MetadataEntryMenu.scss b/src/client/views/MetadataEntryMenu.scss
index a6df3cd1e..bcfc9a82d 100644
--- a/src/client/views/MetadataEntryMenu.scss
+++ b/src/client/views/MetadataEntryMenu.scss
@@ -37,6 +37,8 @@
 .react-autosuggest__suggestions-container--open {
     display: block;
     position: fixed;
+    overflow-y: auto;
+    max-height: 400px;
     width: 180px;
     border: 1px solid #aaa;
     background-color: #fff;
diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx
index 5ee661944..bd5a307b3 100644
--- a/src/client/views/MetadataEntryMenu.tsx
+++ b/src/client/views/MetadataEntryMenu.tsx
@@ -158,6 +158,7 @@ export class MetadataEntryMenu extends React.Component<MetadataEntryProps>{
                 <Autosuggest inputProps={{ value: this._currentKey, onChange: this.onKeyChange }}
                     getSuggestionValue={this.getSuggestionValue}
                     suggestions={this.suggestions}
+                    alwaysRenderSuggestions
                     renderSuggestion={this.renderSuggestion}
                     onSuggestionsFetchRequested={this.onSuggestionFetch}
                     onSuggestionsClearRequested={this.onSuggestionClear}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index b75cf7d5e..19e280444 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -485,7 +485,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     const script = this.Document[key];
                     let originalText: string | undefined = undefined;
                     if (script) originalText = script.script.originalScript;
-                    let scriptingBox = <ScriptBox initialText={originalText} onCancel={overlayDisposer} onSave={(text, onError) => {
+                    // tslint:disable-next-line: no-unnecessary-callback-wrapper
+                    let scriptingBox = <ScriptBox initialText={originalText} onCancel={() => overlayDisposer()} onSave={(text, onError) => {
                         const script = CompileScript(text, {
                             params,
                             requiredType,
-- 
cgit v1.2.3-70-g09d2


From bd18843342c186dd0e829250ba70bb8a2a8736b4 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Tue, 16 Jul 2019 20:20:31 -0400
Subject: Made video annotations stay for longer

---
 src/client/views/InkingCanvas.tsx                                       | 2 +-
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx
index 37a6bbab7..3e0d7b476 100644
--- a/src/client/views/InkingCanvas.tsx
+++ b/src/client/views/InkingCanvas.tsx
@@ -152,7 +152,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> {
     get drawnPaths() {
         let curPage = NumCast(this.props.Document.curPage, -1);
         let paths = Array.from(this.inkData).reduce((paths, [id, strokeData]) => {
-            if (strokeData.page === -1 || Math.round(strokeData.page) === Math.round(curPage)) {
+            if (strokeData.page === -1 || (Math.abs(Math.round(strokeData.page) - Math.round(curPage)) < 3)) {
                 paths.push(<InkingStroke key={id} id={id}
                     line={strokeData.pathData}
                     count={strokeData.pathData.length}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 19e280444..06055a04d 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -429,7 +429,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         let docviews = docs.reduce((prev, doc) => {
             if (!(doc instanceof Doc)) return prev;
             var page = NumCast(doc.page, -1);
-            if (Math.round(page) === Math.round(curPage) || page === -1) {
+            if ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1) {
                 let minim = BoolCast(doc.isMinimized, false);
                 if (minim === undefined || !minim) {
                     const pos = script ? this.getCalculatedPositions(script, { doc, index: prev.length, collection: this.Document, docs, state }) : {};
-- 
cgit v1.2.3-70-g09d2


From ee385cd02a6ce99d59eb02a768bb587b566328e9 Mon Sep 17 00:00:00 2001
From: kimdahey <claire_kim1@brown.edu>
Date: Wed, 17 Jul 2019 10:55:31 -0400
Subject: jumping to a region from a link now shows the whole region supposedly

---
 src/client/views/collections/CollectionPDFView.tsx                    | 4 ++--
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx   | 2 +-
 src/client/views/pdf/Annotation.tsx                                   | 2 +-
 src/client/views/pdf/PDFViewer.tsx                                    | 4 +++-
 4 files changed, 7 insertions(+), 5 deletions(-)

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

diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 8ab360984..781692eef 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -1,6 +1,6 @@
 import { action, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
-import { WidthSym } from "../../../new_fields/Doc";
+import { WidthSym, HeightSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { NumCast } from "../../../new_fields/Types";
 import { emptyFunction } from "../../../Utils";
@@ -34,7 +34,7 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
                 // console.log(this._buttonTray.current.offsetHeight);
                 // console.log(NumCast(this.props.Document.scrollY));
                 let scale = this.nativeWidth() / this.props.Document[WidthSym]();
-                this.props.Document.panY = NumCast(this.props.Document.scrollY);
+                this.props.Document.panY = NumCast(this.props.Document.scrollY) - this.props.Document[HeightSym]();
                 // console.log(scale);
                 // }
                 // console.log(this.props.Document[HeightSym]());
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 06055a04d..4532239d6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -267,7 +267,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         // this.props.Document.panX = panX;
         // this.props.Document.panY = panY;
         if (this.props.Document.scrollY) {
-            this.props.Document.scrollY = panY;
+            this.props.Document.scrollY = panY - this.props.Document[HeightSym]();
         }
     }
 
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 104241237..ed7081b1d 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -75,7 +75,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
             () => this.props.parent.Index,
             () => {
                 if (this.props.parent.Index === this.props.index) {
-                    this.props.parent.scrollTo(this.props.y * scale - (NumCast(this.props.parent.props.parent.Document.pdfHeight) / 2));
+                    this.props.parent.scrollTo(this.props.y * scale);
                 }
             }
         );
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index c560e581c..1e10cb022 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -192,7 +192,9 @@ export class Viewer extends React.Component<IViewerProps> {
     }
 
     scrollTo(y: number) {
-        this.props.parent.scrollTo(y);
+        if (this.props.mainCont.current) {
+            this.props.parent.scrollTo(y - this.props.mainCont.current.clientHeight);
+        }
     }
 
     @action
-- 
cgit v1.2.3-70-g09d2


From 9a4b4e9367d9d1fd245450db62124f0e530e4175 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Wed, 17 Jul 2019 11:23:19 -0400
Subject: fixed following links to regons seriously

---
 src/client/views/collections/CollectionPDFView.tsx             | 10 +---------
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 src/client/views/nodes/LinkMenuItem.tsx                        |  2 +-
 3 files changed, 3 insertions(+), 11 deletions(-)

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

diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 781692eef..9074854d6 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -29,15 +29,7 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
         this._reactionDisposer = reaction(
             () => NumCast(this.props.Document.scrollY),
             () => {
-                // let transform = this.props.ScreenToLocalTransform();
-                // if (this._buttonTray.current) {
-                // console.log(this._buttonTray.current.offsetHeight);
-                // console.log(NumCast(this.props.Document.scrollY));
-                let scale = this.nativeWidth() / this.props.Document[WidthSym]();
-                this.props.Document.panY = NumCast(this.props.Document.scrollY) - this.props.Document[HeightSym]();
-                // console.log(scale);
-                // }
-                // console.log(this.props.Document[HeightSym]());
+                this.props.Document.panY = NumCast(this.props.Document.scrollY);
             },
             { fireImmediately: true }
         );
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4532239d6..b91aaedee 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -267,7 +267,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         // this.props.Document.panX = panX;
         // this.props.Document.panY = panY;
         if (this.props.Document.scrollY) {
-            this.props.Document.scrollY = panY - this.props.Document[HeightSym]();
+            this.props.Document.scrollY = panY - scale * this.props.Document[HeightSym]();
         }
     }
 
diff --git a/src/client/views/nodes/LinkMenuItem.tsx b/src/client/views/nodes/LinkMenuItem.tsx
index 42007018c..a0c37a719 100644
--- a/src/client/views/nodes/LinkMenuItem.tsx
+++ b/src/client/views/nodes/LinkMenuItem.tsx
@@ -52,7 +52,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
                 DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, document => CollectionDockingView.Instance.AddRightSplit(targetContext!, undefined));
             }
             else if (this.props.destinationDoc === self.props.linkDoc.anchor1 && sourceContext) {
-                DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, document => CllectionDockingView.Instance.AddRightSplit(sourceContext!, undefined));
+                DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, document => CollectionDockingView.Instance.AddRightSplit(sourceContext!, undefined));
             }
         }
     }
-- 
cgit v1.2.3-70-g09d2


From 33ba82d031266e87b6915de9f84bef2d914c2ae5 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 17 Jul 2019 16:21:21 -0400
Subject: patch for pdf's panning to wrong location.

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index b91aaedee..58218e641 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -4,7 +4,7 @@ import { Doc, DocListCastAsync, HeightSym, WidthSym, DocListCast } from "../../.
 import { Id } from "../../../../new_fields/FieldSymbols";
 import { InkField, StrokeData } from "../../../../new_fields/InkField";
 import { createSchema, makeInterface } from "../../../../new_fields/Schema";
-import { BoolCast, Cast, FieldValue, NumCast } from "../../../../new_fields/Types";
+import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types";
 import { emptyFunction, returnOne } from "../../../../Utils";
 import { DocumentManager } from "../../../util/DocumentManager";
 import { DragManager } from "../../../util/DragManager";
@@ -263,7 +263,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX));
         const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY));
         this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX;
-        this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY;
+        this.props.Document.panY = this.isAnnotationOverlay && StrCast(this.props.Document.backgroundLayout).indexOf("PDFBox") === -1 ? newPanY : panY;
         // this.props.Document.panX = panX;
         // this.props.Document.panY = panY;
         if (this.props.Document.scrollY) {
-- 
cgit v1.2.3-70-g09d2


From fe188e93f2f8d61356bfdc3216273f72ae074e10 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tschicke@gmail.com>
Date: Mon, 22 Jul 2019 00:10:01 -0400
Subject: Added a bunch of REPL functionality

---
 src/client/util/Scripting.ts                       |  69 ++++++-
 src/client/views/OverlayView.scss                  |  25 ++-
 src/client/views/OverlayView.tsx                   |  52 ++++-
 src/client/views/ScriptingRepl.scss                |  39 ++++
 src/client/views/ScriptingRepl.tsx                 | 228 +++++++++++++++++++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   2 +-
 src/client/views/nodes/DocumentView.tsx            |   2 +-
 7 files changed, 387 insertions(+), 30 deletions(-)

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

diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts
index 62c2cfe85..46dc320b0 100644
--- a/src/client/util/Scripting.ts
+++ b/src/client/util/Scripting.ts
@@ -1,5 +1,7 @@
-// import * as ts from "typescript"
-let ts = (window as any).ts;
+import * as ts from "typescript";
+export { ts };
+// export const ts = (window as any).ts;
+
 // // @ts-ignore
 // import * as typescriptlib from '!!raw-loader!../../../node_modules/typescript/lib/lib.d.ts'
 // // @ts-ignore
@@ -55,13 +57,35 @@ export namespace Scripting {
         }
         scriptingGlobals[n] = obj;
     }
+
+    export function makeMutableGlobalsCopy(globals?: { [name: string]: any }) {
+        return { ..._scriptingGlobals, ...(globals || {}) };
+    }
+
+    export function setScriptingGlobals(globals: { [key: string]: any }) {
+        scriptingGlobals = globals;
+    }
+
+    export function resetScriptingGlobals() {
+        scriptingGlobals = _scriptingGlobals;
+    }
+
+    // const types = Object.keys(ts.SyntaxKind).map(kind => ts.SyntaxKind[kind]);
+    export function printNodeType(node: any, indentation = "") {
+        console.log(indentation + ts.SyntaxKind[node.kind]);
+    }
+
+    export function getGlobals() {
+        return Object.keys(scriptingGlobals);
+    }
 }
 
 export function scriptingGlobal(constructor: { new(...args: any[]): any }) {
     Scripting.addGlobal(constructor);
 }
 
-const scriptingGlobals: { [name: string]: any } = {};
+const _scriptingGlobals: { [name: string]: any } = {};
+let scriptingGlobals: { [name: string]: any } = _scriptingGlobals;
 
 function Run(script: string | undefined, customParams: string[], diagnostics: any[], originalScript: string, options: ScriptOptions): CompileResult {
     const errors = diagnostics.some(diag => diag.category === ts.DiagnosticCategory.Error);
@@ -162,6 +186,8 @@ class ScriptingCompilerHost {
     }
 }
 
+export type Traverser = (node: ts.Node, indentation: string) => boolean | void;
+export type TraverserParam = Traverser | { onEnter: Traverser, onLeave: Traverser };
 export interface ScriptOptions {
     requiredType?: string;
     addReturn?: boolean;
@@ -169,10 +195,23 @@ export interface ScriptOptions {
     capturedVariables?: { [name: string]: Field };
     typecheck?: boolean;
     editable?: boolean;
+    traverser?: TraverserParam;
+    transformer?: ts.TransformerFactory<ts.SourceFile>;
+    globals?: { [name: string]: any };
+}
+
+// function forEachNode(node:ts.Node, fn:(node:any) => void);
+function forEachNode(node: ts.Node, onEnter: Traverser, onExit?: Traverser, indentation = "") {
+    return onEnter(node, indentation) || ts.forEachChild(node, (n: any) => {
+        forEachNode(n, onEnter, onExit, indentation + "    ");
+    }) || (onExit && onExit(node, indentation));
 }
 
 export function CompileScript(script: string, options: ScriptOptions = {}): CompileResult {
     const { requiredType = "", addReturn = false, params = {}, capturedVariables = {}, typecheck = true } = options;
+    if (options.globals) {
+        Scripting.setScriptingGlobals(options.globals);
+    }
     let host = new ScriptingCompilerHost;
     let paramNames: string[] = [];
     if ("this" in params || "this" in capturedVariables) {
@@ -192,10 +231,27 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
         paramList.push(`${key}: ${capturedVariables[key].constructor.name}`);
     }
     let paramString = paramList.join(", ");
+    if (options.traverser) {
+        const sourceFile = ts.createSourceFile('script.ts', script, ts.ScriptTarget.ES2015, true);
+        const onEnter = typeof options.traverser === "object" ? options.traverser.onEnter : options.traverser;
+        const onLeave = typeof options.traverser === "object" ? options.traverser.onLeave : undefined;
+        forEachNode(sourceFile, onEnter, onLeave);
+    }
+    if (options.transformer) {
+        const sourceFile = ts.createSourceFile('script.ts', script, ts.ScriptTarget.ES2015, true);
+        const result = ts.transform(sourceFile, [options.transformer]);
+        const transformed = result.transformed;
+        const printer = ts.createPrinter({
+            newLine: ts.NewLineKind.LineFeed
+        });
+        script = printer.printFile(transformed[0]);
+        result.dispose();
+    }
     let funcScript = `(function(${paramString})${requiredType ? `: ${requiredType}` : ''} {
         ${addReturn ? `return ${script};` : script}
     })`;
     host.writeFile("file.ts", funcScript);
+
     if (typecheck) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib);
     let program = ts.createProgram(["file.ts"], {}, host);
     let testResult = program.emit();
@@ -203,7 +259,12 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp
 
     let diagnostics = ts.getPreEmitDiagnostics(program).concat(testResult.diagnostics);
 
-    return Run(outputText, paramNames, diagnostics, script, options);
+    const result = Run(outputText, paramNames, diagnostics, script, options);
+
+    if (options.globals) {
+        Scripting.resetScriptingGlobals();
+    }
+    return result;
 }
 
 Scripting.addGlobal(CompileScript);
\ No newline at end of file
diff --git a/src/client/views/OverlayView.scss b/src/client/views/OverlayView.scss
index 9d0abc96d..4d1e8cf0b 100644
--- a/src/client/views/OverlayView.scss
+++ b/src/client/views/OverlayView.scss
@@ -1,21 +1,42 @@
 .overlayWindow-outerDiv {
-    position: absolute;
     border-radius: 5px;
     overflow: hidden;
     display: flex;
     flex-direction: column;
 }
 
+.overlayWindow-outerDiv,
+.overlayView-wrapperDiv {
+    position: absolute;
+    z-index: 1;
+}
+
 .overlayWindow-titleBar {
-    height: 30px;
+    flex: 0 1 30px;
     background: darkslategray;
     color: whitesmoke;
     text-align: center;
     cursor: move;
 }
 
+.overlayWindow-content {
+    flex: 1 1 auto;
+    display: flex;
+    flex-direction: column;
+}
+
 .overlayWindow-closeButton {
     float: right;
     height: 30px;
     width: 30px;
+}
+
+.overlayWindow-resizeDragger {
+    background-color: red;
+    position: absolute;
+    right: 0px;
+    bottom: 0px;
+    width: 10px;
+    height: 10px;
+    cursor: nwse-resize;
 }
\ No newline at end of file
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 6b72abebf..2f2579057 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -25,16 +25,16 @@ export interface OverlayWindowProps {
 export class OverlayWindow extends React.Component<OverlayWindowProps> {
     @observable x: number;
     @observable y: number;
-    @observable width?: number;
-    @observable height?: number;
+    @observable width: number;
+    @observable height: number;
     constructor(props: OverlayWindowProps) {
         super(props);
 
         const opts = props.overlayOptions;
         this.x = opts.x;
         this.y = opts.y;
-        this.width = opts.width;
-        this.height = opts.height;
+        this.width = opts.width || 200;
+        this.height = opts.height || 200;
     }
 
     onPointerDown = (_: React.PointerEvent) => {
@@ -44,10 +44,27 @@ export class OverlayWindow extends React.Component<OverlayWindowProps> {
         document.addEventListener("pointerup", this.onPointerUp);
     }
 
+    onResizerPointerDown = (_: React.PointerEvent) => {
+        document.removeEventListener("pointermove", this.onResizerPointerMove);
+        document.removeEventListener("pointerup", this.onResizerPointerUp);
+        document.addEventListener("pointermove", this.onResizerPointerMove);
+        document.addEventListener("pointerup", this.onResizerPointerUp);
+    }
+
     @action
     onPointerMove = (e: PointerEvent) => {
         this.x += e.movementX;
+        this.x = Math.max(Math.min(this.x, window.innerWidth - this.width), 0);
         this.y += e.movementY;
+        this.y = Math.max(Math.min(this.y, window.innerHeight - this.height), 0);
+    }
+
+    @action
+    onResizerPointerMove = (e: PointerEvent) => {
+        this.width += e.movementX;
+        this.width = Math.max(this.width, 30);
+        this.height += e.movementY;
+        this.height = Math.max(this.height, 30);
     }
 
     onPointerUp = (e: PointerEvent) => {
@@ -55,6 +72,11 @@ export class OverlayWindow extends React.Component<OverlayWindowProps> {
         document.removeEventListener("pointerup", this.onPointerUp);
     }
 
+    onResizerPointerUp = (e: PointerEvent) => {
+        document.removeEventListener("pointermove", this.onResizerPointerMove);
+        document.removeEventListener("pointerup", this.onResizerPointerUp);
+    }
+
     render() {
         return (
             <div className="overlayWindow-outerDiv" style={{ transform: `translate(${this.x}px, ${this.y}px)`, width: this.width, height: this.height }}>
@@ -62,7 +84,10 @@ export class OverlayWindow extends React.Component<OverlayWindowProps> {
                     {this.props.overlayOptions.title || "Untitled"}
                     <button onClick={this.props.onClick} className="overlayWindow-closeButton">X</button>
                 </div>
-                {this.props.children}
+                <div className="overlayWindow-content">
+                    {this.props.children}
+                </div>
+                <div className="overlayWindow-resizeDragger" onPointerDown={this.onResizerPointerDown}></div>
             </div>
         );
     }
@@ -87,11 +112,26 @@ export class OverlayView extends React.Component {
             const index = this._elements.indexOf(ele);
             if (index !== -1) this._elements.splice(index, 1);
         });
-        ele = <OverlayWindow onClick={remove} key={Utils.GenerateGuid()} overlayOptions={options}>{ele}</OverlayWindow>;
+        ele = <div key={Utils.GenerateGuid()} className="overlayView-wrapperDiv" style={{
+            transform: `translate(${options.x}px, ${options.y}px)`,
+            width: options.width,
+            height: options.height
+        }}>{ele}</div>;
         this._elements.push(ele);
         return remove;
     }
 
+    @action
+    addWindow(contents: JSX.Element, options: OverlayElementOptions): OverlayDisposer {
+        const remove = action(() => {
+            const index = this._elements.indexOf(contents);
+            if (index !== -1) this._elements.splice(index, 1);
+        });
+        contents = <OverlayWindow onClick={remove} key={Utils.GenerateGuid()} overlayOptions={options}>{contents}</OverlayWindow>;
+        this._elements.push(contents);
+        return remove;
+    }
+
     render() {
         return (
             <div>
diff --git a/src/client/views/ScriptingRepl.scss b/src/client/views/ScriptingRepl.scss
index 1eedb52fa..f1ef64193 100644
--- a/src/client/views/ScriptingRepl.scss
+++ b/src/client/views/ScriptingRepl.scss
@@ -1,5 +1,8 @@
 .scriptingRepl-outerContainer {
     background-color: whitesmoke;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
 }
 
 .scriptingRepl-resultContainer {
@@ -8,4 +11,40 @@
 
 .scriptingRepl-commandInput {
     width: 100%;
+}
+
+.scriptingRepl-commandResult,
+.scriptingRepl-commandString {
+    overflow-wrap: break-word;
+}
+
+.scriptingRepl-commandsContainer {
+    flex: 1 1 auto;
+    overflow-y: scroll;
+}
+
+.documentIcon-outerDiv {
+    background-color: white;
+    border-width: 1px;
+    border-style: solid;
+    border-radius: 25%;
+    padding: 2px;
+}
+
+.scriptingObject-icon {
+    padding: 3px;
+    cursor: pointer;
+}
+
+.scriptingObject-iconCollapsed {
+    padding-left: 4px;
+    padding-right: 5px;
+}
+
+.scriptingObject-fields {
+    padding-left: 10px;
+}
+
+.scriptingObject-leaf {
+    margin-left: 15px;
 }
\ No newline at end of file
diff --git a/src/client/views/ScriptingRepl.tsx b/src/client/views/ScriptingRepl.tsx
index bd6fc9dfb..6eabc7b70 100644
--- a/src/client/views/ScriptingRepl.tsx
+++ b/src/client/views/ScriptingRepl.tsx
@@ -2,32 +2,193 @@ import * as React from 'react';
 import { observer } from 'mobx-react';
 import { observable, action } from 'mobx';
 import './ScriptingRepl.scss';
-import { Scripting, CompileScript } from '../util/Scripting';
+import { Scripting, CompileScript, ts } from '../util/Scripting';
+import { DocumentManager } from '../util/DocumentManager';
+import { DocumentView } from './nodes/DocumentView';
+import { OverlayView } from './OverlayView';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { library } from '@fortawesome/fontawesome-svg-core';
+import { faCaretDown, faCaretRight } from '@fortawesome/free-solid-svg-icons';
+
+library.add(faCaretDown);
+library.add(faCaretRight);
+
+@observer
+export class DocumentIcon extends React.Component<{ view: DocumentView, index: number }> {
+    render() {
+        this.props.view.props.ScreenToLocalTransform();
+        this.props.view.props.Document.width;
+        this.props.view.props.Document.height;
+        const screenCoords = this.props.view.screenRect();
+
+        return (
+            <div className="documentIcon-outerDiv" style={{
+                position: "absolute",
+                transform: `translate(${screenCoords.left + screenCoords.width / 2}px, ${screenCoords.top}px)`,
+            }}>
+                <p >${this.props.index}</p>
+            </div>
+        );
+    }
+}
+
+@observer
+export class DocumentIconContainer extends React.Component {
+    render() {
+        return DocumentManager.Instance.DocumentViews.map((dv, i) => <DocumentIcon key={i} index={i} view={dv} />);
+    }
+}
+
+@observer
+export class ScriptingObjectDisplay extends React.Component<{ scrollToBottom: () => void, value: { [key: string]: any }, name?: string }> {
+    @observable collapsed = true;
+
+    @action
+    toggle = () => {
+        this.collapsed = !this.collapsed;
+        this.props.scrollToBottom();
+    }
+
+    render() {
+        const val = this.props.value;
+        const proto = Object.getPrototypeOf(val);
+        const name = (proto && proto.constructor && proto.constructor.name) || String(val);
+        const title = this.props.name ? <><b>{this.props.name} : </b>{name}</> : name;
+        if (this.collapsed) {
+            return (
+                <div className="scriptingObject-collapsed">
+                    <span onClick={this.toggle} className="scriptingObject-icon scriptingObject-iconCollapsed"><FontAwesomeIcon icon="caret-right" size="sm" /></span>{title} (+{Object.keys(val).length})
+                </div>
+            );
+        } else {
+            return (
+                <div className="scriptingObject-open">
+                    <div>
+                        <span onClick={this.toggle} className="scriptingObject-icon"><FontAwesomeIcon icon="caret-down" size="sm" /></span>{title}
+                    </div>
+                    <div className="scriptingObject-fields">
+                        {Object.keys(val).map(key => <ScriptingValueDisplay {...this.props} name={key} />)}
+                    </div>
+                </div>
+            );
+        }
+    }
+}
+
+@observer
+export class ScriptingValueDisplay extends React.Component<{ scrollToBottom: () => void, value: any, name?: string }> {
+    render() {
+        const val = this.props.name ? this.props.value[this.props.name] : this.props.value;
+        if (typeof val === "object") {
+            return <ScriptingObjectDisplay scrollToBottom={this.props.scrollToBottom} value={val} name={this.props.name} />;
+        } else if (typeof val === "function") {
+            const name = "[Function]";
+            const title = this.props.name ? <><b>{this.props.name} : </b>{name}</> : name;
+            return <div className="scriptingObject-leaf">{title}</div>;
+        } else {
+            const name = String(val);
+            const title = this.props.name ? <><b>{this.props.name} : </b>{name}</> : name;
+            return <div className="scriptingObject-leaf">{title}</div>;
+        }
+    }
+}
 
 @observer
 export class ScriptingRepl extends React.Component {
     @observable private commands: { command: string, result: any }[] = [];
 
     @observable private commandString: string = "";
+    private commandBuffer: string = "";
+
+    @observable private historyIndex: number = -1;
+
+    private commandsRef = React.createRef<HTMLDivElement>();
 
     private args: any = {};
 
+    getTransformer: ts.TransformerFactory<ts.SourceFile> = context => {
+        const knownVars: { [name: string]: number } = {};
+        const usedDocuments: number[] = [];
+        Scripting.getGlobals().forEach(global => knownVars[global] = 1);
+        return root => {
+            function visit(node: ts.Node) {
+                node = ts.visitEachChild(node, visit, context);
+
+                if (ts.isIdentifier(node)) {
+                    const isntPropAccess = !ts.isPropertyAccessExpression(node.parent) || node.parent.expression === node;
+                    const isntPropAssign = !ts.isPropertyAssignment(node.parent) || node.parent.name !== node;
+                    if (isntPropAccess && isntPropAssign && !(node.text in knownVars) && !(node.text in globalThis)) {
+                        const match = node.text.match(/\$([0-9]+)/);
+                        if (match) {
+                            const m = parseInt(match[1]);
+                            usedDocuments.push(m);
+                        } else {
+                            return ts.createPropertyAccess(ts.createIdentifier("args"), node);
+                        }
+                    }
+                }
+
+                return node;
+            }
+            return ts.visitNode(root, visit);
+        };
+    }
+
     @action
     onKeyDown = (e: React.KeyboardEvent) => {
-        if (e.key === "Enter") {
-            e.stopPropagation();
+        let stopProp = true;
+        switch (e.key) {
+            case "Enter": {
+                const docGlobals: { [name: string]: any } = {};
+                DocumentManager.Instance.DocumentViews.forEach((dv, i) => docGlobals[`$${i}`] = dv.props.Document);
+                const globals = Scripting.makeMutableGlobalsCopy(docGlobals);
+                const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: "any" }, transformer: this.getTransformer, globals });
+                if (!script.compiled) {
+                    return;
+                }
+                const result = script.run({ args: this.args });
+                if (!result.success) {
+                    return;
+                }
+                this.commands.push({ command: this.commandString, result: result.result });
+
+                this.maybeScrollToBottom();
 
-            const script = CompileScript(this.commandString, { typecheck: false, addReturn: true, editable: true, params: { args: "any" } });
-            if (!script.compiled) {
-                return;
+                this.commandString = "";
+                this.commandBuffer = "";
+                this.historyIndex = -1;
+                break;
             }
-            const result = script.run({ args: this.args });
-            if (!result.success) {
-                return;
+            case "ArrowUp": {
+                if (this.historyIndex < this.commands.length - 1) {
+                    this.historyIndex++;
+                    if (this.historyIndex === 0) {
+                        this.commandBuffer = this.commandString;
+                    }
+                    this.commandString = this.commands[this.commands.length - 1 - this.historyIndex].command;
+                }
+                break;
             }
-            this.commands.push({ command: this.commandString, result: result.result });
+            case "ArrowDown": {
+                if (this.historyIndex >= 0) {
+                    this.historyIndex--;
+                    if (this.historyIndex === -1) {
+                        this.commandString = this.commandBuffer;
+                        this.commandBuffer = "";
+                    } else {
+                        this.commandString = this.commands[this.commands.length - 1 - this.historyIndex].command;
+                    }
+                }
+                break;
+            }
+            default:
+                stopProp = false;
+                break;
+        }
 
-            this.commandString = "";
+        if (stopProp) {
+            e.stopPropagation();
+            e.preventDefault();
         }
     }
 
@@ -36,21 +197,56 @@ export class ScriptingRepl extends React.Component {
         this.commandString = e.target.value;
     }
 
+    private shouldScroll: boolean = false;
+    private maybeScrollToBottom = () => {
+        const ele = this.commandsRef.current;
+        if (ele && ele.scrollTop === (ele.scrollHeight - ele.offsetHeight)) {
+            this.shouldScroll = true;
+            this.forceUpdate();
+        }
+    }
+
+    private scrollToBottom() {
+        const ele = this.commandsRef.current;
+        ele && ele.scroll({ behavior: "auto", top: ele.scrollHeight });
+    }
+
+    componentDidUpdate() {
+        if (this.shouldScroll) {
+            this.shouldScroll = false;
+            this.scrollToBottom();
+        }
+    }
+
+    overlayDisposer?: () => void;
+    onFocus = () => {
+        if (this.overlayDisposer) {
+            this.overlayDisposer();
+        }
+        this.overlayDisposer = OverlayView.Instance.addElement(<DocumentIconContainer />, { x: 0, y: 0 });
+    }
+
+    onBlur = () => {
+        this.overlayDisposer && this.overlayDisposer();
+    }
+
     render() {
         return (
             <div className="scriptingRepl-outerContainer">
-                <div className="scriptingRepl-commandsContainer">
-                    {this.commands.map(({ command, result }) => {
+                <div className="scriptingRepl-commandsContainer" ref={this.commandsRef}>
+                    {this.commands.map(({ command, result }, i) => {
                         return (
-                            <div className="scriptingRepl-resultContainer">
-                                <div className="scriptingRepl-commandString">{command}</div>
-                                <div className="scriptingRepl-commandResult">{String(result)}</div>
+                            <div className="scriptingRepl-resultContainer" key={i}>
+                                <div className="scriptingRepl-commandString">{command || <br />}</div>
+                                <div className="scriptingRepl-commandResult">{<ScriptingValueDisplay scrollToBottom={this.maybeScrollToBottom} value={result} />}</div>
                             </div>
                         );
                     })}
                 </div>
                 <input
                     className="scriptingRepl-commandInput"
+                    onFocus={this.onFocus}
+                    onBlur={this.onBlur}
                     value={this.commandString}
                     onChange={this.onChange}
                     onKeyDown={this.onKeyDown}></input>
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 58218e641..652aca8f3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -502,7 +502,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                         overlayDisposer();
                         setTimeout(() => docs.map(d => d.transition = undefined), 1200);
                     }} />;
-                    overlayDisposer = OverlayView.Instance.addElement(scriptingBox, options);
+                    overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, options);
                 };
                 addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300 }, { collection: "Doc", docs: "Doc[]" }, undefined);
                 addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300 }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}");
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 52ba643e0..7ff095573 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -557,7 +557,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc?
             }, icon: "search"
         });
-        cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addElement(<ScriptingRepl />, { x: 100, y: 100 }) });
+        cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200 }) });
         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(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" });
-- 
cgit v1.2.3-70-g09d2


From 33744cb0068d7dc470d0b39ca70344f256a9cad9 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tschicke@gmail.com>
Date: Mon, 22 Jul 2019 00:12:31 -0400
Subject: Added titles to overlay windows

---
 .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx   | 4 ++--
 src/client/views/nodes/DocumentView.tsx                               | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 652aca8f3..703873681 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -504,8 +504,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                     }} />;
                     overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, options);
                 };
-                addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300 }, { collection: "Doc", docs: "Doc[]" }, undefined);
-                addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300 }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}");
+                addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300, title: "Layout Initialization" }, { collection: "Doc", docs: "Doc[]" }, undefined);
+                addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300, title: "Layout Script" }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}");
             }
         });
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7ff095573..1c03bfc81 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -557,7 +557,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                 this.props.addDocTab && this.props.addDocTab(Docs.Create.SchemaDocument(["title"], aliases, {}), undefined, "onRight"); // bcz: dataDoc?
             }, icon: "search"
         });
-        cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200 }) });
+        cm.addItem({ description: "Add Repl", event: () => OverlayView.Instance.addWindow(<ScriptingRepl />, { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" }) });
         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(Utils.prepend("/doc/" + this.props.Document[Id])), icon: "link" });
-- 
cgit v1.2.3-70-g09d2

