From 2ef1dd2089ad991f1d4897022f2d28c2eb130837 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Fri, 14 Jun 2019 15:47:43 -0400 Subject: highlighting --- src/client/views/pdf/PDFMenu.tsx | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 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 cc5c0b77b..a0230113b 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -3,6 +3,8 @@ import "./PDFMenu.scss"; import { observable } from "mobx"; import { observer } from "mobx-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { emptyFunction } from "../../../Utils"; +import { Doc } from "../../../new_fields/Doc"; @observer export default class PDFMenu extends React.Component { @@ -10,6 +12,8 @@ export default class PDFMenu extends React.Component { @observable Top: number = 0; @observable Left: number = 0; + StartDrag: (e: PointerEvent) => void = emptyFunction; + Highlight: (d: Doc | undefined) => void = emptyFunction; constructor(props: Readonly<{}>) { super(props); @@ -17,11 +21,28 @@ export default class PDFMenu extends React.Component { PDFMenu.Instance = this; } + pointerDown = (e: React.PointerEvent) => { + document.removeEventListener("pointermove", this.StartDrag); + document.addEventListener("pointermove", this.StartDrag); + document.removeEventListener("pointerup", this.pointerUp) + document.addEventListener("pointerup", this.pointerUp) + + e.stopPropagation(); + e.preventDefault(); + } + + pointerUp = (e: PointerEvent) => { + document.removeEventListener("pointermove", this.StartDrag); + document.removeEventListener("pointerup", this.pointerUp); + e.stopPropagation(); + e.preventDefault(); + } + render() { return (
- - + +
) } -- cgit v1.2.3-70-g09d2 From b987e2edbf7befbe90fafbdee476ee3b6513cc50 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Fri, 14 Jun 2019 17:44:17 -0400 Subject: pinning things --- src/client/views/MainView.tsx | 3 +- src/client/views/pdf/PDFMenu.scss | 13 ++++- src/client/views/pdf/PDFMenu.tsx | 119 +++++++++++++++++++++++++++++++++++--- src/client/views/pdf/Page.tsx | 21 ++++--- 4 files changed, 137 insertions(+), 19 deletions(-) (limited to 'src/client/views/pdf/PDFMenu.tsx') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 384cd2860..29015995f 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, 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 } 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'; @@ -92,6 +92,7 @@ export class MainView extends React.Component { library.add(faMusic); library.add(faTree); library.add(faCommentAlt); + library.add(faThumbtack); this.initEventListeners(); this.initAuthenticationRouters(); } diff --git a/src/client/views/pdf/PDFMenu.scss b/src/client/views/pdf/PDFMenu.scss index b84ebc12d..22868082a 100644 --- a/src/client/views/pdf/PDFMenu.scss +++ b/src/client/views/pdf/PDFMenu.scss @@ -1,18 +1,25 @@ .pdfMenu-cont { position: absolute; z-index: 10000; - width: 100px; - height: 30px; + height: 35px; background: #323232; box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.25); - border-radius: 0px 4px 4px 4px; + border-radius: 0px 6px 6px 6px; overflow: hidden; + display: flex; .pdfMenu-button { background-color: transparent; + width: 35px; + height: 35px; } .pdfMenu-button:hover { background-color: #121212; } + + .pdfMenu-dragger { + height: 100%; + transition: width .2s; + } } \ No newline at end of file diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index a0230113b..d2a20fb6e 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -1,6 +1,6 @@ import React = require("react"); import "./PDFMenu.scss"; -import { observable } from "mobx"; +import { observable, action } from "mobx"; import { observer } from "mobx-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { emptyFunction } from "../../../Utils"; @@ -10,10 +10,18 @@ import { Doc } from "../../../new_fields/Doc"; export default class PDFMenu extends React.Component { static Instance: PDFMenu; - @observable Top: number = 0; - @observable Left: number = 0; + @observable private _top: number = 0; + @observable private _left: number = 0; + @observable private _opacity: number = 1; + @observable private _transition: string = "opacity 0.5s"; + @observable private _transitionDelay: string = ""; + @observable private _pinned: boolean = false; + StartDrag: (e: PointerEvent) => void = emptyFunction; Highlight: (d: Doc | undefined) => void = emptyFunction; + @observable Highlighting: boolean = false; + + private _timeout: NodeJS.Timeout | undefined; constructor(props: Readonly<{}>) { super(props); @@ -38,12 +46,109 @@ export default class PDFMenu extends React.Component { e.preventDefault(); } + @action + jumpTo = (x: number, y: number) => { + if (!this._pinned) { + this._transition = this._transitionDelay = ""; + this._opacity = 1; + this._left = x; + this._top = y; + } + } + + @action + fadeOut = (forceOut: boolean) => { + if (!this._pinned) { + if (this._opacity === 0.2) { + this._transition = "opacity 0.1s"; + this._transitionDelay = ""; + this._opacity = 0; + this._left = this._top = -300; + } + + if (forceOut) { + this._transition = ""; + this._transitionDelay = ""; + this._opacity = 0; + this._left = this._top = -300; + } + } + } + + @action + pointerLeave = (e: React.PointerEvent) => { + if (!this._pinned) { + this._transition = "opacity 0.5s"; + this._transitionDelay = "1s"; + this._opacity = 0.2; + setTimeout(() => this.fadeOut(false), 3000); + } + } + + @action + pointerEntered = (e: React.PointerEvent) => { + this._transition = "opacity 0.1s"; + this._transitionDelay = ""; + this._opacity = 1; + } + + @action + togglePin = (e: React.MouseEvent) => { + this._pinned = !this._pinned; + } + + @action + dragging = (e: PointerEvent) => { + this._left += e.movementX; + this._top += e.movementY; + + e.stopPropagation(); + e.preventDefault(); + } + + dragEnd = (e: PointerEvent) => { + document.removeEventListener("pointermove", this.dragging); + document.removeEventListener("pointerup", this.dragEnd); + e.stopPropagation(); + e.preventDefault(); + } + + dragStart = (e: React.PointerEvent) => { + document.removeEventListener("pointermove", this.dragging); + document.addEventListener("pointermove", this.dragging); + document.removeEventListener("pointerup", this.dragEnd); + document.addEventListener("pointerup", this.dragEnd); + + e.stopPropagation(); + e.preventDefault(); + } + + @action + highlightClicked = (e: React.MouseEvent) => { + if (!this._pinned) { + this.Highlight(undefined); + } + else { + this.Highlighting = !this.Highlighting; + this.Highlight(undefined); + } + } + render() { return ( -
- - -
+
+ + + +
+
) } } \ No newline at end of file diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index 44c502a04..3bc3ac33c 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -132,6 +132,7 @@ export default class Page extends React.Component { } } + @action highlight = (targetDoc: Doc | undefined) => { // creates annotation documents for current highlights let annotationDoc = this.props.makeAnnotationDocuments(targetDoc); @@ -196,6 +197,7 @@ export default class Page extends React.Component { // document.addEventListener("pointerup", this.endDrag); } else if (e.button === 0) { + PDFMenu.Instance.fadeOut(true); let target: any = e.target; if (target && target.parentElement === this._textLayer.current) { e.stopPropagation(); @@ -304,25 +306,28 @@ export default class Page extends React.Component { } copy.className = this._marquee.current.className; this.props.createAnnotation(copy, this.props.page); - PDFMenu.Instance.StartDrag = this.startDrag; - PDFMenu.Instance.Highlight = this.highlight; this._marquee.current.style.opacity = "0"; } this._marqueeHeight = this._marqueeWidth = 0; - PDFMenu.Instance.Left = e.clientX; - PDFMenu.Instance.Top = e.clientY; + PDFMenu.Instance.jumpTo(e.clientX, e.clientY); } else { let sel = window.getSelection(); if (sel && sel.type === "Range") { - PDFMenu.Instance.StartDrag = this.startDrag; - PDFMenu.Instance.Highlight = this.highlight; this.createTextAnnotation(sel); - PDFMenu.Instance.Left = e.clientX; - PDFMenu.Instance.Top = e.clientY; + PDFMenu.Instance.jumpTo(e.clientX, e.clientY); } } + + + if (PDFMenu.Instance.Highlighting) { + this.highlight(undefined); + } + else { + PDFMenu.Instance.StartDrag = this.startDrag; + PDFMenu.Instance.Highlight = this.highlight; + } // let x = (e.clientX - boundingRect.left) * (current.offsetWidth / boundingRect.width); // let y = (e.clientY - boundingRect.top) * (current.offsetHeight / boundingRect.height); // if (this._marqueeing) { -- cgit v1.2.3-70-g09d2 From 747fdb6d26afabad067f3f8d98789bfc7ca44f8d Mon Sep 17 00:00:00 2001 From: yipstanley Date: Fri, 14 Jun 2019 18:11:41 -0400 Subject: small stuffs --- src/client/views/pdf/PDFMenu.tsx | 1 + src/client/views/pdf/PDFViewer.tsx | 13 +++++++------ src/client/views/pdf/Page.tsx | 13 ++++++++----- 3 files changed, 16 insertions(+), 11 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 d2a20fb6e..2ba875e42 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -95,6 +95,7 @@ export default class PDFMenu extends React.Component { @action togglePin = (e: React.MouseEvent) => { this._pinned = !this._pinned; + this.Highlighting = this._pinned === false; } @action diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index dee891ba6..55d15893a 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -21,6 +21,7 @@ import { DocumentView } from "../nodes/DocumentView"; import { DragManager } from "../../util/DragManager"; import { Dictionary } from "typescript-collections"; +export const scale = 2; interface IPDFViewerProps { url: string; loaded: (nw: number, nh: number, np: number) => void; @@ -156,10 +157,10 @@ class Viewer extends React.Component { 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); - 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); + 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.type = AnnotationTypes.Region; @@ -572,7 +573,7 @@ class PinAnnotation extends React.Component {
{ render() { return (
+ 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._backgroundColor }}>
); } } \ No newline at end of file diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index 455e1d831..bd2cae749 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -13,9 +13,10 @@ import { emptyFunction } from "../../../Utils"; import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { listSpec } from "../../../new_fields/Schema"; import { menuBar } from "prosemirror-menu"; -import { AnnotationTypes } from "./PDFViewer"; +import { AnnotationTypes, PDFViewer, scale } from "./PDFViewer"; import PDFMenu from "./PDFMenu"; + interface IPageProps { pdf: Opt; name: string; @@ -28,7 +29,7 @@ interface IPageProps { sendAnnotations: (annotations: HTMLDivElement[], page: number) => void; receiveAnnotations: (page: number) => HTMLDivElement[] | undefined; createAnnotation: (div: HTMLDivElement, page: number) => void; - makeAnnotationDocuments: (doc: Doc | undefined) => Doc; + makeAnnotationDocuments: (doc: Doc | undefined, scale: number) => Doc; } @observer @@ -103,7 +104,6 @@ export default class Page extends React.Component { @action private renderPage = (page: Pdfjs.PDFPageProxy): void => { // lower scale = easier to read at small sizes, higher scale = easier to read at large sizes - let scale = 2; let viewport = page.getViewport(scale); let canvas = this._canvas.current; let textLayer = this._textLayer.current; @@ -135,7 +135,7 @@ export default class Page extends React.Component { @action highlight = (targetDoc?: Doc) => { // creates annotation documents for current highlights - let annotationDoc = this.props.makeAnnotationDocuments(targetDoc); + let annotationDoc = this.props.makeAnnotationDocuments(targetDoc, scale); let targetAnnotations = Cast(this.props.parent.Document.annotations, listSpec(Doc)); if (targetAnnotations === undefined) { Doc.GetProto(this.props.parent.Document).annotations = new List([annotationDoc]); @@ -307,8 +307,11 @@ export default class Page extends React.Component { this._marquee.current.style.opacity = "0"; } + if (this._marqueeWidth > 10 || this._marqueeHeight > 10) { + PDFMenu.Instance.jumpTo(e.clientX, e.clientY); + } + this._marqueeHeight = this._marqueeWidth = 0; - PDFMenu.Instance.jumpTo(e.clientX, e.clientY); } else { let sel = window.getSelection(); -- cgit v1.2.3-70-g09d2 From d9fba98b4022d2be68f67d830f17fea79580d2c4 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Fri, 14 Jun 2019 18:13:18 -0400 Subject: small --- src/client/views/pdf/PDFMenu.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (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 2ba875e42..b0735f63b 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -95,7 +95,9 @@ export default class PDFMenu extends React.Component { @action togglePin = (e: React.MouseEvent) => { this._pinned = !this._pinned; - this.Highlighting = this._pinned === false; + if (!this._pinned) { + this.Highlighting = false; + } } @action -- cgit v1.2.3-70-g09d2 From 122607408882617235af255af84ce78828b7982f Mon Sep 17 00:00:00 2001 From: yipstanley Date: Mon, 17 Jun 2019 13:42:21 -0400 Subject: page sizes loaded --- src/client/views/pdf/PDFMenu.tsx | 6 +++--- src/client/views/pdf/PDFViewer.tsx | 30 +++++++++++++++++++++++++++--- src/client/views/pdf/Page.tsx | 8 ++++---- 3 files changed, 34 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 b0735f63b..b44370e3d 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -18,7 +18,7 @@ export default class PDFMenu extends React.Component { @observable private _pinned: boolean = false; StartDrag: (e: PointerEvent) => void = emptyFunction; - Highlight: (d: Doc | undefined) => void = emptyFunction; + Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction; @observable Highlighting: boolean = false; private _timeout: NodeJS.Timeout | undefined; @@ -129,11 +129,11 @@ export default class PDFMenu extends React.Component { @action highlightClicked = (e: React.MouseEvent) => { if (!this._pinned) { - this.Highlight(undefined); + this.Highlight(undefined, "#f4f442"); } else { this.Highlighting = !this.Highlighting; - this.Highlight(undefined); + this.Highlight(undefined, "#f4f442"); } } diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 9becfb419..d74a16f3f 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -23,6 +23,7 @@ import { Dictionary } from "typescript-collections"; import * as rp from "request-promise"; import { restProperty } from "babel-types"; import { DocServer } from "../../DocServer"; +import { number } from "prop-types"; export const scale = 2; interface IPDFViewerProps { @@ -141,10 +142,33 @@ class Viewer extends React.Component { setTimeout(() => { // this.renderPages(this.startIndex, this.endIndex, true); - this.saveThumbnail(); + this.initialLoad(); }, 1000); } + @action + initialLoad = () => { + let pdf = this.props.pdf; + if (pdf) { + this._pageSizes = Array<{ width: number, height: number }>(pdf.numPages); + let rendered = 0; + for (let i = 0; i < pdf.numPages; i++) { + pdf.getPage(i + 1).then( + (page: Pdfjs.PDFPageProxy) => { + runInAction(() => { + this._pageSizes[i] = { width: page.view[2] * scale, height: page.view[3] * scale }; + }); + console.log(`page ${i} size retreieved`); + rendered++; + if (rendered === pdf!.numPages - 1) { + this.saveThumbnail(); + } + } + ); + } + } + } + private mainCont = (div: HTMLDivElement | null) => { if (this._dropDisposer) { this._dropDisposer(); @@ -186,7 +210,7 @@ class Viewer extends React.Component { drop = async (e: Event, de: DragManager.DropEvent) => { if (de.data instanceof DragManager.LinkDragData) { let sourceDoc = de.data.linkSourceDocument; - let destDoc = this.makeAnnotationDocument(sourceDoc); + let destDoc = this.makeAnnotationDocument(sourceDoc, 1, "red"); let targetAnnotations = DocListCast(this.props.parent.Document.annotations); if (targetAnnotations) { targetAnnotations.push(destDoc); @@ -392,7 +416,7 @@ class Viewer extends React.Component { let numPages = this.props.pdf ? this.props.pdf.numPages : 0; let index = 0; let currOffset = vOffset; - while (index < numPages && currOffset - (this._pageSizes[index] ? this._pageSizes[index].height : 792 * scale) > 0) { + while (index < this._pageSizes.length && currOffset - (this._pageSizes[index] ? this._pageSizes[index].height : 792 * scale) > 0) { currOffset -= this._pageSizes[index] ? this._pageSizes[index].height : this._pageSizes[0].height; index++; } diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index e706a0d5c..bb87ec9d4 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -133,9 +133,9 @@ export default class Page extends React.Component { } @action - highlight = (targetDoc?: Doc) => { + highlight = (targetDoc?: Doc, color: string = "red") => { // creates annotation documents for current highlights - let annotationDoc = this.props.makeAnnotationDocuments(targetDoc, scale, "#f4f442"); + let annotationDoc = this.props.makeAnnotationDocuments(targetDoc, scale, color); let targetAnnotations = Cast(this.props.parent.Document.annotations, listSpec(Doc)); if (targetAnnotations === undefined) { Doc.GetProto(this.props.parent.Document).annotations = new List([annotationDoc]); @@ -162,7 +162,7 @@ export default class Page extends React.Component { // document that this annotation is linked to let targetDoc = Docs.TextDocument({ width: 200, height: 200, title: "New Annotation" }); targetDoc.targetPage = this.props.page; - let annotationDoc = this.highlight(targetDoc); + let annotationDoc = this.highlight(targetDoc, "red"); // create dragData and star tdrag let dragData = new DragManager.AnnotationDragData(thisDoc, annotationDoc, targetDoc); if (this._textLayer.current) { @@ -323,7 +323,7 @@ export default class Page extends React.Component { if (PDFMenu.Instance.Highlighting) { - this.highlight(undefined); + this.highlight(undefined, "#f4f442"); } else { PDFMenu.Instance.StartDrag = this.startDrag; -- cgit v1.2.3-70-g09d2 From cc032e2f60015728f64f46ef009c9306e36746a0 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Tue, 18 Jun 2019 10:05:49 -0400 Subject: fixes --- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/pdf/PDFMenu.tsx | 24 +++++++++++++++++------- src/client/views/pdf/PDFViewer.tsx | 21 +++++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) (limited to 'src/client/views/pdf/PDFMenu.tsx') diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 655c12ab3..ae68a530e 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -62,7 +62,7 @@ export class PDFBox extends DocComponent(PdfDocumen createRef = (ele: HTMLDivElement | null) => { if (this._reactionDisposer) this._reactionDisposer(); this._reactionDisposer = reaction(() => this.props.Document.scrollY, () => { - ele && ele.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "smooth" }); + ele && ele.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "auto" }); }); } diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index b44370e3d..7817e8c26 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -10,8 +10,8 @@ import { Doc } from "../../../new_fields/Doc"; export default class PDFMenu extends React.Component { static Instance: PDFMenu; - @observable private _top: number = 0; - @observable private _left: number = 0; + @observable private _top: number = -300; + @observable private _left: number = -300; @observable private _opacity: number = 1; @observable private _transition: string = "opacity 0.5s"; @observable private _transitionDelay: string = ""; @@ -22,18 +22,25 @@ export default class PDFMenu extends React.Component { @observable Highlighting: boolean = false; private _timeout: NodeJS.Timeout | undefined; + private _offsetY: number = 0; + private _offsetX: number = 0; + private _mainCont: React.RefObject; constructor(props: Readonly<{}>) { super(props); PDFMenu.Instance = this; + + this._mainCont = React.createRef(); } pointerDown = (e: React.PointerEvent) => { document.removeEventListener("pointermove", this.StartDrag); document.addEventListener("pointermove", this.StartDrag); - document.removeEventListener("pointerup", this.pointerUp) - document.addEventListener("pointerup", this.pointerUp) + document.removeEventListener("pointerup", this.pointerUp); + document.addEventListener("pointerup", this.pointerUp); + + console.log(this.StartDrag); e.stopPropagation(); e.preventDefault(); @@ -102,8 +109,8 @@ export default class PDFMenu extends React.Component { @action dragging = (e: PointerEvent) => { - this._left += e.movementX; - this._top += e.movementY; + this._left = e.pageX - this._offsetX; + this._top = e.pageY - this._offsetY; e.stopPropagation(); e.preventDefault(); @@ -122,6 +129,9 @@ export default class PDFMenu extends React.Component { document.removeEventListener("pointerup", this.dragEnd); document.addEventListener("pointerup", this.dragEnd); + this._offsetX = this._mainCont.current!.getBoundingClientRect().width - e.nativeEvent.offsetX; + this._offsetY = e.nativeEvent.offsetY; + e.stopPropagation(); e.preventDefault(); } @@ -139,7 +149,7 @@ export default class PDFMenu extends React.Component { render() { return ( -
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 69372f43b..8c0aaea00 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -198,7 +198,7 @@ class Viewer extends React.Component { { @action getPageImage = async (page: number) => { let handleError = () => this.getRenderedPage(page); - if (this._isPage[page] != "image") { + if (this._isPage[page] !== "image") { this._isPage[page] = "image"; const address = this.props.url; let res = JSON.parse(await rp.get(DocServer.prepend(`/thumbnail${address.substring("files/".length, address.length - ".pdf".length)}-${page + 1}.PNG`))); diff --git a/src/server/index.ts b/src/server/index.ts index 7ef542b01..2901f61ed 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -172,7 +172,7 @@ function LoadPage(file: string, pageNumber: number, res: Response) { canvasContext: canvasAndContext.context, viewport: viewport, canvasFactory: factory - } + }; console.log("read " + pageNumber); page.render(renderContext).promise -- cgit v1.2.3-70-g09d2 From 37f327ab659e6fa1221f9f4ed7649402c5dedc00 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Wed, 19 Jun 2019 11:24:32 -0400 Subject: aspect ratio, dragging, and full screen scrolling fixed --- src/client/views/nodes/PDFBox.tsx | 2 +- src/client/views/pdf/PDFMenu.tsx | 20 ++++++++++++++++---- src/client/views/pdf/PDFViewer.tsx | 15 ++++++++++----- src/client/views/pdf/Page.tsx | 10 +++------- 4 files changed, 30 insertions(+), 17 deletions(-) (limited to 'src/client/views/pdf/PDFMenu.tsx') diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 7dd2b1dc5..d2de1cb1c 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -97,7 +97,7 @@ export class PDFBox extends DocComponent(PdfDocumen render() { // uses mozilla pdf as default const pdfUrl = Cast(this.props.Document.data, PdfField, new PdfField(window.origin + RouteStore.corsProxy + "/https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf")); - let classname = "pdfBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); + let classname = "pdfBox-cont" + (this.props.active() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); return (
; + 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(); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 8c0aaea00..67278b1eb 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -90,7 +90,8 @@ class Viewer extends React.Component { @action componentDidMount = () => { this._reactionDisposer = reaction( - () => [this.props.parent.props.active(), this.startIndex, this.endIndex], + + () => [this.props.parent.props.active(), this.startIndex, this._pageSizes.length ? this.endIndex : 0], async () => { await this.initialLoad(); this.renderPages(); @@ -114,12 +115,16 @@ class Viewer extends React.Component { let pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages); this._isPage = Array(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 })); + 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); + pageSizes[i] = { width: x.width, height: x.height }; + })); } runInAction(() => Array.from(Array((this._pageSizes = pageSizes).length).keys()).map(this.getPlaceholderPage)); - this.props.loaded(pageSizes[0].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); + // this.props.loaded(Math.max(...pageSizes.map(i => i.width)), pageSizes[0].height, this.props.pdf.numPages); } } @@ -236,7 +241,7 @@ class Viewer extends React.Component { // endIndex: where to end rendering pages @computed get endIndex(): number { - return Math.min(this.props.pdf.numPages - 1, this.getPageFromScroll(this.scrollY) + this._pageBuffer); + return Math.min(this.props.pdf.numPages - 1, this.getPageFromScroll(this.scrollY + this._pageSizes[0].height) + this._pageBuffer); } @action diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index a19b64eda..2697c9eee 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -51,7 +51,6 @@ export default class Page extends React.Component { private _marquee: React.RefObject; private _curly: React.RefObject; private _marqueeing: boolean = false; - private _dragging: boolean = false; private _reactionDisposer?: IReactionDisposer; constructor(props: IPageProps) { @@ -151,13 +150,9 @@ export default class Page extends React.Component { */ @action startDrag = (e: PointerEvent): void => { - // the first 5 lines is a hack to prevent text selection while dragging e.preventDefault(); e.stopPropagation(); - if (this._dragging) { - return; - } - this._dragging = true; + console.log("dragging"); let thisDoc = this.props.parent.Document; // document that this annotation is linked to let targetDoc = Docs.TextDocument({ width: 200, height: 200, title: "New Annotation" }); @@ -179,7 +174,6 @@ export default class Page extends React.Component { endDrag = (e: PointerEvent): void => { // document.removeEventListener("pointermove", this.startDrag); // document.removeEventListener("pointerup", this.endDrag); - this._dragging = false; e.stopPropagation(); } @@ -195,6 +189,8 @@ export default class Page extends React.Component { // document.addEventListener("pointerup", this.endDrag); } else if (e.button === 0) { + PDFMenu.Instance.StartDrag = this.startDrag; + PDFMenu.Instance.Highlight = this.highlight; PDFMenu.Instance.fadeOut(true); let target: any = e.target; if (target && target.parentElement === this._textLayer.current) { -- cgit v1.2.3-70-g09d2 From 46d57bc21cda4703855b85a4603bd471975d845b Mon Sep 17 00:00:00 2001 From: yipstanley 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; @@ -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" ? [ + , + , + + ] : [ + + ]; + return ( -
- @@ -171,7 +197,7 @@ export default class PDFMenu extends React.Component { + */}
); 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 { 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 { 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 { } }); - let annoDoc = new Doc(); - annoDoc.annotations = new List(annoDocs); + mainAnnoDoc.annotations = new List(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 { @observable private _backgroundColor: string = "red"; + private _reactionDisposer?: IReactionDisposer; + private _mainCont: React.RefObject; + + 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(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 { 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 ( -
); } 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 { 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 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 { , , ] : [ @@ -198,7 +199,7 @@ export default class PDFMenu extends React.Component { style={this._pinned ? { backgroundColor: "#121212" } : {}}> */} -
+
); } -- cgit v1.2.3-70-g09d2 From 135e252902a3ca93e95672602122afb3be6cd015 Mon Sep 17 00:00:00 2001 From: yipstanley Date: Thu, 20 Jun 2019 10:43:58 -0400 Subject: basic pdf snippetting --- src/client/views/MainView.tsx | 3 ++- src/client/views/nodes/PDFBox.tsx | 20 ++++++++++++----- src/client/views/pdf/PDFMenu.tsx | 45 +++++++++++++++++++++++++++++++++++--- src/client/views/pdf/PDFViewer.tsx | 6 ++++- src/client/views/pdf/Page.tsx | 31 +++++++++++++++++++++----- 5 files changed, 89 insertions(+), 16 deletions(-) (limited to 'src/client/views/pdf/PDFMenu.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(); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index d2de1cb1c..0aeb9afc8 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -27,8 +27,22 @@ export class PDFBox extends DocComponent(PdfDocumen @observable private _alt = false; @observable private _scrollY: number = 0; + private _mainCont: React.RefObject; private _reactionDisposer?: IReactionDisposer; + constructor(props: FieldViewProps) { + super(props); + + this._mainCont = React.createRef(); + this._reactionDisposer = reaction( + () => this.props.Document.scrollY, + () => { + if (this._mainCont.current) { + this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "smooth" }); + } + }); + } + componentDidMount() { if (this.props.setPdfBox) this.props.setPdfBox(this); } @@ -60,10 +74,6 @@ export class PDFBox extends DocComponent(PdfDocumen } createRef = (ele: HTMLDivElement | null) => { - if (this._reactionDisposer) this._reactionDisposer(); - this._reactionDisposer = reaction(() => this.props.Document.scrollY, () => { - ele && ele.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "auto" }); - }); } loaded = (nw: number, nh: number, np: number) => { @@ -105,7 +115,7 @@ export class PDFBox extends DocComponent(PdfDocumen overflowY: "scroll", overflowX: "hidden", marginTop: `${NumCast(this.props.ContainingCollectionView!.props.Document.panY)}px` }} - ref={this.createRef} + ref={this._mainCont} onWheel={(e: React.WheelEvent) => { e.stopPropagation(); }} className={classname}> diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index 39b15fb11..a8e176858 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -5,6 +5,8 @@ import { observer } from "mobx-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { emptyFunction } from "../../../Utils"; import { Doc } from "../../../new_fields/Doc"; +import { DragManager } from "../../util/DragManager"; +import { DocUtils } from "../../documents/Documents"; @observer export default class PDFMenu extends React.Component { @@ -16,19 +18,23 @@ export default class PDFMenu extends React.Component { @observable private _transition: string = "opacity 0.5s"; @observable private _transitionDelay: string = ""; - @observable public Pinned: boolean = false; StartDrag: (e: PointerEvent) => void = emptyFunction; Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction; Delete: () => void = emptyFunction; + Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction; @observable public Highlighting: boolean = false; - @observable public Status: "pdf" | "annotation" | "" = ""; + @observable public Status: "pdf" | "annotation" | "snippet" | "" = ""; + @observable public Pinned: boolean = false; + + public Marquee: { left: number; top: number; width: number; height: number; } | undefined; private _offsetY: number = 0; private _offsetX: number = 0; private _mainCont: React.RefObject; private _dragging: boolean = false; + private _snippetButton: React.RefObject; constructor(props: Readonly<{}>) { super(props); @@ -36,6 +42,7 @@ export default class PDFMenu extends React.Component { PDFMenu.Instance = this; this._mainCont = React.createRef(); + this._snippetButton = React.createRef(); } pointerDown = (e: React.PointerEvent) => { @@ -171,13 +178,45 @@ export default class PDFMenu extends React.Component { e.preventDefault(); } + snippetStart = (e: React.PointerEvent) => { + document.removeEventListener("pointermove", this.snippetDrag); + document.addEventListener("pointermove", this.snippetDrag); + document.removeEventListener("pointerup", this.snippetEnd); + document.addEventListener("pointerup", this.snippetEnd); + + e.stopPropagation(); + e.preventDefault(); + } + + snippetDrag = (e: PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + if (this._dragging) { + return; + } + this._dragging = true; + + if (this.Marquee) { + this.Snippet(this.Marquee); + } + } + + snippetEnd = (e: PointerEvent) => { + this._dragging = false; + document.removeEventListener("pointermove", this.snippetDrag); + document.removeEventListener("pointerup", this.snippetEnd); + e.stopPropagation(); + e.preventDefault(); + } + render() { - let buttons = this.Status === "pdf" ? [ + let buttons = this.Status === "pdf" || this.Status === "snippet" ? [ , , + this.Status === "snippet" ? : undefined,
+ style={{ gridColumn: 1 }} ref={this._keyRef} /> + style={{ gridColumn: 3 }} ref={this._valueRef} />
- +
+ , - , + , this.Status === "snippet" ? : undefined, - ] : [ - + , +
+ + +
, + , ]; return (
{buttons} - {/* - - */}
); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 1eab13bc5..3df7dd77b 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -20,8 +20,8 @@ import "./PDFViewer.scss"; import React = require("react"); import PDFMenu from "./PDFMenu"; import { UndoManager } from "../../util/UndoManager"; -import { ScriptField } from "../../../fields/ScriptField"; import { CompileScript, CompiledScript, CompileResult } from "../../util/Scripting"; +import { ScriptField } from "../../../new_fields/ScriptField"; export const scale = 2; interface IPDFViewerProps { @@ -63,8 +63,6 @@ interface IViewerProps { url: string; } -const PinRadius = 25; - /** * Handles rendering and virtualization of the pdf */ @@ -85,14 +83,18 @@ class Viewer extends React.Component { private _annotationReactionDisposer?: IReactionDisposer; private _dropDisposer?: DragManager.DragDropDisposer; private _filterReactionDisposer?: IReactionDisposer; + private _viewer: React.RefObject; + private _mainCont: React.RefObject; + private _textContent: Pdfjs.TextContent[] = []; - @action - constructor(props: IViewerProps) { - super(props); + constructor(props: IViewerProps) { + super(props); - let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField); - this._script = scriptfield ? CompileScript(scriptfield.scriptString, { params: { this: Doc.name } }) : CompileScript("return true");; - } + let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField); + this._script = scriptfield ? scriptfield.script : CompileScript("return true"); + this._viewer = React.createRef(); + this._mainCont = React.createRef(); + } componentDidUpdate = (prevProps: IViewerProps) => { if (this.scrollY !== prevProps.scrollY) { @@ -118,21 +120,37 @@ class Viewer extends React.Component { if (this.props.parent.props.ContainingCollectionView) { this._filterReactionDisposer = reaction( - () => this.props.parent.Document.filterScript || this.props.parent.props.ContainingCollectionView!.props.Document.filterScript, + () => this.props.parent.Document.filterScript, () => { runInAction(() => { let scriptfield = Cast(this.props.parent.Document.filterScript, ScriptField); - this._script = scriptfield ? CompileScript(scriptfield.scriptString, { params: { this: Doc.name } }) : CompileScript("return true");; + this._script = scriptfield ? scriptfield.script : CompileScript("return true"); + if (this.props.parent.props.ContainingCollectionView) { + let ccvAnnos = DocListCast(this.props.parent.props.ContainingCollectionView.props.Document.annotations); + ccvAnnos.forEach(d => { + if (this._script && this._script.compiled) { + let run = this._script.run(d); + if (run.success) { + d.opacity = run.result ? 1 : 0; + } + } + }) + } }); } ); } + + if (this._mainCont.current) { + this._dropDisposer = this._mainCont.current && DragManager.MakeDropTarget(this._mainCont.current, { handlers: { drop: this.drop.bind(this) } }); + } } componentWillUnmount = () => { this._reactionDisposer && this._reactionDisposer(); this._annotationReactionDisposer && this._annotationReactionDisposer(); this._filterReactionDisposer && this._filterReactionDisposer(); + this._dropDisposer && this._dropDisposer(); } @action @@ -140,10 +158,14 @@ class Viewer extends React.Component { if (this._pageSizes.length === 0) { let pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages); this._isPage = Array(this.props.pdf.numPages); + this._textContent = Array(this.props.pdf.numPages); for (let i = 0; i < this.props.pdf.numPages; i++) { await this.props.pdf.getPage(i + 1).then(page => runInAction(() => { // pageSizes[i] = { width: page.view[2] * scale, height: page.view[3] * scale }; let x = page.getViewport(scale); + page.getTextContent().then((text: Pdfjs.TextContent) => { + this._textContent[i] = text; + }) pageSizes[i] = { width: x.width, height: x.height }; })); } @@ -162,13 +184,6 @@ class Viewer extends React.Component { } } - private mainCont = (div: HTMLDivElement | null) => { - this._dropDisposer && this._dropDisposer(); - if (div) { - this._dropDisposer = div && DragManager.MakeDropTarget(div, { handlers: { drop: this.drop.bind(this) } }); - } - } - makeAnnotationDocument = (sourceDoc: Doc | undefined, s: number, color: string): Doc => { let annoDocs: Doc[] = []; let mainAnnoDoc = Docs.CreateInstance(new Doc(), "", {}); @@ -222,6 +237,7 @@ class Viewer extends React.Component { pageLoaded = (index: number, page: Pdfjs.PDFPageViewport): void => { this.props.loaded(page.width, page.height, this.props.pdf.numPages); } + @action getPlaceholderPage = (page: number) => { if (this._isPage[page] !== "none") { @@ -232,6 +248,7 @@ class Viewer extends React.Component { ); } } + @action getRenderedPage = (page: number) => { if (this._isPage[page] !== "page") { @@ -374,11 +391,16 @@ class Viewer extends React.Component { return res; } + pointerDown = () => { + + let x = this._textContent; + } + render() { let compiled = this._script; return ( -
-
+
+
{this._visibleElements}
{ } if (e.button === 2) { PDFMenu.Instance.Status = "annotation"; - PDFMenu.Instance.Delete = this.deleteAnnotation; + PDFMenu.Instance.Delete = this.deleteAnnotation.bind(this); PDFMenu.Instance.Pinned = false; + PDFMenu.Instance.AddTag = this.addTag.bind(this); PDFMenu.Instance.jumpTo(e.clientX, e.clientY, true); } } + addTag = (key: string, value: string): boolean => { + let group = FieldValue(Cast(this.props.document.group, Doc)); + if (group) { + let valNum = parseInt(value); + group[key] = isNaN(valNum) ? value : valNum; + return true; + } + return false; + } + render() { return (
Date: Mon, 1 Jul 2019 13:12:10 -0400 Subject: small changes --- src/client/views/nodes/PDFBox.scss | 5 ++++- src/client/views/pdf/Annotation.tsx | 9 +++++++++ src/client/views/pdf/PDFMenu.tsx | 7 +++++-- src/client/views/pdf/Page.tsx | 7 +++++-- 4 files changed, 23 insertions(+), 5 deletions(-) (limited to 'src/client/views/pdf/PDFMenu.tsx') diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 9a38d6241..e7655d598 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -32,15 +32,18 @@ height: 100px; } -.pdfBox-cont, .pdfBox-cont-interactive { +.pdfBox-cont, +.pdfBox-cont-interactive { display: flex; flex-direction: row; height: 100%; overflow-y: scroll; overflow-x: hidden; } + .pdfBox-cont { pointer-events: none; + .textlayer { pointer-events: none; diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index ff77612d6..e88839edd 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -8,6 +8,7 @@ import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import PDFMenu from "./PDFMenu"; import { DocumentManager } from "../../util/DocumentManager"; +import { PresentationView } from "../presentationview/PresentationView"; interface IAnnotationProps { anno: Doc; @@ -101,6 +102,13 @@ class RegionAnnotation extends React.Component { PDFMenu.Instance.fadeOut(true); } + pinToPres = () => { + let group = FieldValue(Cast(this.props.document.group, Doc)); + if (group) { + PresentationView.Instance.PinDoc(group); + } + } + @action onPointerDown = (e: React.PointerEvent) => { if (e.button === 0) { @@ -114,6 +122,7 @@ class RegionAnnotation extends React.Component { PDFMenu.Instance.Delete = this.deleteAnnotation.bind(this); PDFMenu.Instance.Pinned = false; PDFMenu.Instance.AddTag = this.addTag.bind(this); + PDFMenu.Instance.PinToPres = this.pinToPres; PDFMenu.Instance.jumpTo(e.clientX, e.clientY, true); } } diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index aeed5213c..f93b2e59f 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -7,6 +7,7 @@ import { emptyFunction, returnZero, returnTrue, returnFalse } from "../../../Uti import { Doc } from "../../../new_fields/Doc"; import { DragManager } from "../../util/DragManager"; import { DocUtils } from "../../documents/Documents"; +import { PresentationView } from "../presentationview/PresentationView"; @observer export default class PDFMenu extends React.Component { @@ -24,6 +25,7 @@ export default class PDFMenu extends React.Component { Delete: () => void = emptyFunction; Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction; AddTag: (key: string, value: string) => boolean = returnFalse; + PinToPres: () => void = emptyFunction; @observable public Highlighting: boolean = false; @observable public Status: "pdf" | "annotation" | "snippet" | "" = ""; @@ -252,11 +254,12 @@ export default class PDFMenu extends React.Component { ] : [ , -
+ , +
, - , + , ]; return ( diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index 782dbd261..e63ac23da 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -183,8 +183,11 @@ export default class Page extends React.Component { let doc = this.props.parent.Document; let view = Doc.MakeAlias(doc); let data = Doc.MakeDelegate(doc.proto!); + data.title = StrCast(data.title) + "_snippet"; view.proto = data; view.nativeHeight = marquee.height; + view.height = (doc[WidthSym]() / NumCast(doc.nativeWidth)) * marquee.height; + view.nativeWidth = doc.nativeWidth; view.startY = marquee.top + this.props.getScrollFromPage(this.props.page); view.width = doc[WidthSym](); let dragData = new DragManager.DocumentDragData([view], [undefined]); @@ -341,7 +344,7 @@ export default class Page extends React.Component { if (PDFMenu.Instance.Highlighting) { - this.highlight(undefined, "#f4f442"); + this.highlight(undefined, "goldenrod"); } else { PDFMenu.Instance.StartDrag = this.startDrag; @@ -402,7 +405,7 @@ export default class Page extends React.Component {
+ style={{ left: `${this._marqueeX}px`, top: `${this._marqueeY}px`, width: `${this._marqueeWidth}px`, height: `${this._marqueeHeight}px`, background: "red", border: "10px dashed black" }}> {/* */}
-- cgit v1.2.3-70-g09d2 From 400c525875af607dd76d7ec46949fedc418caabf Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 8 Jul 2019 10:54:53 -0400 Subject: fixed annotation dragging on PDFs. fixed panning after zooming on images. --- src/client/util/DragManager.ts | 1 + src/client/views/collections/CollectionSubView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 12 ++++-------- src/client/views/pdf/PDFMenu.tsx | 19 +++++++------------ src/client/views/pdf/Page.tsx | 4 ++-- 5 files changed, 15 insertions(+), 22 deletions(-) (limited to 'src/client/views/pdf/PDFMenu.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index ce1f9d890..a269d7eba 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -321,6 +321,7 @@ export namespace DragManager { dragElement.style.top = "0"; dragElement.style.bottom = ""; dragElement.style.left = "0"; + dragElement.style.transition = "none"; dragElement.style.color = "black"; dragElement.style.transformOrigin = "0 0"; dragElement.style.zIndex = globalCssVariables.contextMenuZindex;// "1000"; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 79c23d71a..5287d3c13 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -102,6 +102,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { return added; } else if (de.data instanceof DragManager.AnnotationDragData) { + e.stopPropagation(); return this.props.addDocument(de.data.dropDocument); } return false; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 7c0591600..7a22b7ec3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -249,16 +249,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { 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 ? newPanY : panY; - this.props.Document.panX = panX; + this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; + this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; + // this.props.Document.panX = panX; + // this.props.Document.panY = panY; if (this.props.Document.scrollY) { this.props.Document.scrollY = panY; - this.props.Document.panY = panY; - } - else { - - this.props.Document.panY = panY; } } diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index f93b2e59f..d6970e7f4 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -3,11 +3,8 @@ import "./PDFMenu.scss"; import { observable, action, runInAction } from "mobx"; import { observer } from "mobx-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { emptyFunction, returnZero, returnTrue, returnFalse } from "../../../Utils"; +import { emptyFunction, returnFalse } from "../../../Utils"; import { Doc } from "../../../new_fields/Doc"; -import { DragManager } from "../../util/DragManager"; -import { DocUtils } from "../../documents/Documents"; -import { PresentationView } from "../presentationview/PresentationView"; @observer export default class PDFMenu extends React.Component { @@ -20,7 +17,7 @@ export default class PDFMenu extends React.Component { @observable private _transitionDelay: string = ""; - StartDrag: (e: PointerEvent) => void = emptyFunction; + StartDrag: (e: PointerEvent, ele: HTMLDivElement) => void = emptyFunction; Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction; Delete: () => void = emptyFunction; Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction; @@ -35,9 +32,10 @@ export default class PDFMenu extends React.Component { private _offsetY: number = 0; private _offsetX: number = 0; - private _mainCont: React.RefObject; + private _mainCont: React.RefObject = React.createRef(); + private _commentCont: React.RefObject = React.createRef(); + private _snippetButton: React.RefObject = React.createRef(); private _dragging: boolean = false; - private _snippetButton: React.RefObject; @observable private _keyValue: string = ""; @observable private _valueValue: string = ""; @observable private _added: boolean = false; @@ -46,9 +44,6 @@ export default class PDFMenu extends React.Component { super(props); PDFMenu.Instance = this; - - this._mainCont = React.createRef(); - this._snippetButton = React.createRef(); } pointerDown = (e: React.PointerEvent) => { @@ -69,7 +64,7 @@ export default class PDFMenu extends React.Component { return; } - this.StartDrag(e); + this.StartDrag(e, this._commentCont.current!); this._dragging = true; } @@ -246,7 +241,7 @@ export default class PDFMenu extends React.Component { style={this.Highlighting ? { backgroundColor: "#121212" } : {}}> , - , + , this.Status === "snippet" ? : undefined,