From 135e252902a3ca93e95672602122afb3be6cd015 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Thu, 20 Jun 2019 10:43:58 -0400
Subject: basic pdf snippetting

---
 src/client/views/MainView.tsx | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index e3d4ff8b5..2645e2789 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
 import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt } from '@fortawesome/free-solid-svg-icons';
+import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt, faCut } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, runInAction, trace } from 'mobx';
 import { observer } from 'mobx-react';
@@ -91,6 +91,7 @@ export class MainView extends React.Component {
         library.add(faFilm);
         library.add(faMusic);
         library.add(faTree);
+        library.add(faCut);
         library.add(faCommentAlt);
         library.add(faThumbtack);
         this.initEventListeners();
-- 
cgit v1.2.3-70-g09d2


From 65288e33b49404d21012323fcb53fefb3f646fbf Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Mon, 24 Jun 2019 13:57:59 -0400
Subject: basic viewspecs

---
 src/client/views/MainView.tsx      |  3 +-
 src/client/views/nodes/PDFBox.scss | 68 +++++++++++++++++++++++++++++++
 src/client/views/nodes/PDFBox.tsx  | 83 +++++++++++++++++++++++++++++++++++++-
 src/client/views/pdf/PDFViewer.tsx | 36 +++++++++++++----
 4 files changed, 180 insertions(+), 10 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 2645e2789..08755b427 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
 import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt, faCut } from '@fortawesome/free-solid-svg-icons';
+import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faCheck, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt, faCut } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, runInAction, trace } from 'mobx';
 import { observer } from 'mobx-react';
@@ -94,6 +94,7 @@ export class MainView extends React.Component {
         library.add(faCut);
         library.add(faCommentAlt);
         library.add(faThumbtack);
+        library.add(faCheck);
         this.initEventListeners();
         this.initAuthenticationRouters();
     }
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 8bcae4f1e..5edff69f3 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -36,12 +36,15 @@
     pointer-events: none;
     display: flex;
     flex-direction: row;
+
     .textlayer {
         pointer-events: none;
+
         span {
             pointer-events: none !important;
         }
     }
+
     .page-cont {
         pointer-events: none;
     }
@@ -51,6 +54,7 @@
     pointer-events: all;
     display: flex;
     flex-direction: row;
+
     .textlayer {
         span {
             pointer-events: all !important;
@@ -62,4 +66,68 @@
 .pdfBox-contentContainer {
     position: absolute;
     transform-origin: left top;
+}
+
+.pdfBox-settingsCont {
+    position: absolute;
+    right: 0;
+    top: 0;
+
+    .pdfBox-settingsButton {
+        border-bottom-left-radius: 50%;
+        display: flex;
+        justify-content: space-evenly;
+        align-items: center;
+        height: 70px;
+        background: none;
+        padding: 0;
+
+        .pdfBox-settingsButton-arrow {
+            width: 0;
+            height: 0;
+            border-top: 25px solid transparent;
+            border-bottom: 25px solid transparent;
+            border-right: 25px solid #121721;
+            transition: all 0.5s;
+        }
+
+        .pdfBox-settingsButton-iconCont {
+            background: #121721;
+            height: 50px;
+            width: 70px;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            margin-left: -2px;
+            border-radius: 3px;
+        }
+    }
+
+    .pdfBox-settingsButton:hover {
+        background: none;
+    }
+
+    .pdfBox-settingsFlyout {
+        width: 600px;
+        position: absolute;
+        background: #323232;
+        box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25);
+        left: -400px;
+        border-radius: 7px;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        font-size: 30px;
+        transition: all 0.5s;
+
+        .pdfBox-settingsFlyout-title {
+            color: white;
+        }
+
+        .pdfBox-settingsFlyout-kvpInput {
+            margin-top: 20px;
+            display: grid;
+            grid-template-columns: 47.5% 5% 47.5%;
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 10a346269..aa421ff9c 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -19,6 +19,8 @@ import "./PDFBox.scss";
 import React = require("react");
 import { CompileScript } from '../../util/Scripting';
 import { ScriptField } from '../../../fields/ScriptField';
+import { Flyout, anchorPoints } from '../DocumentDecorations';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 
 type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>;
 const PdfDocument = makeInterface(positionSchema, pageSchema);
@@ -29,8 +31,12 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
 
     @observable private _alt = false;
     @observable private _scrollY: number = 0;
+    @observable private _flyout: boolean = false;
     private _mainCont: React.RefObject<HTMLDivElement>;
     private _reactionDisposer?: IReactionDisposer;
+    private _keyValue: string = "";
+    private _valueValue: string = "";
+    private _scriptValue: string = "";
 
     constructor(props: FieldViewProps) {
         super(props);
@@ -45,7 +51,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
             }
         );
 
-        let script = CompileScript("return this.page === 2", { params: { this: Doc.name } });
+        let script = CompileScript("return this.page === 0", { params: { this: Doc.name } });
         if (script.compiled) {
             this.props.Document.filterScript = new ScriptField(script);
         }
@@ -55,6 +61,10 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         if (this.props.setPdfBox) this.props.setPdfBox(this);
     }
 
+    componentWillUnmount() {
+        this._reactionDisposer && this._reactionDisposer();
+    }
+
     public GetPage() {
         return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.Document.pdfHeight)) + 1;
     }
@@ -81,7 +91,75 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         }
     }
 
-    createRef = (ele: HTMLDivElement | null) => {
+    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;
+    }
+
+    private applyFilter = (e: React.MouseEvent<HTMLButtonElement>) => {
+        let scriptText = "";
+        if (this._scriptValue.length > 0) {
+            scriptText = this._scriptValue;
+        } else if (this._keyValue.length > 0 && this._valueValue.length > 0) {
+            scriptText = `return this.${this._keyValue} === ${this._valueValue}`;
+        }
+        let script = CompileScript(scriptText, { params: { this: Doc.name } });
+        if (script.compiled) {
+            this.props.Document.filterScript = new ScriptField(script);
+        }
+    }
+
+    @action
+    private toggleFlyout = () => {
+        this._flyout = !this._flyout;
+    }
+
+    settingsPanel() {
+        return !this.props.active() ? (null) :
+            (
+                <div className="pdfBox-settingsCont" onPointerDown={(e) => e.stopPropagation()}>
+                    <button className="pdfBox-settingsButton" onClick={this.toggleFlyout}
+                        style={{ marginTop: `${NumCast(this.props.ContainingCollectionView!.props.Document.panY)}px` }}>
+                        <div className="pdfBox-settingsButton-arrow"
+                            style={{
+                                borderTop: `25px solid ${this._flyout ? "#121721" : "transparent"}`,
+                                borderBottom: `25px solid ${this._flyout ? "#121721" : "transparent"}`,
+                                borderRight: `25px solid ${this._flyout ? "transparent" : "#121721"}`,
+                                transform: `scaleX(${this._flyout ? -1 : 1})`
+                            }}></div>
+                        <div className="pdfBox-settingsButton-iconCont">
+                            <FontAwesomeIcon style={{ color: "white" }} icon="cog" size="3x" />
+                        </div>
+                    </button>
+                    <div className="pdfBox-settingsFlyout" style={{ left: `${this._flyout ? -600 : 100}px` }} >
+                        <div className="pdfBox-settingsFlyout-title">
+                            Annotation View Settings
+                        </div>
+                        <div className="pdfBox-settingsFlyout-kvpInput">
+                            <input placeholder="Key" className="pdfBox-settingsFlyout-input" onChange={this.newKeyChange}
+                                style={{ gridColumn: 1 }} />
+                            <input placeholder="Value" className="pdfBox-settingsFlyout-input" onChange={this.newValueChange}
+                                style={{ gridColumn: 3 }} />
+                        </div>
+                        <div className="pdfBox-settingsFlyout-kvpInput">
+                            <input placeholder="Custom Script" onChange={this.newScriptChange} style={{ gridColumn: "1 / 4" }} />
+                        </div>
+                        <div className="pdfBox-settingsFlyout-kvpInput">
+                            <button style={{ gridColumn: 3 }} onClick={this.applyFilter}>
+                                <FontAwesomeIcon style={{ color: "white" }} icon="check" size="lg" />
+                                &nbsp; Apply
+                            </button>
+                        </div>
+                    </div>
+                </div>
+            );
     }
 
     loaded = (nw: number, nh: number, np: number) => {
@@ -129,6 +207,7 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
                 }} className={classname}>
                 <PDFViewer url={pdfUrl.url.pathname} loaded={this.loaded} scrollY={this._scrollY} parent={this} />
                 {/* <div style={{ width: "100px", height: "300px" }}></div> */}
+                {this.settingsPanel()}
             </div>
         );
     }
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 75a8b042d..1fb208525 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -21,7 +21,7 @@ import React = require("react");
 import PDFMenu from "./PDFMenu";
 import { UndoManager } from "../../util/UndoManager";
 import { ScriptField } from "../../../fields/ScriptField";
-import { CompileScript, CompiledScript } from "../../util/Scripting";
+import { CompileScript, CompiledScript, CompileResult } from "../../util/Scripting";
 
 export const scale = 2;
 interface IPDFViewerProps {
@@ -77,7 +77,7 @@ class Viewer 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: ScriptField | undefined = this.props.parent.Document.filterScript;
+    @observable private _script: CompileResult | undefined;
 
     private _pageBuffer: number = 1;
     private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
@@ -86,6 +86,14 @@ class Viewer extends React.Component<IViewerProps> {
     private _dropDisposer?: DragManager.DragDropDisposer;
     private _filterReactionDisposer?: IReactionDisposer;
 
+    @action
+        constructor(props: IViewerProps) {
+            super(props);
+
+            let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField);
+            this._script = scriptfield ? CompileScript(scriptfield.scriptString, { params: { this: Doc.name } }) : CompileScript("return true");;
+        }
+
     componentDidUpdate = (prevProps: IViewerProps) => {
         if (this.scrollY !== prevProps.scrollY) {
             this.renderPages();
@@ -112,7 +120,10 @@ class Viewer extends React.Component<IViewerProps> {
             this._filterReactionDisposer = reaction(
                 () => this.props.parent.Document.filterScript || this.props.parent.props.ContainingCollectionView!.props.Document.filterScript,
                 () => {
-                    this._script = Cast(this.props.parent.Document.filterScript, ScriptField);
+                    runInAction(() => {
+                        let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField);
+                        this._script = scriptfield ? CompileScript(scriptfield.scriptString, { params: { this: Doc.name } }) : CompileScript("return true");;
+                    });
                 }
             );
         }
@@ -121,6 +132,7 @@ class Viewer extends React.Component<IViewerProps> {
     componentWillUnmount = () => {
         this._reactionDisposer && this._reactionDisposer();
         this._annotationReactionDisposer && this._annotationReactionDisposer();
+        this._filterReactionDisposer && this._filterReactionDisposer();
     }
 
     @action
@@ -159,10 +171,12 @@ class Viewer extends React.Component<IViewerProps> {
 
     makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string): Doc => {
         let annoDocs: Doc[] = [];
-        let mainAnnoDoc = new Doc();
+        let mainAnnoDoc = Docs.CreateInstance(new Doc(), "", {});
+
+        mainAnnoDoc.page = Math.round(Math.random());
         this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => {
             for (let anno of value) {
-                let annoDoc = Docs.CreateInstance(new Doc(), this.props.parent.Document, {});
+                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;
@@ -360,7 +374,7 @@ class Viewer extends React.Component<IViewerProps> {
     }
 
     render() {
-        let compiled = this._script ? CompileScript(this._script.scriptString, { params: { this: Doc.name } }) : CompileScript("return true");
+        let compiled = this._script;
         return (
             <div ref={this.mainCont} style={{ pointerEvents: "all" }}>
                 <div className="viewer">
@@ -372,7 +386,15 @@ class Viewer extends React.Component<IViewerProps> {
                         pointerEvents: this.props.parent.props.active() ? "none" : "all"
                     }}>
                     <div className="pdfViewer-annotationLayer-subCont" ref={this._annotationLayer}>
-                        {this._annotations.filter(anno => compiled.compiled ? compiled.run(anno) : true).map(anno => this.renderAnnotation(anno))}
+                        {this._annotations.filter(anno => {
+                            if (compiled && compiled.compiled) {
+                                let run = compiled.run({ this: anno });
+                                if (run.success) {
+                                    return run.result;
+                                }
+                            }
+                            return true;
+                        }).map(anno => this.renderAnnotation(anno))}
                     </div>
                 </div>
             </div >
-- 
cgit v1.2.3-70-g09d2


From 914eb8cb8e8ba25f3adb31da01bd005fb3bce234 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Wed, 26 Jun 2019 16:41:34 -0400
Subject: better search, prev/next annotations

---
 src/client/views/MainView.tsx       |   4 +-
 src/client/views/nodes/PDFBox.tsx   |   6 +
 src/client/views/pdf/PDFViewer.scss |  46 +++++-
 src/client/views/pdf/PDFViewer.tsx  | 294 +++++++++++++++++++++++++++++-------
 4 files changed, 290 insertions(+), 60 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 226eb458b..a9932feed 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
 import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faCheck, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt, faCut } from '@fortawesome/free-solid-svg-icons';
+import { faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faArrowDown, faArrowUp, faCheck, faPenNib, faThumbtack, faRedoAlt, faTable, faTree, faUndoAlt, faBell, faCommentAlt, faCut } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, runInAction, trace } from 'mobx';
 import { observer } from 'mobx-react';
@@ -95,6 +95,8 @@ export class MainView extends React.Component {
         library.add(faCommentAlt);
         library.add(faThumbtack);
         library.add(faCheck);
+        library.add(faArrowDown);
+        library.add(faArrowUp);
         this.initEventListeners();
         this.initAuthenticationRouters();
     }
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index c0f2d313a..44028ddf7 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -143,6 +143,12 @@ export class PDFBox extends DocComponent<FieldViewProps, PdfDocument>(PdfDocumen
         this.applyFilter();
     }
 
+    scrollTo(y: number) {
+        if (this._mainCont.current) {
+            this._mainCont.current.scrollTo({ top: y });
+        }
+    }
+
     settingsPanel() {
         return !this.props.active() ? (null) :
             (
diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss
index 2f705781f..5a89a85f4 100644
--- a/src/client/views/pdf/PDFViewer.scss
+++ b/src/client/views/pdf/PDFViewer.scss
@@ -53,14 +53,52 @@
     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-overlaySearchBar {
-        width: 20%;
-        height: 100%;
-        font-size: 30px;
+    .pdfViewer-overlayButton-iconCont {
+        background: #121721;
+        height: 50px;
+        width: 70px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        margin-left: -2px;
+        border-radius: 3px;
     }
 }
 
+.pdfViewer-overlayButton:hover {
+    background: none;
+}
+
 .pdfViewer-annotationBox {
     position: absolute;
     background-color: red;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 41961602d..d1d239f41 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -80,17 +80,23 @@ class Viewer extends React.Component<IViewerProps> {
     @observable private _script: CompileResult | undefined;
     @observable private _searching: boolean = false;
 
+    @observable public 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 _activeReactionDisposer?: IReactionDisposer;
     private _viewer: React.RefObject<HTMLDivElement>;
     private _mainCont: React.RefObject<HTMLDivElement>;
-    private _textContent: Pdfjs.TextContent[] = [];
+    // private _textContent: Pdfjs.TextContent[] = [];
     private _pdfFindController: any;
     private _searchString: string = "";
+    private _rendered: boolean = false;
+    private _pageIndex: number = -1;
+    private _matchIndex: number = 0;
 
     constructor(props: IViewerProps) {
         super(props);
@@ -123,6 +129,24 @@ class Viewer extends React.Component<IViewerProps> {
                 annotations && annotations.length && this.renderAnnotations(annotations, true),
             { fireImmediately: true });
 
+        this._activeReactionDisposer = reaction(
+            () => this.props.parent.props.active(),
+            () => {
+                runInAction(() => {
+                    if (!this.props.parent.props.active()) {
+                        this._searching = false;
+                        this._pdfFindController = null;
+                        if (this._viewer.current) {
+                            let cns = this._viewer.current.childNodes;
+                            for (let i = cns.length - 1; i >= 0; i--) {
+                                cns.item(i).remove();
+                            }
+                        }
+                    }
+                });
+            }
+        )
+
         if (this.props.parent.props.ContainingCollectionView) {
             this._filterReactionDisposer = reaction(
                 () => this.props.parent.Document.filterScript,
@@ -158,24 +182,28 @@ class Viewer extends React.Component<IViewerProps> {
         this._dropDisposer && this._dropDisposer();
     }
 
+    scrollTo(y: number) {
+        this.props.parent.scrollTo(y);
+    }
+
     @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);
+            // this._textContent = Array<Pdfjs.TextContent>(this.props.pdf.numPages);
             for (let i = 0; i < this.props.pdf.numPages; i++) {
                 await this.props.pdf.getPage(i + 1).then(page => runInAction(() => {
                     // pageSizes[i] = { width: page.view[2] * scale, height: page.view[3] * scale };
                     let x = page.getViewport(scale);
-                    page.getTextContent().then((text: Pdfjs.TextContent) => {
-                        // let tc = new Pdfjs.TextContentItem()
-                        // let tc = {str: }
-                        this._textContent[i] = text;
-                        // text.items.forEach(t => {
-                        //     tcStr += t.str;
-                        // })
-                    });
+                    // 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 };
                 }));
             }
@@ -385,7 +413,7 @@ class Viewer extends React.Component<IViewerProps> {
         }
     }
 
-    renderAnnotation = (anno: Doc): JSX.Element[] => {
+    renderAnnotation = (anno: Doc, index: number): JSX.Element[] => {
         let annotationDocs = DocListCast(anno.annotations);
         let res = annotationDocs.map(a => {
             let type = NumCast(a.type);
@@ -393,7 +421,7 @@ class Viewer extends React.Component<IViewerProps> {
                 // case AnnotationTypes.Pin:
                 //     return <PinAnnotation parent={this} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />;
                 case AnnotationTypes.Region:
-                    return <RegionAnnotation parent={this} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />;
+                    return <RegionAnnotation parent={this} document={a} index={index} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />;
                 default:
                     return <div></div>;
             }
@@ -403,14 +431,7 @@ class Viewer extends React.Component<IViewerProps> {
 
     @action
     pointerDown = () => {
-        this._searching = false;
-        this._pdfFindController = null;
-        if (this._viewer.current) {
-            let cns = this._viewer.current.childNodes;
-            for (let i = cns.length - 1; i >= 0; i--) {
-                cns.item(i).remove();
-            }
-        }
+        // this._searching = false;
     }
 
     @action
@@ -418,23 +439,20 @@ class Viewer extends React.Component<IViewerProps> {
         if (searchString.length === 0) {
             return;
         }
-        this._searching = true;
-
-        let container = this._mainCont.current;
-        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;
+
+        if (this._rendered) {
+            this._pdfFindController.executeCommand('find',
+                {
+                    caseSensitive: false,
+                    findPrevious: undefined,
+                    highlightAll: true,
+                    phraseSearch: true,
+                    query: searchString
                 });
+        }
+        else {
+            let container = this._mainCont.current;
+            if (container) {
                 container.addEventListener("pagerendered", () => {
                     console.log("rendered");
                     this._pdfFindController.executeCommand('find',
@@ -445,29 +463,151 @@ class Viewer extends React.Component<IViewerProps> {
                             phraseSearch: true,
                             query: searchString
                         });
+                    this._rendered = true;
                 });
-                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
-                });
-        }
+
+        // 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
+        //         });
+        // }
     }
 
     searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
         this._searchString = e.currentTarget.value;
     }
 
+    @action
+    toggleSearch = (e: React.MouseEvent) => {
+        e.stopPropagation();
+        this._searching = !this._searching;
+
+        if (this._searching) {
+            let container = this._mainCont.current;
+            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._rendered = true;
+                    });
+                    pdfViewer.setDocument(this.props.pdf);
+                    this._pdfFindController = new PDFJSViewer.PDFFindController(pdfViewer);
+                    // this._pdfFindController._linkService = pdfLinkService;
+                    pdfViewer.findController = this._pdfFindController;
+                }
+            }
+        }
+        else {
+            this._pdfFindController = null;
+            if (this._viewer.current) {
+                let cns = this._viewer.current.childNodes;
+                for (let i = cns.length - 1; i >= 0; i--) {
+                    cns.item(i).remove();
+                }
+            }
+        }
+    }
+
+    @action
+    prevAnnotation = (e: React.MouseEvent) => {
+        e.stopPropagation();
+
+        if (this.Index > 0) {
+            this.Index--;
+        }
+    }
+
+    @action
+    nextAnnotation = (e: React.MouseEvent) => {
+        e.stopPropagation();
+
+        let compiled = this._script;
+        if (this.Index < this._annotations.filter(anno => {
+            if (compiled && compiled.compiled) {
+                let run = compiled.run({ this: anno });
+                if (run.success) {
+                    return run.result;
+                }
+            }
+            return true;
+        }).length) {
+            this.Index++;
+        }
+    }
+
+    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 (
@@ -490,13 +630,39 @@ class Viewer extends React.Component<IViewerProps> {
                                 }
                             }
                             return true;
-                        }).map(anno => this.renderAnnotation(anno))}
+                        }).map((anno: Doc, index: number) => this.renderAnnotation(anno, index))}
                     </div>
                 </div>
-                <div className="pdfViewer-overlayCont" onPointerDown={(e) => e.stopPropagation()}>
+                <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>
+                    {/* <button title="Previous Result" onClick={() => this.search(this._searchString)}><FontAwesomeIcon icon="arrow-up" size="3x" color="white" /></button>
+                    <button title="Next Result" onClick={this.nextResult}><FontAwesomeIcon icon="arrow-down" size="3x" color="white" /></button> */}
                     <input placeholder="Search" className="pdfViewer-overlaySearchBar" onChange={this.searchStringChanged} />
                     <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" }}>
+                    <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" }}>
+                    <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" }}>
+                    <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 >
         );
     }
@@ -511,14 +677,17 @@ interface IAnnotationProps {
     y: number;
     width: number;
     height: number;
+    index: number;
     parent: Viewer;
     document: Doc;
 }
 
+@observer
 class RegionAnnotation extends React.Component<IAnnotationProps> {
     @observable private _backgroundColor: string = "red";
 
     private _reactionDisposer?: IReactionDisposer;
+    private _scrollDisposer?: IReactionDisposer;
     private _mainCont: React.RefObject<HTMLDivElement>;
 
     constructor(props: IAnnotationProps) {
@@ -539,10 +708,20 @@ class RegionAnnotation extends React.Component<IAnnotationProps> {
             },
             { fireImmediately: true }
         );
+
+        this._scrollDisposer = reaction(
+            () => this.props.parent.Index,
+            () => {
+                if (this.props.parent.Index === this.props.index) {
+                    this.props.parent.scrollTo(this.props.y - 50);
+                }
+            }
+        )
     }
 
     componentWillUnmount() {
         this._reactionDisposer && this._reactionDisposer();
+        this._scrollDisposer && this._scrollDisposer();
     }
 
     deleteAnnotation = () => {
@@ -591,7 +770,14 @@ class RegionAnnotation extends React.Component<IAnnotationProps> {
     render() {
         return (
             <div className="pdfViewer-annotationBox" 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, pointerEvents: "all", backgroundColor: StrCast(this.props.document.color) }}></div>
+                style={{
+                    top: this.props.y * scale,
+                    left: this.props.x * scale,
+                    width: this.props.width * scale,
+                    height: this.props.height * scale,
+                    pointerEvents: "all",
+                    backgroundColor: this.props.parent.Index === this.props.index ? "goldenrod" : StrCast(this.props.document.color)
+                }}></div>
         );
     }
 }
@@ -601,8 +787,6 @@ class SimpleLinkService {
     externalLinkRel: any = null;
     pdf: any = null;
 
-    constructor() { }
-
     navigateTo(dest: any) { }
 
     getDestinationHash(dest: any) { return "#"; }
-- 
cgit v1.2.3-70-g09d2

