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/pdf/PDFViewer.tsx | 412 +++++++++++--------------------------
 1 file changed, 122 insertions(+), 290 deletions(-)

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

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" />
-- 
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/PDFViewer.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 149a411e553706af2126ffdf2a141553ccc5aa13 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Tue, 6 Aug 2019 23:35:36 -0400
Subject: more cleanup of pdfs

---
 src/Utils.ts                       |   2 +
 src/client/views/pdf/PDFViewer.tsx | 373 +++++++++++++++----------------------
 src/client/views/pdf/Page.scss     |  16 +-
 src/client/views/pdf/Page.tsx      |  52 ++----
 4 files changed, 178 insertions(+), 265 deletions(-)

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

diff --git a/src/Utils.ts b/src/Utils.ts
index 502540eb0..bad875f0d 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -132,6 +132,8 @@ export function WithKeys(obj: any, keys: string[], addKeyFunc?: (dup: any) => vo
     return dup;
 }
 
+export function numberRange(num: number) { return Array.from(Array(num)).map((v, i) => i); }
+
 export function returnTrue() { return true; }
 
 export function returnFalse() { return false; }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 9abb22553..411857223 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -5,16 +5,16 @@ 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 } from "../../../new_fields/Doc";
+import { Doc, DocListCast, FieldResult } 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 { Utils, numberRange } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { Docs, DocUtils } from "../../documents/Documents";
 import { KeyCodes } from "../../northstar/utils/KeyCodes";
-import { CompileResult, CompileScript } from "../../util/Scripting";
+import { CompileScript, CompiledScript } from "../../util/Scripting";
 import Annotation from "./Annotation";
 import Page from "./Page";
 import "./PDFViewer.scss";
@@ -48,7 +48,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
     @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 = CompileScript("return true");
+    @observable private _script: CompiledScript = CompileScript("return true") as CompiledScript;
     @observable private _searching: boolean = false;
     @observable private Index: number = -1;
 
@@ -64,18 +64,32 @@ export class PDFViewer extends React.Component<IViewerProps> {
     private _searchString: string = "";
     private _selectionText: string = "";
 
-    componentDidUpdate = (prevProps: IViewerProps) => {
-        this.scrollY !== prevProps.scrollY && this.renderPages();
+    @computed get scrollY(): number { return this.props.scrollY; }
+
+    // startIndex: where to start rendering pages
+    @computed get startIndex(): number { return Math.max(0, this.getPageFromScroll(this.scrollY) - this._pageBuffer); }
+
+    // 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] ? this._pageSizes[0].height : 0)) + this._pageBuffer);
     }
 
-    @action
-    componentDidMount = () => {
+    @computed get filteredAnnotations() {
+        return this._annotations.filter(anno => {
+            let run = this._script.run({ this: anno });
+            return run.success ? run.result : true;
+        });
+    }
+
+    componentDidUpdate = (prevProps: IViewerProps) => this.scrollY !== prevProps.scrollY && this.renderPages();
+
+    componentDidMount = async () => {
+        await this.initialLoad();
+
         this._reactionDisposer = reaction(
             () => [this.props.active(), this.startIndex, this._pageSizes.length ? this.endIndex : 0],
-            async () => {
-                await this.initialLoad();
-                this.renderPages();
-            }, { fireImmediately: true });
+            () => this.renderPages(),
+            { fireImmediately: true });
 
         this._annotationReactionDisposer = reaction(
             () => this.props.fieldExtensionDoc && DocListCast(this.props.fieldExtensionDoc.annotations),
@@ -83,17 +97,12 @@ export class PDFViewer extends React.Component<IViewerProps> {
             { fireImmediately: true });
 
         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;
-                        }
-                    }
+            () => ({ scriptField: Cast(this.props.Document.filterScript, ScriptField), annos: this._annotations.slice() }),
+            action(({ scriptField, annos }: { scriptField: FieldResult<ScriptField>, annos: Doc[] }) => {
+                this._script = scriptField && scriptField.script.compiled ? scriptField.script : CompileScript("return true") as CompiledScript;
+                annos.forEach(d => {
+                    let run = this._script.run(d);
+                    d.opacity = !run.success || run.result ? 1 : 0;
                 });
                 this.Index = -1;
             }),
@@ -111,13 +120,11 @@ export class PDFViewer extends React.Component<IViewerProps> {
         document.removeEventListener("copy", this.copy);
     }
 
-    private copy = (e: ClipboardEvent) => {
+    copy = (e: ClipboardEvent) => {
         if (this.props.active() && e.clipboardData) {
-            let text = this._selectionText;
-            let annoDoc = this.makeAnnotationDocument(undefined, 0, "#0390fc");
-            e.clipboardData.setData("text/plain", text);
+            e.clipboardData.setData("text/plain", this._selectionText);
             e.clipboardData.setData("dash/pdfOrigin", this.props.Document[Id]);
-            e.clipboardData.setData("dash/pdfRegion", annoDoc[Id]);
+            e.clipboardData.setData("dash/pdfRegion", this.makeAnnotationDocument(undefined, 0, "#0390fc")[Id]);
             e.preventDefault();
         }
     }
@@ -130,9 +137,13 @@ export class PDFViewer extends React.Component<IViewerProps> {
         }
     }
 
-    setSelectionText = (text: string) => {
-        this._selectionText = text;
-    }
+    searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => this._searchString = e.currentTarget.value;
+
+    pageLoaded = (page: Pdfjs.PDFPageViewport): void => this.props.loaded(page.width, page.height, this.props.pdf.numPages);
+
+    setSelectionText = (text: string) => this._selectionText = text;
+
+    getIndex = () => this.Index;
 
     @action
     initialLoad = async () => {
@@ -157,32 +168,27 @@ export class PDFViewer extends React.Component<IViewerProps> {
 
     @action
     makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string, createLink: boolean = true): Doc => {
-        let annoDocs: Doc[] = [];
         let mainAnnoDoc = Docs.Create.InstanceFromProto(new Doc(), "", {});
+        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;
+            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));
+        }));
 
         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) {
-                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;
-                    minY = Math.min(parseInt(anno.style.top), minY);
-                }
-                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;
-                annoDoc.target = sourceDoc;
-                annoDoc.group = mainAnnoDoc;
-                annoDoc.color = color;
-                annoDoc.type = AnnotationTypes.Region;
-                annoDocs.push(annoDoc);
-                anno.remove();
-            }
-        });
-
         mainAnnoDoc.y = Math.max(minY, 0);
         mainAnnoDoc.annotations = new List<Doc>(annoDocs);
         if (sourceDoc && createLink) {
@@ -193,15 +199,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
         return mainAnnoDoc;
     }
 
-    /**
-     * 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 = (page: Pdfjs.PDFPageViewport): void => {
-        this.props.loaded(page.width, page.height, this.props.pdf.numPages);
-    }
-
     @action
     getPlaceholderPage = (page: number) => {
         if (this._isPage[page] !== "none") {
@@ -218,25 +215,19 @@ export class PDFViewer extends React.Component<IViewerProps> {
     getRenderedPage = (page: number) => {
         if (this._isPage[page] !== "page") {
             this._isPage[page] = "page";
-            this._visibleElements[page] = (
-                <Page
-                    setSelectionText={this.setSelectionText}
-                    size={this._pageSizes[page]}
-                    pdf={this.props.pdf}
-                    page={page}
-                    numPages={this.props.pdf.numPages}
-                    key={`${this.props.url}-rendered-${page + 1}`}
-                    name={`${this.props.pdf.fingerprint + `-page${page + 1}`}`}
-                    pageLoaded={this.pageLoaded}
-                    fieldExtensionDoc={this.props.fieldExtensionDoc}
-                    Document={this.props.Document}
-                    renderAnnotations={this.renderAnnotations}
-                    createAnnotation={this.createAnnotation}
-                    sendAnnotations={this.receiveAnnotations}
-                    makeAnnotationDocuments={this.makeAnnotationDocument}
-                    getScrollFromPage={this.getScrollFromPage}
-                    {...this.props} />
-            );
+            this._visibleElements[page] = (<Page {...this.props}
+                size={this._pageSizes[page]}
+                numPages={this.props.pdf.numPages}
+                setSelectionText={this.setSelectionText}
+                page={page}
+                key={`${this.props.url}-rendered-${page + 1}`}
+                name={`${this.props.pdf.fingerprint + `-page${page + 1}`}`}
+                pageLoaded={this.pageLoaded}
+                renderAnnotations={this.renderAnnotations}
+                createAnnotation={this.createAnnotation}
+                sendAnnotations={this.receiveAnnotations}
+                makeAnnotationDocuments={this.makeAnnotationDocument}
+                getScrollFromPage={this.getScrollFromPage} />);
         }
     }
 
@@ -244,13 +235,12 @@ export class PDFViewer extends React.Component<IViewerProps> {
     // file address of the pdf
     @action
     getPageImage = async (page: number) => {
-        let handleError = () => this.getRenderedPage(page);
         if (this._isPage[page] !== "image") {
             this._isPage[page] = "image";
             try {
                 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}
+                    <img key={res.path} src={res.path} onError={() => this.getRenderedPage(page)}
                         style={{ width: `${parseInt(res.width) * scale}px`, height: `${parseInt(res.height) * scale}px` }} />);
             } catch (e) {
                 console.log(e);
@@ -258,26 +248,14 @@ export class PDFViewer extends React.Component<IViewerProps> {
         }
     }
 
-    @computed get scrollY(): number { return this.props.scrollY; }
-
-    // startIndex: where to start rendering pages
-    @computed get startIndex(): number { return Math.max(0, this.getPageFromScroll(this.scrollY) - this._pageBuffer); }
-
-    // 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] ? this._pageSizes[0].height : 0)) + this._pageBuffer);
-    }
-
-    @action
     renderPages = () => {
-        Array.from(Array(this.props.pdf.numPages).keys()).filter(p => this._isPage[p] !== undefined).map(i =>
+        numberRange(this.props.pdf.numPages).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)
-        );
+                this.props.active() ? this.getRenderedPage(i) : this.getPageImage(i));
     }
 
     @action
-    private renderAnnotations = (annotations: Doc[], removeOldAnnotations: boolean): void => {
+    renderAnnotations = (annotations: Doc[], removeOldAnnotations: boolean): void => {
         if (removeOldAnnotations) {
             this._annotations = annotations;
         }
@@ -288,6 +266,21 @@ export class PDFViewer extends React.Component<IViewerProps> {
     }
 
     @action
+    prevAnnotation = (e: React.MouseEvent) => {
+        e.stopPropagation();
+        this.Index = Math.max(this.Index - 1, 0);
+    }
+
+    @action
+    nextAnnotation = (e: React.MouseEvent) => {
+        e.stopPropagation();
+        this.Index = Math.min(this.Index + 1, this.filteredAnnotations.length - 1);
+    }
+
+    sendAnnotations = (page: number) => {
+        return this._savedAnnotations.getValue(page);
+    }
+
     receiveAnnotations = (annotations: HTMLDivElement[], page: number) => {
         if (page === -1) {
             this._savedAnnotations.values().forEach(v => v.forEach(a => a.remove()));
@@ -298,10 +291,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
         }
     }
 
-    sendAnnotations = (page: number): HTMLDivElement[] | undefined => {
-        return this._savedAnnotations.getValue(page);
-    }
-
     // get the page index that the vertical offset passed in is on
     getPageFromScroll = (vOffset: number) => {
         let index = 0;
@@ -313,13 +302,10 @@ export class PDFViewer extends React.Component<IViewerProps> {
     }
 
     getScrollFromPage = (index: number): number => {
-        let counter = 0;
-        for (let i = 0; i < Math.min(this.props.pdf.numPages, index); i++) {
-            counter += this._pageSizes[i].height;
-        }
-        return counter;
+        return numberRange(Math.min(this.props.pdf.numPages, index)).reduce((counter, i) => counter + this._pageSizes[i].height, 0);
     }
 
+    @action
     createAnnotation = (div: HTMLDivElement, page: number) => {
         if (this._annotationLayer.current) {
             if (div.style.top) {
@@ -337,8 +323,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
         }
     }
 
-    getIndex = () => this.Index;
-
     @action
     search = (searchString: string) => {
         if (this._pdfViewer._pageViewsReady) {
@@ -350,27 +334,16 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 query: searchString
             });
         }
-        else {
-            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
-                    })
-                );
-            }
+        else if (this._mainCont.current) {
+            let executeFind = () => this._pdfFindController.executeCommand('find', {
+                caseSensitive: false,
+                findPrevious: undefined,
+                highlightAll: true,
+                phraseSearch: true,
+                query: searchString
+            });
+            this._mainCont.current.addEventListener("pagesloaded", executeFind);
+            this._mainCont.current.addEventListener("pagerendered", executeFind);
         }
 
         // let viewer = this._viewer.current;
@@ -416,9 +389,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
         // }
     }
 
-    searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
-        this._searchString = e.currentTarget.value;
-    }
 
     @action
     toggleSearch = (e: React.MouseEvent) => {
@@ -426,23 +396,19 @@ export class PDFViewer extends React.Component<IViewerProps> {
         this._searching = !this._searching;
 
         if (this._searching) {
-            let container = this._mainCont.current;
-
-            if (!this._pdfFindController) {
-                if (container && this._viewer.current) {
-                    let simpleLinkService = new SimpleLinkService();
-                    this._pdfViewer = new PDFJSViewer.PDFViewer({
-                        container: container,
-                        viewer: this._viewer.current,
-                        linkService: simpleLinkService
-                    });
-                    simpleLinkService.setPdf(this.props.pdf);
-                    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._pdfViewer.findController = this._pdfFindController;
-                }
+            if (!this._pdfFindController && this._mainCont.current && this._viewer.current) {
+                let simpleLinkService = new SimpleLinkService();
+                this._pdfViewer = new PDFJSViewer.PDFViewer({
+                    container: this._mainCont.current,
+                    viewer: this._viewer.current,
+                    linkService: simpleLinkService
+                });
+                simpleLinkService.setPdf(this.props.pdf);
+                this._mainCont.current.addEventListener("pagesinit", () => this._pdfViewer.currentScaleValue = 1);
+                this._mainCont.current.addEventListener("pagerendered", () => console.log("rendered"));
+                this._pdfViewer.setDocument(this.props.pdf);
+                this._pdfFindController = new PDFJSViewer.PDFFindController(this._pdfViewer);
+                this._pdfViewer.findController = this._pdfFindController;
             }
         }
         else {
@@ -456,86 +422,47 @@ export class PDFViewer extends React.Component<IViewerProps> {
         }
     }
 
-    @action
-    prevAnnotation = (e: React.MouseEvent) => {
-        e.stopPropagation();
-        this.Index = Math.max(this.Index - 1, 0);
-    }
-
-    @action
-    nextAnnotation = (e: React.MouseEvent) => {
-        e.stopPropagation();
-
-        let compiled = this._script;
-        let filtered = this._annotations.filter(anno => {
-            if (compiled && compiled.compiled) {
-                let run = compiled.run({ this: anno });
-                if (run.success) {
-                    return run.result;
-                }
-            }
-            return true;
-        });
-        this.Index = Math.min(this.Index + 1, filtered.length - 1);
-    }
-
     render() {
-        return (
-            <div className="pdfViewer-viewer" ref={this._mainCont} >
-                <div className="pdfViewer-visibleElements" style={this._searching ? { position: "absolute", top: 0 } : {}}>
-                    {this._visibleElements}
+        return (<div className="pdfViewer-viewer" ref={this._mainCont} >
+            <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) }} ref={this._annotationLayer}>
+                {this.filteredAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map((anno, index) =>
+                    <Annotation {...this.props} ParentIndex={this.getIndex} anno={anno} index={index} key={`${anno[Id]}-annotation`} />)}
+            </div>
+            <div className="pdfViewer-overlayCont" onPointerDown={(e) => e.stopPropagation()}
+                style={{ nbottom: -this.props.scrollY, left: `${this._searching ? 0 : 100}%` }}>
+                <button className="pdfViewer-overlayButton" title="Open Search Bar" />
+                <input className="pdfViewer-overlaySearchBar" placeholder="Search" onChange={this.searchStringChanged}
+                    onKeyDown={(e: React.KeyboardEvent) => e.keyCode === KeyCodes.ENTER ? this.search(this._searchString) : e.keyCode === KeyCodes.BACKSPACE ? e.stopPropagation() : true} />
+                <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.active() ? "flex" : "none" }}>
+                <div className="pdfViewer-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
+                    <FontAwesomeIcon style={{ color: "white" }} icon={"arrow-up"} size="3x" />
                 </div>
-                <div className="pdfViewer-text" ref={this._viewer} />
-                <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`} />
-                        )}
+            </button>
+            <button className="pdfViewer-overlayButton" onClick={this.nextAnnotation} title="Next Annotation"
+                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>
-                <div className="pdfViewer-overlayCont" onPointerDown={(e) => e.stopPropagation()}
-                    style={{
-                        bottom: -this.props.scrollY,
-                        left: `${this._searching ? 0 : 100}%`
-                    }}>
-                    <button className="pdfViewer-overlayButton" title="Open Search Bar"></button>
-                    <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>
+            </button>
+            <button className="pdfViewer-overlayButton" onClick={this.toggleSearch} title="Open Search Bar"
+                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" />
                 </div>
-                <button className="pdfViewer-overlayButton" onClick={this.prevAnnotation} title="Previous Annotation"
-                    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.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.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" />
-                    </div>
-                </button>
-            </div >
-        );
+            </button>
+        </div >);
     }
 }
 
-export enum AnnotationTypes {
-    Region
-}
+export enum AnnotationTypes { Region }
 
 class SimpleLinkService {
     externalLinkTarget: any = null;
diff --git a/src/client/views/pdf/Page.scss b/src/client/views/pdf/Page.scss
index 6467c4979..af1628a6f 100644
--- a/src/client/views/pdf/Page.scss
+++ b/src/client/views/pdf/Page.scss
@@ -1,21 +1,21 @@
 
 .pdfPage-cont {
+    position: relative;
+
+    .pdfPage-canvasContainer {
+        position: absolute;
+    }
 
     .pdfPage-dragAnnotationBox {
         position: absolute;
         background-color: transparent;
         opacity: 0.1;
     }
-    .pdfPage-annotationLayer {
-        pointer-events: none;
+
+    .pdfPage-textLayer {
+        position: absolute;
         width: 100%;
         height: 100%;
-        position: relative;
-        top: -100%;
-    }
-
-    .PdfPage-textLayer {
-        position: relative;
         div {
             user-select: text;
         }
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 47f2e7b56..fd4fbfb21 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -49,30 +49,21 @@ export default class Page extends React.Component<IPageProps> {
     private _startY: number = 0;
     private _startX: number = 0;
 
-    componentDidMount = (): void => {
-        this.loadPage(this.props.pdf);
-    }
+    componentDidMount = (): void => this.loadPage(this.props.pdf);
 
-    componentDidUpdate = (): void => {
-        this.loadPage(this.props.pdf);
-    }
+    componentDidUpdate = (): void => this.loadPage(this.props.pdf);
 
-    componentWillUnmount = (): void => {
-        this._reactionDisposer && this._reactionDisposer();
-    }
+    componentWillUnmount = (): void => this._reactionDisposer && this._reactionDisposer();
 
-    private loadPage = (pdf: Pdfjs.PDFDocumentProxy): void => {
-        this._state !== "rendering" && !this._page && pdf.getPage(this._currPage).then(
-            (page: Pdfjs.PDFPageProxy): void => {
-                this._state = "rendering";
-                this.renderPage(page);
-            });
+    loadPage = (pdf: Pdfjs.PDFDocumentProxy): void => {
+        pdf.getPage(this._currPage).then(page => this.renderPage(page));
     }
 
     @action
-    private renderPage = (page: Pdfjs.PDFPageProxy): void => {
+    renderPage = (page: Pdfjs.PDFPageProxy): void => {
         // lower scale = easier to read at small sizes, higher scale = easier to read at large sizes
-        if (this._canvas.current && this._textLayer.current) {
+        if (this._state !== "rendering" && !this._page && this._canvas.current && this._textLayer.current) {
+            this._state = "rendering";
             let viewport = page.getViewport(scale);
             this._canvas.current.width = this._width = viewport.width;
             this._canvas.current.height = this._height = viewport.height;
@@ -113,7 +104,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, "pink");
+            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, {
@@ -293,23 +284,16 @@ export default class Page extends React.Component<IPageProps> {
     render() {
         return (
             <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="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>
+                <canvas className="PdfPage-canvasContainer" ref={this._canvas} />
+                <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 className="pdfPage-textlayer"
-                    ref={this._textLayer}
-                    style={{ top: `-${2 * this._height}px`, height: `${this._height}px` }}
-                />
+                <div className="pdfPage-textlayer" ref={this._textLayer} />
             </div>
         );
     }
-}
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From d906398528e6ab35bb1b8d9c36de61027380afd9 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 7 Aug 2019 08:01:00 -0400
Subject: fixed typo.  moved fields to annotation data doc

---
 src/client/views/pdf/PDFViewer.tsx | 26 +++++++++++++-------------
 src/client/views/pdf/Page.tsx      |  1 -
 2 files changed, 13 insertions(+), 14 deletions(-)

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

diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 411857223..7c445c373 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -187,12 +187,14 @@ export class PDFViewer extends React.Component<IViewerProps> {
             (annoDoc.y !== undefined) && (minY = Math.min(NumCast(annoDoc.y), minY));
         }));
 
-        mainAnnoDoc.title = "Annotation on " + StrCast(this.props.Document.title);
-        mainAnnoDoc.pdfDoc = this.props.Document;
-        mainAnnoDoc.y = Math.max(minY, 0);
-        mainAnnoDoc.annotations = new List<Doc>(annoDocs);
+        let mainAnnoDocProto = Doc.GetProto(mainAnnoDoc);
+        mainAnnoDocProto.title = "Annotation on " + StrCast(this.props.Document.title);
+        mainAnnoDocProto.pdfDoc = this.props.Document;
+        mainAnnoDocProto.annotationOn = this.props.Document;
+        mainAnnoDocProto.y = Math.max(minY, 0);
+        mainAnnoDocProto.annotations = new List<Doc>(annoDocs);
         if (sourceDoc && createLink) {
-            DocUtils.MakeLink(sourceDoc, mainAnnoDoc, undefined, `Annotation from ${StrCast(this.props.Document.title)}`, "", StrCast(this.props.Document.title));
+            DocUtils.MakeLink(sourceDoc, mainAnnoDocProto, undefined, `Annotation from ${StrCast(this.props.Document.title)}`, "", StrCast(this.props.Document.title));
         }
         this._savedAnnotations.clear();
         this.Index = -1;
@@ -433,30 +435,28 @@ export class PDFViewer extends React.Component<IViewerProps> {
                     <Annotation {...this.props} ParentIndex={this.getIndex} anno={anno} index={index} key={`${anno[Id]}-annotation`} />)}
             </div>
             <div className="pdfViewer-overlayCont" onPointerDown={(e) => e.stopPropagation()}
-                style={{ nbottom: -this.props.scrollY, left: `${this._searching ? 0 : 100}%` }}>
+                style={{ bottom: -this.props.scrollY, left: `${this._searching ? 0 : 100}%` }}>
                 <button className="pdfViewer-overlayButton" title="Open Search Bar" />
                 <input className="pdfViewer-overlaySearchBar" placeholder="Search" onChange={this.searchStringChanged}
                     onKeyDown={(e: React.KeyboardEvent) => e.keyCode === KeyCodes.ENTER ? this.search(this._searchString) : e.keyCode === KeyCodes.BACKSPACE ? e.stopPropagation() : true} />
-                <button title="Search" onClick={() => this.search(this._searchString)}><FontAwesomeIcon icon="search" size="3x" color="white" /></button>
+                <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.active() ? "flex" : "none" }}>
                 <div className="pdfViewer-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
-                    <FontAwesomeIcon style={{ color: "white" }} icon={"arrow-up"} size="3x" />
-                </div>
+                    <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.active() ? "flex" : "none" }}>
                 <div className="pdfViewer-overlayButton-iconCont" onPointerDown={(e) => e.stopPropagation()}>
-                    <FontAwesomeIcon style={{ color: "white" }} icon={"arrow-down"} size="3x" />
-                </div>
+                    <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.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" />
-                </div>
+                    <FontAwesomeIcon style={{ color: "white" }} icon={this._searching ? "times" : "search"} size="3x" /></div>
             </button>
         </div >);
     }
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index a1f807f13..a15bed255 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -88,7 +88,6 @@ export default class Page extends React.Component<IPageProps> {
     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;
         Doc.AddDocToList(this.props.fieldExtensionDoc, "annotations", annotationDoc);
         return annotationDoc;
     }
-- 
cgit v1.2.3-70-g09d2


From adb91b035bd18ff407ce0b2decc07c779282c008 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 7 Aug 2019 12:40:45 -0400
Subject: added zooming to pdfs

---
 src/client/views/Main.tsx                          |  5 ++
 .../collectionFreeForm/CollectionFreeFormView.tsx  | 63 ++++++++++------------
 src/client/views/nodes/PDFBox.scss                 |  3 ++
 src/client/views/nodes/PDFBox.tsx                  | 59 ++++++++------------
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 src/client/views/pdf/Page.tsx                      | 29 +++++-----
 6 files changed, 75 insertions(+), 86 deletions(-)

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

diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 1cf13aa74..5fd42c0df 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -39,5 +39,10 @@ let swapDocs = async () => {
     (await Cast(CurrentUserUtils.UserDocument.sidebar, Doc))!.chromeStatus = "disabled";
     CurrentUserUtils.UserDocument.chromeStatus = "disabled";
     await swapDocs();
+    document.getElementById('root')!.addEventListener('wheel', event => {
+        if (event.ctrlKey) {
+            event.preventDefault()
+        }
+    }, true);
     ReactDOM.render(<MainView />, document.getElementById('root'));
 })();
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index a08a12426..d347e02b6 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -352,12 +352,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
         if (BoolCast(this.props.Document.lockedPosition)) return;
-        // if (!this.props.active()) {
-        //     return;
-        // }
-        if (this.props.Document.type === "pdf") {
+        if (!e.ctrlKey && this.props.Document.scrollY !== undefined) {
+            e.stopPropagation();
             return;
         }
+
         let childSelected = this.childDocs.some(doc => {
             var dv = DocumentManager.Instance.getDocumentView(doc);
             return dv && SelectionManager.IsSelected(dv) ? true : false;
@@ -366,21 +365,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             return;
         }
         e.stopPropagation();
-        const coefficient = 1000;
-
-        if (e.ctrlKey) {
-            let deltaScale = (1 - (e.deltaY / coefficient));
-            let nw = this.nativeWidth * deltaScale;
-            let nh = this.nativeHeight * deltaScale;
-            if (nw && nh) {
-                this.props.Document.nativeWidth = nw;
-                this.props.Document.nativeHeight = nh;
-            }
-            e.stopPropagation();
-            e.preventDefault();
-        } else {
-            // if (modes[e.deltaMode] === 'pixels') coefficient = 50;
-            // else if (modes[e.deltaMode] === 'lines') coefficient = 1000; // This should correspond to line-height??
+
+        // bcz: this changes the nativewidth/height, but ImageBox will just revert it back to its defaults.  need more logic to fix.
+        // if (e.ctrlKey && this.props.Document.scrollY === undefined) {
+        //     let deltaScale = (1 - (e.deltaY / coefficient));
+        //     let nw = this.nativeWidth * deltaScale;
+        //     let nh = this.nativeHeight * deltaScale;
+        //     if (nw && nh) {
+        //         this.props.Document.nativeWidth = nw;
+        //         this.props.Document.nativeHeight = nh;
+        //     }
+        //     e.preventDefault();
+        // } 
+        // else 
+        {
             let deltaScale = e.deltaY > 0 ? (1 / 1.1) : 1.1;
             if (deltaScale * this.zoomScaling() < 1 && this.isAnnotationOverlay) {
                 deltaScale = 1 / this.zoomScaling();
@@ -392,21 +390,21 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             let safeScale = Math.min(Math.max(0.15, localTransform.Scale), 40);
             this.props.Document.scale = Math.abs(safeScale);
             this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale);
-            e.stopPropagation();
+            e.preventDefault();
         }
     }
 
     @action
     setPan(panX: number, panY: number) {
-        if (BoolCast(this.props.Document.lockedPosition)) return;
-        this.props.Document.panTransformType = "None";
-        var scale = this.getLocalTransform().inverse().Scale;
-        const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX));
-        const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY));
-        this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX;
-        this.props.Document.panY = this.isAnnotationOverlay && StrCast(this.props.Document.backgroundLayout).indexOf("PDFBox") === -1 ? newPanY : panY;
-        if (this.props.Document.scrollY) {
-            this.props.Document.scrollY = panY - scale * this.props.Document[HeightSym]();
+        if (!BoolCast(this.props.Document.lockedPosition)) {
+            this.props.Document.panTransformType = "None";
+            var scale = this.getLocalTransform().inverse().Scale;
+            const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX));
+            const newPanY = Math.min((this.props.Document.scrollHeight !== undefined ? NumCast(this.props.Document.scrollHeight) : (1 - 1 / scale) * this.nativeHeight), Math.max(0, panY));
+            this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX;
+            this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY;
+            if (this.props.Document.scrollHeight !== undefined) this.props.Document.scrollY = this.isAnnotationOverlay ? newPanY : panY;
+            else this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY;
         }
     }
 
@@ -490,12 +488,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         this.Document.scale = scale;
     }
 
-    getScale = () => {
-        if (this.Document.scale) {
-            return this.Document.scale;
-        }
-        return 1;
-    }
+    getScale = () => this.Document.scale ? this.Document.scale : 1;
 
 
     getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps {
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index a1bab0409..c88a94c28 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -5,6 +5,9 @@
     height: 100%;
     overflow-y: scroll;
     overflow-x: hidden;
+    .pdfBox-scrollHack {
+        pointer-events: none;
+    }
 }
 
 .pdfBox-cont {
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 56e720bf7..2759b46d4 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -30,10 +30,11 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
 
     @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; }
+    @computed get fieldExtensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); }
 
     private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
     private _reactionDisposer?: IReactionDisposer;
@@ -62,16 +63,16 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     }
 
     public GetPage() {
-        return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.pdfHeight)) + 1;
+        return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.nativeHeight)) + 1;
     }
 
     @action
     public BackPage() {
-        let cp = Math.ceil(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.pdfHeight)) + 1;
+        let cp = Math.ceil(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.nativeHeight)) + 1;
         cp = cp - 1;
         if (cp > 0) {
             this.props.Document.curPage = cp;
-            this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.pdfHeight);
+            this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.nativeHeight);
         }
     }
 
@@ -79,7 +80,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     public GotoPage(p: number) {
         if (p > 0 && p <= NumCast(this.props.Document.numPages)) {
             this.props.Document.curPage = p;
-            this.props.Document.scrollY = (p - 1) * NumCast(this.dataDoc.pdfHeight);
+            this.props.Document.scrollY = (p - 1) * NumCast(this.dataDoc.nativeHeight);
         }
     }
 
@@ -88,31 +89,16 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         let cp = this.GetPage() + 1;
         if (cp <= NumCast(this.props.Document.numPages)) {
             this.props.Document.curPage = cp;
-            this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.pdfHeight);
+            this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.nativeHeight);
         }
     }
 
-    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;
-    }
-
-    private newValueChange = (e: React.ChangeEvent<HTMLInputElement>) => {
-        this._valueValue = e.currentTarget.value;
-    }
-
-    private newScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => {
-        this._scriptValue = e.currentTarget.value;
-    }
-
+    @action
     private applyFilter = () => {
         let scriptText = this._scriptValue.length > 0 ? this._scriptValue :
             this._keyValue.length > 0 && this._valueValue.length > 0 ?
@@ -121,7 +107,10 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         script.compiled && (this.props.Document.filterScript = new ScriptField(script));
     }
 
-    @action
+    scrollTo = (y: number) => {
+        this._mainCont.current && this._mainCont.current.scrollTo({ top: Math.max(y - (this._mainCont.current.offsetHeight / 2), 0), behavior: "auto" });
+    }
+
     private resetFilters = () => {
         this._keyValue = this._valueValue = "";
         this._scriptValue = "return true";
@@ -130,6 +119,9 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         this._scriptRef.current && (this._scriptRef.current.value = "");
         this.applyFilter();
     }
+    private newKeyChange = (e: React.ChangeEvent<HTMLInputElement>) => this._keyValue = e.currentTarget.value;
+    private newValueChange = (e: React.ChangeEvent<HTMLInputElement>) => this._valueValue = e.currentTarget.value;
+    private newScriptChange = (e: React.ChangeEvent<HTMLInputElement>) => this._scriptValue = e.currentTarget.value;
 
     settingsPanel() {
         return !this.props.active() ? (null) :
@@ -176,12 +168,12 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
 
     loaded = (nw: number, nh: number, np: number) => {
         this.dataDoc.numPages = np;
-        if (!this.dataDoc.nativeWidth || !this.dataDoc.nativeHeight) {
+        if (!this.dataDoc.nativeWidth || !this.dataDoc.nativeHeight || !this.dataDoc.scrollHeight) {
             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);
+            this.dataDoc.height = this.dataDoc[WidthSym]() * (nh / nw);
+            this.dataDoc.scrollHeight = np * this.dataDoc.nativeHeight;
         }
     }
 
@@ -189,14 +181,10 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     onScroll = (e: React.UIEvent<HTMLDivElement>) => {
         if (e.currentTarget && this.containingCollectionDocument) {
             this.containingCollectionDocument.panTransformType = "None";
-            this.containingCollectionDocument.scrollY = this._scrollY = e.currentTarget.scrollTop;
+            this.containingCollectionDocument.scrollY = e.currentTarget.scrollTop;
         }
     }
 
-    @computed get fieldExtensionDoc() {
-        return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true");
-    }
-
     render() {
         const pdfUrl = Cast(this.props.Document.data, PdfField);
         let classname = "pdfBox-cont" + (this.props.active() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : "");
@@ -205,14 +193,13 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             <div className={classname}
                 onScroll={this.onScroll}
                 style={{ marginTop: `${this.containingCollectionDocument ? NumCast(this.containingCollectionDocument.panY) : 0}px` }}
-                ref={this._mainCont}
-                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}
+                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%" }} />
+                <PDFViewer pdf={this._pdf} url={pdfUrl.url.pathname} active={this.props.active} scrollTo={this.scrollTo} loaded={this.loaded} scrollY={NumCast(this.props.Document.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>
-        );
+            </div>);
     }
 }
\ No newline at end of file
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 7c445c373..021c04723 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -160,7 +160,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 }))));
             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);
+            let startY = NumCast(this.props.Document.startY, NumCast(this.props.Document.scrollY));
             this.props.setPanY && this.props.setPanY(startY);
             this.props.Document.scrollY = startY + 1;
         }
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index a15bed255..6de2db427 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -143,6 +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 (e.altKey && e.button === 0) {
             e.stopPropagation();
         }
@@ -197,21 +198,21 @@ export default class Page extends React.Component<IPageProps> {
     onSelectEnd = (e: PointerEvent): void => {
         if (this._marqueeing) {
             this._marqueeing = false;
-            if (this._marquee.current) { // make a copy of the marquee
-                let copy = document.createElement("div");
-                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;
-                copy.style.border = style.border;
-                copy.style.opacity = style.opacity;
-                copy.className = "pdfPage-annotationBox";
-                this.props.createAnnotation(copy, this.props.page);
-                this._marquee.current.style.opacity = "0";
-            }
-
             if (this._marqueeWidth > 10 || this._marqueeHeight > 10) {
+                if (this._marquee.current) { // make a copy of the marquee
+                    let copy = document.createElement("div");
+                    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;
+                    copy.style.border = style.border;
+                    copy.style.opacity = style.opacity;
+                    copy.className = "pdfPage-annotationBox";
+                    this.props.createAnnotation(copy, this.props.page);
+                    this._marquee.current.style.opacity = "0";
+                }
+
                 if (!e.ctrlKey) {
                     PDFMenu.Instance.Status = "snippet";
                     PDFMenu.Instance.Marquee = { left: this._marqueeX, top: this._marqueeY, width: this._marqueeWidth, height: this._marqueeHeight };
-- 
cgit v1.2.3-70-g09d2


From 221acd0cfb4831435d1d1b61b86c2cc5e3d3b413 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Wed, 7 Aug 2019 12:50:58 -0400
Subject: got rid of scrollY from pdfs!

---
 src/client/views/collections/CollectionPDFView.tsx  | 16 +---------------
 .../collectionFreeForm/CollectionFreeFormView.tsx   |  6 ++----
 src/client/views/nodes/PDFBox.tsx                   | 18 +++++++++---------
 src/client/views/pdf/PDFViewer.tsx                  | 21 ++++++++++-----------
 4 files changed, 22 insertions(+), 39 deletions(-)

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

diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx
index 3736ebada..8eda4d9ee 100644
--- a/src/client/views/collections/CollectionPDFView.tsx
+++ b/src/client/views/collections/CollectionPDFView.tsx
@@ -1,7 +1,6 @@
-import { action, IReactionDisposer, observable, reaction, computed } from "mobx";
+import { computed } from "mobx";
 import { observer } from "mobx-react";
 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";
@@ -19,21 +18,8 @@ export class CollectionPDFView extends React.Component<FieldViewProps> {
     }
 
     private _pdfBox?: PDFBox;
-    private _reactionDisposer?: IReactionDisposer;
     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),
-            { fireImmediately: true }
-        );
-    }
-
-    componentWillUnmount() {
-        this._reactionDisposer && this._reactionDisposer();
-    }
-
     @computed
     get uIButtons() {
         return (
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index d347e02b6..8322625f1 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -352,7 +352,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
     @action
     onPointerWheel = (e: React.WheelEvent): void => {
         if (BoolCast(this.props.Document.lockedPosition)) return;
-        if (!e.ctrlKey && this.props.Document.scrollY !== undefined) {
+        if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming
             e.stopPropagation();
             return;
         }
@@ -367,7 +367,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
         e.stopPropagation();
 
         // bcz: this changes the nativewidth/height, but ImageBox will just revert it back to its defaults.  need more logic to fix.
-        // if (e.ctrlKey && this.props.Document.scrollY === undefined) {
+        // if (e.ctrlKey && this.props.Document.scrollHeight === undefined) {
         //     let deltaScale = (1 - (e.deltaY / coefficient));
         //     let nw = this.nativeWidth * deltaScale;
         //     let nh = this.nativeHeight * deltaScale;
@@ -403,8 +403,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
             const newPanY = Math.min((this.props.Document.scrollHeight !== undefined ? NumCast(this.props.Document.scrollHeight) : (1 - 1 / scale) * this.nativeHeight), Math.max(0, panY));
             this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX;
             this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY;
-            if (this.props.Document.scrollHeight !== undefined) this.props.Document.scrollY = this.isAnnotationOverlay ? newPanY : panY;
-            else this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY;
         }
     }
 
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 2759b46d4..e9207404e 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -53,8 +53,8 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             Pdfjs.getDocument(pdfUrl.url.pathname).promise.then(pdf => runInAction(() => this._pdf = pdf));
         }
         this._reactionDisposer = reaction(
-            () => this.props.Document.scrollY,
-            () => this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "auto" })
+            () => this.props.Document.panY,
+            () => this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.Document.panY), behavior: "auto" })
         );
     }
 
@@ -63,16 +63,16 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     }
 
     public GetPage() {
-        return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.nativeHeight)) + 1;
+        return Math.floor(NumCast(this.props.Document.panY) / NumCast(this.dataDoc.nativeHeight)) + 1;
     }
 
     @action
     public BackPage() {
-        let cp = Math.ceil(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.nativeHeight)) + 1;
+        let cp = Math.ceil(NumCast(this.props.Document.panY) / NumCast(this.dataDoc.nativeHeight)) + 1;
         cp = cp - 1;
         if (cp > 0) {
             this.props.Document.curPage = cp;
-            this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.nativeHeight);
+            this.props.Document.panY = (cp - 1) * NumCast(this.dataDoc.nativeHeight);
         }
     }
 
@@ -80,7 +80,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     public GotoPage(p: number) {
         if (p > 0 && p <= NumCast(this.props.Document.numPages)) {
             this.props.Document.curPage = p;
-            this.props.Document.scrollY = (p - 1) * NumCast(this.dataDoc.nativeHeight);
+            this.props.Document.panY = (p - 1) * NumCast(this.dataDoc.nativeHeight);
         }
     }
 
@@ -89,7 +89,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         let cp = this.GetPage() + 1;
         if (cp <= NumCast(this.props.Document.numPages)) {
             this.props.Document.curPage = cp;
-            this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.nativeHeight);
+            this.props.Document.panY = (cp - 1) * NumCast(this.dataDoc.nativeHeight);
         }
     }
 
@@ -181,7 +181,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
     onScroll = (e: React.UIEvent<HTMLDivElement>) => {
         if (e.currentTarget && this.containingCollectionDocument) {
             this.containingCollectionDocument.panTransformType = "None";
-            this.containingCollectionDocument.scrollY = e.currentTarget.scrollTop;
+            this.containingCollectionDocument.panY = e.currentTarget.scrollTop;
         }
     }
 
@@ -195,7 +195,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
                 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%" }} />
-                <PDFViewer pdf={this._pdf} url={pdfUrl.url.pathname} active={this.props.active} scrollTo={this.scrollTo} loaded={this.loaded} scrollY={NumCast(this.props.Document.scrollY)}
+                <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}
                     fieldKey={this.props.fieldKey} fieldExtensionDoc={this.fieldExtensionDoc} />
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 021c04723..f3281047a 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -31,7 +31,7 @@ interface IViewerProps {
     fieldExtensionDoc: Doc;
     fieldKey: string;
     loaded: (nw: number, nh: number, np: number) => void;
-    scrollY: number;
+    panY: number;
     scrollTo: (y: number) => void;
     active: () => boolean;
     setPanY?: (n: number) => void;
@@ -64,14 +64,14 @@ export class PDFViewer extends React.Component<IViewerProps> {
     private _searchString: string = "";
     private _selectionText: string = "";
 
-    @computed get scrollY(): number { return this.props.scrollY; }
+    @computed get panY(): number { return this.props.panY; }
 
     // startIndex: where to start rendering pages
-    @computed get startIndex(): number { return Math.max(0, this.getPageFromScroll(this.scrollY) - this._pageBuffer); }
+    @computed get startIndex(): number { return Math.max(0, this.getPageFromScroll(this.panY) - this._pageBuffer); }
 
     // 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] ? this._pageSizes[0].height : 0)) + this._pageBuffer);
+        return Math.min(this.props.pdf.numPages - 1, this.getPageFromScroll(this.panY + (this._pageSizes[0] ? this._pageSizes[0].height : 0)) + this._pageBuffer);
     }
 
     @computed get filteredAnnotations() {
@@ -81,7 +81,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         });
     }
 
-    componentDidUpdate = (prevProps: IViewerProps) => this.scrollY !== prevProps.scrollY && this.renderPages();
+    componentDidUpdate = (prevProps: IViewerProps) => this.panY !== prevProps.panY && this.renderPages();
 
     componentDidMount = async () => {
         await this.initialLoad();
@@ -160,9 +160,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
                 }))));
             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, NumCast(this.props.Document.scrollY));
+            let startY = NumCast(this.props.Document.startY, NumCast(this.props.Document.panY));
             this.props.setPanY && this.props.setPanY(startY);
-            this.props.Document.scrollY = startY + 1;
         }
     }
 
@@ -435,7 +434,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
                     <Annotation {...this.props} ParentIndex={this.getIndex} anno={anno} index={index} key={`${anno[Id]}-annotation`} />)}
             </div>
             <div className="pdfViewer-overlayCont" onPointerDown={(e) => e.stopPropagation()}
-                style={{ bottom: -this.props.scrollY, left: `${this._searching ? 0 : 100}%` }}>
+                style={{ bottom: -this.props.panY, left: `${this._searching ? 0 : 100}%` }}>
                 <button className="pdfViewer-overlayButton" title="Open Search Bar" />
                 <input className="pdfViewer-overlaySearchBar" placeholder="Search" onChange={this.searchStringChanged}
                     onKeyDown={(e: React.KeyboardEvent) => e.keyCode === KeyCodes.ENTER ? this.search(this._searchString) : e.keyCode === KeyCodes.BACKSPACE ? e.stopPropagation() : true} />
@@ -443,17 +442,17 @@ export class PDFViewer extends React.Component<IViewerProps> {
                     <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.active() ? "flex" : "none" }}>
+                style={{ bottom: -this.props.panY + 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.active() ? "flex" : "none" }}>
+                style={{ bottom: -this.props.panY + 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.active() ? "flex" : "none" }}>
+                style={{ bottom: -this.props.panY + 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" /></div>
-- 
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/PDFViewer.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


From ebddce0975fa7e224e022cc075eee71abeacbe1d Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Wed, 7 Aug 2019 23:27:21 -0400
Subject: changed pdfs to render regions as collections.  changed libraryBrush
 implementation.

---
 src/client/views/SearchItem.tsx                    |  6 ++--
 .../views/collections/CollectionDockingView.tsx    |  2 +-
 .../views/collections/CollectionSchemaView.tsx     |  2 +-
 .../views/collections/CollectionTreeView.tsx       |  8 ++---
 src/client/views/nodes/DocumentView.tsx            | 37 ++++++++++-----------
 src/client/views/nodes/FormattedTextBox.tsx        |  2 +-
 src/client/views/pdf/PDFViewer.tsx                 |  3 +-
 src/client/views/pdf/Page.tsx                      |  9 ++---
 .../views/presentationview/PresentationElement.tsx |  4 +--
 src/client/views/search/SearchItem.tsx             | 38 +++++++---------------
 src/new_fields/Doc.ts                              | 18 ++++++++++
 src/new_fields/util.ts                             |  1 -
 src/scraping/buxton/scraper.py                     |  9 ++---
 13 files changed, 65 insertions(+), 74 deletions(-)

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

diff --git a/src/client/views/SearchItem.tsx b/src/client/views/SearchItem.tsx
index 13e4b88f7..fd4b2420d 100644
--- a/src/client/views/SearchItem.tsx
+++ b/src/client/views/SearchItem.tsx
@@ -37,12 +37,10 @@ export class SearchItem extends React.Component<SearchProps> {
         return <FontAwesomeIcon icon={button} className="documentView-minimizedIcon" />;
     }
     onPointerEnter = (e: React.PointerEvent) => {
-        this.props.doc.libraryBrush = true;
-        Doc.SetOnPrototype(this.props.doc, "protoBrush", true);
+        Doc.BrushDoc(this.props.doc);
     }
     onPointerLeave = (e: React.PointerEvent) => {
-        this.props.doc.libraryBrush = false;
-        Doc.SetOnPrototype(this.props.doc, "protoBrush", false);
+        Doc.UnBrushDoc(this.props.doc);
     }
 
     collectionRef = React.createRef<HTMLDivElement>();
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index f559480ed..3af92cbe3 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -405,7 +405,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
                             handlers: { dragComplete: emptyFunction },
                             hideSource: false
                         });
-                    }}><FontAwesomeIcon icon="file" size="lg" /></span>, dragSpan);
+                    }}><FontAwesomeIcon icon="file" color={["white", "maroon", "blue"][Doc.IsBrushedDegree(doc)]} size="lg" /></span>, dragSpan);
                 ReactDOM.render(<ParentDocSelector Document={doc} addDocTab={doc => CollectionDockingView.Instance.AddTab(stack, doc, dataDoc)} />, upDiv);
                 tab.reactComponents = [dragSpan, upDiv];
                 tab.element.append(dragSpan);
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 75787c0a8..ebfa737be 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -50,7 +50,7 @@ const columnTypes: Map<string, ColumnType> = new Map([
     ["title", ColumnType.String],
     ["x", ColumnType.Number], ["y", ColumnType.Number], ["width", ColumnType.Number], ["height", ColumnType.Number],
     ["nativeWidth", ColumnType.Number], ["nativeHeight", ColumnType.Number], ["isPrototype", ColumnType.Boolean],
-    ["page", ColumnType.Number], ["curPage", ColumnType.Number], ["libraryBrush", ColumnType.Boolean], ["zIndex", ColumnType.Number]
+    ["page", ColumnType.Number], ["curPage", ColumnType.Number], ["zIndex", ColumnType.Number]
 ]);
 
 @observer
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 571967743..24bd24d11 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -127,19 +127,19 @@ class TreeView extends React.Component<TreeViewProps> {
 
     onPointerDown = (e: React.PointerEvent) => e.stopPropagation();
     onPointerEnter = (e: React.PointerEvent): void => {
-        this.props.active() && (this.props.document.libraryBrush = true);
+        this.props.active() && Doc.BrushDoc(this.dataDoc);
         if (e.buttons === 1 && SelectionManager.GetIsDragging()) {
             this._header!.current!.className = "treeViewItem-header";
             document.addEventListener("pointermove", this.onDragMove, true);
         }
     }
     onPointerLeave = (e: React.PointerEvent): void => {
-        this.props.document.libraryBrush = false;
+        Doc.UnBrushDoc(this.dataDoc);
         this._header!.current!.className = "treeViewItem-header";
         document.removeEventListener("pointermove", this.onDragMove, true);
     }
     onDragMove = (e: PointerEvent): void => {
-        this.props.document.libraryBrush = false;
+        Doc.UnBrushDoc(this.dataDoc);
         let x = this.props.ScreenToLocalTransform().transformPoint(e.clientX, e.clientY);
         let rect = this._header!.current!.getBoundingClientRect();
         let bounds = this.props.ScreenToLocalTransform().transformPoint(rect.left, rect.top + rect.height / 2);
@@ -359,7 +359,7 @@ class TreeView extends React.Component<TreeViewProps> {
         return <>
             <div className="docContainer" id={`docContainer-${this.props.parentKey}`} ref={reference} onPointerDown={onItemDown}
                 style={{
-                    background: BoolCast(this.props.document.libraryBrush) ? "#06121212" : "0",
+                    background: Doc.IsBrushed(this.props.document) ? "#06121212" : "0",
                     outline: BoolCast(this.props.document.workspaceBrush) ? "dashed 1px #06123232" : undefined,
                     pointerEvents: this.props.active() || SelectionManager.GetIsDragging() ? "all" : "none"
                 }} >
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index a7b4f33db..e911dc47c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -303,7 +303,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             fullScreenAlias.showCaption = true;
             this.props.addDocTab(fullScreenAlias, this.dataDoc, "inTab");
             SelectionManager.DeselectAll();
-            this.props.Document.libraryBrush = false;
+            Doc.UnBrushDoc(this.props.Document);
         }
         else if (CurrentUserUtils.MainDocId !== this.props.Document[Id] &&
             (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
@@ -445,13 +445,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             targetDoc.targetContext = de.data.targetContext;
             let annotations = await DocListCastAsync(annotationDoc.annotations);
             if (annotations) {
-                annotations.forEach(anno => {
-                    anno.target = targetDoc;
-                });
+                annotations.forEach(anno => anno.target = targetDoc);
             }
-            let pdfDoc = await Cast(annotationDoc.pdfDoc, Doc);
-            if (pdfDoc) {
-                DocUtils.MakeLink(annotationDoc, targetDoc, this.props.ContainingCollectionView!.props.Document, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title));
+            let annotDoc = await Cast(annotationDoc.annotationOn, Doc);
+            if (annotDoc) {
+                DocUtils.MakeLink(annotationDoc, targetDoc, this.props.ContainingCollectionView!.props.Document, `Annotation from ${StrCast(annotDoc.title)}`, "", StrCast(annotDoc.title));
             }
         }
         if (de.data instanceof DragManager.LinkDragData) {
@@ -647,8 +645,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         });
     }
 
-    onPointerEnter = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = true; };
-    onPointerLeave = (e: React.PointerEvent): void => { this.props.Document.libraryBrush = false; };
+    onPointerEnter = (e: React.PointerEvent): void => { Doc.BrushDoc(this.props.Document); };
+    onPointerLeave = (e: React.PointerEvent): void => { Doc.UnBrushDoc(this.props.Document); };
 
     isSelected = () => SelectionManager.IsSelected(this);
     @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
@@ -695,22 +693,23 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             });
         }
         let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("<FormattedTextBox") ? showTitle : undefined;
+        let brushDegree = Doc.IsBrushedDegree(this.layoutDoc);
         return (
             <div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
                 ref={this._mainCont}
                 style={{
                     pointerEvents: this.layoutDoc.isBackground && !this.isSelected() ? "none" : "all",
                     color: foregroundColor,
-                    outlineColor: "maroon",
-                    outlineStyle: "dashed",
-                    outlineWidth: BoolCast(this.layoutDoc.libraryBrush) && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
-                        `${this.props.ScreenToLocalTransform().Scale}px` : "0px",
-                    marginLeft: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
-                        `${-1 * this.props.ScreenToLocalTransform().Scale}px` : undefined,
-                    marginTop: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
-                        `${-1 * this.props.ScreenToLocalTransform().Scale}px` : undefined,
-                    border: BoolCast(this.layoutDoc.libraryBrush) && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
-                        `dashed maroon ${this.props.ScreenToLocalTransform().Scale}px` : undefined,
+                    outlineColor: ["transparent", "maroon", "maroon"][brushDegree],
+                    outlineStyle: ["none", "dashed", "solid"][brushDegree],
+                    outlineWidth: brushDegree && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
+                        `${brushDegree * this.props.ScreenToLocalTransform().Scale}px` : "0px",
+                    marginLeft: brushDegree && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
+                        `${-brushDegree * this.props.ScreenToLocalTransform().Scale}px` : undefined,
+                    marginTop: brushDegree && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
+                        `${-brushDegree * this.props.ScreenToLocalTransform().Scale}px` : undefined,
+                    border: brushDegree && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
+                        `${["none", "dashed", "solid"][brushDegree]} ${["transparent", "maroon", "maroon"][brushDegree]} ${this.props.ScreenToLocalTransform().Scale}px` : undefined,
                     borderRadius: "inherit",
                     background: backgroundColor,
                     width: nativeWidth,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 9dd0643df..44b5d2c21 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -674,7 +674,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
                 style={{
                     height: this.props.height ? this.props.height : undefined,
                     background: this.props.hideOnLeave ? "rgba(0,0,0,0.4)" : undefined,
-                    opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || this.props.Document.libraryBrush ? 1 : 0.1) : 1,
+                    opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || Doc.IsBrushed(this.props.Document) ? 1 : 0.1) : 1,
                     color: this.props.color ? this.props.color : this.props.hideOnLeave ? "white" : "inherit",
                     pointerEvents: interactive,
                     fontSize: "13px"
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 95df10c58..7cd62f4e0 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -184,7 +184,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
             annoDoc.color = color;
             annoDoc.type = AnnotationTypes.Region;
             annoDocs.push(annoDoc);
-            annoDoc.isBackground = true;
+            annoDoc.isButton = true;
             anno.remove();
             this.props.addDocument && this.props.addDocument(annoDoc, false);
             mainAnnoDoc = annoDoc;
@@ -208,7 +208,6 @@ export class PDFViewer extends React.Component<IViewerProps> {
             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;
         if (sourceDoc && createLink) {
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 4986f44d5..6bd98cbaa 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -112,8 +112,8 @@ export default class Page extends React.Component<IPageProps> {
                         if (!BoolCast(annotationDoc.linkedToDoc)) {
                             let annotations = await DocListCastAsync(annotationDoc.annotations);
                             annotations && annotations.forEach(anno => anno.target = targetDoc);
-                            let pdfDoc = await Cast(annotationDoc.pdfDoc, Doc);
-                            pdfDoc && DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(pdfDoc.title)}`, "", StrCast(pdfDoc.title))
+                            let parentDoc = await Cast(annotationDoc.annotationOn, Doc);
+                            parentDoc && DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(parentDoc.title)}`, "", StrCast(parentDoc.title))
                         }
                     }
                 },
@@ -144,10 +144,7 @@ export default class Page extends React.Component<IPageProps> {
     onPointerDown = (e: React.PointerEvent): void => {
         // if alt+left click, drag and annotate
         if (NumCast(this.props.Document.scale, 1) !== 1) return;
-        if (e.altKey && e.button === 0) {
-            e.stopPropagation();
-        }
-        else if (e.button === 0) {
+        if (!e.altKey && e.button === 0) {
             PDFMenu.Instance.StartDrag = this.startDrag;
             PDFMenu.Instance.Highlight = this.highlight;
             PDFMenu.Instance.Snippet = this.createSnippet;
diff --git a/src/client/views/presentationview/PresentationElement.tsx b/src/client/views/presentationview/PresentationElement.tsx
index e2d8daea9..d98b66324 100644
--- a/src/client/views/presentationview/PresentationElement.tsx
+++ b/src/client/views/presentationview/PresentationElement.tsx
@@ -706,7 +706,7 @@ export default class PresentationElement extends React.Component<PresentationEle
      * It makes it possible to show dropping lines on drop targets.
      */
     onDragMove = (e: PointerEvent): void => {
-        this.props.document.libraryBrush = false;
+        Doc.UnBrushDoc(this.props.document);
         let x = this.ScreenToLocalListTransform(e.clientX, e.clientY);
         let rect = this.header!.getBoundingClientRect();
         let bounds = this.ScreenToLocalListTransform(rect.left, rect.top + rect.height / 2);
@@ -889,7 +889,7 @@ export default class PresentationElement extends React.Component<PresentationEle
                 style={{
                     outlineColor: "maroon",
                     outlineStyle: "dashed",
-                    outlineWidth: BoolCast(p.document.libraryBrush) ? `1px` : "0px",
+                    outlineWidth: Doc.IsBrushed(p.document) ? `1px` : "0px",
                 }}
                 onClick={e => { p.gotoDocument(p.index, NumCast(this.props.mainDocument.selectedDoc)); e.stopPropagation(); }}>
                 <strong className="presentationView-name">
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index c4af30f5c..8201aa374 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -105,23 +105,11 @@ export interface LinkMenuProps {
 @observer
 export class LinkContextMenu extends React.Component<LinkMenuProps> {
 
-    highlightDoc = (doc: Doc) => {
-        return () => {
-            doc.libraryBrush = true;
-        };
-    }
+    highlightDoc = (doc: Doc) => () => Doc.BrushDoc(doc);
 
-    unHighlightDoc = (doc: Doc) => {
-        return () => {
-            doc.libraryBrush = false;
-        };
-    }
+    unHighlightDoc = (doc: Doc) => () => Doc.UnBrushDoc(doc);
 
-    getOnClick(col: Doc) {
-        return () => {
-            CollectionDockingView.Instance.AddRightSplit(col, undefined);
-        };
-    }
+    getOnClick = (col: Doc) => () => CollectionDockingView.Instance.AddRightSplit(col, undefined);
 
     render() {
         return (
@@ -286,14 +274,12 @@ export class SearchItem extends React.Component<SearchItemProps> {
 
                 let doc1 = Cast(this.props.doc.anchor1, Doc, null);
                 let doc2 = Cast(this.props.doc.anchor2, Doc, null);
-                doc1 && (doc1.libraryBrush = true);
-                doc2 && (doc2.libraryBrush = true);
+                Doc.BrushDoc(doc1);
+                Doc.BrushDoc(doc2);
             }
         } else {
-            let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc);
-            docViews.forEach(element => {
-                element.props.Document.libraryBrush = true;
-            });
+            DocumentManager.Instance.getAllDocumentViews(this.props.doc).forEach(element =>
+                Doc.BrushDoc(element.props.Document));
         }
     }
 
@@ -303,14 +289,12 @@ export class SearchItem extends React.Component<SearchItemProps> {
 
                 let doc1 = Cast(this.props.doc.anchor1, Doc, null);
                 let doc2 = Cast(this.props.doc.anchor2, Doc, null);
-                doc1 && (doc1.libraryBrush = false);
-                doc2 && (doc2.libraryBrush = false);
+                Doc.UnBrushDoc(doc1);
+                Doc.UnBrushDoc(doc2);
             }
         } else {
-            let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc);
-            docViews.forEach(element => {
-                element.props.Document.libraryBrush = false;
-            });
+            DocumentManager.Instance.getAllDocumentViews(this.props.doc).
+                forEach(element => Doc.UnBrushDoc(element.props.Document));
         }
     }
 
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index c01f4e8cf..b3d1dc109 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -542,4 +542,22 @@ export namespace Doc {
             }
         });
     }
+
+    export class DocBrush {
+        @observable BrushedDoc: Doc[] = [];
+    }
+    const manager = new DocBrush();
+    export function IsBrushed(doc: Doc) {
+        return manager.BrushedDoc.some(d => Doc.AreProtosEqual(d, doc));
+    }
+    export function IsBrushedDegree(doc: Doc) {
+        return manager.BrushedDoc.some(d => d === doc) ? 2 : Doc.IsBrushed(doc) ? 1 : 0;
+    }
+    export function BrushDoc(doc: Doc) {
+        if (manager.BrushedDoc.indexOf(doc) === -1) runInAction(() => manager.BrushedDoc.push(doc));
+    }
+    export function UnBrushDoc(doc: Doc) {
+        let index = manager.BrushedDoc.indexOf(doc);
+        if (index !== -1) runInAction(() => manager.BrushedDoc.splice(index, 1));
+    }
 }
\ No newline at end of file
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index c6f693f7f..48ae9f216 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -6,7 +6,6 @@ import { RefField } from "./RefField";
 import { ObjectField } from "./ObjectField";
 import { action } from "mobx";
 import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols";
-import { ComputedField } from "./ScriptField";
 
 function _readOnlySetter(): never {
     throw new Error("Documents can't be modified in read-only mode");
diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py
index f0f45d8f9..29cb8a256 100644
--- a/src/scraping/buxton/scraper.py
+++ b/src/scraping/buxton/scraper.py
@@ -88,8 +88,7 @@ def write_schema(parse_results, display_fields, storage_key):
             "panX": 0,
             "panY": 0,
             "zoomBasis": 1,
-            "zIndex": 2,
-            "libraryBrush": False,
+            "zIndex": 2
             "viewType": 2
         },
         "__type": "Doc"
@@ -130,8 +129,7 @@ def write_text_doc(content):
             "x": 10,
             "y": 10,
             "width": 400,
-            "zIndex": 2,
-            "libraryBrush": False
+            "zIndex": 2
         },
         "__type": "Doc"
     }
@@ -183,8 +181,7 @@ def write_image(folder, name):
             "x": 10,
             "y": 10,
             "width": min(800, native_width),
-            "zIndex": 2,
-            "libraryBrush": False
+            "zIndex": 2
         },
         "__type": "Doc"
     }
-- 
cgit v1.2.3-70-g09d2


From 316c241d72fb83aad5f2bf9b143c317fdc906654 Mon Sep 17 00:00:00 2001
From: bob <bcz@cs.brown.edu>
Date: Thu, 8 Aug 2019 12:23:47 -0400
Subject: fixed issues with jumptoDocument

---
 package.json                                       |  2 +-
 src/client/documents/Documents.ts                  |  3 +--
 src/client/util/DocumentManager.ts                 | 12 ++++++-----
 .../views/collections/CollectionBaseView.tsx       |  5 ++---
 src/client/views/nodes/DocumentView.tsx            | 24 +++++++++-------------
 src/client/views/nodes/LinkMenuItem.tsx            |  4 ++--
 src/client/views/pdf/PDFViewer.tsx                 |  2 +-
 src/client/views/pdf/Page.tsx                      |  3 +--
 8 files changed, 25 insertions(+), 30 deletions(-)

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

diff --git a/package.json b/package.json
index 29a903d71..d699d1e6f 100644
--- a/package.json
+++ b/package.json
@@ -218,4 +218,4 @@
         "xoauth2": "^1.2.0",
         "youtube": "^0.1.0"
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index a8545206a..7dd853156 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -596,7 +596,7 @@ export namespace Docs {
 
 export namespace DocUtils {
 
-    export function MakeLink(source: Doc, target: Doc, targetContext?: Doc, title: string = "", description: string = "", tags: string = "Default", sourceContext?: Doc) {
+    export function MakeLink(source: Doc, target: Doc, targetContext?: Doc, title: string = "", description: string = "", sourceContext?: Doc) {
         if (LinkManager.Instance.doesLinkExist(source, target)) return undefined;
         let sv = DocumentManager.Instance.getDocumentView(source);
         if (sv && sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === target) return;
@@ -610,7 +610,6 @@ export namespace DocUtils {
             linkDocProto.sourceContext = sourceContext;
             linkDocProto.title = title === "" ? source.title + " to " + target.title : title;
             linkDocProto.linkDescription = description;
-            linkDocProto.linkTags = tags;
             linkDocProto.type = DocumentType.LINK;
 
             linkDocProto.anchor1 = source;
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 0d46df406..7f526b247 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -1,5 +1,5 @@
 import { action, computed, observable } from 'mobx';
-import { Doc } from '../../new_fields/Doc';
+import { Doc, DocListCastAsync } from '../../new_fields/Doc';
 import { Id } from '../../new_fields/FieldSymbols';
 import { Cast, NumCast } from '../../new_fields/Types';
 import { CollectionDockingView } from '../views/collections/CollectionDockingView';
@@ -140,13 +140,15 @@ export class DocumentManager {
         if (!forceDockFunc && (docView = DocumentManager.Instance.getDocumentView(doc))) {
             Doc.BrushDoc(docView.props.Document);
             if (linkPage !== undefined) docView.props.Document.curPage = linkPage;
-            UndoManager.RunInBatch(() => {
-                docView!.props.focus(docView!.props.Document, willZoom);
-            }, "focus");
+            UndoManager.RunInBatch(() => docView!.props.focus(docView!.props.Document, willZoom), "focus");
         } else {
             if (!contextDoc) {
-                if (docContext) {
+                let docs = docContext ? await DocListCastAsync(docContext.data) : undefined;
+                let found = false;
+                docs && docs.map(d => found = found || Doc.AreProtosEqual(d, docDelegate));
+                if (docContext && found) {
                     let targetContextView: DocumentView | null;
+
                     if (!forceDockFunc && docContext && (targetContextView = DocumentManager.Instance.getDocumentView(docContext))) {
                         docContext.panTransformType = "Ease";
                         targetContextView.props.focus(docDelegate, willZoom);
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index b53e83eb1..cad87ebcc 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -99,7 +99,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
     addDocument(doc: Doc, allowDuplicates: boolean = false): boolean {
         var curPage = NumCast(this.props.Document.curPage, -1);
         Doc.GetProto(doc).page = curPage;
-        if (curPage >= 0) {
+        if (this.props.fieldExt) { // bcz: fieldExt !== undefined means this is an overlay layer
             Doc.GetProto(doc).annotationOn = this.props.Document;
         }
         allowDuplicates = true;
@@ -126,8 +126,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
         let value = Cast(targetDataDoc[targetField], listSpec(Doc), []);
         let index = value.reduce((p, v, i) => (v instanceof Doc && v[Id] === doc[Id]) ? i : p, -1);
         PromiseValue(Cast(doc.annotationOn, Doc)).then(annotationOn =>
-            annotationOn === this.dataDoc.Document && (doc.annotationOn = undefined)
-        );
+            annotationOn === this.dataDoc.Document && (doc.annotationOn = undefined));
 
         if (index !== -1) {
             value.splice(index, 1);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 861b53abf..c8eab85c2 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -8,7 +8,7 @@ import { Copy, Id } from '../../../new_fields/FieldSymbols';
 import { List } from "../../../new_fields/List";
 import { ObjectField } from "../../../new_fields/ObjectField";
 import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
-import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types";
+import { BoolCast, Cast, FieldValue, NumCast, StrCast, PromiseValue } from "../../../new_fields/Types";
 import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
 import { RouteStore } from '../../../server/RouteStore';
 import { emptyFunction, returnTrue, Utils } from "../../../Utils";
@@ -359,12 +359,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
                     if (!linkedFwdDocs.some(l => l instanceof Promise)) {
                         let maxLocation = StrCast(linkedFwdDocs[0].maximizeLocation, "inTab");
                         let targetContext = !Doc.AreProtosEqual(linkedFwdContextDocs[altKey ? 1 : 0], this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document) ? linkedFwdContextDocs[altKey ? 1 : 0] : undefined;
-                        DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, false, document => {
-                            this.props.focus(this.props.Document, true, 1);
-                            setTimeout(() =>
-                                this.props.addDocTab(document, undefined, maxLocation), 1000);
-                        }
-                            , linkedFwdPage[altKey ? 1 : 0], targetContext);
+                        DocumentManager.Instance.jumpToDocument(linkedFwdDocs[altKey ? 1 : 0], ctrlKey, false,
+                            document => {  // open up target if it's not already in view ...
+                                this.props.focus(this.props.Document, true, 1);  // by zooming into the button document first
+                                setTimeout(() => this.props.addDocTab(document, undefined, maxLocation), 1000); // then after the 1sec animation, open up the target in a new tab
+                            },
+                            linkedFwdPage[altKey ? 1 : 0], targetContext);
                     }
                 }
             }
@@ -445,13 +445,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
             let targetDoc = this.props.Document;
             targetDoc.targetContext = de.data.targetContext;
             let annotations = await DocListCastAsync(annotationDoc.annotations);
-            if (annotations) {
-                annotations.forEach(anno => anno.target = targetDoc);
-            }
-            let annotDoc = await Cast(annotationDoc.annotationOn, Doc);
-            if (annotDoc) {
-                DocUtils.MakeLink(annotationDoc, targetDoc, this.props.ContainingCollectionView!.props.Document, `Annotation from ${StrCast(annotDoc.title)}`, "", StrCast(annotDoc.title));
-            }
+            annotations && annotations.forEach(anno => anno.target = targetDoc);
+
+            DocUtils.MakeLink(annotationDoc, targetDoc, this.props.ContainingCollectionView!.props.Document, `Link from ${StrCast(annotationDoc.title)}`);
         }
         if (de.data instanceof DragManager.LinkDragData) {
             let sourceDoc = de.data.linkSourceDocument;
diff --git a/src/client/views/nodes/LinkMenuItem.tsx b/src/client/views/nodes/LinkMenuItem.tsx
index 1d4fcad69..a119eb39b 100644
--- a/src/client/views/nodes/LinkMenuItem.tsx
+++ b/src/client/views/nodes/LinkMenuItem.tsx
@@ -6,7 +6,7 @@ import { DocumentManager } from "../../util/DocumentManager";
 import { undoBatch } from "../../util/UndoManager";
 import './LinkMenu.scss';
 import React = require("react");
-import { Doc } from '../../../new_fields/Doc';
+import { Doc, DocListCastAsync } from '../../../new_fields/Doc';
 import { StrCast, Cast, FieldValue, NumCast } from '../../../new_fields/Types';
 import { observable, action } from 'mobx';
 import { LinkManager } from '../../util/LinkManager';
@@ -52,7 +52,7 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
         }
 
         if (this.props.destinationDoc === self.props.linkDoc.anchor2 && targetContext) {
-            DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, document => dockingFunc(targetContext!));
+            DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, async document => dockingFunc(document), undefined, targetContext!);
         }
         else if (this.props.destinationDoc === self.props.linkDoc.anchor1 && sourceContext) {
             DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, document => dockingFunc(sourceContext!));
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 7cd62f4e0..08674720d 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -211,7 +211,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
         mainAnnoDocProto.title = "Annotation on " + StrCast(this.props.Document.title);
         mainAnnoDocProto.annotationOn = this.props.Document;
         if (sourceDoc && createLink) {
-            DocUtils.MakeLink(sourceDoc, mainAnnoDocProto, undefined, `Annotation from ${StrCast(this.props.Document.title)}`, "", StrCast(this.props.Document.title));
+            DocUtils.MakeLink(sourceDoc, mainAnnoDocProto, undefined, `Annotation from ${StrCast(this.props.Document.title)}`);
         }
         this._savedAnnotations.clear();
         this.Index = -1;
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 6bd98cbaa..7ca9d2d7d 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -112,8 +112,7 @@ export default class Page extends React.Component<IPageProps> {
                         if (!BoolCast(annotationDoc.linkedToDoc)) {
                             let annotations = await DocListCastAsync(annotationDoc.annotations);
                             annotations && annotations.forEach(anno => anno.target = targetDoc);
-                            let parentDoc = await Cast(annotationDoc.annotationOn, Doc);
-                            parentDoc && DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(parentDoc.title)}`, "", StrCast(parentDoc.title))
+                            DocUtils.MakeLink(annotationDoc, targetDoc, dragData.targetContext, `Annotation from ${StrCast(this.props.Document.title)}`)
                         }
                     }
                 },
-- 
cgit v1.2.3-70-g09d2

