From 16eabe68912ec4e48fc4059f9b377fba0f076ab1 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Mon, 5 Aug 2019 00:43:49 -0400
Subject: a couple of fixes to PDF linking and scrolling

---
 src/client/views/pdf/Annotation.tsx | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

(limited to 'src/client/views/pdf/Annotation.tsx')

diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 513f9fed6..a08ff5969 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -1,16 +1,15 @@
 import React = require("react");
-import { Doc, DocListCast, WidthSym, HeightSym } from "../../../new_fields/Doc";
-import { AnnotationTypes, Viewer, scale } from "./PDFViewer";
+import { action, IReactionDisposer, observable, reaction } from "mobx";
 import { observer } from "mobx-react";
-import { observable, IReactionDisposer, reaction, action } from "mobx";
-import { BoolCast, NumCast, FieldValue, Cast, StrCast } from "../../../new_fields/Types";
+import { Doc, DocListCast, HeightSym, WidthSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
-import PDFMenu from "./PDFMenu";
+import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
 import { DocumentManager } from "../../util/DocumentManager";
 import { PresentationView } from "../presentationview/PresentationView";
-import { LinkManager } from "../../util/LinkManager";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
+import PDFMenu from "./PDFMenu";
+import "./Annotation.scss";
+import { AnnotationTypes, scale, Viewer } from "./PDFViewer";
 
 interface IAnnotationProps {
     anno: Doc;
@@ -118,8 +117,9 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
             if (targetDoc) {
                 let context = await Cast(targetDoc.targetContext, Doc);
                 if (context) {
-                    DocumentManager.Instance.jumpToDocument(targetDoc, false, undefined,
-                        ((doc) => this.props.parent.props.parent.props.addDocTab(context!, context!.proto, e.ctrlKey ? "onRight" : "inTab")));
+                    DocumentManager.Instance.jumpToDocument(targetDoc, false, false,
+                        ((doc) => this.props.parent.props.parent.props.addDocTab(targetDoc!, undefined, e.ctrlKey ? "onRight" : "inTab")),
+                        undefined, undefined);
                 }
             }
         }
@@ -151,7 +151,6 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
                     left: this.props.x * scale,
                     width: this.props.width * scale,
                     height: this.props.height * scale,
-                    pointerEvents: "all",
                     backgroundColor: this.props.parent.Index === this.props.index ? "green" : StrCast(this.props.document.color)
                 }}></div>
         );
-- 
cgit v1.2.3-70-g09d2


From 9419693f37ad53fcc0763a118d2cb865659a2ff4 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 6 Aug 2019 14:08:59 -0400
Subject: multiple changes to PDF related code -- mostly clean up

---
 src/client/views/collections/CollectionPDFView.tsx |  61 +--
 src/client/views/nodes/PDFBox.tsx                  | 241 +++++-------
 src/client/views/pdf/Annotation.tsx                |  69 ++--
 src/client/views/pdf/PDFMenu.tsx                   | 123 +++---
 src/client/views/pdf/PDFViewer.scss                |  14 +-
 src/client/views/pdf/PDFViewer.tsx                 | 412 ++++++---------------
 src/client/views/pdf/Page.tsx                      | 246 +++---------
 7 files changed, 389 insertions(+), 777 deletions(-)

(limited to 'src/client/views/pdf/Annotation.tsx')

diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 70010819a..3736ebada 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -1,36 +1,31 @@
-import { action, IReactionDisposer, observable, reaction } from "mobx";
+import { action, IReactionDisposer, observable, reaction, computed } from "mobx";
 import { observer } from "mobx-react";
-import { WidthSym, HeightSym } 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 { PDFBox } from "../nodes/PDFBox";
 import { CollectionBaseView, CollectionRenderProps, CollectionViewType } from "./CollectionBaseView";
 import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView";
 import "./CollectionPDFView.scss";
 import React = require("react");
-import { PDFBox } from "../nodes/PDFBox";
 
 
 @observer
 export class CollectionPDFView extends React.Component<FieldViewProps> {
+    public static LayoutString(fieldKey: string = "data", fieldExt: string = "annotations") {
+        return FieldView.LayoutString(CollectionPDFView, fieldKey, fieldExt);
+    }
+
     private _pdfBox?: PDFBox;
     private _reactionDisposer?: IReactionDisposer;
-    private _buttonTray: React.RefObject<HTMLDivElement>;
-
-    constructor(props: FieldViewProps) {
-        super(props);
-
-        this._buttonTray = React.createRef();
-    }
+    private _buttonTray: React.RefObject<HTMLDivElement> = React.createRef();
 
     componentDidMount() {
         this._reactionDisposer = reaction(
             () => NumCast(this.props.Document.scrollY),
-            () => {
-                this.props.Document.panY = NumCast(this.props.Document.scrollY);
-            },
+            () => this.props.Document.panY = NumCast(this.props.Document.scrollY),
             { fireImmediately: true }
         );
     }
@@ -39,28 +34,12 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
         this._reactionDisposer && this._reactionDisposer();
     }
 
-    public static LayoutString(fieldKey: string = "data", fieldExt: string = "annotations") {
-        return FieldView.LayoutString(CollectionPDFView, fieldKey, fieldExt);
-    }
-    @observable _inThumb = false;
-
-    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._pdfBox && this._pdfBox.BackPage();
-    @action onPageForward = () => this._pdfBox && this._pdfBox.ForwardPage();
-
-    nativeWidth = () => NumCast(this.props.Document.nativeWidth);
-    nativeHeight = () => NumCast(this.props.Document.nativeHeight);
-    private get uIButtons() {
-        let ratio = (this.curPage - 1) / this.numPages * 100;
+    @computed
+    get uIButtons() {
         return (
             <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-thumb" onPointerDown={this.onThumbDown} style={{ top: `${ratio}%`, width: 50, height: 50 }} />
-                </div> */}
+                <button className="collectionPdfView-backward" onClick={() => this._pdfBox && this._pdfBox.BackPage()}>{"<"}</button>
+                <button className="collectionPdfView-forward" onClick={() => this._pdfBox && this._pdfBox.ForwardPage()}>{">"}</button>
             </div>
         );
     }
@@ -73,20 +52,16 @@ 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} setPdfBox={this.setPdfBox} CollectionView={this} chromeCollapsed={true} />
-                {renderProps.active() ? this.uIButtons : (null)}
-            </>
-        );
+    subView = (_type: CollectionViewType, renderProps: CollectionRenderProps) => {
+        return (<>
+            <CollectionFreeFormView {...this.props} {...renderProps} setPdfBox={this.setPdfBox} CollectionView={this} chromeCollapsed={true} />
+            {renderProps.active() ? this.uIButtons : (null)}
+        </>);
     }
 
     render() {
         return (
-            <CollectionBaseView {...this.props} className={`collectionPdfView-cont${this._inThumb ? "-dragging" : ""}`} onContextMenu={this.onContextMenu}>
+            <CollectionBaseView {...this.props} className={"collectionPdfView-cont"} onContextMenu={this.onContextMenu}>
                 {this.subView}
             </CollectionBaseView>
         );
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index a49709e83..56e720bf7 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -1,31 +1,24 @@
-import { action, IReactionDisposer, observable, reaction, trace, untracked, computed } from 'mobx';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from "mobx-react";
+import * as Pdfjs from "pdfjs-dist";
+import "pdfjs-dist/web/pdf_viewer.css";
 import 'react-image-lightbox/style.css';
-import { WidthSym, Doc } from "../../../new_fields/Doc";
+import { Doc, WidthSym, Opt } from "../../../new_fields/Doc";
 import { makeInterface } from "../../../new_fields/Schema";
-import { Cast, NumCast, BoolCast } from "../../../new_fields/Types";
+import { ScriptField } from '../../../new_fields/ScriptField';
+import { BoolCast, 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 { KeyCodes } from '../../northstar/utils/KeyCodes';
+import { CompileScript } from '../../util/Scripting';
 import { DocComponent } from "../DocComponent";
 import { InkingControl } from "../InkingControl";
-import { FilterBox } from "../search/FilterBox";
-import { Annotation } from './Annotation';
 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 { CompileScript } from '../../util/Scripting';
-import { Flyout, anchorPoints } from '../DocumentDecorations';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { ScriptField } from '../../../new_fields/ScriptField';
-import { KeyCodes } from '../../northstar/utils/KeyCodes';
-import { Utils } from '../../../Utils';
-import { Id } from '../../../new_fields/FieldSymbols';
 
 type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const PdfDocument = makeInterface(positionSchema, pageSchema);
@@ -35,40 +28,33 @@ export const handleBackspace = (e: React.KeyboardEvent) => { if (e.keyCode === K
 export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocument) {
     public static LayoutString() { return FieldView.LayoutString(PDFBox); }
 
+    @observable private _flyout: boolean = false;
     @observable private _alt = false;
     @observable private _scrollY: number = 0;
+    @observable private _pdf: Opt<Pdfjs.PDFDocumentProxy>;
+    @computed get containingCollectionDocument() { return this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document; }
     @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; }
 
-    @observable private _flyout: boolean = false;
-    private _mainCont: React.RefObject<HTMLDivElement>;
+    private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
     private _reactionDisposer?: IReactionDisposer;
     private _keyValue: string = "";
     private _valueValue: string = "";
     private _scriptValue: string = "";
-    private _keyRef: React.RefObject<HTMLInputElement>;
-    private _valueRef: React.RefObject<HTMLInputElement>;
-    private _scriptRef: React.RefObject<HTMLInputElement>;
+    private _keyRef: React.RefObject<HTMLInputElement> = React.createRef();
+    private _valueRef: React.RefObject<HTMLInputElement> = React.createRef();
+    private _scriptRef: React.RefObject<HTMLInputElement> = React.createRef();
 
-    constructor(props: FieldViewProps) {
-        super(props);
+    componentDidMount() {
+        this.props.setPdfBox && this.props.setPdfBox(this);
 
-        this._mainCont = React.createRef();
+        const pdfUrl = Cast(this.props.Document.data, PdfField);
+        if (pdfUrl instanceof PdfField) {
+            Pdfjs.getDocument(pdfUrl.url.pathname).promise.then(pdf => runInAction(() => this._pdf = pdf));
+        }
         this._reactionDisposer = reaction(
             () => this.props.Document.scrollY,
-            () => {
-                if (this._mainCont.current) {
-                    this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "auto" });
-                }
-            }
+            () => this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "auto" })
         );
-
-        this._keyRef = React.createRef();
-        this._valueRef = React.createRef();
-        this._scriptRef = React.createRef();
-    }
-
-    componentDidMount() {
-        if (this.props.setPdfBox) this.props.setPdfBox(this);
     }
 
     componentWillUnmount() {
@@ -78,6 +64,8 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     public GetPage() {
         return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.pdfHeight)) + 1;
     }
+
+    @action
     public BackPage() {
         let cp = Math.ceil(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.pdfHeight)) + 1;
         cp = cp - 1;
@@ -86,6 +74,8 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.pdfHeight);
         }
     }
+
+    @action
     public GotoPage(p: number) {
         if (p > 0 && p <= NumCast(this.props.Document.numPages)) {
             this.props.Document.curPage = p;
@@ -93,6 +83,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         }
     }
 
+    @action
     public ForwardPage() {
         let cp = this.GetPage() + 1;
         if (cp <= NumCast(this.props.Document.numPages)) {
@@ -101,6 +92,15 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         }
     }
 
+    scrollTo = (y: number) => {
+        this._mainCont.current && this._mainCont.current.scrollTo({ top: Math.max(y - (this._mainCont.current.offsetHeight / 2), 0), behavior: "auto" });
+    }
+
+    @action
+    setPanY = (y: number) => {
+        this.containingCollectionDocument && (this.containingCollectionDocument.panY = y);
+    }
+
     private newKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._keyValue = e.currentTarget.value;
     }
@@ -109,151 +109,110 @@ 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 = () => {
-        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 scriptText = this._scriptValue.length > 0 ? this._scriptValue :
+            this._keyValue.length > 0 && this._valueValue.length > 0 ?
+                `return this.${this._keyValue} === ${this._valueValue}` : "return true";
         let script = CompileScript(scriptText, { params: { this: Doc.name } });
-        if (script.compiled) {
-            this.props.Document.filterScript = new ScriptField(script);
-        }
-    }
-
-    @action
-    private toggleFlyout = () => {
-        this._flyout = !this._flyout;
+        script.compiled && (this.props.Document.filterScript = new ScriptField(script));
     }
 
     @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._keyRef.current && (this._keyRef.current.value = "");
+        this._valueRef.current && (this._valueRef.current.value = "");
+        this._scriptRef.current && (this._scriptRef.current.value = "");
         this.applyFilter();
     }
 
-    scrollTo(y: number) {
-        this._mainCont.current && this._mainCont.current.scrollTo({ top: Math.max(y - (this._mainCont.current.offsetHeight / 2), 0), behavior: "auto" });
-    }
-
     settingsPanel() {
         return !this.props.active() ? (null) :
-            (
-                <div className="pdfBox-settingsCont" onPointerDown={(e) => e.stopPropagation()}>
-                    <button className="pdfBox-settingsButton" onClick={this.toggleFlyout} title="Open Annotation Settings"
-                        style={{ marginTop: `${NumCast(this.props.ContainingCollectionView!.props.Document.panY)}px` }}>
-                        <div className="pdfBox-settingsButton-arrow"
-                            style={{
-                                borderTop: `25px solid ${this._flyout ? "#121721" : "transparent"}`,
-                                borderBottom: `25px solid ${this._flyout ? "#121721" : "transparent"}`,
-                                borderRight: `25px solid ${this._flyout ? "transparent" : "#121721"}`,
-                                transform: `scaleX(${this._flyout ? -1 : 1})`
-                            }}></div>
-                        <div className="pdfBox-settingsButton-iconCont">
-                            <FontAwesomeIcon style={{ color: "white" }} icon="cog" size="3x" />
-                        </div>
-                    </button>
-                    <div className="pdfBox-settingsFlyout" style={{ left: `${this._flyout ? -600 : 100}px` }} >
-                        <div className="pdfBox-settingsFlyout-title">
-                            Annotation View Settings
-                        </div>
-                        <div className="pdfBox-settingsFlyout-kvpInput">
-                            <input placeholder="Key" className="pdfBox-settingsFlyout-input" onKeyDown={handleBackspace} onChange={this.newKeyChange}
-                                style={{ gridColumn: 1 }} ref={this._keyRef} />
-                            <input placeholder="Value" className="pdfBox-settingsFlyout-input" onKeyDown={handleBackspace} onChange={this.newValueChange}
-                                style={{ gridColumn: 3 }} ref={this._valueRef} />
-                        </div>
-                        <div className="pdfBox-settingsFlyout-kvpInput">
-                            <input placeholder="Custom Script" onChange={this.newScriptChange} onKeyDown={handleBackspace} style={{ gridColumn: "1 / 4" }} ref={this._scriptRef} />
-                        </div>
-                        <div className="pdfBox-settingsFlyout-kvpInput">
-                            <button style={{ gridColumn: 1 }} onClick={this.resetFilters}>
-                                <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
-                            </button>
-                        </div>
+            (<div className="pdfBox-settingsCont" onPointerDown={(e) => e.stopPropagation()}>
+                <button className="pdfBox-settingsButton" onClick={action(() => this._flyout = !this._flyout)} title="Open Annotation Settings"
+                    style={{ marginTop: `${this.containingCollectionDocument ? NumCast(this.containingCollectionDocument.panY) : 0}px` }}>
+                    <div className="pdfBox-settingsButton-arrow"
+                        style={{
+                            borderTop: `25px solid ${this._flyout ? "#121721" : "transparent"}`,
+                            borderBottom: `25px solid ${this._flyout ? "#121721" : "transparent"}`,
+                            borderRight: `25px solid ${this._flyout ? "transparent" : "#121721"}`,
+                            transform: `scaleX(${this._flyout ? -1 : 1})`
+                        }} />
+                    <div className="pdfBox-settingsButton-iconCont">
+                        <FontAwesomeIcon style={{ color: "white" }} icon="cog" size="3x" />
+                    </div>
+                </button>
+                <div className="pdfBox-settingsFlyout" style={{ left: `${this._flyout ? -600 : 100}px` }} >
+                    <div className="pdfBox-settingsFlyout-title">
+                        Annotation View Settings
+                    </div>
+                    <div className="pdfBox-settingsFlyout-kvpInput">
+                        <input placeholder="Key" className="pdfBox-settingsFlyout-input" onKeyDown={handleBackspace} onChange={this.newKeyChange}
+                            style={{ gridColumn: 1 }} ref={this._keyRef} />
+                        <input placeholder="Value" className="pdfBox-settingsFlyout-input" onKeyDown={handleBackspace} onChange={this.newValueChange}
+                            style={{ gridColumn: 3 }} ref={this._valueRef} />
+                    </div>
+                    <div className="pdfBox-settingsFlyout-kvpInput">
+                        <input placeholder="Custom Script" onChange={this.newScriptChange} onKeyDown={handleBackspace} style={{ gridColumn: "1 / 4" }} ref={this._scriptRef} />
+                    </div>
+                    <div className="pdfBox-settingsFlyout-kvpInput">
+                        <button style={{ gridColumn: 1 }} onClick={this.resetFilters}>
+                            <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
+                        </button>
                     </div>
                 </div>
-            );
+            </div>);
     }
 
     loaded = (nw: number, nh: number, np: number) => {
-        if (this.props.Document) {
-            let doc = this.dataDoc;
-            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;
-            else doc.nativeHeight = nh;
-            let ccv = this.props.ContainingCollectionView;
-            if (ccv) {
-                ccv.props.Document.pdfHeight = nh;
-            }
-            doc.height = nh * (doc[WidthSym]() / nw);
+        this.dataDoc.numPages = np;
+        if (!this.dataDoc.nativeWidth || !this.dataDoc.nativeHeight) {
+            let oldaspect = NumCast(this.dataDoc.nativeHeight) / NumCast(this.dataDoc.nativeWidth, 1);
+            this.dataDoc.nativeWidth = nw;
+            this.dataDoc.nativeHeight = this.dataDoc.nativeHeight ? nw * oldaspect : nh;
+            this.containingCollectionDocument && (this.containingCollectionDocument.pdfHeight = nh);
+            this.dataDoc.height = nh * (this.dataDoc[WidthSym]() / nw);
         }
     }
 
     @action
     onScroll = (e: React.UIEvent<HTMLDivElement>) => {
-
-        if (e.currentTarget) {
-            this._scrollY = e.currentTarget.scrollTop;
-            let ccv = this.props.ContainingCollectionView;
-            if (ccv) {
-                ccv.props.Document.panTransformType = "None";
-                ccv.props.Document.scrollY = this._scrollY;
-            }
+        if (e.currentTarget && this.containingCollectionDocument) {
+            this.containingCollectionDocument.panTransformType = "None";
+            this.containingCollectionDocument.scrollY = this._scrollY = e.currentTarget.scrollTop;
         }
     }
 
-
     @computed get fieldExtensionDoc() {
         return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true");
     }
+
     render() {
-        // uses mozilla pdf as default
         const pdfUrl = Cast(this.props.Document.data, PdfField);
-        if (!(pdfUrl instanceof PdfField)) return <div>{`pdf, ${this.props.Document.data}, not found`}</div>;
         let classname = "pdfBox-cont" + (this.props.active() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
-        return (
+        return (!(pdfUrl instanceof PdfField) || !this._pdf ?
+            <div>{`pdf, ${this.props.Document.data}, not found`}</div> :
             <div className={classname}
                 onScroll={this.onScroll}
-                style={{
-                    marginTop: `${NumCast(this.props.ContainingCollectionView!.props.Document.panY)}px`
-                }}
+                style={{ marginTop: `${this.containingCollectionDocument ? NumCast(this.containingCollectionDocument.panY) : 0}px` }}
                 ref={this._mainCont}
-                onWheel={(e: React.WheelEvent) => {
-                    e.stopPropagation();
-                }}>
-                <PDFViewer url={pdfUrl.url.pathname} loaded={this.loaded} scrollY={this._scrollY} parent={this} />
-                {/* <div style={{ width: "100px", height: "300px" }}></div> */}
+                onWheel={(e: React.WheelEvent) => { e.stopPropagation(); }}>
+                <PDFViewer pdf={this._pdf} url={pdfUrl.url.pathname} active={this.props.active} scrollTo={this.scrollTo} loaded={this.loaded} scrollY={this._scrollY}
+                    Document={this.props.Document} DataDoc={this.props.DataDoc}
+                    addDocTab={this.props.addDocTab} setPanY={this.setPanY}
+                    fieldKey={this.props.fieldKey} fieldExtensionDoc={this.fieldExtensionDoc} />
                 {this.settingsPanel()}
             </div>
         );
     }
-
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index a08ff5969..9d68a86b8 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -4,17 +4,20 @@ import { observer } from "mobx-react";
 import { Doc, DocListCast, HeightSym, WidthSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
-import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
+import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
 import { DocumentManager } from "../../util/DocumentManager";
 import { PresentationView } from "../presentationview/PresentationView";
 import PDFMenu from "./PDFMenu";
 import "./Annotation.scss";
-import { AnnotationTypes, scale, Viewer } from "./PDFViewer";
+import { AnnotationTypes, scale } from "./PDFViewer";
 
 interface IAnnotationProps {
     anno: Doc;
     index: number;
-    parent: Viewer;
+    ParentIndex: () => number;
+    fieldExtensionDoc: Doc;
+    scrollTo?: (n: number) => void;
+    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void;
 }
 
 export default class Annotation extends React.Component<IAnnotationProps> {
@@ -23,10 +26,8 @@ export default class Annotation extends React.Component<IAnnotationProps> {
         let res = annotationDocs.map(a => {
             let type = NumCast(a.type);
             switch (type) {
-                // case AnnotationTypes.Pin:
-                //     return <PinAnnotation parent={this} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />;
                 case AnnotationTypes.Region:
-                    return <RegionAnnotation parent={this.props.parent} document={a} index={this.props.index} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />;
+                    return <RegionAnnotation addDocTab={this.props.addDocTab} document={a} fieldExtensionDoc={this.props.fieldExtensionDoc} scrollTo={this.props.scrollTo} ParentIndex={this.props.ParentIndex} index={this.props.index} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />;
                 default:
                     return <div></div>;
             }
@@ -41,7 +42,10 @@ interface IRegionAnnotationProps {
     width: number;
     height: number;
     index: number;
-    parent: Viewer;
+    ParentIndex: () => number;
+    fieldExtensionDoc: Doc;
+    scrollTo?: (n: number) => void;
+    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void;
     document: Doc;
 }
 
@@ -51,34 +55,18 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
 
     private _reactionDisposer?: IReactionDisposer;
     private _scrollDisposer?: IReactionDisposer;
-    private _mainCont: React.RefObject<HTMLDivElement>;
-
-    constructor(props: IRegionAnnotationProps) {
-        super(props);
-
-        this._mainCont = React.createRef();
-    }
+    private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
 
     componentDidMount() {
         this._reactionDisposer = reaction(
-            () => BoolCast(this.props.document.delete),
-            () => {
-                if (BoolCast(this.props.document.delete)) {
-                    if (this._mainCont.current) {
-                        this._mainCont.current.style.display = "none";
-                    }
-                }
-            },
+            () => this.props.document.delete,
+            () => this.props.document.delete && this._mainCont.current && (this._mainCont.current.style.display = "none"),
             { fireImmediately: true }
         );
 
         this._scrollDisposer = reaction(
-            () => this.props.parent.Index,
-            () => {
-                if (this.props.parent.Index === this.props.index) {
-                    this.props.parent.scrollTo(this.props.y * scale);
-                }
-            }
+            () => this.props.ParentIndex(),
+            () => this.props.ParentIndex() === this.props.index && this.props.scrollTo && this.props.scrollTo(this.props.y * scale)
         );
     }
 
@@ -88,16 +76,15 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
     }
 
     deleteAnnotation = () => {
-        let annotation = DocListCast(this.props.parent.props.parent.fieldExtensionDoc.annotations);
+        let annotation = DocListCast(this.props.fieldExtensionDoc.annotations);
         let group = FieldValue(Cast(this.props.document.group, Doc));
-        if (group && annotation.indexOf(group) !== -1) {
-            let newAnnotations = annotation.filter(a => a !== FieldValue(Cast(this.props.document.group, Doc)));
-            this.props.parent.props.parent.fieldExtensionDoc.annotations = new List<Doc>(newAnnotations);
-        }
-
         if (group) {
-            let groupAnnotations = DocListCast(group.annotations);
-            groupAnnotations.forEach(anno => anno.delete = true);
+            if (annotation.indexOf(group) !== -1) {
+                let newAnnotations = annotation.filter(a => a !== FieldValue(Cast(this.props.document.group, Doc)));
+                this.props.fieldExtensionDoc.annotations = new List<Doc>(newAnnotations);
+            }
+
+            DocListCast(group.annotations).forEach(anno => anno.delete = true);
         }
 
         PDFMenu.Instance.fadeOut(true);
@@ -105,9 +92,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
 
     pinToPres = () => {
         let group = FieldValue(Cast(this.props.document.group, Doc));
-        if (group) {
-            PresentationView.Instance.PinDoc(group);
-        }
+        group && PresentationView.Instance.PinDoc(group);
     }
 
     @action
@@ -118,7 +103,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
                 let context = await Cast(targetDoc.targetContext, Doc);
                 if (context) {
                     DocumentManager.Instance.jumpToDocument(targetDoc, false, false,
-                        ((doc) => this.props.parent.props.parent.props.addDocTab(targetDoc!, undefined, e.ctrlKey ? "onRight" : "inTab")),
+                        ((doc) => this.props.addDocTab(targetDoc!, undefined, e.ctrlKey ? "onRight" : "inTab")),
                         undefined, undefined);
                 }
             }
@@ -151,8 +136,8 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
                     left: this.props.x * scale,
                     width: this.props.width * scale,
                     height: this.props.height * scale,
-                    backgroundColor: this.props.parent.Index === this.props.index ? "green" : StrCast(this.props.document.color)
-                }}></div>
+                    backgroundColor: this.props.ParentIndex() === this.props.index ? "green" : StrCast(this.props.document.color)
+                }} />
         );
     }
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 27c2a8f1a..7b3d5bfae 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -11,36 +11,34 @@ import { handleBackspace } from "../nodes/PDFBox";
 export default class PDFMenu extends React.Component {
     static Instance: PDFMenu;
 
+    private _offsetY: number = 0;
+    private _offsetX: number = 0;
+    private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
+    private _commentCont = React.createRef<HTMLButtonElement>();
+    private _snippetButton: React.RefObject<HTMLButtonElement> = React.createRef();
+    private _dragging: boolean = false;
+
     @observable private _top: number = -300;
     @observable private _left: number = -300;
     @observable private _opacity: number = 1;
     @observable private _transition: string = "opacity 0.5s";
     @observable private _transitionDelay: string = "";
-
-
-    StartDrag: (e: PointerEvent, ele: HTMLElement) => void = emptyFunction;
-    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;
-    PinToPres: () => void = emptyFunction;
+    @observable private _keyValue: string = "";
+    @observable private _valueValue: string = "";
+    @observable private _added: boolean = false;
 
     @observable public Highlighting: boolean = false;
     @observable public Status: "pdf" | "annotation" | "snippet" | "" = "";
     @observable public Pinned: boolean = false;
 
+    public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = emptyFunction;
+    public Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction;
+    public Delete: () => void = emptyFunction;
+    public Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction;
+    public AddTag: (key: string, value: string) => boolean = returnFalse;
+    public PinToPres: () => void = emptyFunction;
     public Marquee: { left: number; top: number; width: number; height: number; } | undefined;
 
-    private _offsetY: number = 0;
-    private _offsetX: number = 0;
-    private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
-    private _commentCont = React.createRef<HTMLButtonElement>();
-    private _snippetButton: React.RefObject<HTMLButtonElement> = React.createRef();
-    private _dragging: boolean = false;
-    @observable private _keyValue: string = "";
-    @observable private _valueValue: string = "";
-    @observable private _added: boolean = false;
-
     constructor(props: Readonly<{}>) {
         super(props);
 
@@ -61,12 +59,10 @@ export default class PDFMenu extends React.Component {
         e.stopPropagation();
         e.preventDefault();
 
-        if (this._dragging) {
-            return;
+        if (!this._dragging) {
+            this.StartDrag(e, this._commentCont.current!);
+            this._dragging = true;
         }
-
-        this.StartDrag(e, this._commentCont.current!);
-        this._dragging = true;
     }
 
     pointerUp = (e: PointerEvent) => {
@@ -126,9 +122,20 @@ export default class PDFMenu extends React.Component {
     @action
     togglePin = (e: React.MouseEvent) => {
         this.Pinned = !this.Pinned;
-        if (!this.Pinned) {
-            this.Highlighting = false;
-        }
+        !this.Pinned && (this.Highlighting = false);
+    }
+
+    dragStart = (e: React.PointerEvent) => {
+        document.removeEventListener("pointermove", this.dragging);
+        document.addEventListener("pointermove", this.dragging);
+        document.removeEventListener("pointerup", this.dragEnd);
+        document.addEventListener("pointerup", this.dragEnd);
+
+        this._offsetX = this._mainCont.current!.getBoundingClientRect().width - e.nativeEvent.offsetX;
+        this._offsetY = e.nativeEvent.offsetY;
+
+        e.stopPropagation();
+        e.preventDefault();
     }
 
     @action
@@ -147,19 +154,6 @@ export default class PDFMenu extends React.Component {
         e.preventDefault();
     }
 
-    dragStart = (e: React.PointerEvent) => {
-        document.removeEventListener("pointermove", this.dragging);
-        document.addEventListener("pointermove", this.dragging);
-        document.removeEventListener("pointerup", this.dragEnd);
-        document.addEventListener("pointerup", this.dragEnd);
-
-        this._offsetX = this._mainCont.current!.getBoundingClientRect().width - e.nativeEvent.offsetX;
-        this._offsetY = e.nativeEvent.offsetY;
-
-        e.stopPropagation();
-        e.preventDefault();
-    }
-
     @action
     highlightClicked = (e: React.MouseEvent) => {
         if (!this.Pinned) {
@@ -193,13 +187,10 @@ export default class PDFMenu extends React.Component {
     snippetDrag = (e: PointerEvent) => {
         e.stopPropagation();
         e.preventDefault();
-        if (this._dragging) {
-            return;
-        }
-        this._dragging = true;
+        if (!this._dragging) {
+            this._dragging = true;
 
-        if (this.Marquee) {
-            this.Snippet(this.Marquee);
+            this.Marquee && this.Snippet(this.Marquee);
         }
     }
 
@@ -226,36 +217,32 @@ export default class PDFMenu extends React.Component {
         if (this._keyValue.length > 0 && this._valueValue.length > 0) {
             this._added = this.AddTag(this._keyValue, this._valueValue);
 
-            setTimeout(
-                () => {
-                    runInAction(() => {
-                        this._added = false;
-                    });
-                }, 1000
-            );
+            setTimeout(action(() => this._added = false), 1000);
         }
     }
 
     render() {
-        let buttons = this.Status === "pdf" || this.Status === "snippet" ? [
-            <button key="1" className="pdfMenu-button" title="Click to 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="Drag to Annotate" ref={this._commentCont} 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 key="3" 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>
-        ] : [
-                <button key="4" className="pdfMenu-button" title="Delete Anchor" onPointerDown={this.deleteClicked}><FontAwesomeIcon icon="trash-alt" size="lg" key="1" /></button>,
-                <button key="5" className="pdfMenu-button" title="Pin to Presentation" onPointerDown={this.PinToPres}><FontAwesomeIcon icon="map-pin" size="lg" key="2" /></button>,
-                <div className="pdfMenu-addTag" key="3">
+        let buttons = this.Status === "pdf" || this.Status === "snippet" ?
+            [
+                <button key="1" className="pdfMenu-button" title="Click to 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 key="2" className="pdfMenu-button" title="Drag to Annotate" ref={this._commentCont} onPointerDown={this.pointerDown}>
+                    <FontAwesomeIcon icon="comment-alt" size="lg" /></button>,
+                <button key="3" className="pdfMenu-button" title="Drag to Snippetize Selection" style={{ display: this.Status === "snippet" ? "" : "none" }} onPointerDown={this.snippetStart} ref={this._snippetButton}>
+                    <FontAwesomeIcon icon="cut" size="lg" /></button>,
+                <button key="4" 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>
+            ] : [
+                <button key="5" className="pdfMenu-button" title="Delete Anchor" onPointerDown={this.deleteClicked}>
+                    <FontAwesomeIcon icon="trash-alt" size="lg" /></button>,
+                <button key="6" className="pdfMenu-button" title="Pin to Presentation" onPointerDown={this.PinToPres}>
+                    <FontAwesomeIcon icon="map-pin" size="lg" /></button>,
+                <div key="7" className="pdfMenu-addTag" >
                     <input onKeyDown={handleBackspace} onChange={this.keyChanged} placeholder="Key" style={{ gridColumn: 1 }} />
                     <input onKeyDown={handleBackspace} onChange={this.valueChanged} placeholder="Value" style={{ gridColumn: 3 }} />
                 </div>,
-                <button key="6" className="pdfMenu-button" title={`Add tag: ${this._keyValue} with value: ${this._valueValue}`} onPointerDown={this.addTag}><FontAwesomeIcon style={{ transition: "all .2s" }} color={this._added ? "#42f560" : "white"} icon="check" size="lg" key="4" /></button>,
+                <button key="8" 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" /></button>,
             ];
 
         return (
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index 7158aaffa..9bb18c87f 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -23,12 +23,13 @@
 .textLayer {
     user-select: auto;
 }
-.viewer {
-    // position: absolute;
-    // top: 0;
-}
-.pdfViewere-viewer {
+.pdfViewer-viewer {
     pointer-events:inherit;
+    width: 100%;
+}
+
+.pdfviewer-placeholder {
+    content: "HELLO WORLD"
 }
 .pdfViewer-text {
     transform: scale(1.5);
@@ -44,9 +45,6 @@
         }
     }
 }
-.pdfViewer-viewerCont {
-    width:100%;
-}
 
 .page-cont {
     .textLayer {
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 6a99cec59..524bb0420 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -1,167 +1,104 @@
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
 import * as Pdfjs from "pdfjs-dist";
 import "pdfjs-dist/web/pdf_viewer.css";
 import * as rp from "request-promise";
 import { Dictionary } from "typescript-collections";
-import { Doc, DocListCast, Opt } from "../../../new_fields/Doc";
+import { Doc, DocListCast } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
+import { ScriptField } from "../../../new_fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { emptyFunction, Utils } from "../../../Utils";
+import { DocServer } from "../../DocServer";
 import { Docs, DocUtils } from "../../documents/Documents";
-import { DragManager } from "../../util/DragManager";
-import { PDFBox } from "../nodes/PDFBox";
+import { KeyCodes } from "../../northstar/utils/KeyCodes";
+import { CompileResult, CompileScript } from "../../util/Scripting";
+import Annotation from "./Annotation";
 import Page from "./Page";
 import "./PDFViewer.scss";
 import React = require("react");
-import { CompileScript, CompileResult } from "../../util/Scripting";
-import { ScriptField } from "../../../new_fields/ScriptField";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import Annotation from "./Annotation";
-import { KeyCodes } from "../../northstar/utils/KeyCodes";
-import { DocServer } from "../../DocServer";
 const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
 
 export const scale = 2;
-interface IPDFViewerProps {
-    url: string;
-    loaded: (nw: number, nh: number, np: number) => void;
-    scrollY: number;
-    parent: PDFBox;
-}
-
-/**
- * Wrapper that loads the PDF and cascades the pdf down
- */
-@observer
-export class PDFViewer extends React.Component<IPDFViewerProps> {
-    @observable _pdf: Opt<Pdfjs.PDFDocumentProxy>;
-    private _mainDiv = React.createRef<HTMLDivElement>();
-
-    @action
-    componentDidMount() {
-        Pdfjs.getDocument(this.props.url).promise.then(pdf => runInAction(() => this._pdf = pdf));
-    }
-
-    render() {
-        return (
-            <div className="pdfViewer-viewerCont" ref={this._mainDiv}>
-                {!this._pdf ? (null) :
-                    <Viewer pdf={this._pdf} loaded={this.props.loaded} scrollY={this.props.scrollY} parent={this.props.parent} mainCont={this._mainDiv} url={this.props.url} />}
-            </div>
-        );
-    }
-}
 
 interface IViewerProps {
     pdf: Pdfjs.PDFDocumentProxy;
+    url: string;
+    Document: Doc;
+    DataDoc?: Doc;
+    fieldExtensionDoc: Doc;
+    fieldKey: string;
     loaded: (nw: number, nh: number, np: number) => void;
     scrollY: number;
-    parent: PDFBox;
-    mainCont: React.RefObject<HTMLDivElement>;
-    url: string;
+    scrollTo: (y: number) => void;
+    active: () => boolean;
+    setPanY?: (n: number) => void;
+    addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void;
 }
 
 /**
  * Handles rendering and virtualization of the pdf
  */
 @observer
-export class Viewer extends React.Component<IViewerProps> {
-    // _visibleElements is the array of JSX elements that gets rendered
-    @observable.shallow private _visibleElements: JSX.Element[] = [];
-    // _isPage is an array that tells us whether or not an index is rendered as a page or as a placeholder
-    @observable private _isPage: string[] = [];
+export class PDFViewer extends React.Component<IViewerProps> {
+    @observable.shallow private _visibleElements: JSX.Element[] = []; // _visibleElements is the array of JSX elements that gets rendered
+    @observable private _isPage: string[] = [];// _isPage is an array that tells us whether or not an index is rendered as a page or as a placeholder
     @observable private _pageSizes: { width: number, height: number }[] = [];
     @observable private _annotations: Doc[] = [];
     @observable private _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
-    @observable private _script: CompileResult | undefined;
+    @observable private _script: CompileResult | undefined = CompileScript("return true");
     @observable private _searching: boolean = false;
-
-    @observable public Index: number = -1;
+    @observable private Index: number = -1;
 
     private _pageBuffer: number = 1;
     private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
     private _reactionDisposer?: IReactionDisposer;
     private _annotationReactionDisposer?: IReactionDisposer;
-    private _dropDisposer?: DragManager.DragDropDisposer;
     private _filterReactionDisposer?: IReactionDisposer;
-    private _viewer: React.RefObject<HTMLDivElement>;
-    private _mainCont: React.RefObject<HTMLDivElement>;
+    private _viewer: React.RefObject<HTMLDivElement> = React.createRef();
+    private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
     private _pdfViewer: any;
-    // private _textContent: Pdfjs.TextContent[] = [];
     private _pdfFindController: any;
     private _searchString: string = "";
     private _selectionText: string = "";
 
-    constructor(props: IViewerProps) {
-        super(props);
-
-        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();
-    }
-
-    setSelectionText = (text: string) => {
-        this._selectionText = text;
-    }
-
     componentDidUpdate = (prevProps: IViewerProps) => {
-        if (this.scrollY !== prevProps.scrollY) {
-            this.renderPages();
-        }
+        this.scrollY !== prevProps.scrollY && this.renderPages();
     }
 
     @action
     componentDidMount = () => {
         this._reactionDisposer = reaction(
-
-            () => [this.props.parent.props.active(), this.startIndex, this._pageSizes.length ? this.endIndex : 0],
+            () => [this.props.active(), this.startIndex, this._pageSizes.length ? this.endIndex : 0],
             async () => {
                 await this.initialLoad();
                 this.renderPages();
             }, { fireImmediately: true });
 
         this._annotationReactionDisposer = reaction(
-            () => {
-                return this.props.parent && this.props.parent.fieldExtensionDoc && DocListCast(this.props.parent.fieldExtensionDoc.annotations);
-            },
-            (annotations: Doc[]) => {
-                annotations && annotations.length && this.renderAnnotations(annotations, true);
-            },
+            () => this.props.fieldExtensionDoc && DocListCast(this.props.fieldExtensionDoc.annotations),
+            annotations => annotations && annotations.length && this.renderAnnotations(annotations, true),
             { fireImmediately: true });
 
-
-        if (this.props.parent.props.ContainingCollectionView) {
-            this._filterReactionDisposer = reaction(
-                () => this.props.parent.Document.filterScript,
-                () => {
-                    runInAction(() => {
-                        let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField);
-                        this._script = scriptfield ? scriptfield.script : CompileScript("return true");
-                        if (this.props.parent.props.ContainingCollectionView) {
-                            let fieldDoc = Doc.resolvedFieldDataDoc(this.props.parent.props.ContainingCollectionView.props.DataDoc ?
-                                this.props.parent.props.ContainingCollectionView.props.DataDoc : this.props.parent.props.ContainingCollectionView.props.Document, this.props.parent.props.ContainingCollectionView.props.fieldKey, "true");
-                            let ccvAnnos = DocListCast(fieldDoc.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;
-                                    }
-                                }
-                            });
+        this._filterReactionDisposer = reaction(
+            () => this.props.Document.filterScript,
+            action(() => {
+                let scriptfield = Cast(this.props.Document.filterScript, ScriptField);
+                this._script = scriptfield ? scriptfield.script : CompileScript("return true");
+                DocListCast(this.props.fieldExtensionDoc.annotations).forEach(d => {
+                    if (this._script && this._script.compiled) {
+                        let run = this._script.run(d);
+                        if (run.success) {
+                            d.opacity = run.result ? 1 : 0;
                         }
-                        this.Index = -1;
-                    });
-                }
-            );
-        }
-
-        if (this._mainCont.current) {
-            this._dropDisposer = this._mainCont.current && DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } });
-        }
+                    }
+                });
+                this.Index = -1;
+            }),
+            { fireImmediately: true }
+        );
 
         document.removeEventListener("copy", this.copy);
         document.addEventListener("copy", this.copy);
@@ -171,89 +108,50 @@ export class Viewer extends React.Component<IViewerProps> {
         this._reactionDisposer && this._reactionDisposer();
         this._annotationReactionDisposer && this._annotationReactionDisposer();
         this._filterReactionDisposer && this._filterReactionDisposer();
-        this._dropDisposer && this._dropDisposer();
         document.removeEventListener("copy", this.copy);
     }
 
     private copy = (e: ClipboardEvent) => {
-        if (this.props.parent.props.active()) {
+        if (this.props.active() && e.clipboardData) {
             let text = this._selectionText;
-            if (e.clipboardData) {
-                e.clipboardData.setData("text/plain", text);
-                e.clipboardData.setData("dash/pdfOrigin", this.props.parent.props.Document[Id]);
-                let annoDoc = this.makeAnnotationDocument(undefined, 0, "#0390fc");
-                e.clipboardData.setData("dash/pdfRegion", annoDoc[Id]);
-                e.preventDefault();
-            }
+            let annoDoc = this.makeAnnotationDocument(undefined, 0, "#0390fc");
+            e.clipboardData.setData("text/plain", text);
+            e.clipboardData.setData("dash/pdfOrigin", this.props.Document[Id]);
+            e.clipboardData.setData("dash/pdfRegion", annoDoc[Id]);
+            e.preventDefault();
         }
-        // let targetAnnotations = DocListCast(this.props.parent.fieldExtensionDoc.annotations);
-        // if (targetAnnotations) {
-        //     targetAnnotations.push(destDoc);
-        // }
     }
 
     paste = (e: ClipboardEvent) => {
-        if (e.clipboardData) {
-            if (e.clipboardData.getData("dash/pdfOrigin") === this.props.parent.props.Document[Id]) {
-                let linkDocId = e.clipboardData.getData("dash/linkDoc");
-                if (linkDocId) {
-                    DocServer.GetRefField(linkDocId).then(async (link) => {
-                        if (!(link instanceof Doc)) {
-                            return;
-                        }
-                        let proto = Doc.GetProto(link);
-                        let source = await Cast(proto.anchor1, Doc);
-                        proto.anchor2 = this.makeAnnotationDocument(source, 0, "#0390fc", false);
-                    });
-                }
-            }
+        if (e.clipboardData && e.clipboardData.getData("dash/pdfOrigin") === this.props.Document[Id]) {
+            let linkDocId = e.clipboardData.getData("dash/linkDoc");
+            linkDocId && DocServer.GetRefField(linkDocId).then(async (link) =>
+                (link instanceof Doc) && (Doc.GetProto(link).anchor2 = this.makeAnnotationDocument(await Cast(Doc.GetProto(link), Doc), 0, "#0390fc", false)));
         }
     }
 
-    scrollTo(y: number) {
-        if (this.props.mainCont.current) {
-            this.props.parent.scrollTo(y);
-        }
+    setSelectionText = (text: string) => {
+        this._selectionText = text;
     }
 
     @action
     initialLoad = async () => {
         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);
-            const proms: Pdfjs.PDFPromise<any>[] = [];
-            for (let i = 0; i < this.props.pdf.numPages; i++) {
-                proms.push(this.props.pdf.getPage(i + 1).then(page => runInAction(() => {
-                    pageSizes[i] = {
+            this._pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages);
+            await Promise.all(this._pageSizes.map<Pdfjs.PDFPromise<any>>((val, i) =>
+                this.props.pdf.getPage(i + 1).then(action((page: Pdfjs.PDFPageProxy) => {
+                    this._pageSizes.splice(i, 1, {
                         width: (page.view[page.rotate === 0 || page.rotate === 180 ? 2 : 3] - page.view[page.rotate === 0 || page.rotate === 180 ? 0 : 1]) * scale,
                         height: (page.view[page.rotate === 0 || page.rotate === 180 ? 3 : 2] - page.view[page.rotate === 0 || page.rotate === 180 ? 1 : 0]) * scale
-                    };
-                    // let x = page.getViewport(scale);
-                    // page.getTextContent().then((text: Pdfjs.TextContent) => {
-                    //     // let tc = new Pdfjs.TextContentItem()
-                    //     // let tc = {str: }
-                    //     this._textContent[i] = text;
-                    //     // text.items.forEach(t => {
-                    //     //     tcStr += t.str;
-                    //     // })
-                    // });
-                    // pageSizes[i] = { width: x.width, height: x.height };
-                })));
-            }
-            await Promise.all(proms);
-            runInAction(() =>
-                Array.from(Array((this._pageSizes = pageSizes).length).keys()).map(this.getPlaceholderPage));
-            this.props.loaded(Math.max(...pageSizes.map(i => i.width)), pageSizes[0].height, this.props.pdf.numPages);
-            // this.props.loaded(Math.max(...pageSizes.map(i => i.width)), pageSizes[0].height, this.props.pdf.numPages);
-
-            let startY = NumCast(this.props.parent.Document.startY);
-            let ccv = this.props.parent.props.ContainingCollectionView;
-            if (ccv) {
-                ccv.props.Document.panY = startY;
-            }
-            this.props.parent.Document.scrollY = 0;
-            this.props.parent.Document.scrollY = startY + 1;
+                    });
+                    this.getPlaceholderPage(i);
+                }))));
+            this.props.loaded(Math.max(...this._pageSizes.map(i => i.width)), this._pageSizes[0].height, this.props.pdf.numPages);
+
+            let startY = NumCast(this.props.Document.startY);
+            this.props.setPanY && this.props.setPanY(startY);
+            this.props.Document.scrollY = startY + 1;
         }
     }
 
@@ -262,8 +160,8 @@ export class Viewer extends React.Component<IViewerProps> {
         let annoDocs: Doc[] = [];
         let mainAnnoDoc = Docs.Create.InstanceFromProto(new Doc(), "", {});
 
-        mainAnnoDoc.title = "Annotation on " + StrCast(this.props.parent.Document.title);
-        mainAnnoDoc.pdfDoc = this.props.parent.props.Document;
+        mainAnnoDoc.title = "Annotation on " + StrCast(this.props.Document.title);
+        mainAnnoDoc.pdfDoc = this.props.Document;
         let minY = Number.MAX_VALUE;
         this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => {
             for (let anno of value) {
@@ -288,34 +186,19 @@ export class Viewer extends React.Component<IViewerProps> {
         mainAnnoDoc.y = Math.max(minY, 0);
         mainAnnoDoc.annotations = new List<Doc>(annoDocs);
         if (sourceDoc && createLink) {
-            DocUtils.MakeLink(sourceDoc, mainAnnoDoc, undefined, `Annotation from ${StrCast(this.props.parent.Document.title)}`, "", StrCast(this.props.parent.Document.title));
+            DocUtils.MakeLink(sourceDoc, mainAnnoDoc, undefined, `Annotation from ${StrCast(this.props.Document.title)}`, "", StrCast(this.props.Document.title));
         }
         this._savedAnnotations.clear();
         this.Index = -1;
         return mainAnnoDoc;
     }
 
-    drop = async (e: Event, de: DragManager.DropEvent) => {
-        // if (de.data instanceof DragManager.LinkDragData) {
-        //     let sourceDoc = de.data.linkSourceDocument;
-        //     let destDoc = this.makeAnnotationDocument(sourceDoc, 1, "red");
-        //     de.data.droppedDocuments.push(destDoc);
-        //     let targetAnnotations = DocListCast(this.props.parent.fieldExtensionDoc.annotations);
-        //     if (targetAnnotations) {
-        //         targetAnnotations.push(destDoc);
-        //     }
-        //     else {
-        //         this.props.parent.fieldExtensionDoc.annotations = new List<Doc>([destDoc]);
-        //     }
-        //     e.stopPropagation();
-        // }
-    }
     /**
      * Called by the Page class when it gets rendered, initializes the lists and
      * puts a placeholder with all of the correct page sizes when all of the pages have been loaded.
      */
     @action
-    pageLoaded = (index: number, page: Pdfjs.PDFPageViewport): void => {
+    pageLoaded = (page: Pdfjs.PDFPageViewport): void => {
         this.props.loaded(page.width, page.height, this.props.pdf.numPages);
     }
 
@@ -325,8 +208,9 @@ export class Viewer extends React.Component<IViewerProps> {
             this._isPage[page] = "none";
             this._visibleElements[page] = (
                 <div key={`${this.props.url}-placeholder-${page + 1}`} className="pdfviewer-placeholder"
-                    style={{ width: this._pageSizes[page].width, height: this._pageSizes[page].height }} />
-            );
+                    style={{ width: this._pageSizes[page].width, height: this._pageSizes[page].height }}>
+                    "PAGE IS LOADING... "
+                </div>);
         }
     }
 
@@ -344,8 +228,8 @@ export class Viewer extends React.Component<IViewerProps> {
                     key={`${this.props.url}-rendered-${page + 1}`}
                     name={`${this.props.pdf.fingerprint + `-page${page + 1}`}`}
                     pageLoaded={this.pageLoaded}
-                    parent={this.props.parent}
-                    makePin={emptyFunction}
+                    fieldExtensionDoc={this.props.fieldExtensionDoc}
+                    Document={this.props.Document}
                     renderAnnotations={this.renderAnnotations}
                     createAnnotation={this.createAnnotation}
                     sendAnnotations={this.receiveAnnotations}
@@ -363,9 +247,8 @@ export class Viewer extends React.Component<IViewerProps> {
         let handleError = () => this.getRenderedPage(page);
         if (this._isPage[page] !== "image") {
             this._isPage[page] = "image";
-            const address = this.props.url;
             try {
-                let res = JSON.parse(await rp.get(Utils.prepend(`/thumbnail${address.substring("files/".length, address.length - ".pdf".length)}-${page + 1}.PNG`)));
+                let res = JSON.parse(await rp.get(Utils.prepend(`/thumbnail${this.props.url.substring("files/".length, this.props.url.length - ".pdf".length)}-${page + 1}.PNG`)));
                 runInAction(() => this._visibleElements[page] =
                     <img key={res.path} src={res.path} onError={handleError}
                         style={{ width: `${parseInt(res.width) * scale}px`, height: `${parseInt(res.height) * scale}px` }} />);
@@ -382,22 +265,15 @@ export class Viewer extends React.Component<IViewerProps> {
 
     // endIndex: where to end rendering pages
     @computed get endIndex(): number {
-        return Math.min(this.props.pdf.numPages - 1, this.getPageFromScroll(this.scrollY + this._pageSizes[0].height) + this._pageBuffer);
+        return Math.min(this.props.pdf.numPages - 1, this.getPageFromScroll(this.scrollY + (this._pageSizes[0] ? this._pageSizes[0].height : 0)) + this._pageBuffer);
     }
 
     @action
     renderPages = () => {
-        for (let i = 0; i < this.props.pdf.numPages; i++) {
-            if (i < this.startIndex || i > this.endIndex) {
-                this.getPlaceholderPage(i);  // pages outside of the pdf use empty stand-in divs
-            } else {
-                if (this.props.parent.props.active()) {
-                    this.getRenderedPage(i);
-                } else {
-                    this.getPageImage(i);
-                }
-            }
-        }
+        Array.from(Array(this.props.pdf.numPages).keys()).filter(p => this._isPage[p] !== undefined).map(i =>
+            (i < this.startIndex || i > this.endIndex) ? this.getPlaceholderPage(i) : // pages outside of the pdf use empty stand-in divs
+                this.props.active() ? this.getRenderedPage(i) : this.getPageImage(i)
+        );
     }
 
     @action
@@ -430,7 +306,7 @@ export class Viewer extends React.Component<IViewerProps> {
     getPageFromScroll = (vOffset: number) => {
         let index = 0;
         let currOffset = vOffset;
-        while (index < this._pageSizes.length && currOffset - this._pageSizes[index].height > 0) {
+        while (index < this._pageSizes.length && this._pageSizes[index] && currOffset - this._pageSizes[index].height > 0) {
             currOffset -= this._pageSizes[index++].height;
         }
         return index;
@@ -461,52 +337,39 @@ export class Viewer extends React.Component<IViewerProps> {
         }
     }
 
-    renderAnnotation = (anno: Doc, index: number): JSX.Element => {
-        return <Annotation anno={anno} index={index} parent={this} key={`${anno[Id]}-annotation`} />;
-    }
-
-    @action
-    pointerDown = () => {
-        // this._searching = false;
-    }
+    getIndex = () => this.Index;
 
     @action
     search = (searchString: string) => {
         if (this._pdfViewer._pageViewsReady) {
-            this._pdfFindController.executeCommand('find',
-                {
-                    caseSensitive: false,
-                    findPrevious: undefined,
-                    highlightAll: true,
-                    phraseSearch: true,
-                    query: searchString
-                });
+            this._pdfFindController.executeCommand('find', {
+                caseSensitive: false,
+                findPrevious: undefined,
+                highlightAll: true,
+                phraseSearch: true,
+                query: searchString
+            });
         }
         else {
-            let container = this._mainCont.current;
-            if (container) {
-                container.addEventListener("pagesloaded", () => {
-                    console.log("rendered");
-                    this._pdfFindController.executeCommand('find',
-                        {
-                            caseSensitive: false,
-                            findPrevious: undefined,
-                            highlightAll: true,
-                            phraseSearch: true,
-                            query: searchString
-                        });
-                });
-                container.addEventListener("pagerendered", () => {
-                    console.log("rendered");
-                    this._pdfFindController.executeCommand('find',
-                        {
-                            caseSensitive: false,
-                            findPrevious: undefined,
-                            highlightAll: true,
-                            phraseSearch: true,
-                            query: searchString
-                        });
-                });
+            if (this._mainCont.current) {
+                this._mainCont.current.addEventListener("pagesloaded", () =>
+                    this._pdfFindController.executeCommand('find', {
+                        caseSensitive: false,
+                        findPrevious: undefined,
+                        highlightAll: true,
+                        phraseSearch: true,
+                        query: searchString
+                    })
+                );
+                this._mainCont.current.addEventListener("pagerendered", () =>
+                    this._pdfFindController.executeCommand('find', {
+                        caseSensitive: false,
+                        findPrevious: undefined,
+                        highlightAll: true,
+                        phraseSearch: true,
+                        query: searchString
+                    })
+                );
             }
         }
 
@@ -575,15 +438,10 @@ export class Viewer extends React.Component<IViewerProps> {
                         linkService: simpleLinkService
                     });
                     simpleLinkService.setPdf(this.props.pdf);
-                    container.addEventListener("pagesinit", () => {
-                        this._pdfViewer.currentScaleValue = 1;
-                    });
-                    container.addEventListener("pagerendered", () => {
-                        console.log("rendered");
-                    });
+                    container.addEventListener("pagesinit", () => this._pdfViewer.currentScaleValue = 1);
+                    container.addEventListener("pagerendered", () => console.log("rendered"));
                     this._pdfViewer.setDocument(this.props.pdf);
                     this._pdfFindController = new PDFJSViewer.PDFFindController(this._pdfViewer);
-                    // this._pdfFindController._linkService = pdfLinkService;
                     this._pdfViewer.findController = this._pdfFindController;
                 }
             }
@@ -602,10 +460,6 @@ export class Viewer extends React.Component<IViewerProps> {
     @action
     prevAnnotation = (e: React.MouseEvent) => {
         e.stopPropagation();
-
-        // if (this.Index > 0) {
-        //     this.Index--;
-        // }
         this.Index = Math.max(this.Index - 1, 0);
     }
 
@@ -626,49 +480,27 @@ export class Viewer extends React.Component<IViewerProps> {
         this.Index = Math.min(this.Index + 1, filtered.length - 1);
     }
 
-    nextResult = () => {
-        // if (this._viewer.current) {
-        //     let results = this._pdfFindController.pageMatches;
-        //     if (results && results.length) {
-        //         if (this._pageIndex === this.props.pdf.numPages && this._matchIndex === results[this._pageIndex].length - 1) {
-        //             return;
-        //         }
-        //         if (this._pageIndex === -1 || this._matchIndex === results[this._pageIndex].length - 1) {
-        //             this._matchIndex = 0;
-        //             this._pageIndex++;
-        //         }
-        //         else {
-        //             this._matchIndex++;
-        //         }
-        //         this._pdfFindController._nextMatch()
-        // let nextMatch = this._viewer.current.children[this._pageIndex].children[1].children[results[this._pageIndex][this._matchIndex]];
-        // rconsole.log(nextMatch);
-        // this.props.parent.scrollTo(nextMatch.getBoundingClientRect().top);
-        // nextMatch.setAttribute("style", nextMatch.getAttribute("style") ? nextMatch.getAttribute("style") + ", background-color: green" : "background-color: green");
-        // }
-        // }
-    }
-
     render() {
-        let compiled = this._script;
         return (
-            <div className="pdfViewer-viewer" ref={this._mainCont} onPointerDown={this.pointerDown}>
+            <div className="pdfViewer-viewer" ref={this._mainCont} >
                 <div className="viewer" style={this._searching ? { position: "absolute", top: 0 } : {}}>
                     {this._visibleElements}
                 </div>
                 <div className="pdfViewer-text" ref={this._viewer} />
-                <div className="pdfViewer-annotationLayer" style={{ height: this.props.parent.Document.nativeHeight }}>
+                <div className="pdfViewer-annotationLayer" style={{ height: NumCast(this.props.Document.nativeHeight) }}>
                     <div className="pdfViewer-annotationLayer-subCont" ref={this._annotationLayer}>
                         {this._annotations.filter(anno => {
-                            if (compiled && compiled.compiled) {
-                                let run = compiled.run({ this: anno });
+                            if (this._script && this._script.compiled) {
+                                let run = this._script.run({ this: anno });
                                 if (run.success) {
                                     return run.result;
                                 }
                             }
                             return true;
                         }).sort((a: Doc, b: Doc) => NumCast(a.y) - NumCast(b.y))
-                            .map((anno: Doc, index: number) => this.renderAnnotation(anno, index))}
+                            .map((anno: Doc, index: number) =>
+                                <Annotation anno={anno} scrollTo={this.props.scrollTo} fieldExtensionDoc={this.props.fieldExtensionDoc} ParentIndex={this.getIndex} addDocTab={this.props.addDocTab} index={index} key={`${anno[Id]}-annotation`} />
+                            )}
                     </div>
                 </div>
                 <div className="pdfViewer-overlayCont" onPointerDown={(e) => e.stopPropagation()}
@@ -683,19 +515,19 @@ export class Viewer extends React.Component<IViewerProps> {
                     <button title="Search" onClick={() => this.search(this._searchString)}><FontAwesomeIcon icon="search" size="3x" color="white" /></button>
                 </div>
                 <button className="pdfViewer-overlayButton" onClick={this.prevAnnotation} title="Previous Annotation"
-                    style={{ bottom: -this.props.scrollY + 280, right: 10, display: this.props.parent.props.active() ? "flex" : "none" }}>
+                    style={{ bottom: -this.props.scrollY + 280, right: 10, display: this.props.active() ? "flex" : "none" }}>
                     <div className="pdfViewer-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
                         <FontAwesomeIcon style={{ color: "white" }} icon={"arrow-up"} size="3x" />
                     </div>
                 </button>
                 <button className="pdfViewer-overlayButton" onClick={this.nextAnnotation} title="Next Annotation"
-                    style={{ bottom: -this.props.scrollY + 200, right: 10, display: this.props.parent.props.active() ? "flex" : "none" }}>
+                    style={{ bottom: -this.props.scrollY + 200, right: 10, display: this.props.active() ? "flex" : "none" }}>
                     <div className="pdfViewer-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
                         <FontAwesomeIcon style={{ color: "white" }} icon={"arrow-down"} size="3x" />
                     </div>
                 </button>
                 <button className="pdfViewer-overlayButton" onClick={this.toggleSearch} title="Open Search Bar"
-                    style={{ bottom: -this.props.scrollY + 10, right: 0, display: this.props.parent.props.active() ? "flex" : "none" }}>
+                    style={{ bottom: -this.props.scrollY + 10, right: 0, display: this.props.active() ? "flex" : "none" }}>
                     <div className="pdfViewer-overlayButton-arrow" onPointerDown={(e) => e.stopPropagation()}></div>
                     <div className="pdfViewer-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
                         <FontAwesomeIcon style={{ color: "white" }} icon={this._searching ? "times" : "search"} size="3x" />
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index dea4e0da1..1da41bca1 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -3,12 +3,9 @@ import { observer } from "mobx-react";
 import * as Pdfjs from "pdfjs-dist";
 import "pdfjs-dist/web/pdf_viewer.css";
 import { Doc, DocListCastAsync, Opt, WidthSym } from "../../../new_fields/Doc";
-import { List } from "../../../new_fields/List";
-import { listSpec } from "../../../new_fields/Schema";
-import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types";
+import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
-import { PDFBox } from "../nodes/PDFBox";
 import PDFMenu from "./PDFMenu";
 import { scale } from "./PDFViewer";
 import "./PDFViewer.scss";
@@ -17,14 +14,14 @@ import React = require("react");
 
 interface IPageProps {
     size: { width: number, height: number };
-    pdf: Opt<Pdfjs.PDFDocumentProxy>;
+    pdf: Pdfjs.PDFDocumentProxy;
     name: string;
     numPages: number;
     page: number;
-    pageLoaded: (index: number, page: Pdfjs.PDFPageViewport) => void;
-    parent: PDFBox;
+    pageLoaded: (page: Pdfjs.PDFPageViewport) => void;
+    fieldExtensionDoc: Doc,
+    Document: Doc,
     renderAnnotations: (annotations: Doc[], removeOld: boolean) => void;
-    makePin: (x: number, y: number, page: number) => void;
     sendAnnotations: (annotations: HTMLDivElement[], page: number) => void;
     createAnnotation: (div: HTMLDivElement, page: number) => void;
     makeAnnotationDocuments: (doc: Doc | undefined, scale: number, color: string, linkTo: boolean) => Doc;
@@ -34,7 +31,7 @@ interface IPageProps {
 
 @observer
 export default class Page extends React.Component<IPageProps> {
-    @observable private _state: string = "N/A";
+    @observable private _state: "N/A" | "rendering" = "N/A";
     @observable private _width: number = this.props.size.width;
     @observable private _height: number = this.props.size.height;
     @observable private _page: Opt<Pdfjs.PDFPageProxy>;
@@ -43,90 +40,54 @@ export default class Page extends React.Component<IPageProps> {
     @observable private _marqueeY: number = 0;
     @observable private _marqueeWidth: number = 0;
     @observable private _marqueeHeight: number = 0;
-    @observable private _rotate: string = "";
 
-    private _canvas: React.RefObject<HTMLCanvasElement>;
-    private _textLayer: React.RefObject<HTMLDivElement>;
-    private _annotationLayer: React.RefObject<HTMLDivElement>;
-    private _marquee: React.RefObject<HTMLDivElement>;
-    // private _curly: React.RefObject<HTMLImageElement>;
+    private _canvas: React.RefObject<HTMLCanvasElement> = React.createRef();
+    private _textLayer: React.RefObject<HTMLDivElement> = React.createRef();
+    private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
+    private _marquee: React.RefObject<HTMLDivElement> = React.createRef();
     private _marqueeing: boolean = false;
     private _reactionDisposer?: IReactionDisposer;
     private _startY: number = 0;
     private _startX: number = 0;
 
-    constructor(props: IPageProps) {
-        super(props);
-        this._canvas = React.createRef();
-        this._textLayer = React.createRef();
-        this._annotationLayer = React.createRef();
-        this._marquee = React.createRef();
-        // this._curly = React.createRef();
-    }
-
     componentDidMount = (): void => {
-        if (this.props.pdf) {
-            this.update(this.props.pdf);
-        }
-    }
-
-    componentWillUnmount = (): void => {
-        if (this._reactionDisposer) {
-            this._reactionDisposer();
-        }
+        this.loadPage(this.props.pdf);
     }
 
     componentDidUpdate = (): void => {
-        if (this.props.pdf) {
-            this.update(this.props.pdf);
-        }
+        this.loadPage(this.props.pdf);
     }
 
-    private update = (pdf: Pdfjs.PDFDocumentProxy): void => {
-        if (pdf) {
-            this.loadPage(pdf);
-        }
-        else {
-            this._state = "loading";
-        }
+    componentWillUnmount = (): void => {
+        this._reactionDisposer && this._reactionDisposer();
     }
 
     private loadPage = (pdf: Pdfjs.PDFDocumentProxy): void => {
-        if (this._state === "rendering" || this._page) return;
-
-        pdf.getPage(this._currPage).then(
+        this._state !== "rendering" && !this._page && pdf.getPage(this._currPage).then(
             (page: Pdfjs.PDFPageProxy): void => {
                 this._state = "rendering";
                 this.renderPage(page);
-            }
-        );
+            });
     }
 
     @action
     private renderPage = (page: Pdfjs.PDFPageProxy): void => {
         // lower scale = easier to read at small sizes, higher scale = easier to read at large sizes
-        let viewport = page.getViewport(scale);
-        let canvas = this._canvas.current;
-        let textLayer = this._textLayer.current;
-        if (canvas && textLayer) {
-            let ctx = canvas.getContext("2d");
-            canvas.width = viewport.width;
-            this._width = viewport.width;
-            canvas.height = viewport.height;
-            this._height = viewport.height;
-            this.props.pageLoaded(this._currPage, viewport);
+        if (this._canvas.current && this._textLayer.current) {
+            let viewport = page.getViewport(scale);
+            this._canvas.current.width = this._width = viewport.width;
+            this._canvas.current.height = this._height = viewport.height;
+            this.props.pageLoaded(viewport);
+            let ctx = this._canvas.current.getContext("2d");
             if (ctx) {
-                // renders the page onto the canvas context
-                page.render({ canvasContext: ctx, viewport: viewport });
-                // renders text onto the text container
-                page.getTextContent().then((res: Pdfjs.TextContent): void => {
+                page.render({ canvasContext: ctx, viewport: viewport }); // renders the page onto the canvas context
+                page.getTextContent().then(res =>                   // renders text onto the text container
                     //@ts-ignore
                     Pdfjs.renderTextLayer({
                         textContent: res,
-                        container: textLayer,
+                        container: this._textLayer.current,
                         viewport: viewport
-                    });
-                });
+                    }));
 
                 this._page = page;
             }
@@ -137,12 +98,8 @@ export default class Page extends React.Component<IPageProps> {
     highlight = (targetDoc?: Doc, color: string = "red") => {
         // creates annotation documents for current highlights
         let annotationDoc = this.props.makeAnnotationDocuments(targetDoc, scale, color, false);
-        let targetAnnotations = Cast(this.props.parent.fieldExtensionDoc.annotations, listSpec(Doc));
-        if (targetAnnotations === undefined) {
-            Doc.GetProto(this.props.parent.fieldExtensionDoc).annotations = new List([annotationDoc]);
-        } else {
-            targetAnnotations.push(annotationDoc);
-        }
+        Doc.GetProto(annotationDoc).annotationOn = this.props.Document;
+        Doc.AddDocToList(this.props.fieldExtensionDoc, "annotations", annotationDoc);
         return annotationDoc;
     }
 
@@ -154,16 +111,12 @@ export default class Page extends React.Component<IPageProps> {
     startDrag = (e: PointerEvent, ele: HTMLElement): void => {
         e.preventDefault();
         e.stopPropagation();
-        let thisDoc = this.props.parent.Document;
-        // document that this annotation is linked to
-        let targetDoc = Docs.Create.TextDocument({ width: 200, height: 200, title: "New Annotation" });
-        targetDoc.targetPage = this.props.page;
-        let annotationDoc = this.highlight(undefined, "red");
-        Doc.GetProto(annotationDoc).annotationOn = thisDoc;
-        annotationDoc.linkedToDoc = false;
-        // create dragData and star tdrag
-        let dragData = new DragManager.AnnotationDragData(thisDoc, annotationDoc, targetDoc);
         if (this._textLayer.current) {
+            let targetDoc = Docs.Create.TextDocument({ width: 200, height: 200, title: "New Annotation" });
+            targetDoc.targetPage = this.props.page;
+            let annotationDoc = this.highlight(undefined, "red");
+            annotationDoc.linkedToDoc = false;
+            let dragData = new DragManager.AnnotationDragData(this.props.Document, annotationDoc, targetDoc);
             DragManager.StartAnnotationDrag([ele], dragData, e.pageX, e.pageY, {
                 handlers: {
                     dragComplete: async () => {
@@ -171,9 +124,7 @@ export default class Page extends React.Component<IPageProps> {
                             let annotations = await DocListCastAsync(annotationDoc.annotations);
                             annotations && annotations.forEach(anno => anno.target = targetDoc);
                             let pdfDoc = await Cast(annotationDoc.pdfDoc, Doc);
-                            if (pdfDoc) {
-                                DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title));
-                            }
+                            pdfDoc && DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title))
                         }
                     }
                 },
@@ -184,24 +135,20 @@ export default class Page extends React.Component<IPageProps> {
 
     // cleans up events and boolean
     endDrag = (e: PointerEvent): void => {
-        // document.removeEventListener("pointermove", this.startDrag);
-        // document.removeEventListener("pointerup", this.endDrag);
         e.stopPropagation();
     }
 
     createSnippet = (marquee: { left: number, top: number, width: number, height: number }): void => {
-        let doc = this.props.parent.Document;
-        let view = Doc.MakeAlias(doc);
-        let data = Doc.MakeDelegate(doc.proto!);
+        let view = Doc.MakeAlias(this.props.Document);
+        let data = Doc.MakeDelegate(Doc.GetProto(this.props.Document));
         data.title = StrCast(data.title) + "_snippet";
         view.proto = data;
         view.nativeHeight = marquee.height;
-        view.height = (doc[WidthSym]() / NumCast(doc.nativeWidth)) * marquee.height;
-        view.nativeWidth = doc.nativeWidth;
+        view.height = (this.props.Document[WidthSym]() / NumCast(this.props.Document.nativeWidth)) * marquee.height;
+        view.nativeWidth = this.props.Document.nativeWidth;
         view.startY = marquee.top + this.props.getScrollFromPage(this.props.page);
-        view.width = doc[WidthSym]();
-        let dragData = new DragManager.DocumentDragData([view], [undefined]);
-        DragManager.StartDocumentDrag([], dragData, 0, 0);
+        view.width = this.props.Document[WidthSym]();
+        DragManager.StartDocumentDrag([], new DragManager.DocumentDragData([view], [undefined]), 0, 0);
     }
 
     @action
@@ -209,11 +156,6 @@ export default class Page extends React.Component<IPageProps> {
         // if alt+left click, drag and annotate
         if (e.altKey && e.button === 0) {
             e.stopPropagation();
-
-            // document.removeEventListener("pointermove", this.startDrag);
-            // document.addEventListener("pointermove", this.startDrag);
-            // document.removeEventListener("pointerup", this.endDrag);
-            // document.addEventListener("pointerup", this.endDrag);
         }
         else if (e.button === 0) {
             PDFMenu.Instance.StartDrag = this.startDrag;
@@ -221,20 +163,18 @@ export default class Page extends React.Component<IPageProps> {
             PDFMenu.Instance.Snippet = this.createSnippet;
             PDFMenu.Instance.Status = "pdf";
             PDFMenu.Instance.fadeOut(true);
-            let target: any = e.target;
-            if (target && target.parentElement === this._textLayer.current) {
+            if (e.target && (e.target as any).parentElement === this._textLayer.current) {
                 e.stopPropagation();
             }
             else {
                 // set marquee x and y positions to the spatially transformed position
-                let current = this._textLayer.current;
-                if (current) {
-                    let boundingRect = current.getBoundingClientRect();
-                    this._startX = this._marqueeX = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width);
-                    this._startY = this._marqueeY = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height);
+                if (this._textLayer.current) {
+                    let boundingRect = this._textLayer.current.getBoundingClientRect();
+                    this._startX = this._marqueeX = (e.clientX - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width);
+                    this._startY = this._marqueeY = (e.clientY - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height);
                 }
                 this._marqueeing = true;
-                if (this._marquee.current) this._marquee.current.style.opacity = "0.2";
+                this._marquee.current && (this._marquee.current.style.opacity = "0.2");
             }
             document.removeEventListener("pointermove", this.onSelectStart);
             document.addEventListener("pointermove", this.onSelectStart);
@@ -248,63 +188,23 @@ export default class Page extends React.Component<IPageProps> {
 
     @action
     onSelectStart = (e: PointerEvent): void => {
-        let target: any = e.target;
-        if (this._marqueeing) {
-            let current = this._textLayer.current;
-            if (current) {
-                // transform positions and find the width and height to set the marquee to
-                let boundingRect = current.getBoundingClientRect();
-                this._marqueeWidth = ((e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width)) - this._startX;
-                this._marqueeHeight = ((e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height)) - this._startY;
-                this._marqueeX = Math.min(this._startX, this._startX + this._marqueeWidth);
-                this._marqueeY = Math.min(this._startY, this._startY + this._marqueeHeight);
-                this._marqueeWidth = Math.abs(this._marqueeWidth);
-                this._marqueeHeight = Math.abs(this._marqueeHeight);
-                let { background, opacity, transform: transform } = this.getCurlyTransform();
-                if (this._marquee.current /*&& this._curly.current*/) {
-                    this._marquee.current.style.background = background;
-                    // this._curly.current.style.opacity = opacity;
-                    this._rotate = transform;
-                }
-            }
+        if (this._marqueeing && this._textLayer.current) {
+            // transform positions and find the width and height to set the marquee to
+            let boundingRect = this._textLayer.current.getBoundingClientRect();
+            this._marqueeWidth = ((e.clientX - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)) - this._startX;
+            this._marqueeHeight = ((e.clientY - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)) - this._startY;
+            this._marqueeX = Math.min(this._startX, this._startX + this._marqueeWidth);
+            this._marqueeY = Math.min(this._startY, this._startY + this._marqueeHeight);
+            this._marqueeWidth = Math.abs(this._marqueeWidth);
+            this._marquee.current && (this._marquee.current.style.background = "red");
             e.stopPropagation();
             e.preventDefault();
         }
-        else if (target && target.parentElement === this._textLayer.current) {
+        else if (e.target && (e.target as any).parentElement === this._textLayer.current) {
             e.stopPropagation();
         }
     }
 
-    getCurlyTransform = (): { background: string, opacity: string, transform: string } => {
-        // let background = "", opacity = "", transform = "";
-        // if (this._marquee.current && this._curly.current) {
-        //     if (this._marqueeWidth > 100 && this._marqueeHeight > 100) {
-        //         background = "red";
-        //         opacity = "0";
-        //     }
-        //     else {
-        //         background = "transparent";
-        //         opacity = "1";
-        //     }
-
-        //     // split up for simplicity, could be done in a nested ternary. please do not. -syip2
-        //     let ratio = this._marqueeWidth / this._marqueeHeight;
-        //     if (ratio > 1.5) {
-        //         // vertical
-        //         transform = "rotate(90deg) scale(1, 5)";
-        //     }
-        //     else if (ratio < 0.5) {
-        //         // horizontal
-        //         transform = "scale(2, 1)";
-        //     }
-        //     else {
-        //         // diagonal
-        //         transform = "rotate(45deg) scale(1.5, 1.5)";
-        //     }
-        // }
-        return { background: "red", opacity: "0.5", transform: "" };
-    }
-
     @action
     onSelectEnd = (e: PointerEvent): void => {
         if (this._marqueeing) {
@@ -319,20 +219,9 @@ export default class Page extends React.Component<IPageProps> {
                 copy.style.height = style.height;
 
                 // apply the appropriate background, opacity, and transform
-                let { background, opacity, transform } = this.getCurlyTransform();
-                copy.style.background = background;
-                // if curly bracing, add a curly brace
-                // if (opacity === "1" && this._curly.current) {
-                //     copy.style.opacity = opacity;
-                //     let img = this._curly.current.cloneNode();
-                //     (img as any).style.opacity = opacity;
-                //     (img as any).style.transform = transform;
-                //     copy.appendChild(img);
-                // }
-                // else {
+                copy.style.background = "red";
                 copy.style.border = style.border;
                 copy.style.opacity = style.opacity;
-                // }
                 copy.className = this._marquee.current.className;
                 this.props.createAnnotation(copy, this.props.page);
                 this._marquee.current.style.opacity = "0";
@@ -357,7 +246,6 @@ export default class Page extends React.Component<IPageProps> {
             }
         }
 
-
         if (PDFMenu.Instance.Highlighting) {
             this.highlight(undefined, "goldenrod");
         }
@@ -371,9 +259,9 @@ export default class Page extends React.Component<IPageProps> {
 
     @action
     createTextAnnotation = (sel: Selection, selRange: Range) => {
-        let clientRects = selRange.getClientRects();
         if (this._textLayer.current) {
             let boundingRect = this._textLayer.current.getBoundingClientRect();
+            let clientRects = selRange.getClientRects();
             for (let i = 0; i < clientRects.length; i++) {
                 let rect = clientRects.item(i);
                 if (rect && rect.width !== this._textLayer.current.getBoundingClientRect().width && rect.height !== this._textLayer.current.getBoundingClientRect().height) {
@@ -389,9 +277,8 @@ export default class Page extends React.Component<IPageProps> {
             }
         }
         let text = selRange.extractContents().textContent;
-        if (text) {
-            this.props.setSelectionText(text);
-        }
+        text && this.props.setSelectionText(text);
+
         // clear selection
         if (sel.empty) {  // Chrome
             sel.empty();
@@ -401,19 +288,9 @@ export default class Page extends React.Component<IPageProps> {
     }
 
     doubleClick = (e: React.MouseEvent) => {
-        let target: any = e.target;
-        // if double clicking text
-        if (target && target.parentElement === this._textLayer.current) {
+        if (e.target && (e.target as any).parentElement === this._textLayer.current) {
             // do something to select the paragraph ideally
         }
-
-        let current = this._textLayer.current;
-        if (current) {
-            let boundingRect = current.getBoundingClientRect();
-            let x = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width);
-            let y = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height);
-            this.props.makePin(x, y, this.props.page);
-        }
     }
 
     render() {
@@ -425,7 +302,6 @@ export default class Page extends React.Component<IPageProps> {
                 <div className="pdfInkingLayer-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`, background: "red", border: `${this._marqueeWidth === 0 ? "" : "10px dashed black"}` }}>
-                        {/* <img ref={this._curly} src="https://static.thenounproject.com/png/331760-200.png" style={{ width: "100%", height: "100%", transform: `${this._rotate}` }} /> */}
                     </div>
                 </div>
                 <div className="textlayer" ref={this._textLayer} style={{ "position": "relative", "top": `-${2 * this._height}px`, "height": `${this._height}px` }} />
-- 
cgit v1.2.3-70-g09d2


From acbe0ced15150d15d81110cd2259b99e942d02e6 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Tue, 6 Aug 2019 18:17:48 -0400
Subject: pdf css cleanup

---
 src/client/views/nodes/PDFBox.scss   |  64 +++---------
 src/client/views/pdf/Annotation.scss |   5 +-
 src/client/views/pdf/Annotation.tsx  |   2 +-
 src/client/views/pdf/PDFMenu.tsx     |   2 +-
 src/client/views/pdf/PDFViewer.scss  | 186 ++++++++++++++---------------------
 src/client/views/pdf/PDFViewer.tsx   |  37 +++----
 src/client/views/pdf/Page.scss       |  31 ++++++
 src/client/views/pdf/Page.tsx        |  32 +++---
 8 files changed, 161 insertions(+), 198 deletions(-)
 create mode 100644 src/client/views/pdf/Page.scss

(limited to 'src/client/views/pdf/Annotation.tsx')

diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index e7655d598..a1bab0409 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -1,37 +1,3 @@
-.react-pdf__Page {
-    transform-origin: left top;
-    position: absolute;
-    top: 0;
-    left: 0;
-}
-
-.react-pdf__Page__textContent span {
-    user-select: text;
-}
-
-.react-pdf__Document {
-    position: absolute;
-}
-
-.pdfBox-buttonTray {
-    position: absolute;
-    top: 0;
-    left: 0;
-    z-index: 25;
-    pointer-events: all;
-}
-
-.pdfBox-thumbnail {
-    position: absolute;
-    width: 100%;
-}
-
-.pdfButton {
-    pointer-events: all;
-    width: 100px;
-    height: 100px;
-}
-
 .pdfBox-cont,
 .pdfBox-cont-interactive {
     display: flex;
@@ -43,26 +9,17 @@
 
 .pdfBox-cont {
     pointer-events: none;
-
-    .textlayer {
-        pointer-events: none;
-
+    .pdfPage-textlayer {
         span {
             pointer-events: none !important;
+            user-select: none; 
         }
     }
-
-    .page-cont {
-        pointer-events: none;
-    }
 }
 
 .pdfBox-cont-interactive {
     pointer-events: all;
-    display: flex;
-    flex-direction: row;
-
-    .textlayer {
+    .pdfPage-textlayer {
         span {
             pointer-events: all !important;
             user-select: text;
@@ -70,11 +27,22 @@
     }
 }
 
-.pdfBox-contentContainer {
-    position: absolute;
+.react-pdf__Page {
     transform-origin: left top;
+    position: absolute;
+    top: 0;
+    left: 0;
+}
+
+.react-pdf__Page__textContent span {
+    user-select: text;
+}
+
+.react-pdf__Document {
+    position: absolute;
 }
 
+
 .pdfBox-settingsCont {
     position: absolute;
     right: 0;
diff --git a/src/client/views/pdf/Annotation.scss b/src/client/views/pdf/Annotation.scss
index 0ea85d522..817115690 100644
--- a/src/client/views/pdf/Annotation.scss
+++ b/src/client/views/pdf/Annotation.scss
@@ -1,4 +1,7 @@
-.pdfViewer-annotationBox {
+.pdfAnnotation {
     pointer-events: all;
     user-select: none;
+    position: absolute;
+    background-color: pink;
+    opacity: 0.1;
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 9d68a86b8..947f5a2e8 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -130,7 +130,7 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
 
     render() {
         return (
-            <div className="pdfViewer-annotationBox" onPointerDown={this.onPointerDown} ref={this._mainCont}
+            <div className="pdfAnnotation" onPointerDown={this.onPointerDown} ref={this._mainCont}
                 style={{
                     top: this.props.y * scale,
                     left: this.props.x * scale,
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 7b3d5bfae..3ed81faef 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -32,7 +32,7 @@ export default class PDFMenu extends React.Component {
     @observable public Pinned: boolean = false;
 
     public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = emptyFunction;
-    public Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction;
+    public Highlight: (d: Doc | undefined, color: string) => void = emptyFunction;
     public Delete: () => void = emptyFunction;
     public Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction;
     public AddTag: (key: string, value: string) => boolean = returnFalse;
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index 41efb0c00..a2f3911c5 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -1,131 +1,93 @@
 
-.textLayer {
-    div {
-        user-select: text;
-    }
-}
-.viewer-button-cont {
-    position: absolute;
-    display: flex;
-    justify-content: space-evenly;
-    align-items: center;
-}
-
-.viewer-previousPage,
-.viewer-nextPage {
-    background: grey;
-    font-weight: bold;
-    opacity: 0.5;
-    padding: 0 10px;
-    border-radius: 5px;
-}
-
-.textLayer {
-    user-select: auto;
-}
 .pdfViewer-viewer {
     pointer-events:inherit;
     width: 100%;
-}
-
-.pdfViewer-text {
-    transform: scale(1.5);
-    transform-origin: top left;
-    .page {
-        .canvasWrapper {
-            display: none;
-        }
-
-        .textLayer {
-            position: relative;
-            user-select: none;
+    .pdfViewer-visibleElements {
+        .pdfPage-cont {
+            .pdfPage-textLayer {
+                div {
+                    user-select: text;
+                }
+                span {
+                    color: transparent;
+                    position: absolute;
+                    white-space: pre;
+                    cursor: text;
+                    -webkit-transform-origin: 0% 0%;
+                    transform-origin: 0% 0%;
+                }
+            }
         }
     }
-}
-
-.page-cont {
-    .textLayer {
-        user-select: auto;
-
-        div {
-            user-select: text;
-        }
+    .pdfViewer-text {
+        transform: scale(1.5);
+        transform-origin: top left;
     }
-}
-
-.pdfViewer-overlayCont {
-    position: absolute;
-    width: 100%;
-    height: 100px;
-    background: #121721;
-    bottom: 0;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    padding: 20px;
-    overflow: hidden;
-    transition: left .5s;
-}
 
-.pdfViewer-overlaySearchBar {
-    width: 20%;
-    height: 100%;
-    font-size: 30px;
-    padding: 5px;
-}
-
-.pdfViewer-overlayButton {
-    border-bottom-left-radius: 50%;
-    display: flex;
-    justify-content: space-evenly;
-    align-items: center;
-    height: 70px;
-    background: none;
-    padding: 0;
-    position: absolute;
-
-    .pdfViewer-overlayButton-arrow {
-        width: 0;
-        height: 0;
-        border-top: 25px solid transparent;
-        border-bottom: 25px solid transparent;
-        border-right: 25px solid #121721;
-        transition: all 0.5s;
+    .pdfViewer-annotationLayer {
+        position: absolute;
+        top: 0;
+        width: 100%;
+        pointer-events: none;
+        .pdfPage-annotationBox {
+            position: absolute;
+            background-color: red;
+            opacity: 0.1;
+        }
     }
 
-    .pdfViewer-overlayButton-iconCont {
+    .pdfViewer-overlayCont {
+        position: absolute;
+        width: 100%;
+        height: 100px;
         background: #121721;
-        height: 50px;
-        width: 70px;
+        bottom: 0;
         display: flex;
         justify-content: center;
         align-items: center;
-        margin-left: -2px;
-        border-radius: 3px;
+        padding: 20px;
+        overflow: hidden;
+        transition: left .5s;
+        .pdfViewer-overlaySearchBar {
+            width: 20%;
+            height: 100%;
+            font-size: 30px;
+            padding: 5px;
+        }
     }
-}
 
-.pdfViewer-overlayButton:hover {
-    background: none;
-}
+    .pdfViewer-overlayButton {
+        border-bottom-left-radius: 50%;
+        display: flex;
+        justify-content: space-evenly;
+        align-items: center;
+        height: 70px;
+        background: none;
+        padding: 0;
+        position: absolute;
+
+        .pdfViewer-overlayButton-arrow {
+            width: 0;
+            height: 0;
+            border-top: 25px solid transparent;
+            border-bottom: 25px solid transparent;
+            border-right: 25px solid #121721;
+            transition: all 0.5s;
+        }
 
-.pdfViewer-annotationBox {
-    position: absolute;
-    background-color: red;
-    opacity: 0.1;
-}
+        .pdfViewer-overlayButton-iconCont {
+            background: #121721;
+            height: 50px;
+            width: 70px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            margin-left: -2px;
+            border-radius: 3px;
+        }
+    }
 
-.pdfViewer-annotationLayer {
-    position: absolute;
-    top: 0;
-         width: 100%;
-        pointer-events: none;
+    .pdfViewer-overlayButton:hover {
+        background: none;
+    }
 }
-
-
-
-.pdfViewer-pinAnnotation {
-    background-color: red;
-    position: absolute;
-    border-radius: 100%;
-}
\ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 524bb0420..9abb22553 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -427,14 +427,13 @@ export class PDFViewer extends React.Component<IViewerProps> {
 
         if (this._searching) {
             let container = this._mainCont.current;
-            let viewer = this._viewer.current;
 
             if (!this._pdfFindController) {
-                if (container && viewer) {
+                if (container && this._viewer.current) {
                     let simpleLinkService = new SimpleLinkService();
                     this._pdfViewer = new PDFJSViewer.PDFViewer({
                         container: container,
-                        viewer: viewer,
+                        viewer: this._viewer.current,
                         linkService: simpleLinkService
                     });
                     simpleLinkService.setPdf(this.props.pdf);
@@ -483,25 +482,23 @@ export class PDFViewer extends React.Component<IViewerProps> {
     render() {
         return (
             <div className="pdfViewer-viewer" ref={this._mainCont} >
-                <div className="viewer" style={this._searching ? { position: "absolute", top: 0 } : {}}>
+                <div className="pdfViewer-visibleElements" style={this._searching ? { position: "absolute", top: 0 } : {}}>
                     {this._visibleElements}
                 </div>
                 <div className="pdfViewer-text" ref={this._viewer} />
-                <div className="pdfViewer-annotationLayer" style={{ height: NumCast(this.props.Document.nativeHeight) }}>
-                    <div className="pdfViewer-annotationLayer-subCont" ref={this._annotationLayer}>
-                        {this._annotations.filter(anno => {
-                            if (this._script && this._script.compiled) {
-                                let run = this._script.run({ this: anno });
-                                if (run.success) {
-                                    return run.result;
-                                }
+                <div className="pdfViewer-annotationLayer" style={{ height: NumCast(this.props.Document.nativeHeight) }} ref={this._annotationLayer}>
+                    {this._annotations.filter(anno => {
+                        if (this._script && this._script.compiled) {
+                            let run = this._script.run({ this: anno });
+                            if (run.success) {
+                                return run.result;
                             }
-                            return true;
-                        }).sort((a: Doc, b: Doc) => NumCast(a.y) - NumCast(b.y))
-                            .map((anno: Doc, index: number) =>
-                                <Annotation anno={anno} scrollTo={this.props.scrollTo} fieldExtensionDoc={this.props.fieldExtensionDoc} ParentIndex={this.getIndex} addDocTab={this.props.addDocTab} index={index} key={`${anno[Id]}-annotation`} />
-                            )}
-                    </div>
+                        }
+                        return true;
+                    }).sort((a: Doc, b: Doc) => NumCast(a.y) - NumCast(b.y))
+                        .map((anno: Doc, index: number) =>
+                            <Annotation anno={anno} scrollTo={this.props.scrollTo} fieldExtensionDoc={this.props.fieldExtensionDoc} ParentIndex={this.getIndex} addDocTab={this.props.addDocTab} index={index} key={`${anno[Id]}-annotation`} />
+                        )}
                 </div>
                 <div className="pdfViewer-overlayCont" onPointerDown={(e) => e.stopPropagation()}
                     style={{
@@ -509,9 +506,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                         left: `${this._searching ? 0 : 100}%`
                     }}>
                     <button className="pdfViewer-overlayButton" title="Open Search Bar"></button>
-                    {/* <button title="Previous Result" onClick={() => this.search(this._searchString)}><FontAwesomeIcon icon="arrow-up" size="3x" color="white" /></button>
-                    <button title="Next Result" onClick={this.nextResult}><FontAwesomeIcon icon="arrow-down" size="3x" color="white" /></button> */}
-                    <input onKeyDown={(e: React.KeyboardEvent) => e.keyCode === KeyCodes.ENTER ? this.search(this._searchString) : e.keyCode === KeyCodes.BACKSPACE ? e.stopPropagation() : true} placeholder="Search" className="pdfViewer-overlaySearchBar" onChange={this.searchStringChanged} />
+                    <input className="pdfViewer-overlaySearchBar" onKeyDown={(e: React.KeyboardEvent) => e.keyCode === KeyCodes.ENTER ? this.search(this._searchString) : e.keyCode === KeyCodes.BACKSPACE ? e.stopPropagation() : true} placeholder="Search" onChange={this.searchStringChanged} />
                     <button title="Search" onClick={() => this.search(this._searchString)}><FontAwesomeIcon icon="search" size="3x" color="white" /></button>
                 </div>
                 <button className="pdfViewer-overlayButton" onClick={this.prevAnnotation} title="Previous Annotation"
diff --git a/src/client/views/pdf/Page.scss b/src/client/views/pdf/Page.scss
new file mode 100644
index 000000000..6467c4979
--- /dev/null
+++ b/src/client/views/pdf/Page.scss
@@ -0,0 +1,31 @@
+
+.pdfPage-cont {
+
+    .pdfPage-dragAnnotationBox {
+        position: absolute;
+        background-color: transparent;
+        opacity: 0.1;
+    }
+    .pdfPage-annotationLayer {
+        pointer-events: none;
+        width: 100%;
+        height: 100%;
+        position: relative;
+        top: -100%;
+    }
+
+    .PdfPage-textLayer {
+        position: relative;
+        div {
+            user-select: text;
+        }
+        span {
+            color: transparent;
+            position: absolute;
+            white-space: pre;
+            cursor: text;
+            -webkit-transform-origin: 0% 0%;
+            transform-origin: 0% 0%;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 1da41bca1..47f2e7b56 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -8,7 +8,7 @@ import { Docs, DocUtils } from "../../documents/Documents";
 import { DragManager } from "../../util/DragManager";
 import PDFMenu from "./PDFMenu";
 import { scale } from "./PDFViewer";
-import "./PDFViewer.scss";
+import "./Page.scss";
 import React = require("react");
 
 
@@ -43,7 +43,6 @@ export default class Page extends React.Component<IPageProps> {
 
     private _canvas: React.RefObject<HTMLCanvasElement> = React.createRef();
     private _textLayer: React.RefObject<HTMLDivElement> = React.createRef();
-    private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
     private _marquee: React.RefObject<HTMLDivElement> = React.createRef();
     private _marqueeing: boolean = false;
     private _reactionDisposer?: IReactionDisposer;
@@ -95,7 +94,7 @@ export default class Page extends React.Component<IPageProps> {
     }
 
     @action
-    highlight = (targetDoc?: Doc, color: string = "red") => {
+    highlight = (targetDoc: Doc | undefined, color: string) => {
         // creates annotation documents for current highlights
         let annotationDoc = this.props.makeAnnotationDocuments(targetDoc, scale, color, false);
         Doc.GetProto(annotationDoc).annotationOn = this.props.Document;
@@ -114,7 +113,7 @@ export default class Page extends React.Component<IPageProps> {
         if (this._textLayer.current) {
             let targetDoc = Docs.Create.TextDocument({ width: 200, height: 200, title: "New Annotation" });
             targetDoc.targetPage = this.props.page;
-            let annotationDoc = this.highlight(undefined, "red");
+            let annotationDoc = this.highlight(undefined, "pink");
             annotationDoc.linkedToDoc = false;
             let dragData = new DragManager.AnnotationDragData(this.props.Document, annotationDoc, targetDoc);
             DragManager.StartAnnotationDrag([ele], dragData, e.pageX, e.pageY, {
@@ -196,7 +195,6 @@ export default class Page extends React.Component<IPageProps> {
             this._marqueeX = Math.min(this._startX, this._startX + this._marqueeWidth);
             this._marqueeY = Math.min(this._startY, this._startY + this._marqueeHeight);
             this._marqueeWidth = Math.abs(this._marqueeWidth);
-            this._marquee.current && (this._marquee.current.style.background = "red");
             e.stopPropagation();
             e.preventDefault();
         }
@@ -219,10 +217,9 @@ export default class Page extends React.Component<IPageProps> {
                 copy.style.height = style.height;
 
                 // apply the appropriate background, opacity, and transform
-                copy.style.background = "red";
                 copy.style.border = style.border;
                 copy.style.opacity = style.opacity;
-                copy.className = this._marquee.current.className;
+                copy.className = "pdfPage-annotationBox";
                 this.props.createAnnotation(copy, this.props.page);
                 this._marquee.current.style.opacity = "0";
             }
@@ -266,7 +263,7 @@ export default class Page extends React.Component<IPageProps> {
                 let rect = clientRects.item(i);
                 if (rect && rect.width !== this._textLayer.current.getBoundingClientRect().width && rect.height !== this._textLayer.current.getBoundingClientRect().height) {
                     let annoBox = document.createElement("div");
-                    annoBox.className = "pdfViewer-annotationBox";
+                    annoBox.className = "pdfPage-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();
@@ -295,16 +292,23 @@ export default class Page extends React.Component<IPageProps> {
 
     render() {
         return (
-            <div onPointerDown={this.onPointerDown} onDoubleClick={this.doubleClick} className={"page-cont"} style={{ "width": this._width, "height": this._height }}>
-                <div className="canvasContainer">
+            <div className={"pdfPage-cont"} onPointerDown={this.onPointerDown} onDoubleClick={this.doubleClick} style={{ "width": this._width, "height": this._height }}>
+                <div className="PdfPage-canvasContainer">
                     <canvas ref={this._canvas} />
                 </div>
-                <div className="pdfInkingLayer-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`, background: "red", border: `${this._marqueeWidth === 0 ? "" : "10px dashed black"}` }}>
+                <div className="pdfPage-annotationLayer">
+                    <div className="pdfPage-dragAnnotationBox" ref={this._marquee}
+                        style={{
+                            left: `${this._marqueeX}px`, top: `${this._marqueeY}px`,
+                            width: `${this._marqueeWidth}px`, height: `${this._marqueeHeight}px`,
+                            border: `${this._marqueeWidth === 0 ? "" : "10px dashed black"}`
+                        }}>
                     </div>
                 </div>
-                <div className="textlayer" ref={this._textLayer} style={{ "position": "relative", "top": `-${2 * this._height}px`, "height": `${this._height}px` }} />
+                <div className="pdfPage-textlayer"
+                    ref={this._textLayer}
+                    style={{ top: `-${2 * this._height}px`, height: `${this._height}px` }}
+                />
             </div>
         );
     }
-- 
cgit v1.2.3-70-g09d2


From 913055f1b6f8eac88eda2ba08715c9cc3b013f08 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 6 Aug 2019 23:54:39 -0400
Subject: pdf tweaks.

---
 src/client/views/pdf/Annotation.tsx | 39 +++++++++++++------------------------
 src/client/views/pdf/Page.tsx       |  8 ++------
 2 files changed, 15 insertions(+), 32 deletions(-)

(limited to 'src/client/views/pdf/Annotation.tsx')

diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 947f5a2e8..2610f6c6e 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -9,7 +9,7 @@ import { DocumentManager } from "../../util/DocumentManager";
 import { PresentationView } from "../presentationview/PresentationView";
 import PDFMenu from "./PDFMenu";
 import "./Annotation.scss";
-import { AnnotationTypes, scale } from "./PDFViewer";
+import { scale } from "./PDFViewer";
 
 interface IAnnotationProps {
     anno: Doc;
@@ -22,17 +22,8 @@ interface IAnnotationProps {
 
 export default class Annotation extends React.Component<IAnnotationProps> {
     render() {
-        let annotationDocs = DocListCast(this.props.anno.annotations);
-        let res = annotationDocs.map(a => {
-            let type = NumCast(a.type);
-            switch (type) {
-                case AnnotationTypes.Region:
-                    return <RegionAnnotation addDocTab={this.props.addDocTab} document={a} fieldExtensionDoc={this.props.fieldExtensionDoc} scrollTo={this.props.scrollTo} ParentIndex={this.props.ParentIndex} index={this.props.index} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />;
-                default:
-                    return <div></div>;
-            }
-        });
-        return res;
+        return DocListCast(this.props.anno.annotations).map(a => (
+            <RegionAnnotation {...this.props} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />));
     }
 }
 
@@ -51,8 +42,6 @@ interface IRegionAnnotationProps {
 
 @observer
 class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
-    @observable private _backgroundColor: string = "red";
-
     private _reactionDisposer?: IReactionDisposer;
     private _scrollDisposer?: IReactionDisposer;
     private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
@@ -60,13 +49,13 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
     componentDidMount() {
         this._reactionDisposer = reaction(
             () => this.props.document.delete,
-            () => this.props.document.delete && this._mainCont.current && (this._mainCont.current.style.display = "none"),
+            (del) => del && this._mainCont.current && (this._mainCont.current.style.display = "none"),
             { fireImmediately: true }
         );
 
         this._scrollDisposer = reaction(
             () => this.props.ParentIndex(),
-            () => this.props.ParentIndex() === this.props.index && this.props.scrollTo && this.props.scrollTo(this.props.y * scale)
+            (ind) => ind === this.props.index && this.props.scrollTo && this.props.scrollTo(this.props.y * scale)
         );
     }
 
@@ -129,15 +118,13 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
     }
 
     render() {
-        return (
-            <div className="pdfAnnotation" onPointerDown={this.onPointerDown} ref={this._mainCont}
-                style={{
-                    top: this.props.y * scale,
-                    left: this.props.x * scale,
-                    width: this.props.width * scale,
-                    height: this.props.height * scale,
-                    backgroundColor: this.props.ParentIndex() === this.props.index ? "green" : StrCast(this.props.document.color)
-                }} />
-        );
+        return (<div className="pdfAnnotation" onPointerDown={this.onPointerDown} ref={this._mainCont}
+            style={{
+                top: this.props.y * scale,
+                left: this.props.x * scale,
+                width: this.props.width * scale,
+                height: this.props.height * scale,
+                backgroundColor: this.props.ParentIndex() === this.props.index ? "green" : StrCast(this.props.document.color)
+            }} />);
     }
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index fd4fbfb21..a1f807f13 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -198,16 +198,13 @@ export default class Page extends React.Component<IPageProps> {
     onSelectEnd = (e: PointerEvent): void => {
         if (this._marqueeing) {
             this._marqueeing = false;
-            if (this._marquee.current) {
+            if (this._marquee.current) { // make a copy of the marquee
                 let copy = document.createElement("div");
-                // make a copy of the marquee
                 let style = this._marquee.current.style;
                 copy.style.left = style.left;
                 copy.style.top = style.top;
                 copy.style.width = style.width;
                 copy.style.height = style.height;
-
-                // apply the appropriate background, opacity, and transform
                 copy.style.border = style.border;
                 copy.style.opacity = style.opacity;
                 copy.className = "pdfPage-annotationBox";
@@ -293,7 +290,6 @@ export default class Page extends React.Component<IPageProps> {
                     }}>
                 </div>
                 <div className="pdfPage-textlayer" ref={this._textLayer} />
-            </div>
-        );
+            </div>);
     }
 }
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 941c50617a0cbaef054f2be856de013bd69ea81f Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 7 Aug 2019 18:15:38 -0400
Subject: pdf annotaitons

---
 src/client/documents/Documents.ts    |  1 +
 src/client/views/nodes/PDFBox.tsx    |  3 +-
 src/client/views/pdf/Annotation.scss |  2 +-
 src/client/views/pdf/Annotation.tsx  |  8 +--
 src/client/views/pdf/PDFViewer.tsx   | 95 ++++++++++++++----------------------
 src/client/views/pdf/Page.tsx        |  6 +--
 6 files changed, 47 insertions(+), 68 deletions(-)

(limited to 'src/client/views/pdf/Annotation.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index e804d5440..9c1278150 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -84,6 +84,7 @@ export interface DocumentOptions {
     templates?: List<string>;
     viewType?: number;
     backgroundColor?: string;
+    opacity?: number;
     defaultBackgroundColor?: string;
     dropAction?: dropActionType;
     backgroundLayout?: string;
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index e9207404e..6450cb826 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -194,10 +194,11 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
                 onScroll={this.onScroll}
                 style={{ marginTop: `${this.containingCollectionDocument ? NumCast(this.containingCollectionDocument.panY) : 0}px` }}
                 ref={this._mainCont}>
-                <div className="pdfBox-scrollHack" style={{ height: NumCast(this.props.Document.scrollHeight) + (NumCast(this.props.Document.nativeHeight) - NumCast(this.props.Document.nativeHeight) / NumCast(this.props.Document.scale)), width: "100%" }} />
+                <div className="pdfBox-scrollHack" style={{ height: NumCast(this.props.Document.scrollHeight) + (NumCast(this.props.Document.nativeHeight) - NumCast(this.props.Document.nativeHeight) / NumCast(this.props.Document.scale, 1)), width: "100%" }} />
                 <PDFViewer pdf={this._pdf} url={pdfUrl.url.pathname} active={this.props.active} scrollTo={this.scrollTo} loaded={this.loaded} panY={NumCast(this.props.Document.panY)}
                     Document={this.props.Document} DataDoc={this.props.DataDoc}
                     addDocTab={this.props.addDocTab} setPanY={this.setPanY}
+                    addDocument={this.props.addDocument}
                     fieldKey={this.props.fieldKey} fieldExtensionDoc={this.fieldExtensionDoc} />
                 {this.settingsPanel()}
             </div>);
diff --git a/src/client/views/pdf/Annotation.scss b/src/client/views/pdf/Annotation.scss
index 817115690..0c6df74f0 100644
--- a/src/client/views/pdf/Annotation.scss
+++ b/src/client/views/pdf/Annotation.scss
@@ -2,6 +2,6 @@
     pointer-events: all;
     user-select: none;
     position: absolute;
-    background-color: pink;
+    background-color: red;
     opacity: 0.1;
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx
index 2610f6c6e..7ba7b6d14 100644
--- a/src/client/views/pdf/Annotation.tsx
+++ b/src/client/views/pdf/Annotation.tsx
@@ -120,10 +120,10 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> {
     render() {
         return (<div className="pdfAnnotation" onPointerDown={this.onPointerDown} ref={this._mainCont}
             style={{
-                top: this.props.y * scale,
-                left: this.props.x * scale,
-                width: this.props.width * scale,
-                height: this.props.height * scale,
+                top: this.props.y,
+                left: this.props.x,
+                width: this.props.width,
+                height: this.props.height,
                 backgroundColor: this.props.ParentIndex() === this.props.index ? "green" : StrCast(this.props.document.color)
             }} />);
     }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index f3281047a..95df10c58 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -36,6 +36,7 @@ interface IViewerProps {
     active: () => boolean;
     setPanY?: (n: number) => void;
     addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void;
+    addDocument?: (doc: Doc, allowDuplicates?: boolean) => boolean;
 }
 
 /**
@@ -124,7 +125,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         if (this.props.active() && e.clipboardData) {
             e.clipboardData.setData("text/plain", this._selectionText);
             e.clipboardData.setData("dash/pdfOrigin", this.props.Document[Id]);
-            e.clipboardData.setData("dash/pdfRegion", this.makeAnnotationDocument(undefined, 0, "#0390fc")[Id]);
+            e.clipboardData.setData("dash/pdfRegion", this.makeAnnotationDocument(undefined, "#0390fc")[Id]);
             e.preventDefault();
         }
     }
@@ -133,7 +134,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         if (e.clipboardData && e.clipboardData.getData("dash/pdfOrigin") === this.props.Document[Id]) {
             let linkDocId = e.clipboardData.getData("dash/linkDoc");
             linkDocId && DocServer.GetRefField(linkDocId).then(async (link) =>
-                (link instanceof Doc) && (Doc.GetProto(link).anchor2 = this.makeAnnotationDocument(await Cast(Doc.GetProto(link), Doc), 0, "#0390fc", false)));
+                (link instanceof Doc) && (Doc.GetProto(link).anchor2 = this.makeAnnotationDocument(await Cast(Doc.GetProto(link), Doc), "#0390fc", false)));
         }
     }
 
@@ -166,32 +167,50 @@ export class PDFViewer extends React.Component<IViewerProps> {
     }
 
     @action
-    makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string, createLink: boolean = true): Doc => {
+    makeAnnotationDocument = (sourceDoc: Doc | undefined, color: string, createLink: boolean = true): Doc => {
         let mainAnnoDoc = Docs.Create.InstanceFromProto(new Doc(), "", {});
+        let mainAnnoDocProto = Doc.GetProto(mainAnnoDoc);
         let annoDocs: Doc[] = [];
         let minY = Number.MAX_VALUE;
-        this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => value.map(anno => {
-            let annoDoc = new Doc();
-            if (anno.style.left) annoDoc.x = parseInt(anno.style.left) / scale;
-            if (anno.style.top) annoDoc.y = parseInt(anno.style.top) / scale;
-            if (anno.style.height) annoDoc.height = parseInt(anno.style.height) / scale;
-            if (anno.style.width) annoDoc.width = parseInt(anno.style.width) / scale;
-            annoDoc.page = key;
+        if (this._savedAnnotations.size() === 1 && this._savedAnnotations.values()[0].length === 1 && !createLink) {
+            let anno = this._savedAnnotations.values()[0][0];
+            let annoDoc = Docs.Create.FreeformDocument([], { backgroundColor: "rgba(255, 0, 0, 0.1)", title: "Annotation on " + StrCast(this.props.Document.title) });
+            if (anno.style.left) annoDoc.x = parseInt(anno.style.left);
+            if (anno.style.top) annoDoc.y = parseInt(anno.style.top);
+            if (anno.style.height) annoDoc.height = parseInt(anno.style.height);
+            if (anno.style.width) annoDoc.width = parseInt(anno.style.width);
             annoDoc.target = sourceDoc;
             annoDoc.group = mainAnnoDoc;
             annoDoc.color = color;
             annoDoc.type = AnnotationTypes.Region;
             annoDocs.push(annoDoc);
+            annoDoc.isBackground = true;
             anno.remove();
-            (annoDoc.y !== undefined) && (minY = Math.min(NumCast(annoDoc.y), minY));
-        }));
-
-        let mainAnnoDocProto = Doc.GetProto(mainAnnoDoc);
-        mainAnnoDocProto.title = "Annotation on " + StrCast(this.props.Document.title);
+            this.props.addDocument && this.props.addDocument(annoDoc, false);
+            mainAnnoDoc = annoDoc;
+            mainAnnoDocProto = Doc.GetProto(annoDoc);
+        } else {
+            this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => value.map(anno => {
+                let annoDoc = new Doc();
+                if (anno.style.left) annoDoc.x = parseInt(anno.style.left);
+                if (anno.style.top) annoDoc.y = parseInt(anno.style.top);
+                if (anno.style.height) annoDoc.height = parseInt(anno.style.height);
+                if (anno.style.width) annoDoc.width = parseInt(anno.style.width);
+                annoDoc.target = sourceDoc;
+                annoDoc.group = mainAnnoDoc;
+                annoDoc.color = color;
+                annoDoc.type = AnnotationTypes.Region;
+                annoDocs.push(annoDoc);
+                anno.remove();
+                (annoDoc.y !== undefined) && (minY = Math.min(NumCast(annoDoc.y), minY));
+            }));
+
+            mainAnnoDocProto.y = Math.max(minY, 0);
+            mainAnnoDocProto.annotations = new List<Doc>(annoDocs);
+        }
         mainAnnoDocProto.pdfDoc = this.props.Document;
+        mainAnnoDocProto.title = "Annotation on " + StrCast(this.props.Document.title);
         mainAnnoDocProto.annotationOn = this.props.Document;
-        mainAnnoDocProto.y = Math.max(minY, 0);
-        mainAnnoDocProto.annotations = new List<Doc>(annoDocs);
         if (sourceDoc && createLink) {
             DocUtils.MakeLink(sourceDoc, mainAnnoDocProto, undefined, `Annotation from ${StrCast(this.props.Document.title)}`, "", StrCast(this.props.Document.title));
         }
@@ -346,48 +365,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
             this._mainCont.current.addEventListener("pagesloaded", executeFind);
             this._mainCont.current.addEventListener("pagerendered", executeFind);
         }
-
-        // let viewer = this._viewer.current;
-
-        // if (!this._pdfFindController) {
-        //     if (container && viewer) {
-        //         let simpleLinkService = new SimpleLinkService();
-        //         let pdfViewer = new PDFJSViewer.PDFViewer({
-        //             container: container,
-        //             viewer: viewer,
-        //             linkService: simpleLinkService
-        //         });
-        //         simpleLinkService.setPdf(this.props.pdf);
-        //         container.addEventListener("pagesinit", () => {
-        //             pdfViewer.currentScaleValue = 1;
-        //         });
-        //         container.addEventListener("pagerendered", () => {
-        //             console.log("rendered");
-        //             this._pdfFindController.executeCommand('find',
-        //                 {
-        //                     caseSensitive: false,
-        //                     findPrevious: undefined,
-        //                     highlightAll: true,
-        //                     phraseSearch: true,
-        //                     query: searchString
-        //                 });
-        //         });
-        //         pdfViewer.setDocument(this.props.pdf);
-        //         this._pdfFindController = new PDFJSViewer.PDFFindController(pdfViewer);
-        //         // this._pdfFindController._linkService = pdfLinkService;
-        //         pdfViewer.findController = this._pdfFindController;
-        //     }
-        // }
-        // else {
-        //     this._pdfFindController.executeCommand('find',
-        //         {
-        //             caseSensitive: false,
-        //             findPrevious: undefined,
-        //             highlightAll: true,
-        //             phraseSearch: true,
-        //             query: searchString
-        //         });
-        // }
     }
 
 
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 6de2db427..4986f44d5 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -24,7 +24,7 @@ interface IPageProps {
     renderAnnotations: (annotations: Doc[], removeOld: boolean) => void;
     sendAnnotations: (annotations: HTMLDivElement[], page: number) => void;
     createAnnotation: (div: HTMLDivElement, page: number) => void;
-    makeAnnotationDocuments: (doc: Doc | undefined, scale: number, color: string, linkTo: boolean) => Doc;
+    makeAnnotationDocuments: (doc: Doc | undefined, color: string, linkTo: boolean) => Doc;
     getScrollFromPage: (page: number) => number;
     setSelectionText: (text: string) => void;
 }
@@ -87,7 +87,7 @@ export default class Page extends React.Component<IPageProps> {
     @action
     highlight = (targetDoc: Doc | undefined, color: string) => {
         // creates annotation documents for current highlights
-        let annotationDoc = this.props.makeAnnotationDocuments(targetDoc, scale, color, false);
+        let annotationDoc = this.props.makeAnnotationDocuments(targetDoc, color, false);
         Doc.AddDocToList(this.props.fieldExtensionDoc, "annotations", annotationDoc);
         return annotationDoc;
     }
@@ -143,7 +143,7 @@ export default class Page extends React.Component<IPageProps> {
     @action
     onPointerDown = (e: React.PointerEvent): void => {
         // if alt+left click, drag and annotate
-        if (this.props.Document.scale !== 1) return;
+        if (NumCast(this.props.Document.scale, 1) !== 1) return;
         if (e.altKey && e.button === 0) {
             e.stopPropagation();
         }
-- 
cgit v1.2.3-70-g09d2

