From 1087133d71ef2ac7df6976c61685167ed0fe71d9 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 5 Jun 2019 14:09:40 -0400
Subject: cleaned up selections somewhat so that PDFs don't flicker when
 manipulating annotations.

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

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

diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 5e51437a4..25c1535b3 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -70,7 +70,7 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
         return (
             <>
                 <CollectionFreeFormView {...props} CollectionView={this} />
-                {this.props.isSelected() ? this.uIButtons : (null)}
+                {this.props.active() ? this.uIButtons : (null)}
             </>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From 24d2e6d7d24aff60c7a3084bc5d5d660ef6b4608 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 5 Jun 2019 14:49:35 -0400
Subject: PDF scroll/UI shows up only when its active now.

---
 src/client/util/SelectionManager.ts                           | 11 -----------
 src/client/views/collections/CollectionPDFView.tsx            |  2 +-
 .../collections/collectionFreeForm/CollectionFreeFormView.tsx |  2 +-
 3 files changed, 2 insertions(+), 13 deletions(-)

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

diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index 5311841e1..6e0e6fd3a 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -21,14 +21,6 @@ export namespace SelectionManager {
                 doc.props.whenActiveChanged(true);
             }
         }
-        @action
-        DeSelectDoc(doc: DocumentView): void {
-            if (manager.SelectedDocuments.indexOf(doc) !== -1) {
-                manager.SelectedDocuments.splice(manager.SelectedDocuments.indexOf(doc), 1);
-                doc.props.whenActiveChanged(false);
-            }
-        }
-
         @action
         DeselectAll(): void {
             manager.SelectedDocuments.map(dv => dv.props.whenActiveChanged(false));
@@ -46,9 +38,6 @@ export namespace SelectionManager {
     export function IsSelected(doc: DocumentView): boolean {
         return manager.SelectedDocuments.indexOf(doc) !== -1;
     }
-    export function DeSelectDoc(doc: DocumentView): void {
-        manager.DeSelectDoc(doc);
-    }
 
     export function DeselectAll(except?: Doc): void {
         let found: DocumentView | undefined = undefined;
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 25c1535b3..bf887ce7c 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -70,7 +70,7 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
         return (
             <>
                 <CollectionFreeFormView {...props} CollectionView={this} />
-                {this.props.active() ? this.uIButtons : (null)}
+                {renderProps.active() ? this.uIButtons : (null)}
             </>
         );
     }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 582f93c2e..d23bef2d3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -348,7 +348,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
                         <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" />
                     </CollectionFreeFormViewPannableContents>
                 </MarqueeView>
-                <CollectionFreeFormOverlayView {...this.getDocumentViewProps(this.props.Document)} {...this.props} />
+                <CollectionFreeFormOverlayView  {...this.props} {...this.getDocumentViewProps(this.props.Document)} />
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From 0a14ecf9b9fa5e15bc3e5373c8f042f9cd876c8a Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Thu, 6 Jun 2019 18:26:57 -0400
Subject: region annotation basics

---
 src/client/views/collections/CollectionPDFView.tsx |   3 +
 src/client/views/pdf/PDFAnnotationLayer.tsx        |  24 ++++
 src/client/views/pdf/PDFViewer.scss                |   2 +-
 src/client/views/pdf/PDFViewer.tsx                 | 125 +++++++++++++++++----
 4 files changed, 129 insertions(+), 25 deletions(-)
 create mode 100644 src/client/views/pdf/PDFAnnotationLayer.tsx

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

diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 5e51437a4..773e4ae60 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -13,6 +13,9 @@ import { Id } from "../../../new_fields/FieldSymbols";
 
 @observer
 export class CollectionPDFView extends React.Component<FieldViewProps> {
+    constructor(props: FieldViewProps) {
+        super(props);
+    }
 
     public static LayoutString(fieldKey: string = "data") {
         return FieldView.LayoutString(CollectionPDFView, fieldKey);
diff --git a/src/client/views/pdf/PDFAnnotationLayer.tsx b/src/client/views/pdf/PDFAnnotationLayer.tsx
new file mode 100644
index 000000000..e92dcacbf
--- /dev/null
+++ b/src/client/views/pdf/PDFAnnotationLayer.tsx
@@ -0,0 +1,24 @@
+import React = require("react");
+import { observer } from "mobx-react";
+
+interface IAnnotationProps {
+
+}
+
+@observer
+export class PDFAnnotationLayer extends React.Component {
+    onPointerDown = (e: React.PointerEvent) => {
+        if (e.ctrlKey) {
+            console.log("annotating");
+            e.stopPropagation();
+        }
+    }
+
+    render() {
+        return (
+            <div className="pdfAnnotationLayer-cont" style={{ width: "100%", height: "100%", position: "relative", top: "-200%" }} onPointerDown={this.onPointerDown}>
+
+            </div>
+        )
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index 484d9dc04..cb1aef410 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -27,5 +27,5 @@
 .pdfViewer-annotationBox {
     position: absolute;
     background-color: red;
-    opacity: 0.5;
+    opacity: 0.1;
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index d5a0a7aa1..5c480090c 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -6,6 +6,9 @@ import { Opt } from "../../../new_fields/Doc";
 import "./PDFViewer.scss";
 import "pdfjs-dist/web/pdf_viewer.css";
 import { PDFBox } from "../nodes/PDFBox";
+import { PDFAnnotationLayer } from "./PDFAnnotationLayer";
+import { TSMethodSignature } from "babel-types";
+import { checkPropTypes } from "prop-types";
 
 interface IPDFViewerProps {
     url: string;
@@ -268,15 +271,24 @@ class Page extends React.Component<IPageProps> {
     @observable private _height: number = 0;
     @observable private _page: Opt<Pdfjs.PDFPageProxy>;
     @observable private _currPage: number = this.props.page + 1;
+    @observable private _marqueeX: number = 0;
+    @observable private _marqueeY: number = 0;
+    @observable private _marqueeWidth: number = 0;
+    @observable private _marqueeHeight: number = 0;
 
     private _canvas: React.RefObject<HTMLCanvasElement>;
-    private _currentAnnotations: HTMLDivElement[] = [];
     private _textLayer: React.RefObject<HTMLDivElement>;
+    private _annotationLayer: React.RefObject<HTMLDivElement>;
+    private _marquee: React.RefObject<HTMLDivElement>;
+    private _currentAnnotations: HTMLDivElement[] = [];
+    private _marqueeing: boolean = false;
 
     constructor(props: IPageProps) {
         super(props);
         this._canvas = React.createRef();
         this._textLayer = React.createRef();
+        this._annotationLayer = React.createRef();
+        this._marquee = React.createRef();
     }
 
     componentDidMount() {
@@ -342,9 +354,26 @@ class Page extends React.Component<IPageProps> {
         }
     }
 
+    @action
     onPointerDown = (e: React.PointerEvent) => {
         if (e.button === 0) {
-            e.stopPropagation();
+            let target: any = e.target;
+            if (target && target.parentElement === this._textLayer.current) {
+                e.stopPropagation();
+            }
+            else {
+                e.stopPropagation();
+                runInAction(() => {
+                    let current = this._textLayer.current;
+                    if (current) {
+                        let boundingRect = current.getBoundingClientRect();
+                        this._marqueeX = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width);
+                        this._marqueeY = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height);
+                    }
+                });
+                this._marqueeing = true;
+                if (this._marquee.current) this._marquee.current.style.opacity = "0.2";
+            }
             document.addEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointerup", this.onPointerUp);
             if (!e.ctrlKey) {
@@ -355,8 +384,22 @@ class Page extends React.Component<IPageProps> {
         }
     }
 
+    @action
     onPointerMove = (e: PointerEvent) => {
-        if (e.button === 0) {
+        let target: any = e.target;
+        if (this._marqueeing) {
+            let current = this._textLayer.current;
+            if (current) {
+                let boundingRect = current.getBoundingClientRect();
+                this._marqueeWidth = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width) - this._marqueeX;
+                this._marqueeHeight = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height) - this._marqueeY;
+                console.log(this._marqueeWidth);
+                console.log(this._marqueeHeight);
+            }
+            e.stopPropagation();
+            e.preventDefault();
+        }
+        else if (target && target.parentElement === this._textLayer.current) {
             e.stopPropagation();
         }
     }
@@ -369,42 +412,76 @@ class Page extends React.Component<IPageProps> {
         e.stopPropagation();
     }
 
+    @action
     onPointerUp = (e: PointerEvent) => {
-        let sel = window.getSelection();
-        // if selecting over a range of things
-        if (sel && sel.type === "Range") {
-            let clientRects = sel.getRangeAt(0).getClientRects();
-            if (this._textLayer.current) {
-                let boundingRect = this._textLayer.current.getBoundingClientRect();
-                for (let i = 0; i < clientRects.length; i++) {
-                    let rect = clientRects.item(i);
-                    if (rect) {
-                        let annoBox = document.createElement("div");
-                        annoBox.className = "pdfViewer-annotationBox";
-                        // transforms the positions from screen onto the pdf div
-                        annoBox.style.top = ((rect.top - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)).toString();
-                        annoBox.style.left = ((rect.left - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)).toString();
-                        annoBox.style.width = (rect.width * this._textLayer.current.offsetWidth / boundingRect.width).toString();
-                        annoBox.style.height = (rect.height * this._textLayer.current.offsetHeight / boundingRect.height).toString();
-                        annoBox.ondragstart = this.startAnnotation;
-                        annoBox.onpointerdown = this.pointerDownCancel;
-                        this._textLayer.current.appendChild(annoBox);
-                        this._currentAnnotations.push(annoBox);
+        if (this._marqueeing) {
+            this._marqueeing = false;
+            if (this._marquee.current) {
+                let copy = document.createElement("div");
+                copy.style.left = this._marquee.current.style.left;
+                copy.style.top = this._marquee.current.style.top;
+                copy.style.width = this._marquee.current.style.width;
+                copy.style.height = this._marquee.current.style.height;
+                copy.style.opacity = this._marquee.current.style.opacity;
+                copy.className = this._marquee.current.className;
+                if (this._annotationLayer.current) {
+                    this._annotationLayer.current.append(copy);
+                    this._currentAnnotations.push(copy);
+                }
+                this._marquee.current.style.opacity = "0";
+            }
+
+            this._marqueeHeight = this._marqueeWidth = 0;
+        }
+        else {
+            let sel = window.getSelection();
+            // if selecting over a range of things
+            if (sel && sel.type === "Range") {
+                let clientRects = sel.getRangeAt(0).getClientRects();
+                if (this._textLayer.current) {
+                    let boundingRect = this._textLayer.current.getBoundingClientRect();
+                    for (let i = 0; i < clientRects.length; i++) {
+                        let rect = clientRects.item(i);
+                        if (rect) {
+                            let annoBox = document.createElement("div");
+                            annoBox.className = "pdfViewer-annotationBox";
+                            // transforms the positions from screen onto the pdf div
+                            annoBox.style.top = ((rect.top - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)).toString();
+                            annoBox.style.left = ((rect.left - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)).toString();
+                            annoBox.style.width = (rect.width * this._textLayer.current.offsetWidth / boundingRect.width).toString();
+                            annoBox.style.height = (rect.height * this._textLayer.current.offsetHeight / boundingRect.height).toString();
+                            annoBox.ondragstart = this.startAnnotation;
+                            annoBox.onpointerdown = this.pointerDownCancel;
+                            if (this._annotationLayer.current) this._annotationLayer.current.append(annoBox);
+                            this._currentAnnotations.push(annoBox);
+                        }
                     }
                 }
+                if (sel.empty) {  // Chrome
+                    sel.empty();
+                } else if (sel.removeAllRanges) {  // Firefox
+                    sel.removeAllRanges();
+                }
             }
         }
         document.removeEventListener("pointermove", this.onPointerMove);
         document.removeEventListener("pointerup", this.onPointerUp);
     }
 
+    annotationPointerDown = (e: React.PointerEvent) => {
+        console.log("annotation");
+    }
+
     render() {
         return (
             <div onPointerDown={this.onPointerDown} className={this.props.name} style={{ "width": this._width, "height": this._height }}>
                 <div className="canvasContainer">
                     <canvas ref={this._canvas} />
                 </div>
-                <div className="textlayer" ref={this._textLayer} style={{ "position": "relative", "top": `-${this._height}px`, "height": `${this._height}px` }} />
+                <div className="pdfAnnotationLayer-cont" ref={this._annotationLayer} style={{ width: "100%", height: "100%", position: "relative", top: "-100%" }}>
+                    <div className="pdfViewer-annotationBox" ref={this._marquee} style={{ left: `${this._marqueeX}px`, top: `${this._marqueeY}px`, width: `${this._marqueeWidth}px`, height: `${this._marqueeHeight}px` }}></div>
+                </div>
+                <div className="textlayer" ref={this._textLayer} style={{ "position": "relative", "top": `-${2 * this._height}px`, "height": `${this._height}px` }} />
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From b631beaf11db59549e75cc38ae7288a0ba8845cf Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Thu, 13 Jun 2019 22:00:33 -0400
Subject: added collection back

---
 src/client/documents/Documents.ts                  |  2 +-
 src/client/views/collections/CollectionPDFView.tsx | 32 +++++++++++++++++++---
 src/client/views/nodes/PDFBox.tsx                  | 13 ++++++++-
 src/client/views/pdf/PDFViewer.scss                |  1 -
 src/client/views/pdf/PDFViewer.tsx                 | 30 ++++++++++++++------
 src/client/views/pdf/Page.tsx                      |  2 +-
 6 files changed, 64 insertions(+), 16 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index dfbe2e136..91d3707f6 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -170,7 +170,7 @@ export namespace Docs {
         return textProto;
     }
     function CreatePdfPrototype(): Doc {
-        let pdfProto = setupPrototypeOptions(pdfProtoId, "PDF_PROTO", PDFBox.LayoutString(),
+        let pdfProto = setupPrototypeOptions(pdfProtoId, "PDF_PROTO", CollectionPDFView.LayoutString("annotations"),
             { x: 0, y: 0, width: 300, height: 300, backgroundLayout: PDFBox.LayoutString(), curPage: 1 });
         return pdfProto;
     }
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 62e8adbec..4af89d780 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -1,4 +1,4 @@
-import { action, observable } from "mobx";
+import { action, observable, IReactionDisposer, reaction } from "mobx";
 import { observer } from "mobx-react";
 import { ContextMenu } from "../ContextMenu";
 import "./CollectionPDFView.scss";
@@ -9,12 +9,36 @@ import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from ".
 import { emptyFunction } from "../../../Utils";
 import { NumCast } from "../../../new_fields/Types";
 import { Id } from "../../../new_fields/FieldSymbols";
+import { HeightSym, WidthSym } from "../../../new_fields/Doc";
 
 
 @observer
 export class CollectionPDFView extends React.Component<FieldViewProps> {
+    private _reactionDisposer?: IReactionDisposer;
+    private _buttonTray: React.RefObject<HTMLDivElement>;
+
     constructor(props: FieldViewProps) {
         super(props);
+
+        this._buttonTray = React.createRef();
+    }
+
+    componentDidMount() {
+        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);
+                    // console.log(scale);
+                }
+                // console.log(this.props.Document[HeightSym]());
+            },
+            { fireImmediately: true }
+        )
     }
 
     public static LayoutString(fieldKey: string = "data") {
@@ -52,12 +76,12 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
     private get uIButtons() {
         let ratio = (this.curPage - 1) / this.numPages * 100;
         return (
-            <div className="collectionPdfView-buttonTray" key="tray" style={{ height: "100%" }}>
+            <div className="collectionPdfView-buttonTray" ref={this._buttonTray} key="tray" style={{ height: "100%" }}>
                 <button className="collectionPdfView-backward" onClick={this.onPageBack}>{"<"}</button>
                 <button className="collectionPdfView-forward" onClick={this.onPageForward}>{">"}</button>
-                <div className="collectionPdfView-slider" onPointerDown={this.onThumbDown} style={{ top: 60, left: -20, width: 50, height: `calc(100% - 80px)` }} >
+                {/* <div className="collectionPdfView-slider" onPointerDown={this.onThumbDown} style={{ top: 60, left: -20, width: 50, height: `calc(100% - 80px)` }} >
                     <div className="collectionPdfView-thumb" onPointerDown={this.onThumbDown} style={{ top: `${ratio}%`, width: 50, height: 50 }} />
-                </div>
+                </div> */}
             </div>
         );
     }
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 4214a6777..acb430deb 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -36,6 +36,10 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             let doc = this.props.Document.proto ? this.props.Document.proto : this.props.Document;
             doc.nativeWidth = nw;
             doc.nativeHeight = nh;
+            let ccv = this.props.ContainingCollectionView;
+            if (ccv) {
+                ccv.props.Document.pdfHeight = nh;
+            }
             doc.height = nh * (doc[WidthSym]() / nw);
         }
     }
@@ -45,6 +49,10 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         if (e.currentTarget) {
             this._scrollY = e.currentTarget.scrollTop;
             // e.currentTarget.scrollTo({ top: 1000, behavior: "smooth" });
+            let ccv = this.props.ContainingCollectionView;
+            if (ccv) {
+                ccv.props.Document.scrollY = this._scrollY;
+            }
         }
     }
 
@@ -56,7 +64,10 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
         return (
             <div onScroll={this.onScroll}
-                style={{ overflowY: "scroll", overflowX: "hidden", height: `${NumCast(this.props.Document.nativeHeight ? this.props.Document.nativeHeight : 300)}px` }}
+                style={{
+                    overflowY: "scroll", overflowX: "hidden", height: `${NumCast(this.props.Document.nativeHeight ? this.props.Document.nativeHeight : 300)}px`,
+                    marginTop: `${NumCast(this.props.ContainingCollectionView!.props.Document.panY)}px`
+                }}
                 onWheel={(e: React.WheelEvent) => e.stopPropagation()} className={classname}>
                 <PDFViewer url={pdfUrl.url.href} loaded={this.loaded} scrollY={this._scrollY} parent={this} />
                 {/* <div style={{ width: "100px", height: "300px" }}></div> */}
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index 57be04b93..a73df2d58 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -33,7 +33,6 @@
 .pdfViewer-annotationLayer {
     position: absolute;
     top: 0;
-    overflow: visible hidden;
 }
 
 .pdfViewer-pinAnnotation {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index fe442c906..144fca9e0 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -188,8 +188,8 @@ class Viewer extends React.Component<IViewerProps> {
             else {
                 this.props.parent.Document.annotations = new List<Doc>([destDoc]);
             }
+            e.stopPropagation();
         }
-        e.stopPropagation();
     }
 
     componentWillUnmount = () => {
@@ -465,7 +465,7 @@ class Viewer extends React.Component<IViewerProps> {
                     {this._visibleElements}
                 </div>
                 <div className="pdfViewer-annotationLayer" style={{ height: this.props.parent.Document.nativeHeight, width: `100%`, pointerEvents: this._pointerEvents }}>
-                    <div className="pdfViewer-annotationLayer-subCont" style={{ transform: `translateY(${-this.scrollY}px)` }} ref={this._annotationLayer}>
+                    <div className="pdfViewer-annotationLayer-subCont" ref={this._annotationLayer}>
                         {this._annotations.map(anno => this.renderAnnotation(anno))}
                     </div>
                 </div>
@@ -501,17 +501,31 @@ class PinAnnotation extends React.Component<IAnnotationProps> {
 
     componentDidMount = () => {
         let selected = this.props.document.selected;
-        if (selected && BoolCast(selected)) {
+        if (!BoolCast(selected)) {
             runInAction(() => {
-                this._backgroundColor = "green";
-                this._display = "initial";
-            })
+                this._backgroundColor = "red";
+                this._display = "none";
+            });
+        }
+        if (selected) {
+            if (BoolCast(selected)) {
+                runInAction(() => {
+                    this._backgroundColor = "green";
+                    this._display = "initial";
+                });
+            }
+            else {
+                runInAction(() => {
+                    this._backgroundColor = "red";
+                    this._display = "none";
+                });
+            }
         }
         else {
             runInAction(() => {
                 this._backgroundColor = "red";
                 this._display = "none";
-            })
+            });
         }
     }
 
@@ -572,7 +586,7 @@ class PinAnnotation extends React.Component<IAnnotationProps> {
                             PanelWidth={() => NumCast(this.props.parent.props.parent.Document.nativeWidth)}
                             PanelHeight={() => NumCast(this.props.parent.props.parent.Document.nativeHeight)}
                             focus={emptyFunction}
-                            selectOnLoad={false}
+                            selectOnLoad={true}
                             parentActive={this.props.parent.props.parent.props.active}
                             whenActiveChanged={this.props.parent.props.parent.props.whenActiveChanged}
                             bringToFront={emptyFunction}
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 9e3bf4954..1c305caa3 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -257,7 +257,7 @@ export default class Page extends React.Component<IPageProps> {
             let ratio = this._marqueeWidth / this._marqueeHeight;
             if (ratio > 1.5) {
                 // vertical
-                transform = "rotate(90deg) scale(1, 2)";
+                transform = "rotate(90deg) scale(1, 5)";
             }
             else if (ratio < 0.5) {
                 // horizontal
-- 
cgit v1.2.3-70-g09d2


From f6e8b7a0f8a13ddf059cf701e46b8cbb8d9228f7 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Fri, 14 Jun 2019 17:27:49 -0400
Subject: added page fwd/back/goto

---
 src/client/views/collections/CollectionPDFView.tsx | 48 ++++++-----------
 src/client/views/nodes/DocumentView.tsx            |  1 -
 src/client/views/nodes/FieldView.tsx               |  2 +
 src/client/views/nodes/PDFBox.tsx                  | 62 ++++++++++++++++------
 src/client/views/pdf/PDFViewer.tsx                 |  6 +--
 src/client/views/pdf/Page.tsx                      | 12 ++---
 6 files changed, 72 insertions(+), 59 deletions(-)

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

diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 4af89d780..b62d3f7bb 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -1,19 +1,21 @@
-import { action, observable, IReactionDisposer, reaction } from "mobx";
+import { action, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
+import { WidthSym } from "../../../new_fields/Doc";
+import { Id } from "../../../new_fields/FieldSymbols";
+import { NumCast } from "../../../new_fields/Types";
+import { emptyFunction } from "../../../Utils";
 import { ContextMenu } from "../ContextMenu";
+import { FieldView, FieldViewProps } from "../nodes/FieldView";
+import { CollectionBaseView, CollectionRenderProps, CollectionViewType } from "./CollectionBaseView";
+import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
 import "./CollectionPDFView.scss";
 import React = require("react");
-import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
-import { FieldView, FieldViewProps } from "../nodes/FieldView";
-import { CollectionRenderProps, CollectionBaseView, CollectionViewType } from "./CollectionBaseView";
-import { emptyFunction } from "../../../Utils";
-import { NumCast } from "../../../new_fields/Types";
-import { Id } from "../../../new_fields/FieldSymbols";
-import { HeightSym, WidthSym } from "../../../new_fields/Doc";
+import { PDFBox } from "../nodes/PDFBox";
 
 
 @observer
 export class CollectionPDFView extends React.Component<FieldViewProps> {
+    private _pdfBox?: PDFBox;
     private _reactionDisposer?: IReactionDisposer;
     private _buttonTray: React.RefObject<HTMLDivElement>;
 
@@ -46,31 +48,12 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
     }
     @observable _inThumb = false;
 
-    private set curPage(value: number) { this.props.Document.curPage = value; }
+    private set curPage(value: number) { this._pdfBox && this._pdfBox.GotoPage(value); }
     private get curPage() { return NumCast(this.props.Document.curPage, -1); }
     private get numPages() { return NumCast(this.props.Document.numPages); }
-    @action onPageBack = () => this.curPage > 1 ? (this.props.Document.curPage = this.curPage - 1) : -1;
-    @action onPageForward = () => this.curPage < this.numPages ? (this.props.Document.curPage = this.curPage + 1) : -1;
+    @action onPageBack = () => this._pdfBox && this._pdfBox.BackPage();
+    @action onPageForward = () => this._pdfBox && this._pdfBox.ForwardPage();
 
-    @action
-    onThumbDown = (e: React.PointerEvent) => {
-        document.addEventListener("pointermove", this.onThumbMove, false);
-        document.addEventListener("pointerup", this.onThumbUp, false);
-        e.stopPropagation();
-        this._inThumb = true;
-    }
-    @action
-    onThumbMove = (e: PointerEvent) => {
-        let pso = (e.clientY - (e as any).target.parentElement.getBoundingClientRect().top) / (e as any).target.parentElement.getBoundingClientRect().height;
-        this.curPage = Math.trunc(Math.min(this.numPages, pso * this.numPages + 1));
-        e.stopPropagation();
-    }
-    @action
-    onThumbUp = (e: PointerEvent) => {
-        this._inThumb = false;
-        document.removeEventListener("pointermove", this.onThumbMove);
-        document.removeEventListener("pointerup", this.onThumbUp);
-    }
     nativeWidth = () => NumCast(this.props.Document.nativeWidth);
     nativeHeight = () => NumCast(this.props.Document.nativeHeight);
     private get uIButtons() {
@@ -92,11 +75,14 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
         }
     }
 
+    setPdfBox = (pdfBox: PDFBox) => { this._pdfBox = pdfBox; };
+
+
     private subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => {
         let props = { ...this.props, ...renderProps };
         return (
             <>
-                <CollectionFreeFormView {...props} CollectionView={this} />
+                <CollectionFreeFormView {...props} setPdfBox={this.setPdfBox} CollectionView={this} />
                 {renderProps.active() ? this.uIButtons : (null)}
             </>
         );
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 583fa3e1a..0d5df550a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -453,7 +453,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     render() {
         var scaling = this.props.ContentScaling();
         var nativeWidth = this.nativeWidth > 0 ? `${this.nativeWidth}px` : "100%";
-        let ph = this.props.PanelHeight();
         var nativeHeight = BoolCast(this.props.Document.ignoreAspect) ? this.props.PanelHeight() / this.props.ContentScaling() : this.nativeHeight > 0 ? `${this.nativeHeight}px` : "100%";
         return (
             <div className={`documentView-node${this.props.isTopMost ? "-topmost" : ""}`}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 5a83de8e3..cf6d2012f 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -18,6 +18,7 @@ import { FormattedTextBox } from "./FormattedTextBox";
 import { IconBox } from "./IconBox";
 import { ImageBox } from "./ImageBox";
 import { VideoBox } from "./VideoBox";
+import { PDFBox } from "./PDFBox";
 
 
 //
@@ -44,6 +45,7 @@ export interface FieldViewProps {
     PanelWidth: () => number;
     PanelHeight: () => number;
     setVideoBox?: (player: VideoBox) => void;
+    setPdfBox?: (player: PDFBox) => void;
 }
 
 @observer
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index b9ccd79e4..243982a3b 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -1,25 +1,22 @@
-import * as htmlToImage from "html-to-image";
-import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx';
+import { action, IReactionDisposer, observable, reaction, trace, untracked } from 'mobx';
 import { observer } from "mobx-react";
 import 'react-image-lightbox/style.css';
-import Measure from "react-measure";
+import { WidthSym } from "../../../new_fields/Doc";
+import { makeInterface } from "../../../new_fields/Schema";
+import { Cast, NumCast } from "../../../new_fields/Types";
+import { PdfField } from "../../../new_fields/URLField";
 //@ts-ignore
 // import { Document, Page } from "react-pdf";
 // import 'react-pdf/dist/Page/AnnotationLayer.css';
 import { RouteStore } from "../../../server/RouteStore";
 import { DocComponent } from "../DocComponent";
 import { InkingControl } from "../InkingControl";
+import { PDFViewer } from "../pdf/PDFViewer";
 import { positionSchema } from "./DocumentView";
 import { FieldView, FieldViewProps } from './FieldView';
 import { pageSchema } from "./ImageBox";
 import "./PDFBox.scss";
 import React = require("react");
-import { NumCast, StrCast, Cast } from "../../../new_fields/Types";
-import { makeInterface } from "../../../new_fields/Schema";
-import { PDFViewer } from "../pdf/PDFViewer";
-import { PdfField } from "../../../new_fields/URLField";
-import { HeightSym, WidthSym } from "../../../new_fields/Doc";
-import { CollectionStackingView } from "../collections/CollectionStackingView";
 
 type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const PdfDocument = makeInterface(positionSchema, pageSchema);
@@ -31,19 +28,50 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     @observable private _alt = false;
     @observable private _scrollY: number = 0;
     private _reactionDisposer?: IReactionDisposer;
-    _targetDiv: any = undefined;
 
-    componentDidMount: () => void = () => {
+    componentDidMount() {
+        if (this.props.setPdfBox) this.props.setPdfBox(this);
+    }
+
+    public GetPage() {
+        return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.Document.pdfHeight)) + 1;
+    }
+    public BackPage() {
+        let cp = Math.ceil(NumCast(this.props.Document.scrollY) / NumCast(this.Document.pdfHeight)) + 1;
+        cp = cp - 1;
+        if (cp > 0) {
+            this.props.Document.curPage = cp;
+            this.props.Document.scrollY = (cp - 1) * NumCast(this.Document.pdfHeight);
+        }
+    }
+    public GotoPage(p: number) {
+        if (p > 0 && p <= NumCast(this.props.Document.numPages)) {
+            this.props.Document.curPage = p;
+            this.props.Document.scrollY = (p - 1) * NumCast(this.Document.pdfHeight);
+        }
+    }
+
+    public ForwardPage() {
+        let cp = this.GetPage() + 1;
+        if (cp <= NumCast(this.props.Document.numPages)) {
+            this.props.Document.curPage = cp;
+            this.props.Document.scrollY = (cp - 1) * NumCast(this.Document.pdfHeight);
+        }
+    }
+
+    createRef = (ele: HTMLDivElement | null) => {
         if (this._reactionDisposer) this._reactionDisposer();
-        this._reactionDisposer = reaction(() => this.props.Document.scrollY, () =>
-            this._targetDiv && this._targetDiv.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "smooth" })
-        );
+        this._reactionDisposer = reaction(() => this.props.Document.scrollY, () => {
+            ele && ele.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "smooth" });
+        });
     }
 
-    loaded = (nw: number, nh: number) => {
+    loaded = (nw: number, nh: number, np: number) => {
         if (this.props.Document) {
-            if (this.props.Document.nativeWidth && this.props.Document.nativeHeight) return;
             let doc = this.props.Document.proto ? this.props.Document.proto : this.props.Document;
+            console.log("pages = " + np);
+            doc.numPages = np;
+            if (doc.nativeWidth && doc.nativeHeight) return;
             let oldaspect = NumCast(doc.nativeHeight) / NumCast(doc.nativeWidth, 1);
             doc.nativeWidth = nw;
             if (doc.nativeHeight) doc.nativeHeight = nw * oldaspect;
@@ -59,7 +87,6 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     @action
     onScroll = (e: React.UIEvent<HTMLDivElement>) => {
         if (e.currentTarget) {
-            this._targetDiv = e.currentTarget;
             this._scrollY = e.currentTarget.scrollTop;
             // e.currentTarget.scrollTo({ top: 1000, behavior: "smooth" });
             let ccv = this.props.ContainingCollectionView;
@@ -82,6 +109,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
                     overflowY: "scroll", overflowX: "hidden",
                     marginTop: `${NumCast(this.props.ContainingCollectionView!.props.Document.panY)}px`
                 }}
+                ref={this.createRef}
                 onWheel={(e: React.WheelEvent) => e.stopPropagation()} className={classname}>
                 <PDFViewer url={pdfUrl.url.href} loaded={this.loaded} scrollY={this._scrollY} parent={this} />
                 {/* <div style={{ width: "100px", height: "300px" }}></div> */}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 17f65c7a6..dee891ba6 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -23,7 +23,7 @@ import { Dictionary } from "typescript-collections";
 
 interface IPDFViewerProps {
     url: string;
-    loaded: (nw: number, nh: number) => void;
+    loaded: (nw: number, nh: number, np: number) => void;
     scrollY: number;
     parent: PDFBox;
 }
@@ -61,7 +61,7 @@ export class PDFViewer extends React.Component<IPDFViewerProps> {
 
 interface IViewerProps {
     pdf: Opt<Pdfjs.PDFDocumentProxy>;
-    loaded: (nw: number, nh: number) => void;
+    loaded: (nw: number, nh: number, np: number) => void;
     scrollY: number;
     parent: PDFBox;
     mainCont: React.RefObject<HTMLDivElement>;
@@ -400,7 +400,7 @@ class Viewer extends React.Component<IViewerProps> {
             return;
         }
         let numPages = this.props.pdf ? this.props.pdf.numPages : 0;
-        this.props.loaded(page.width, page.height);
+        this.props.loaded(page.width, page.height, numPages);
         this._pageSizes[index - 1] = { width: page.width, height: page.height };
         this._pagesLoaded++;
         if (this._pagesLoaded === numPages) {
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 44c502a04..e3dbeaebe 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -132,16 +132,14 @@ export default class Page extends React.Component<IPageProps> {
         }
     }
 
-    highlight = (targetDoc: Doc | undefined) => {
+    highlight = (targetDoc?: Doc) => {
         // creates annotation documents for current highlights
         let annotationDoc = this.props.makeAnnotationDocuments(targetDoc);
-        let targetAnnotations = DocListCast(this.props.parent.Document.annotations);
-        if (targetAnnotations) {
+        let targetAnnotations = Cast(this.props.parent.Document.annotations, listSpec(Doc));
+        if (targetAnnotations === undefined) {
+            Doc.GetProto(this.props.parent.Document).annotations = new List([annotationDoc]);
+        } else {
             targetAnnotations.push(annotationDoc);
-            this.props.parent.Document.annotations = new List<Doc>(targetAnnotations);
-        }
-        else {
-            this.props.parent.Document.annotations = new List<Doc>([annotationDoc]);
         }
         return annotationDoc;
     }
-- 
cgit v1.2.3-70-g09d2


From 13e301dea2f537b67b338cc6a98d3f3b5a8e1f36 Mon Sep 17 00:00:00 2001
From: Tyler Schicke <tyler_schicke@brown.edu>
Date: Tue, 18 Jun 2019 20:58:32 -0400
Subject: Fixed linter errors

---
 src/client/northstar/dash-nodes/HistogramBox.tsx             |  3 +--
 src/client/util/DocumentManager.ts                           |  6 +++---
 src/client/util/DragManager.ts                               |  4 +++-
 src/client/util/RichTextSchema.tsx                           | 10 +++++-----
 src/client/util/TooltipTextMenu.tsx                          |  2 +-
 src/client/views/ContextMenu.tsx                             |  4 ++--
 src/client/views/DocumentDecorations.tsx                     |  2 +-
 src/client/views/MainOverlayTextBox.tsx                      |  2 +-
 src/client/views/MainView.tsx                                |  7 ++++---
 src/client/views/PresentationView.tsx                        |  4 ++--
 src/client/views/collections/CollectionBaseView.tsx          |  2 +-
 src/client/views/collections/CollectionDockingView.tsx       |  5 +++--
 src/client/views/collections/CollectionPDFView.tsx           |  2 +-
 src/client/views/collections/CollectionSchemaView.tsx        | 11 ++++++-----
 src/client/views/collections/CollectionStackingView.tsx      |  4 ++--
 src/client/views/collections/CollectionTreeView.tsx          | 10 +++++-----
 .../collectionFreeForm/CollectionFreeFormLinksView.tsx       |  2 +-
 .../collectionFreeForm/CollectionFreeFormView.tsx            |  2 +-
 .../views/collections/collectionFreeForm/MarqueeView.tsx     |  2 +-
 src/client/views/nodes/CollectionFreeFormDocumentView.tsx    |  2 +-
 src/client/views/nodes/DocumentView.tsx                      | 12 ++++++------
 src/client/views/nodes/FormattedTextBox.tsx                  |  2 +-
 src/client/views/nodes/ImageBox.tsx                          |  3 ++-
 src/client/views/pdf/PDFAnnotationLayer.tsx                  |  2 +-
 src/client/views/pdf/PDFMenu.tsx                             |  2 +-
 src/client/views/pdf/PDFViewer.tsx                           |  4 ++--
 src/server/index.ts                                          |  2 +-
 27 files changed, 59 insertions(+), 54 deletions(-)

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

diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx
index d7732ee86..a60eaea85 100644
--- a/src/client/northstar/dash-nodes/HistogramBox.tsx
+++ b/src/client/northstar/dash-nodes/HistogramBox.tsx
@@ -125,8 +125,7 @@ export class HistogramBox extends React.Component<FieldViewProps> {
                                 let mapped = brushingDocs.map((brush, i) => {
                                     brush.backgroundColor = StyleConstants.BRUSH_COLORS[i % StyleConstants.BRUSH_COLORS.length];
                                     let brushed = DocListCast(brush.brushingDocs);
-                                    if (!brushed.length)
-                                        return null;
+                                    if (!brushed.length) return null;
                                     return { l: brush, b: brushed[0][Id] === proto[Id] ? brushed[1] : brushed[0] };
                                 });
                                 runInAction(() => this.HistoOp.BrushLinks.splice(0, this.HistoOp.BrushLinks.length, ...mapped.filter(m => m) as { l: Doc, b: Doc }[]));
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index ff0c1560b..862395d74 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -35,9 +35,9 @@ export class DocumentManager {
         let toReturn: DocumentView | null = null;
         let passes = preferredCollection ? [preferredCollection, undefined] : [undefined];
 
-        for (let i = 0; i < passes.length; i++) {
+        for (let pass of passes) {
             DocumentManager.Instance.DocumentViews.map(view => {
-                if (view.props.Document[Id] === id && (!passes[i] || view.props.ContainingCollectionView === preferredCollection)) {
+                if (view.props.Document[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
                     toReturn = view;
                     return;
                 }
@@ -45,7 +45,7 @@ export class DocumentManager {
             if (!toReturn) {
                 DocumentManager.Instance.DocumentViews.map(view => {
                     let doc = view.props.Document.proto;
-                    if (doc && doc[Id] === id && (!passes[i] || view.props.ContainingCollectionView === preferredCollection)) {
+                    if (doc && doc[Id] === id && (!pass || view.props.ContainingCollectionView === preferredCollection)) {
                         toReturn = view;
                     }
                 });
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 89566e777..c3c92daa5 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -282,11 +282,13 @@ export namespace DragManager {
             // }
             let set = dragElement.getElementsByTagName('*');
             if (dragElement.hasAttribute("style")) (dragElement as any).style.pointerEvents = "none";
-            for (let i = 0; i < set.length; i++)
+            // tslint:disable-next-line: prefer-for-of
+            for (let i = 0; i < set.length; i++) {
                 if (set[i].hasAttribute("style")) {
                     let s = set[i];
                     (s as any).style.pointerEvents = "none";
                 }
+            }
 
 
             dragDiv.appendChild(dragElement);
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index e1e595925..943cdb4d1 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -156,12 +156,12 @@ export const nodes: { [index: string]: NodeSpec } = {
                     title: dom.getAttribute("title"),
                     alt: dom.getAttribute("alt"),
                     width: Math.min(100, Number(dom.getAttribute("width"))),
-                }
+                };
             }
         }],
         toDOM(node) {
-            const attrs = { style: `width: ${node.attrs.width}` }
-            return ["video", { ...node.attrs, ...attrs }]
+            const attrs = { style: `width: ${node.attrs.width}` };
+            return ["video", { ...node.attrs, ...attrs }];
         }
     },
 
@@ -285,7 +285,7 @@ export const marks: { [index: string]: MarkSpec } = {
         toDOM() {
             return ['span', {
                 style: 'color: blue'
-            }]
+            }];
         }
     },
 
@@ -536,4 +536,4 @@ schema.nodeFromJSON = (json: any) => {
         node.attrs.oldtext = Slice.fromJSON(schema, node.attrs.oldtextslice);
     }
     return node;
-}
\ No newline at end of file
+};
\ No newline at end of file
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 0a61b7e7d..f2559db74 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -256,7 +256,7 @@ export class TooltipTextMenu {
             starButton.onclick = () => {
                 let state = this.view.state;
                 this.insertStar(state, this.view.dispatch);
-            }
+            };
 
             this.tooltip.appendChild(starButton);
         }
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index da374455e..eb1937683 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -1,8 +1,8 @@
 import React = require("react");
 import { ContextMenuItem, ContextMenuProps } from "./ContextMenuItem";
 import { observable, action } from "mobx";
-import { observer } from "mobx-react"
-import "./ContextMenu.scss"
+import { observer } from "mobx-react";
+import "./ContextMenu.scss";
 import { library } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { faSearch, faCircle } from '@fortawesome/free-solid-svg-icons';
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index ceca940b6..e60f8c86c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -466,7 +466,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         SelectionManager.SelectedDocuments().forEach(element => {
             const rect = element.ContentDiv ? element.ContentDiv.getBoundingClientRect() : new DOMRect();
 
-            if (rect.width !== 0 && (dX != 0 || dY != 0 || dW != 0 || dH != 0)) {
+            if (rect.width !== 0 && (dX !== 0 || dY !== 0 || dW !== 0 || dH !== 0)) {
                 let doc = PositionDocument(element.props.Document);
                 let nwidth = doc.nativeWidth || 0;
                 let nheight = doc.nativeHeight || 0;
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 0de880175..b4ad5f4d7 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -40,7 +40,7 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
                     this.TextDoc = box.props.Document;
                     let sxf = Utils.GetScreenTransform(box ? box.CurrentDiv : undefined);
                     let xf = () => { box.props.ScreenToLocalTransform(); return new Transform(-sxf.translateX, -sxf.translateY, 1 / sxf.scale); };
-                    this.setTextDoc(box.props.fieldKey, box.CurrentDiv, xf, BoolCast(box.props.Document.autoHeight, false) || box.props.height === "min-content")
+                    this.setTextDoc(box.props.fieldKey, box.CurrentDiv, xf, BoolCast(box.props.Document.autoHeight, false) || box.props.height === "min-content");
                 }
                 else {
                     this.TextDoc = undefined;
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index fd76cbbd3..7f979cd3b 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -237,10 +237,11 @@ export class MainView extends React.Component {
     }
 
     onColorClick = (e: React.MouseEvent) => {
-        let target = (e.nativeEvent! as any).path[0];
-        let parent = (e.nativeEvent! as any).path[1];
-        if (target.localName === "input" || parent.localName === "span")
+        let target = (e.nativeEvent as any).path[0];
+        let parent = (e.nativeEvent as any).path[1];
+        if (target.localName === "input" || parent.localName === "span") {
             e.stopPropagation();
+        }
     }
 
 
diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx
index d2d41a4ba..1dacbb663 100644
--- a/src/client/views/PresentationView.tsx
+++ b/src/client/views/PresentationView.tsx
@@ -40,8 +40,8 @@ class PresentationViewList extends React.Component<PresListProps> {
             //this doc is selected
             className += " presentationView-selected";
         }
-        let onEnter = (e: React.PointerEvent) => { document.libraryBrush = true; }
-        let onLeave = (e: React.PointerEvent) => { document.libraryBrush = false; }
+        let onEnter = (e: React.PointerEvent) => { document.libraryBrush = true; };
+        let onLeave = (e: React.PointerEvent) => { document.libraryBrush = false; };
         return (
             <div className={className} key={document[Id] + index}
                 onPointerEnter={onEnter} onPointerLeave={onLeave}
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 5238ad114..1e42593d1 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -130,7 +130,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
 
     @action.bound
     removeDocument(doc: Doc): boolean {
-        let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView)
+        let docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView);
         docView && SelectionManager.DeselectDoc(docView);
         const props = this.props;
         //TODO This won't create the field if it doesn't already exist
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index f2b3528b8..5beb89315 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -347,7 +347,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                             tab.header.parent.setActiveContentItem(tab.contentItem);
                         }
                         tab.setActive(true);
-                    }
+                    };
                     ReactDOM.render(<ParentDocSelector Document={doc} addDocTab={(doc, location) => CollectionDockingView.Instance.AddTab(stack, doc)} />, upDiv);
                     tab.reactComponents = [upDiv];
                     tab.element.append(upDiv);
@@ -432,8 +432,9 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
     @observable private _document: Opt<Doc>;
     get _stack(): any {
         let parent = (this.props as any).glContainer.parent.parent;
-        if (this._document && this._document.excludeFromLibrary && parent.parent && parent.parent.contentItems.length > 1)
+        if (this._document && this._document.excludeFromLibrary && parent.parent && parent.parent.contentItems.length > 1) {
             return parent.parent.contentItems[1];
+        }
         return parent;
     }
     constructor(props: any) {
diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index b62d3f7bb..b2d016934 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -40,7 +40,7 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
                 // console.log(this.props.Document[HeightSym]());
             },
             { fireImmediately: true }
-        )
+        );
     }
 
     public static LayoutString(fieldKey: string = "data") {
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 14a7d19d0..faea8d44d 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -87,8 +87,9 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             let columnDocs = DocListCast(schemaDoc.data);
             if (columnDocs) {
                 let ddoc = columnDocs.find(doc => doc.title === columnName);
-                if (ddoc)
+                if (ddoc) {
                     return ddoc;
+                }
             }
         }
         return this.props.Document;
@@ -285,7 +286,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
     }
 
     getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(
-        - this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth);
+        - this.borderWidth - this.DIVIDER_WIDTH - this.tableWidth, - this.borderWidth)
 
 
     get documentKeysCheckList() {
@@ -334,7 +335,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             columns={this.tableColumns}
             column={{ ...ReactTableDefaults.column, Cell: this.renderCell, }}
             getTrProps={this.getTrProps}
-        />
+        />;
     }
 
     @computed
@@ -360,7 +361,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
             addDocTab={this.props.addDocTab}
             setPreviewScript={this.setPreviewScript}
             previewScript={this.previewScript}
-        />
+        />;
     }
     @action
     setPreviewScript = (script: string) => {
@@ -409,7 +410,7 @@ export class CollectionSchemaPreview extends React.Component<CollectionSchemaPre
     }
     private PanelWidth = () => this.nativeWidth * this.contentScaling();
     private PanelHeight = () => this.nativeHeight * this.contentScaling();
-    private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling())
+    private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling());
     get centeringOffset() { return (this.props.width() - this.nativeWidth * this.contentScaling()) / 2; }
     @action
     onPreviewScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index e1ac3505b..f5ad4ee95 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -101,7 +101,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
             let childFocus = (doc: Doc) => {
                 doc.libraryBrush = true;
                 this.props.focus(this.props.Document); // just focus on this collection, not the underlying document because the API doesn't support adding an offset to focus on and we can't pan zoom our contents to be centered.
-            }
+            };
             return (<div className="collectionStackingView-masonryDoc"
                 key={d[Id]}
                 ref={dref}
@@ -131,7 +131,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
                     whenActiveChanged={this.props.whenActiveChanged}
                 />
             </div>);
-        })
+        });
     }
     onContextMenu = (e: React.MouseEvent): void => {
         if (!e.isPropagationStopped() && this.props.Document[Id] !== "mainDoc") { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index b13694e9d..3e495b734 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -67,8 +67,8 @@ class TreeView extends React.Component<TreeViewProps> {
     @undoBatch delete = () => this.props.deleteDoc(this.props.document);
     @undoBatch openRight = async () => this.props.addDocTab(this.props.document, "openRight");
 
-    @action onMouseEnter = () => { this._isOver = true; }
-    @action onMouseLeave = () => { this._isOver = false; }
+    @action onMouseEnter = () => { this._isOver = true; };
+    @action onMouseLeave = () => { this._isOver = false; };
 
     onPointerEnter = (e: React.PointerEvent): void => {
         this.props.active() && (this.props.document.libraryBrush = true);
@@ -89,8 +89,8 @@ class TreeView extends React.Component<TreeViewProps> {
         let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
         let before = x[1] < bounds[1];
         let inside = x[0] > bounds[0] + 75 || (!before && this._bulletType === BulletType.Collapsible);
-        this._header!.current!.className = "treeViewItem-header"
-        if (inside && this._bulletType != BulletType.List) this._header!.current!.className += " treeViewItem-header-inside";
+        this._header!.current!.className = "treeViewItem-header";
+        if (inside && this._bulletType !== BulletType.List) this._header!.current!.className += " treeViewItem-header-inside";
         else if (before) this._header!.current!.className += " treeViewItem-header-above";
         else if (!before) this._header!.current!.className += " treeViewItem-header-below";
         e.stopPropagation();
@@ -192,7 +192,7 @@ class TreeView extends React.Component<TreeViewProps> {
             if (inside) {
                 let docList = Cast(this.props.document.data, listSpec(Doc));
                 if (docList !== undefined) {
-                    addDoc = (doc: Doc) => { docList && docList.push(doc); return true; }
+                    addDoc = (doc: Doc) => { docList && docList.push(doc); return true; };
                 }
             }
             let added = false;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
index c4dd534ed..be75c6c5c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx
@@ -109,7 +109,7 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP
                     }
                     return match || found;
                 }, false)) {
-                    drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] })
+                    drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] });
                 }
             });
             return drawnPairs;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 250b6bf5d..84841e469 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -342,7 +342,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     private childViews = () => [
         <CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} />,
         ...this.views
-    ];
+    ]
     render() {
         const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`;
         const easing = () => this.props.Document.panTransformType === "Ease";
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index dedcc3172..05dc6f534 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -321,7 +321,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
                             summary.imageSummary = imageSummary;
                             this.props.addDocument(imageSummary, false);
                         }
-                    })
+                    });
                     newCollection.proto!.summaryDoc = summary;
                     selected = [newCollection];
                     newCollection.x = bounds.left + bounds.width;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index f6b1c62ee..858959d81 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -48,7 +48,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     panelHeight = () => this.props.PanelHeight();
     getTransform = (): Transform => this.props.ScreenToLocalTransform()
         .translate(-this.X, -this.Y)
-        .scale(1 / this.contentScaling()).scale(1 / this.zoom);
+        .scale(1 / this.contentScaling()).scale(1 / this.zoom)
 
     animateBetweenIcon = (icon: number[], stime: number, maximizing: boolean) => {
         this.props.bringToFront(this.props.Document);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 7c058d91c..4992669df 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -168,8 +168,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     public static animateBetweenIconFunc = (doc: Doc, width: number, height: number, stime: number, maximizing: boolean, cb?: (progress: number) => void) => {
         setTimeout(() => {
             let now = Date.now();
-            let progress = now < stime + 200 ? Math.min(1, (now - stime) / 200) : 1
-            doc.width = progress === 1 ? width : maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress
+            let progress = now < stime + 200 ? Math.min(1, (now - stime) / 200) : 1;
+            doc.width = progress === 1 ? width : maximizing ? 25 + (width - 25) * progress : width + (25 - width) * progress;
             doc.height = progress === 1 ? height : maximizing ? 25 + (height - 25) * progress : height + (25 - height) * progress;
             cb && cb(progress);
             if (now < stime + 200) {
@@ -229,7 +229,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         if (minimizedDoc) {
             let scrpt = this.props.ScreenToLocalTransform().scale(this.props.ContentScaling()).inverse().transformPoint(
                 NumCast(minimizedDoc.x) - NumCast(this.Document.x), NumCast(minimizedDoc.y) - NumCast(this.Document.y));
-            this.collapseTargetsToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs))
+            this.collapseTargetsToPoint(scrpt, await DocListCastAsync(minimizedDoc.maximizedDocs));
         }
     }
 
@@ -372,8 +372,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         this._lastTap = Date.now();
     }
 
-    deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); }
-    fieldsClicked = (): void => { this.props.addDocTab(Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight") };
+    deleteClicked = (): void => { this.props.removeDocument && this.props.removeDocument(this.props.Document); };
+    fieldsClicked = (): void => { this.props.addDocTab(Docs.KVPDocument(this.props.Document, { width: 300, height: 300 }), "onRight"); };
     makeBtnClicked = (): void => {
         let doc = Doc.GetProto(this.props.Document);
         doc.isButton = !BoolCast(doc.isButton, false);
@@ -527,7 +527,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; };
 
     isSelected = () => SelectionManager.IsSelected(this);
-    @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }
+    @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
 
     @computed get nativeWidth() { return this.Document.nativeWidth || 0; }
     @computed get nativeHeight() { return this.Document.nativeHeight || 0; }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 36d902c4f..df12f261b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -161,7 +161,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                     de.data.moveDocument(de.data.draggedDocuments[0], stackDoc, (doc) => {
                         Cast(stackDoc.data, listSpec(Doc))!.push(doc);
                         return true;
-                    })
+                    });
                 }
             }
         }
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 6b8b64c5f..f208ce2ce 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -188,8 +188,9 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
     }
     @action onError = () => {
         let timeout = this._curSuffix === "_s" ? this._smallRetryCount : this._curSuffix === "_m" ? this._mediumRetryCount : this._largeRetryCount;
-        if (timeout < 10)
+        if (timeout < 10) {
             setTimeout(this.retryPath, Math.min(10000, timeout * 5));
+        }
     }
     _curSuffix = "_m";
     render() {
diff --git a/src/client/views/pdf/PDFAnnotationLayer.tsx b/src/client/views/pdf/PDFAnnotationLayer.tsx
index e92dcacbf..1f49e0d2f 100644
--- a/src/client/views/pdf/PDFAnnotationLayer.tsx
+++ b/src/client/views/pdf/PDFAnnotationLayer.tsx
@@ -19,6 +19,6 @@ export class PDFAnnotationLayer extends React.Component {
             <div className="pdfAnnotationLayer-cont" style={{ width: "100%", height: "100%", position: "relative", top: "-200%" }} onPointerDown={this.onPointerDown}>
 
             </div>
-        )
+        );
     }
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 7817e8c26..2ed891131 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -162,6 +162,6 @@ export default class PDFMenu extends React.Component {
                 </button>
                 <div className="pdfMenu-dragger" onPointerDown={this.dragStart} style={{ width: this._pinned ? "20px" : "0px" }} />
             </div >
-        )
+        );
     }
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 69372f43b..8c0aaea00 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -198,7 +198,7 @@ class Viewer extends React.Component<IViewerProps> {
                 <Page
                     pdf={this.props.pdf}
                     page={page}
-                    numPages={this.props.pdf!.numPages}
+                    numPages={this.props.pdf.numPages}
                     key={`rendered-${page + 1}`}
                     name={`${this.props.pdf.fingerprint + `-page${page + 1}`}`}
                     pageLoaded={this.pageLoaded}
@@ -219,7 +219,7 @@ class Viewer extends React.Component<IViewerProps> {
     @action
     getPageImage = async (page: number) => {
         let handleError = () => this.getRenderedPage(page);
-        if (this._isPage[page] != "image") {
+        if (this._isPage[page] !== "image") {
             this._isPage[page] = "image";
             const address = this.props.url;
             let res = JSON.parse(await rp.get(DocServer.prepend(`/thumbnail${address.substring("files/".length, address.length - ".pdf".length)}-${page + 1}.PNG`)));
diff --git a/src/server/index.ts b/src/server/index.ts
index 7ef542b01..2901f61ed 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -172,7 +172,7 @@ function LoadPage(file: string, pageNumber: number, res: Response) {
                     canvasContext: canvasAndContext.context,
                     viewport: viewport,
                     canvasFactory: factory
-                }
+                };
                 console.log("read " + pageNumber);
 
                 page.render(renderContext).promise
-- 
cgit v1.2.3-70-g09d2


From e910a6cd56936234e451994c893d8592e430f828 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Tue, 25 Jun 2019 13:54:20 -0400
Subject: pdf view specs fixes/changes

---
 src/client/views/collections/CollectionPDFView.tsx |  4 ++
 src/client/views/nodes/DocumentView.tsx            | 13 +++-
 src/client/views/nodes/PDFBox.tsx                  | 44 ++++++++++---
 src/client/views/pdf/PDFMenu.scss                  |  7 ++
 src/client/views/pdf/PDFMenu.tsx                   | 55 +++++++++++-----
 src/client/views/pdf/PDFViewer.tsx                 | 75 ++++++++++++++++------
 6 files changed, 152 insertions(+), 46 deletions(-)

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

diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index b2d016934..31a73ab36 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -43,6 +43,10 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
         );
     }
 
+    componentWillUnmount() {
+        this._reactionDisposer && this._reactionDisposer();
+    }
+
     public static LayoutString(fieldKey: string = "data") {
         return FieldView.LayoutString(CollectionPDFView, fieldKey);
     }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 522c37989..f5a3f4d5d 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -117,6 +117,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
     private _mainCont = React.createRef<HTMLDivElement>();
     private _dropDisposer?: DragManager.DragDropDisposer;
 
+    @observable private _opacity: number = this.Document.opacity ? NumCast(this.Document.opacity) : 1;
+
     public get ContentDiv() { return this._mainCont.current; }
     @computed get active(): boolean { return SelectionManager.IsSelected(this) || this.props.parentActive(); }
     @computed get topMost(): boolean { return this.props.isTopMost; }
@@ -136,6 +138,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
 
     _animateToIconDisposer?: IReactionDisposer;
     _reactionDisposer?: IReactionDisposer;
+    _opacityDisposer?: IReactionDisposer;
     @action
     componentDidMount() {
         if (this._mainCont.current) {
@@ -160,6 +163,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             (values instanceof List) && this.animateBetweenIcon(values, values[2], values[3] ? true : false)
             , { fireImmediately: true });
         DocumentManager.Instance.DocumentViews.push(this);
+        this._opacityDisposer = reaction(
+            () => NumCast(this.props.Document.opacity),
+            () => {
+                runInAction(() => this._opacity = NumCast(this.props.Document.opacity));
+            }
+        );
     }
 
     animateBetweenIcon = (iconPos: number[], startTime: number, maximizing: boolean) => {
@@ -201,6 +210,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         if (this._reactionDisposer) this._reactionDisposer();
         if (this._animateToIconDisposer) this._animateToIconDisposer();
         if (this._dropDisposer) this._dropDisposer();
+        if (this._opacityDisposer) this._opacityDisposer();
         DocumentManager.Instance.DocumentViews.splice(DocumentManager.Instance.DocumentViews.indexOf(this), 1);
     }
 
@@ -559,7 +569,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     background: this.Document.backgroundColor || "",
                     width: nativeWidth,
                     height: nativeHeight,
-                    transform: `scale(${scaling}, ${scaling})`
+                    transform: `scale(${scaling}, ${scaling})`,
+                    opacity: this._opacity
                 }}
                 onDrop={this.onDrop} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
 
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index a129e89b9..c0f2d313a 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -18,9 +18,9 @@ import { pageSchema } from "./ImageBox";
 import "./PDFBox.scss";
 import React = require("react");
 import { CompileScript } from '../../util/Scripting';
-import { ScriptField } from '../../../fields/ScriptField';
 import { Flyout, anchorPoints } from '../DocumentDecorations';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { ScriptField } from '../../../new_fields/ScriptField';
 
 type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const PdfDocument = makeInterface(positionSchema, pageSchema);
@@ -37,6 +37,9 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     private _keyValue: string = "";
     private _valueValue: string = "";
     private _scriptValue: string = "";
+    private _keyRef: React.RefObject<HTMLInputElement>;
+    private _valueRef: React.RefObject<HTMLInputElement>;
+    private _scriptRef: React.RefObject<HTMLInputElement>;
 
     constructor(props: FieldViewProps) {
         super(props);
@@ -51,10 +54,9 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             }
         );
 
-        let script = CompileScript("return this.page === 0", { params: { this: Doc.name } });
-        if (script.compiled) {
-            this.props.Document.filterScript = new ScriptField(script);
-        }
+        this._keyRef = React.createRef();
+        this._valueRef = React.createRef();
+        this._scriptRef = React.createRef();
     }
 
     componentDidMount() {
@@ -99,17 +101,21 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         this._valueValue = e.currentTarget.value;
     }
 
+    @action
     private newScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._scriptValue = e.currentTarget.value;
     }
 
-    private applyFilter = (e: React.MouseEvent<HTMLButtonElement>) => {
+    private applyFilter = () => {
         let scriptText = "";
         if (this._scriptValue.length > 0) {
             scriptText = this._scriptValue;
         } else if (this._keyValue.length > 0 && this._valueValue.length > 0) {
             scriptText = `return this.${this._keyValue} === ${this._valueValue}`;
         }
+        else {
+            scriptText = "return true";
+        }
         let script = CompileScript(scriptText, { params: { this: Doc.name } });
         if (script.compiled) {
             this.props.Document.filterScript = new ScriptField(script);
@@ -121,6 +127,22 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         this._flyout = !this._flyout;
     }
 
+    @action
+    private resetFilters = () => {
+        this._keyValue = this._valueValue = "";
+        this._scriptValue = "return true";
+        if (this._keyRef.current) {
+            this._keyRef.current.value = "";
+        }
+        if (this._valueRef.current) {
+            this._valueRef.current.value = "";
+        }
+        if (this._scriptRef.current) {
+            this._scriptRef.current.value = "";
+        }
+        this.applyFilter();
+    }
+
     settingsPanel() {
         return !this.props.active() ? (null) :
             (
@@ -144,14 +166,18 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
                         </div>
                         <div className="pdfBox-settingsFlyout-kvpInput">
                             <input placeholder="Key" className="pdfBox-settingsFlyout-input" onChange={this.newKeyChange}
-                                style={{ gridColumn: 1 }} />
+                                style={{ gridColumn: 1 }} ref={this._keyRef} />
                             <input placeholder="Value" className="pdfBox-settingsFlyout-input" onChange={this.newValueChange}
-                                style={{ gridColumn: 3 }} />
+                                style={{ gridColumn: 3 }} ref={this._valueRef} />
                         </div>
                         <div className="pdfBox-settingsFlyout-kvpInput">
-                            <input placeholder="Custom Script" onChange={this.newScriptChange} style={{ gridColumn: "1 / 4" }} />
+                            <input placeholder="Custom Script" onChange={this.newScriptChange} style={{ gridColumn: "1 / 4" }} ref={this._scriptRef} />
                         </div>
                         <div className="pdfBox-settingsFlyout-kvpInput">
+                            <button style={{ gridColumn: 1 }} onClick={this.resetFilters}>
+                                <FontAwesomeIcon style={{ color: "white" }} icon="trash" size="lg" />
+                                &nbsp; Reset Filters
+                            </button>
                             <button style={{ gridColumn: 3 }} onClick={this.applyFilter}>
                                 <FontAwesomeIcon style={{ color: "white" }} icon="check" size="lg" />
                                 &nbsp; Apply
diff --git a/src/client/views/pdf/PDFMenu.scss b/src/client/views/pdf/PDFMenu.scss
index 22868082a..a4624b1f6 100644
--- a/src/client/views/pdf/PDFMenu.scss
+++ b/src/client/views/pdf/PDFMenu.scss
@@ -22,4 +22,11 @@
         height: 100%;
         transition: width .2s;
     }
+
+    .pdfMenu-addTag {
+        display: grid;
+        width: 200px;
+        padding: 5px;
+        grid-template-columns: 90px 20px 90px;
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index a8e176858..e58ad9ccc 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -1,9 +1,9 @@
 import React = require("react");
 import "./PDFMenu.scss";
-import { observable, action } from "mobx";
+import { observable, action, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { emptyFunction } from "../../../Utils";
+import { emptyFunction, returnZero, returnTrue, returnFalse } from "../../../Utils";
 import { Doc } from "../../../new_fields/Doc";
 import { DragManager } from "../../util/DragManager";
 import { DocUtils } from "../../documents/Documents";
@@ -23,6 +23,7 @@ export default class PDFMenu extends React.Component {
     Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction;
     Delete: () => void = emptyFunction;
     Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction;
+    AddTag: (key: string, value: string) => boolean = returnFalse;
 
     @observable public Highlighting: boolean = false;
     @observable public Status: "pdf" | "annotation" | "snippet" | "" = "";
@@ -35,6 +36,9 @@ export default class PDFMenu extends React.Component {
     private _mainCont: React.RefObject<HTMLDivElement>;
     private _dragging: boolean = false;
     private _snippetButton: React.RefObject<HTMLButtonElement>;
+    @observable private _keyValue: string = "";
+    @observable private _valueValue: string = "";
+    @observable private _added: boolean = false;;
 
     constructor(props: Readonly<{}>) {
         super(props);
@@ -209,35 +213,56 @@ export default class PDFMenu extends React.Component {
         e.preventDefault();
     }
 
+    @action
+    keyChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
+        this._keyValue = e.currentTarget.value;
+    }
+
+    @action
+    valueChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
+        this._valueValue = e.currentTarget.value;
+    }
+
+    @action
+    addTag = (e: React.PointerEvent) => {
+        if (this._keyValue.length > 0 && this._valueValue.length > 0) {
+            this._added = this.AddTag(this._keyValue, this._valueValue);
+
+            setTimeout(
+                () => {
+                    runInAction(() => {
+                        this._added = false;
+                    });
+                }, 1000
+            );
+        }
+    }
+
     render() {
         let buttons = this.Status === "pdf" || this.Status === "snippet" ? [
-            <button className="pdfMenu-button" title="Click to Highlight" onClick={this.highlightClicked}
+            <button className="pdfMenu-button" title="Click to Highlight" onClick={this.highlightClicked} key="1"
                 style={this.Highlighting ? { backgroundColor: "#121212" } : {}}>
                 <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} />
             </button>,
-            <button className="pdfMenu-button" title="Drag to Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="lg" /></button>,
+            <button className="pdfMenu-button" title="Drag to Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="lg" key="2" /></button>,
             this.Status === "snippet" ? <button className="pdfMenu-button" title="Drag to Snippetize Selection" onPointerDown={this.snippetStart} ref={this._snippetButton}><FontAwesomeIcon icon="cut" size="lg" /></button> : undefined,
-            <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin}
+            <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin} key="3"
                 style={this.Pinned ? { backgroundColor: "#121212" } : {}}>
                 <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this.Pinned ? "rotate(45deg)" : "" }} />
             </button>
         ] : [
-                <button className="pdfMenu-button" title="Delete Anchor" onPointerDown={this.deleteClicked}><FontAwesomeIcon icon="trash-alt" size="lg" /></button>
+                <button className="pdfMenu-button" title="Delete Anchor" onPointerDown={this.deleteClicked}><FontAwesomeIcon icon="trash-alt" size="lg" key="1" /></button>,
+                <div className="pdfMenu-addTag" key="2">
+                    <input onChange={this.keyChanged} placeholder="Key" style={{ gridColumn: 1 }} />
+                    <input onChange={this.valueChanged} placeholder="Value" style={{ gridColumn: 3 }} />
+                </div>,
+                <button className="pdfMenu-button" title={`Add tag: ${this._keyValue} with value: ${this._valueValue}`} onPointerDown={this.addTag}><FontAwesomeIcon style={{ transition: "all .2s" }} color={this._added ? "#42f560" : "white"} icon="check" size="lg" key="3" /></button>,
             ];
 
         return (
             <div className="pdfMenu-cont" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont} onContextMenu={this.handleContextMenu}
                 style={{ left: this._left, top: this._top, opacity: this._opacity, transition: this._transition, transitionDelay: this._transitionDelay }}>
                 {buttons}
-                {/* <button className="pdfMenu-button" title="Highlight" onClick={this.highlightClicked}
-                    style={this.Highlighting ? { backgroundColor: "#121212" } : {}}>
-                    <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} />
-                </button>
-                <button className="pdfMenu-button" title="Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="lg" /></button>
-                <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin}
-                    style={this._pinned ? { backgroundColor: "#121212" } : {}}>
-                    <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this._pinned ? "rotate(45deg)" : "" }} />
-                </button> */}
                 <div className="pdfMenu-dragger" onPointerDown={this.dragStart} style={{ width: this.Pinned ? "20px" : "0px" }} />
             </div >
         );
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 1eab13bc5..3df7dd77b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -20,8 +20,8 @@ import "./PDFViewer.scss";
 import React = require("react");
 import PDFMenu from "./PDFMenu";
 import { UndoManager } from "../../util/UndoManager";
-import { ScriptField } from "../../../fields/ScriptField";
 import { CompileScript, CompiledScript, CompileResult } from "../../util/Scripting";
+import { ScriptField } from "../../../new_fields/ScriptField";
 
 export const scale = 2;
 interface IPDFViewerProps {
@@ -63,8 +63,6 @@ interface IViewerProps {
     url: string;
 }
 
-const PinRadius = 25;
-
 /**
  * Handles rendering and virtualization of the pdf
  */
@@ -85,14 +83,18 @@ class Viewer extends React.Component<IViewerProps> {
     private _annotationReactionDisposer?: IReactionDisposer;
     private _dropDisposer?: DragManager.DragDropDisposer;
     private _filterReactionDisposer?: IReactionDisposer;
+    private _viewer: React.RefObject<HTMLDivElement>;
+    private _mainCont: React.RefObject<HTMLDivElement>;
+    private _textContent: Pdfjs.TextContent[] = [];
 
-    @action
-        constructor(props: IViewerProps) {
-            super(props);
+    constructor(props: IViewerProps) {
+        super(props);
 
-            let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField);
-            this._script = scriptfield ? CompileScript(scriptfield.scriptString, { params: { this: Doc.name } }) : CompileScript("return true");;
-        }
+        let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField);
+        this._script = scriptfield ? scriptfield.script : CompileScript("return true");
+        this._viewer = React.createRef();
+        this._mainCont = React.createRef();
+    }
 
     componentDidUpdate = (prevProps: IViewerProps) => {
         if (this.scrollY !== prevProps.scrollY) {
@@ -118,21 +120,37 @@ class Viewer extends React.Component<IViewerProps> {
 
         if (this.props.parent.props.ContainingCollectionView) {
             this._filterReactionDisposer = reaction(
-                () => this.props.parent.Document.filterScript || this.props.parent.props.ContainingCollectionView!.props.Document.filterScript,
+                () => this.props.parent.Document.filterScript,
                 () => {
                     runInAction(() => {
                         let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField);
-                        this._script = scriptfield ? CompileScript(scriptfield.scriptString, { params: { this: Doc.name } }) : CompileScript("return true");;
+                        this._script = scriptfield ? scriptfield.script : CompileScript("return true");
+                        if (this.props.parent.props.ContainingCollectionView) {
+                            let ccvAnnos = DocListCast(this.props.parent.props.ContainingCollectionView.props.Document.annotations);
+                            ccvAnnos.forEach(d => {
+                                if (this._script && this._script.compiled) {
+                                    let run = this._script.run(d);
+                                    if (run.success) {
+                                        d.opacity = run.result ? 1 : 0;
+                                    }
+                                }
+                            })
+                        }
                     });
                 }
             );
         }
+
+        if (this._mainCont.current) {
+            this._dropDisposer = this._mainCont.current && DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } });
+        }
     }
 
     componentWillUnmount = () => {
         this._reactionDisposer && this._reactionDisposer();
         this._annotationReactionDisposer && this._annotationReactionDisposer();
         this._filterReactionDisposer && this._filterReactionDisposer();
+        this._dropDisposer && this._dropDisposer();
     }
 
     @action
@@ -140,10 +158,14 @@ class Viewer extends React.Component<IViewerProps> {
         if (this._pageSizes.length === 0) {
             let pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages);
             this._isPage = Array<string>(this.props.pdf.numPages);
+            this._textContent = Array<Pdfjs.TextContent>(this.props.pdf.numPages);
             for (let i = 0; i < this.props.pdf.numPages; i++) {
                 await this.props.pdf.getPage(i + 1).then(page => runInAction(() => {
                     // pageSizes[i] = { width: page.view[2] * scale, height: page.view[3] * scale };
                     let x = page.getViewport(scale);
+                    page.getTextContent().then((text: Pdfjs.TextContent) => {
+                        this._textContent[i] = text;
+                    })
                     pageSizes[i] = { width: x.width, height: x.height };
                 }));
             }
@@ -162,13 +184,6 @@ class Viewer extends React.Component<IViewerProps> {
         }
     }
 
-    private mainCont = (div: HTMLDivElement | null) => {
-        this._dropDisposer && this._dropDisposer();
-        if (div) {
-            this._dropDisposer = div && DragManager.MakeDropTarget(div, { handlers: { drop: this.drop.bind(this) } });
-        }
-    }
-
     makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string): Doc => {
         let annoDocs: Doc[] = [];
         let mainAnnoDoc = Docs.CreateInstance(new Doc(), "", {});
@@ -222,6 +237,7 @@ class Viewer extends React.Component<IViewerProps> {
     pageLoaded = (index: number, page: Pdfjs.PDFPageViewport): void => {
         this.props.loaded(page.width, page.height, this.props.pdf.numPages);
     }
+
     @action
     getPlaceholderPage = (page: number) => {
         if (this._isPage[page] !== "none") {
@@ -232,6 +248,7 @@ class Viewer extends React.Component<IViewerProps> {
             );
         }
     }
+
     @action
     getRenderedPage = (page: number) => {
         if (this._isPage[page] !== "page") {
@@ -374,11 +391,16 @@ class Viewer extends React.Component<IViewerProps> {
         return res;
     }
 
+    pointerDown = () => {
+
+        let x = this._textContent;
+    }
+
     render() {
         let compiled = this._script;
         return (
-            <div ref={this.mainCont} style={{ pointerEvents: "all" }}>
-                <div className="viewer">
+            <div ref={this._mainCont} style={{ pointerEvents: "all" }} onPointerDown={this.pointerDown}>
+                <div className="viewer" ref={this._viewer}>
                     {this._visibleElements}
                 </div>
                 <div className="pdfViewer-annotationLayer"
@@ -472,12 +494,23 @@ class RegionAnnotation extends React.Component<IAnnotationProps> {
         }
         if (e.button === 2) {
             PDFMenu.Instance.Status = "annotation";
-            PDFMenu.Instance.Delete = this.deleteAnnotation;
+            PDFMenu.Instance.Delete = this.deleteAnnotation.bind(this);
             PDFMenu.Instance.Pinned = false;
+            PDFMenu.Instance.AddTag = this.addTag.bind(this);
             PDFMenu.Instance.jumpTo(e.clientX, e.clientY, true);
         }
     }
 
+    addTag = (key: string, value: string): boolean => {
+        let group = FieldValue(Cast(this.props.document.group, Doc));
+        if (group) {
+            let valNum = parseInt(value);
+            group[key] = isNaN(valNum) ? value : valNum;
+            return true;
+        }
+        return false;
+    }
+
     render() {
         return (
             <div className="pdfViewer-annotationBox" onPointerDown={this.onPointerDown} ref={this._mainCont}
-- 
cgit v1.2.3-70-g09d2

