diff options
Diffstat (limited to 'src/client/views/pdf')
| -rw-r--r-- | src/client/views/pdf/PDFMenu.tsx | 75 | ||||
| -rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 368 | ||||
| -rw-r--r-- | src/client/views/pdf/Page.tsx | 81 |
3 files changed, 273 insertions, 251 deletions
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index 2ed891131..39b15fb11 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -15,16 +15,20 @@ 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; - @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>; + private _dragging: boolean = false; constructor(props: Readonly<{}>) { super(props); @@ -35,27 +39,38 @@ 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(); } @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; @@ -65,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 = ""; @@ -84,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; @@ -101,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; } } @@ -138,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 { @@ -147,11 +162,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> @@ -159,8 +198,8 @@ 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> - <div className="pdfMenu-dragger" onPointerDown={this.dragStart} style={{ width: this._pinned ? "20px" : "0px" }} /> + </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 8c0aaea00..7000352e7 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"; @@ -19,6 +19,7 @@ import Page from "./Page"; import "./PDFViewer.scss"; import React = require("react"); import PDFMenu from "./PDFMenu"; +import { UndoManager } from "../../util/UndoManager"; export const scale = 2; interface IPDFViewerProps { @@ -90,7 +91,8 @@ class Viewer extends React.Component<IViewerProps> { @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 +116,16 @@ class Viewer extends React.Component<IViewerProps> { let pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages); this._isPage = Array<string>(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); } } @@ -132,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(); @@ -141,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); @@ -148,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) => { @@ -185,7 +192,7 @@ class Viewer extends React.Component<IViewerProps> { if (this._isPage[page] !== "none") { this._isPage[page] = "none"; this._visibleElements[page] = ( - <div key={`placeholder-${page}`} className="pdfviewer-placeholder" + <div key={`${this.props.url}-placeholder-${page + 1}`} className="pdfviewer-placeholder" style={{ width: this._pageSizes[page].width, height: this._pageSizes[page].height }} /> ); } @@ -199,11 +206,11 @@ class Viewer extends React.Component<IViewerProps> { pdf={this.props.pdf} page={page} numPages={this.props.pdf.numPages} - key={`rendered-${page + 1}`} + key={`${this.props.url}-rendered-${page + 1}`} name={`${this.props.pdf.fingerprint + `-page${page + 1}`}`} pageLoaded={this.pageLoaded} parent={this.props.parent} - makePin={this.createPinAnnotation} + makePin={emptyFunction} renderAnnotations={this.renderAnnotations} createAnnotation={this.createAnnotation} sendAnnotations={this.receiveAnnotations} @@ -236,7 +243,7 @@ class Viewer extends React.Component<IViewerProps> { // endIndex: where to end rendering pages @computed get endIndex(): number { - return Math.min(this.props.pdf.numPages - 1, this.getPageFromScroll(this.scrollY) + this._pageBuffer); + return Math.min(this.props.pdf.numPages - 1, this.getPageFromScroll(this.scrollY + this._pageSizes[0].height) + this._pageBuffer); } @action @@ -280,27 +287,27 @@ class Viewer extends React.Component<IViewerProps> { return this._savedAnnotations.getValue(page); } - createPinAnnotation = (x: number, y: number, page: number): void => { - let targetDoc = Docs.TextDocument({ width: 100, height: 50, title: "New Pin Annotation" }); - let pinAnno = new Doc(); - pinAnno.x = x; - pinAnno.y = y + this.getScrollFromPage(page); - pinAnno.width = pinAnno.height = PinRadius; - pinAnno.page = page; - pinAnno.target = targetDoc; - pinAnno.type = AnnotationTypes.Pin; - // this._annotations.push(pinAnno); - let annoDoc = new Doc(); - annoDoc.annotations = new List<Doc>([pinAnno]); - let annotations = DocListCast(this.props.parent.Document.annotations); - if (annotations && annotations.length) { - annotations.push(annoDoc); - this.props.parent.Document.annotations = new List<Doc>(annotations); - } - else { - this.props.parent.Document.annotations = new List<Doc>([annoDoc]); - } - } + // createPinAnnotation = (x: number, y: number, page: number): void => { + // let targetDoc = Docs.TextDocument({ width: 100, height: 50, title: "New Pin Annotation" }); + // let pinAnno = new Doc(); + // pinAnno.x = x; + // pinAnno.y = y + this.getScrollFromPage(page); + // pinAnno.width = pinAnno.height = PinRadius; + // pinAnno.page = page; + // pinAnno.target = targetDoc; + // pinAnno.type = AnnotationTypes.Pin; + // // this._annotations.push(pinAnno); + // let annoDoc = new Doc(); + // annoDoc.annotations = new List<Doc>([pinAnno]); + // let annotations = DocListCast(this.props.parent.Document.annotations); + // if (annotations && annotations.length) { + // annotations.push(annoDoc); + // this.props.parent.Document.annotations = new List<Doc>(annotations); + // } + // else { + // this.props.parent.Document.annotations = new List<Doc>([annoDoc]); + // } + // } // get the page index that the vertical offset passed in is on getPageFromScroll = (vOffset: number) => { @@ -334,26 +341,6 @@ class Viewer extends React.Component<IViewerProps> { else { this._savedAnnotations.setValue(page, [div]); } - PDFMenu.Instance.StartDrag = this.startDrag; - } - } - - startDrag = (e: PointerEvent) => { - e.preventDefault(); - e.stopPropagation(); - let thisDoc = this.props.parent.Document; - // document that this annotation is linked to - let targetDoc = Docs.TextDocument({ width: 200, height: 200, title: "New Annotation" }); - targetDoc.targetPage = Math.min(...this._savedAnnotations.keys()); - let annotationDoc = this.makeAnnotationDocument(targetDoc, 1, "red"); - let dragData = new DragManager.AnnotationDragData(thisDoc, annotationDoc, targetDoc); - if (this._annotationLayer.current) { - DragManager.StartAnnotationDrag([this._annotationLayer.current], dragData, e.pageX, e.pageY, { - handlers: { - dragComplete: action(emptyFunction), - }, - hideSource: false - }); } } @@ -362,8 +349,8 @@ class Viewer extends React.Component<IViewerProps> { let res = annotationDocs.map(a => { let type = NumCast(a.type); switch (type) { - case AnnotationTypes.Pin: - return <PinAnnotation parent={this} document={a} x={NumCast(a.x)} y={NumCast(a.y)} width={a[WidthSym]()} height={a[HeightSym]()} key={a[Id]} />; + // case AnnotationTypes.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]} />; default: @@ -394,7 +381,7 @@ class Viewer extends React.Component<IViewerProps> { } export enum AnnotationTypes { - Region, Pin + Region } interface IAnnotationProps { @@ -406,132 +393,193 @@ interface IAnnotationProps { document: Doc; } -@observer -class PinAnnotation extends React.Component<IAnnotationProps> { - @observable private _backgroundColor: string = "green"; - @observable private _display: string = "initial"; +// @observer +// class PinAnnotation extends React.Component<IAnnotationProps> { +// @observable private _backgroundColor: string = "green"; +// @observable private _display: string = "initial"; + +// private _mainCont: React.RefObject<HTMLDivElement>; + +// constructor(props: IAnnotationProps) { +// super(props); +// this._mainCont = React.createRef(); +// } + +// componentDidMount = () => { +// let selected = this.props.document.selected; +// if (!BoolCast(selected)) { +// runInAction(() => { +// this._backgroundColor = "red"; +// this._display = "none"; +// }); +// } +// if (selected) { +// if (BoolCast(selected)) { +// runInAction(() => { +// this._backgroundColor = "green"; +// this._display = "initial"; +// }); +// } +// else { +// runInAction(() => { +// this._backgroundColor = "red"; +// this._display = "none"; +// }); +// } +// } +// else { +// runInAction(() => { +// this._backgroundColor = "red"; +// this._display = "none"; +// }); +// } +// } + +// @action +// pointerDown = (e: React.PointerEvent) => { +// let selected = this.props.document.selected; +// if (selected && BoolCast(selected)) { +// this._backgroundColor = "red"; +// this._display = "none"; +// this.props.document.selected = false; +// } +// else { +// this._backgroundColor = "green"; +// this._display = "initial"; +// this.props.document.selected = true; +// } +// e.preventDefault(); +// e.stopPropagation(); +// } + +// @action +// doubleClick = (e: React.MouseEvent) => { +// if (this._mainCont.current) { +// let annotations = DocListCast(this.props.parent.props.parent.Document.annotations); +// if (annotations && annotations.length) { +// let index = annotations.indexOf(this.props.document); +// annotations.splice(index, 1); +// this.props.parent.props.parent.Document.annotations = new List<Doc>(annotations); +// } +// // this._mainCont.current.childNodes.forEach(e => e.remove()); +// this._mainCont.current.style.display = "none"; +// // if (this._mainCont.current.parentElement) { +// // this._mainCont.current.remove(); +// // } +// } +// e.stopPropagation(); +// } + +// render() { +// let targetDoc = Cast(this.props.document.target, Doc); +// if (targetDoc instanceof Doc) { +// return ( +// <div className="pdfViewer-pinAnnotation" onPointerDown={this.pointerDown} +// onDoubleClick={this.doubleClick} ref={this._mainCont} +// style={{ +// top: this.props.y * scale - PinRadius / 2, left: this.props.x * scale - PinRadius / 2, width: PinRadius, +// height: PinRadius, pointerEvents: "all", backgroundColor: this._backgroundColor +// }}> +// <div style={{ +// position: "absolute", top: "25px", left: "25px", transform: "scale(3)", transformOrigin: "top left", +// display: this._display, width: targetDoc[WidthSym](), height: targetDoc[HeightSym]() +// }}> +// <DocumentView Document={targetDoc} +// ContainingCollectionView={undefined} +// ScreenToLocalTransform={this.props.parent.props.parent.props.ScreenToLocalTransform} +// isTopMost={false} +// ContentScaling={() => 1} +// PanelWidth={() => NumCast(this.props.parent.props.parent.Document.nativeWidth)} +// PanelHeight={() => NumCast(this.props.parent.props.parent.Document.nativeHeight)} +// focus={emptyFunction} +// selectOnLoad={false} +// parentActive={this.props.parent.props.parent.props.active} +// whenActiveChanged={this.props.parent.props.parent.props.whenActiveChanged} +// bringToFront={emptyFunction} +// addDocTab={this.props.parent.props.parent.props.addDocTab} +// /> +// </div> +// </div > +// ); +// } +// return null; +// } +// } + +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 = () => { - let selected = this.props.document.selected; - if (!BoolCast(selected)) { - runInAction(() => { - this._backgroundColor = "red"; - this._display = "none"; - }); - } - if (selected) { - if (BoolCast(selected)) { - runInAction(() => { - this._backgroundColor = "green"; - this._display = "initial"; - }); - } - else { - runInAction(() => { - this._backgroundColor = "red"; - this._display = "none"; - }); - } - } - else { - runInAction(() => { - this._backgroundColor = "red"; - this._display = "none"; - }); - } + 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 } + ); } - @action - pointerDown = (e: React.PointerEvent) => { - let selected = this.props.document.selected; - if (selected && BoolCast(selected)) { - this._backgroundColor = "red"; - this._display = "none"; - this.props.document.selected = false; - } - else { - this._backgroundColor = "green"; - this._display = "initial"; - this.props.document.selected = true; - } - e.preventDefault(); - e.stopPropagation(); + componentWillUnmount() { + this._reactionDisposer && this._reactionDisposer(); } - @action - doubleClick = (e: React.MouseEvent) => { - if (this._mainCont.current) { - let annotations = DocListCast(this.props.parent.props.parent.Document.annotations); - if (annotations && annotations.length) { - let index = annotations.indexOf(this.props.document); - annotations.splice(index, 1); - this.props.parent.props.parent.Document.annotations = new List<Doc>(annotations); - } - // this._mainCont.current.childNodes.forEach(e => e.remove()); - this._mainCont.current.style.display = "none"; - // if (this._mainCont.current.parentElement) { - // this._mainCont.current.remove(); - // } + 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); } - e.stopPropagation(); - } - render() { - let targetDoc = Cast(this.props.document.target, Doc); - if (targetDoc instanceof Doc) { - return ( - <div className="pdfViewer-pinAnnotation" onPointerDown={this.pointerDown} - onDoubleClick={this.doubleClick} ref={this._mainCont} - style={{ - top: this.props.y * scale - PinRadius / 2, left: this.props.x * scale - PinRadius / 2, width: PinRadius, - height: PinRadius, pointerEvents: "all", backgroundColor: this._backgroundColor - }}> - <div style={{ - position: "absolute", top: "25px", left: "25px", transform: "scale(3)", transformOrigin: "top left", - display: this._display, width: targetDoc[WidthSym](), height: targetDoc[HeightSym]() - }}> - <DocumentView Document={targetDoc} - ContainingCollectionView={undefined} - ScreenToLocalTransform={this.props.parent.props.parent.props.ScreenToLocalTransform} - isTopMost={false} - ContentScaling={() => 1} - PanelWidth={() => NumCast(this.props.parent.props.parent.Document.nativeWidth)} - PanelHeight={() => NumCast(this.props.parent.props.parent.Document.nativeHeight)} - focus={emptyFunction} - selectOnLoad={false} - parentActive={this.props.parent.props.parent.props.active} - whenActiveChanged={this.props.parent.props.parent.props.whenActiveChanged} - bringToFront={emptyFunction} - addDocTab={this.props.parent.props.parent.props.addDocTab} - /> - </div> - </div > - ); + if (group) { + let groupAnnotations = DocListCast(group.annotations); + groupAnnotations.forEach(anno => anno.delete = true); } - return null; + + PDFMenu.Instance.fadeOut(true); } -} -class RegionAnnotation extends React.Component<IAnnotationProps> { - @observable private _backgroundColor: string = "red"; - onPointerDown = (e: React.MouseEvent) => { - let targetDoc = Cast(this.props.document.target, Doc, null); - if (targetDoc) { - DocumentManager.Instance.jumpToDocument(targetDoc); + // 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); + if (targetDoc) { + DocumentManager.Instance.jumpToDocument(targetDoc); + } + } + if (e.button === 2) { + PDFMenu.Instance.Status = "annotation"; + PDFMenu.Instance.Delete = this.deleteAnnotation; + PDFMenu.Instance.Pinned = false; + PDFMenu.Instance.jumpTo(e.clientX, e.clientY, true); } } render() { return ( - <div className="pdfViewer-annotationBox" onClick={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 a19b64eda..b6f362702 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -15,9 +15,11 @@ import { listSpec } from "../../../new_fields/Schema"; import { menuBar } from "prosemirror-menu"; import { AnnotationTypes, PDFViewer, scale } from "./PDFViewer"; import PDFMenu from "./PDFMenu"; +import { UndoManager } from "../../util/UndoManager"; interface IPageProps { + size: { width: number, height: number }; pdf: Opt<Pdfjs.PDFDocumentProxy>; name: string; numPages: number; @@ -35,8 +37,8 @@ interface IPageProps { @observer export default class Page extends React.Component<IPageProps> { @observable private _state: string = "N/A"; - @observable private _width: number = 0; - @observable private _height: number = 0; + @observable private _width: number = this.props.size.width; + @observable private _height: number = this.props.size.height; @observable private _page: Opt<Pdfjs.PDFPageProxy>; @observable private _currPage: number = this.props.page + 1; @observable private _marqueeX: number = 0; @@ -51,7 +53,6 @@ export default class Page extends React.Component<IPageProps> { private _marquee: React.RefObject<HTMLDivElement>; private _curly: React.RefObject<HTMLImageElement>; private _marqueeing: boolean = false; - private _dragging: boolean = false; private _reactionDisposer?: IReactionDisposer; constructor(props: IPageProps) { @@ -151,13 +152,8 @@ export default class Page extends React.Component<IPageProps> { */ @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; let thisDoc = this.props.parent.Document; // document that this annotation is linked to let targetDoc = Docs.TextDocument({ width: 200, height: 200, title: "New Annotation" }); @@ -168,7 +164,7 @@ export default class Page extends React.Component<IPageProps> { if (this._textLayer.current) { DragManager.StartAnnotationDrag([this._textLayer.current], dragData, e.pageX, e.pageY, { handlers: { - dragComplete: action(emptyFunction), + dragComplete: emptyFunction, }, hideSource: false }); @@ -179,7 +175,6 @@ export default class Page extends React.Component<IPageProps> { endDrag = (e: PointerEvent): void => { // document.removeEventListener("pointermove", this.startDrag); // document.removeEventListener("pointerup", this.endDrag); - this._dragging = false; e.stopPropagation(); } @@ -195,6 +190,9 @@ export default class Page extends React.Component<IPageProps> { // document.addEventListener("pointerup", this.endDrag); } 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) { @@ -329,68 +327,6 @@ export default class Page extends React.Component<IPageProps> { 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) { - // this._marqueeing = false; - // if (this._marquee.current) { - // let copy = document.createElement("div"); - // // make a copy of the marquee - // copy.style.left = this._marquee.current.style.left; - // copy.style.top = this._marquee.current.style.top; - // copy.style.width = this._marquee.current.style.width; - // copy.style.height = this._marquee.current.style.height; - - // // apply the appropriate background, opacity, and transform - // let { background, opacity, transform } = this.getCurlyTransform(); - // copy.style.background = background; - // // if curly bracing, add a curly brace - // if (opacity === "1" && this._curly.current) { - // copy.style.opacity = opacity; - // let img = this._curly.current.cloneNode(); - // (img as any).style.opacity = opacity; - // (img as any).style.transform = transform; - // copy.appendChild(img); - // } - // else { - // copy.style.opacity = this._marquee.current.style.opacity; - // } - // copy.className = this._marquee.current.className; - // this.props.createAnnotation(copy, this.props.page); - // this._marquee.current.style.opacity = "0"; - // } - - // this._marqueeHeight = this._marqueeWidth = 0; - // } - // else { - // let sel = window.getSelection(); - // // if selecting over a range of things - // if (sel && sel.type === "Range") { - // let clientRects = sel.getRangeAt(0).getClientRects(); - // if (this._textLayer.current) { - // let boundingRect = this._textLayer.current.getBoundingClientRect(); - // for (let i = 0; i < clientRects.length; i++) { - // let rect = clientRects.item(i); - // if (rect) { - // let annoBox = document.createElement("div"); - // annoBox.className = "pdfViewer-annotationBox"; - // // transforms the positions from screen onto the pdf div - // annoBox.style.top = ((rect.top - boundingRect.top) * (this._textLayer.current.offsetHeight / boundingRect.height)).toString(); - // annoBox.style.left = ((rect.left - boundingRect.left) * (this._textLayer.current.offsetWidth / boundingRect.width)).toString(); - // annoBox.style.width = (rect.width * this._textLayer.current.offsetWidth / boundingRect.width).toString(); - // annoBox.style.height = (rect.height * this._textLayer.current.offsetHeight / boundingRect.height).toString(); - // this.props.createAnnotation(annoBox, this.props.page); - // } - // } - // } - // // clear selection - // if (sel.empty) { // Chrome - // sel.empty(); - // } else if (sel.removeAllRanges) { // Firefox - // sel.removeAllRanges(); - // } - // } - // } document.removeEventListener("pointermove", this.onSelectStart); document.removeEventListener("pointerup", this.onSelectEnd); } @@ -403,7 +339,6 @@ export default class Page extends React.Component<IPageProps> { for (let i = 0; i < clientRects.length; i++) { let rect = clientRects.item(i); if (rect && rect.width !== this._textLayer.current.getBoundingClientRect().width && rect.height !== this._textLayer.current.getBoundingClientRect().height) { - console.log(rect); let annoBox = document.createElement("div"); annoBox.className = "pdfViewer-annotationBox"; // transforms the positions from screen onto the pdf div |
