From 37f327ab659e6fa1221f9f4ed7649402c5dedc00 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Wed, 19 Jun 2019 11:24:32 -0400
Subject: aspect ratio, dragging, and full screen scrolling fixed

---
 src/client/views/pdf/PDFMenu.tsx | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 2ed891131..2462a5f94 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -25,6 +25,7 @@ export default class PDFMenu extends React.Component {
     private _offsetY: number = 0;
     private _offsetX: number = 0;
     private _mainCont: React.RefObject<HTMLDivElement>;
+    private _dragging: boolean = false;
 
     constructor(props: Readonly<{}>) {
         super(props);
@@ -35,19 +36,30 @@ export default class PDFMenu extends React.Component {
     }
 
     pointerDown = (e: React.PointerEvent) => {
-        document.removeEventListener("pointermove", this.StartDrag);
-        document.addEventListener("pointermove", this.StartDrag);
+        document.removeEventListener("pointermove", this.pointerMove);
+        document.addEventListener("pointermove", this.pointerMove);
         document.removeEventListener("pointerup", this.pointerUp);
         document.addEventListener("pointerup", this.pointerUp);
 
-        console.log(this.StartDrag);
+        e.stopPropagation();
+        e.preventDefault();
+    }
 
+    pointerMove = (e: PointerEvent) => {
         e.stopPropagation();
         e.preventDefault();
+
+        if (this._dragging) {
+            return;
+        }
+
+        this.StartDrag(e);
+        this._dragging = true;
     }
 
     pointerUp = (e: PointerEvent) => {
-        document.removeEventListener("pointermove", this.StartDrag);
+        this._dragging = false;
+        document.removeEventListener("pointermove", this.pointerMove);
         document.removeEventListener("pointerup", this.pointerUp);
         e.stopPropagation();
         e.preventDefault();
-- 
cgit v1.2.3-70-g09d2


From 46d57bc21cda4703855b85a4603bd471975d845b Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Wed, 19 Jun 2019 14:25:47 -0400
Subject: deleting annotations

---
 src/client/views/pdf/PDFMenu.tsx   | 40 +++++++++++++++++----
 src/client/views/pdf/PDFViewer.tsx | 74 ++++++++++++++++++++++++++++++++------
 src/client/views/pdf/Page.tsx      |  1 +
 3 files changed, 97 insertions(+), 18 deletions(-)

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

diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 2462a5f94..5dd7b4bcd 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -19,9 +19,11 @@ export default class PDFMenu extends React.Component {
 
     StartDrag: (e: PointerEvent) => void = emptyFunction;
     Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction;
-    @observable Highlighting: boolean = false;
+    Delete: () => void = emptyFunction;
+
+    @observable public Highlighting: boolean = false;
+    @observable public Status: "pdf" | "annotation" | "" = "";
 
-    private _timeout: NodeJS.Timeout | undefined;
     private _offsetY: number = 0;
     private _offsetX: number = 0;
     private _mainCont: React.RefObject<HTMLDivElement>;
@@ -66,8 +68,8 @@ export default class PDFMenu extends React.Component {
     }
 
     @action
-    jumpTo = (x: number, y: number) => {
-        if (!this._pinned) {
+    jumpTo = (x: number, y: number, forceJump: boolean = false) => {
+        if (!this._pinned || forceJump) {
             this._transition = this._transitionDelay = "";
             this._opacity = 1;
             this._left = x;
@@ -159,11 +161,35 @@ export default class PDFMenu extends React.Component {
         }
     }
 
+    deleteClicked = (e: React.PointerEvent) => {
+        this.Delete();
+    }
+
+    handleContextMenu = (e: React.MouseEvent) => {
+        e.stopPropagation();
+        e.preventDefault();
+    }
+
     render() {
+        let buttons = this.Status === "pdf" ? [
+            <button className="pdfMenu-button" title="Click to Highlight" onClick={this.highlightClicked}
+                style={this.Highlighting ? { backgroundColor: "#121212" } : {}}>
+                <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} />
+            </button>,
+            <button className="pdfMenu-button" title="Drag to Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="lg" /></button>,
+            <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin}
+                style={this._pinned ? { backgroundColor: "#121212" } : {}}>
+                <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this._pinned ? "rotate(45deg)" : "" }} />
+            </button>
+        ] : [
+                <button className="pdfMenu-button" title="Delete Anchor" onPointerDown={this.deleteClicked}><FontAwesomeIcon icon="trash-alt" size="lg" /></button>
+            ];
+
         return (
-            <div className="pdfMenu-cont" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont}
+            <div className="pdfMenu-cont" onPointerLeave={this.pointerLeave} onPointerEnter={this.pointerEntered} ref={this._mainCont} onContextMenu={this.handleContextMenu}
                 style={{ left: this._left, top: this._top, opacity: this._opacity, transition: this._transition, transitionDelay: this._transitionDelay }}>
-                <button className="pdfMenu-button" title="Highlight" onClick={this.highlightClicked}
+                {buttons}
+                {/* <button className="pdfMenu-button" title="Highlight" onClick={this.highlightClicked}
                     style={this.Highlighting ? { backgroundColor: "#121212" } : {}}>
                     <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} />
                 </button>
@@ -171,7 +197,7 @@ export default class PDFMenu extends React.Component {
                 <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin}
                     style={this._pinned ? { backgroundColor: "#121212" } : {}}>
                     <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this._pinned ? "rotate(45deg)" : "" }} />
-                </button>
+                </button> */}
                 <div className="pdfMenu-dragger" onPointerDown={this.dragStart} style={{ width: this._pinned ? "20px" : "0px" }} />
             </div >
         );
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index f0e55705d..ea4c0bca2 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -7,7 +7,7 @@ import { Dictionary } from "typescript-collections";
 import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc";
 import { Id } from "../../../new_fields/FieldSymbols";
 import { List } from "../../../new_fields/List";
-import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types";
+import { BoolCast, Cast, NumCast, StrCast, FieldValue } from "../../../new_fields/Types";
 import { emptyFunction } from "../../../Utils";
 import { DocServer } from "../../DocServer";
 import { Docs, DocUtils } from "../../documents/Documents";
@@ -138,6 +138,7 @@ class Viewer extends React.Component<IViewerProps> {
 
     makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string): Doc => {
         let annoDocs: Doc[] = [];
+        let mainAnnoDoc = new Doc();
         this._savedAnnotations.forEach((key: number, value: HTMLDivElement[]) => {
             for (let anno of value) {
                 let annoDoc = new Doc();
@@ -147,6 +148,7 @@ class Viewer extends React.Component<IViewerProps> {
                 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);
@@ -154,13 +156,12 @@ class Viewer extends React.Component<IViewerProps> {
             }
         });
 
-        let annoDoc = new Doc();
-        annoDoc.annotations = new List<Doc>(annoDocs);
+        mainAnnoDoc.annotations = new List<Doc>(annoDocs);
         if (sourceDoc) {
-            DocUtils.MakeLink(sourceDoc, annoDoc, 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.parent.Document.title)}`, "", StrCast(this.props.parent.Document.title));
         }
         this._savedAnnotations.clear();
-        return annoDoc;
+        return mainAnnoDoc;
     }
 
     drop = async (e: Event, de: DragManager.DropEvent) => {
@@ -508,6 +509,57 @@ interface IAnnotationProps {
 class RegionAnnotation extends React.Component<IAnnotationProps> {
     @observable private _backgroundColor: string = "red";
 
+    private _reactionDisposer?: IReactionDisposer;
+    private _mainCont: React.RefObject<HTMLDivElement>;
+
+    constructor(props: IAnnotationProps) {
+        super(props);
+
+        this._mainCont = React.createRef();
+    }
+
+    componentDidMount() {
+        this._reactionDisposer = reaction(
+            () => BoolCast(this.props.document.delete),
+            () => {
+                if (BoolCast(this.props.document.delete)) {
+                    if (this._mainCont.current) {
+                        this._mainCont.current.style.display = "none";
+                    }
+                }
+            },
+            { fireImmediately: true }
+        );
+    }
+
+    componentWillUnmount() {
+        this._reactionDisposer && this._reactionDisposer();
+    }
+
+    deleteAnnotation = () => {
+        let annotation = DocListCast(this.props.parent.props.parent.Document.annotations);
+        let group = FieldValue(Cast(this.props.document.group, Doc));
+        if (group && annotation.indexOf(group) !== -1) {
+            let newAnnotations = annotation.filter(a => a !== FieldValue(Cast(this.props.document.group, Doc)));
+            this.props.parent.props.parent.Document.annotations = new List<Doc>(newAnnotations);
+        }
+
+        if (group) {
+            let groupAnnotations = DocListCast(group.annotations);
+            groupAnnotations.forEach(anno => anno.delete = true);
+        }
+    }
+
+
+    // annotateThis = (e: PointerEvent) => {
+    //     e.preventDefault();
+    //     e.stopPropagation();
+    //     // document that this annotation is linked to
+    //     let targetDoc = Docs.TextDocument({ width: 200, height: 200, title: "New Annotation" });
+    //     let group = FieldValue(Cast(this.props.document.group, Doc));
+    // }
+
+    @action
     onPointerDown = (e: React.PointerEvent) => {
         if (e.button === 0) {
             let targetDoc = Cast(this.props.document.target, Doc, null);
@@ -515,16 +567,16 @@ class RegionAnnotation extends React.Component<IAnnotationProps> {
                 DocumentManager.Instance.jumpToDocument(targetDoc);
             }
         }
-        // if (e.button === 2) {
-        //     console.log("right");
-        //     e.stopPropagation();
-        //     e.preventDefault();
-        // }
+        if (e.button === 2) {
+            PDFMenu.Instance.Status = "annotation";
+            PDFMenu.Instance.Delete = this.deleteAnnotation;
+            PDFMenu.Instance.jumpTo(e.clientX, e.clientY, true);
+        }
     }
 
     render() {
         return (
-            <div className="pdfViewer-annotationBox" onPointerDown={this.onPointerDown}
+            <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>
         );
     }
diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx
index 39e737c32..734dff7fc 100644
--- a/src/client/views/pdf/Page.tsx
+++ b/src/client/views/pdf/Page.tsx
@@ -191,6 +191,7 @@ export default class Page extends React.Component<IPageProps> {
         else if (e.button === 0) {
             PDFMenu.Instance.StartDrag = this.startDrag;
             PDFMenu.Instance.Highlight = this.highlight;
+            PDFMenu.Instance.Status = "pdf";
             PDFMenu.Instance.fadeOut(true);
             let target: any = e.target;
             if (target && target.parentElement === this._textLayer.current) {
-- 
cgit v1.2.3-70-g09d2


From b960a876d6a31b3eaebb0ac6eca6f191a0d4c900 Mon Sep 17 00:00:00 2001
From: yipstanley <stanley_yip@brown.edu>
Date: Wed, 19 Jun 2019 14:38:43 -0400
Subject: oop

---
 src/client/views/pdf/PDFMenu.tsx | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

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

diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index 5dd7b4bcd..39b15fb11 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -15,7 +15,8 @@ export default class PDFMenu extends React.Component {
     @observable private _opacity: number = 1;
     @observable private _transition: string = "opacity 0.5s";
     @observable private _transitionDelay: string = "";
-    @observable private _pinned: boolean = false;
+
+    @observable public Pinned: boolean = false;
 
     StartDrag: (e: PointerEvent) => void = emptyFunction;
     Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction;
@@ -69,7 +70,7 @@ export default class PDFMenu extends React.Component {
 
     @action
     jumpTo = (x: number, y: number, forceJump: boolean = false) => {
-        if (!this._pinned || forceJump) {
+        if (!this.Pinned || forceJump) {
             this._transition = this._transitionDelay = "";
             this._opacity = 1;
             this._left = x;
@@ -79,7 +80,7 @@ export default class PDFMenu extends React.Component {
 
     @action
     fadeOut = (forceOut: boolean) => {
-        if (!this._pinned) {
+        if (!this.Pinned) {
             if (this._opacity === 0.2) {
                 this._transition = "opacity 0.1s";
                 this._transitionDelay = "";
@@ -98,7 +99,7 @@ export default class PDFMenu extends React.Component {
 
     @action
     pointerLeave = (e: React.PointerEvent) => {
-        if (!this._pinned) {
+        if (!this.Pinned) {
             this._transition = "opacity 0.5s";
             this._transitionDelay = "1s";
             this._opacity = 0.2;
@@ -115,8 +116,8 @@ export default class PDFMenu extends React.Component {
 
     @action
     togglePin = (e: React.MouseEvent) => {
-        this._pinned = !this._pinned;
-        if (!this._pinned) {
+        this.Pinned = !this.Pinned;
+        if (!this.Pinned) {
             this.Highlighting = false;
         }
     }
@@ -152,7 +153,7 @@ export default class PDFMenu extends React.Component {
 
     @action
     highlightClicked = (e: React.MouseEvent) => {
-        if (!this._pinned) {
+        if (!this.Pinned) {
             this.Highlight(undefined, "#f4f442");
         }
         else {
@@ -178,8 +179,8 @@ export default class PDFMenu extends React.Component {
             </button>,
             <button className="pdfMenu-button" title="Drag to Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="lg" /></button>,
             <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin}
-                style={this._pinned ? { backgroundColor: "#121212" } : {}}>
-                <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this._pinned ? "rotate(45deg)" : "" }} />
+                style={this.Pinned ? { backgroundColor: "#121212" } : {}}>
+                <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this.Pinned ? "rotate(45deg)" : "" }} />
             </button>
         ] : [
                 <button className="pdfMenu-button" title="Delete Anchor" onPointerDown={this.deleteClicked}><FontAwesomeIcon icon="trash-alt" size="lg" /></button>
@@ -198,7 +199,7 @@ export default class PDFMenu extends React.Component {
                     style={this._pinned ? { backgroundColor: "#121212" } : {}}>
                     <FontAwesomeIcon icon="thumbtack" size="lg" style={{ transition: "transform 0.1s", transform: this._pinned ? "rotate(45deg)" : "" }} />
                 </button> */}
-                <div className="pdfMenu-dragger" onPointerDown={this.dragStart} style={{ width: this._pinned ? "20px" : "0px" }} />
+                <div className="pdfMenu-dragger" onPointerDown={this.dragStart} style={{ width: this.Pinned ? "20px" : "0px" }} />
             </div >
         );
     }
-- 
cgit v1.2.3-70-g09d2

