From 9419693f37ad53fcc0763a118d2cb865659a2ff4 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 6 Aug 2019 14:08:59 -0400 Subject: multiple changes to PDF related code -- mostly clean up --- src/client/views/nodes/PDFBox.tsx | 241 ++++++++++++++++---------------------- 1 file changed, 100 insertions(+), 141 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index a49709e83..56e720bf7 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -1,31 +1,24 @@ -import { action, IReactionDisposer, observable, reaction, trace, untracked, computed } from 'mobx'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from "mobx-react"; +import * as Pdfjs from "pdfjs-dist"; +import "pdfjs-dist/web/pdf_viewer.css"; import 'react-image-lightbox/style.css'; -import { WidthSym, Doc } from "../../../new_fields/Doc"; +import { Doc, WidthSym, Opt } from "../../../new_fields/Doc"; import { makeInterface } from "../../../new_fields/Schema"; -import { Cast, NumCast, BoolCast } from "../../../new_fields/Types"; +import { ScriptField } from '../../../new_fields/ScriptField'; +import { BoolCast, Cast, NumCast } from "../../../new_fields/Types"; import { PdfField } from "../../../new_fields/URLField"; -//@ts-ignore -// import { Document, Page } from "react-pdf"; -// import 'react-pdf/dist/Page/AnnotationLayer.css'; -import { RouteStore } from "../../../server/RouteStore"; +import { KeyCodes } from '../../northstar/utils/KeyCodes'; +import { CompileScript } from '../../util/Scripting'; import { DocComponent } from "../DocComponent"; import { InkingControl } from "../InkingControl"; -import { FilterBox } from "../search/FilterBox"; -import { Annotation } from './Annotation'; import { PDFViewer } from "../pdf/PDFViewer"; import { positionSchema } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { pageSchema } from "./ImageBox"; import "./PDFBox.scss"; import React = require("react"); -import { CompileScript } from '../../util/Scripting'; -import { Flyout, anchorPoints } from '../DocumentDecorations'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { ScriptField } from '../../../new_fields/ScriptField'; -import { KeyCodes } from '../../northstar/utils/KeyCodes'; -import { Utils } from '../../../Utils'; -import { Id } from '../../../new_fields/FieldSymbols'; type PdfDocument = makeInterface<[typeof positionSchema, typeof pageSchema]>; const PdfDocument = makeInterface(positionSchema, pageSchema); @@ -35,40 +28,33 @@ export const handleBackspace = (e: React.KeyboardEvent) => { if (e.keyCode === K export class PDFBox extends DocComponent(PdfDocument) { public static LayoutString() { return FieldView.LayoutString(PDFBox); } + @observable private _flyout: boolean = false; @observable private _alt = false; @observable private _scrollY: number = 0; + @observable private _pdf: Opt; + @computed get containingCollectionDocument() { return this.props.ContainingCollectionView && this.props.ContainingCollectionView.props.Document; } @computed get dataDoc() { return BoolCast(this.props.Document.isTemplate) && this.props.DataDoc ? this.props.DataDoc : this.props.Document; } - @observable private _flyout: boolean = false; - private _mainCont: React.RefObject; + private _mainCont: React.RefObject = React.createRef(); private _reactionDisposer?: IReactionDisposer; private _keyValue: string = ""; private _valueValue: string = ""; private _scriptValue: string = ""; - private _keyRef: React.RefObject; - private _valueRef: React.RefObject; - private _scriptRef: React.RefObject; + private _keyRef: React.RefObject = React.createRef(); + private _valueRef: React.RefObject = React.createRef(); + private _scriptRef: React.RefObject = React.createRef(); - constructor(props: FieldViewProps) { - super(props); + componentDidMount() { + this.props.setPdfBox && this.props.setPdfBox(this); - this._mainCont = React.createRef(); + const pdfUrl = Cast(this.props.Document.data, PdfField); + if (pdfUrl instanceof PdfField) { + Pdfjs.getDocument(pdfUrl.url.pathname).promise.then(pdf => runInAction(() => this._pdf = pdf)); + } this._reactionDisposer = reaction( () => this.props.Document.scrollY, - () => { - if (this._mainCont.current) { - this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "auto" }); - } - } + () => this._mainCont.current && this._mainCont.current.scrollTo({ top: NumCast(this.Document.scrollY), behavior: "auto" }) ); - - this._keyRef = React.createRef(); - this._valueRef = React.createRef(); - this._scriptRef = React.createRef(); - } - - componentDidMount() { - if (this.props.setPdfBox) this.props.setPdfBox(this); } componentWillUnmount() { @@ -78,6 +64,8 @@ export class PDFBox extends DocComponent(PdfDocumen public GetPage() { return Math.floor(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.pdfHeight)) + 1; } + + @action public BackPage() { let cp = Math.ceil(NumCast(this.props.Document.scrollY) / NumCast(this.dataDoc.pdfHeight)) + 1; cp = cp - 1; @@ -86,6 +74,8 @@ export class PDFBox extends DocComponent(PdfDocumen this.props.Document.scrollY = (cp - 1) * NumCast(this.dataDoc.pdfHeight); } } + + @action public GotoPage(p: number) { if (p > 0 && p <= NumCast(this.props.Document.numPages)) { this.props.Document.curPage = p; @@ -93,6 +83,7 @@ export class PDFBox extends DocComponent(PdfDocumen } } + @action public ForwardPage() { let cp = this.GetPage() + 1; if (cp <= NumCast(this.props.Document.numPages)) { @@ -101,6 +92,15 @@ export class PDFBox extends DocComponent(PdfDocumen } } + scrollTo = (y: number) => { + this._mainCont.current && this._mainCont.current.scrollTo({ top: Math.max(y - (this._mainCont.current.offsetHeight / 2), 0), behavior: "auto" }); + } + + @action + setPanY = (y: number) => { + this.containingCollectionDocument && (this.containingCollectionDocument.panY = y); + } + private newKeyChange = (e: React.ChangeEvent) => { this._keyValue = e.currentTarget.value; } @@ -109,151 +109,110 @@ export class PDFBox extends DocComponent(PdfDocumen this._valueValue = e.currentTarget.value; } - @action private newScriptChange = (e: React.ChangeEvent) => { this._scriptValue = e.currentTarget.value; } private applyFilter = () => { - let scriptText = ""; - if (this._scriptValue.length > 0) { - scriptText = this._scriptValue; - } else if (this._keyValue.length > 0 && this._valueValue.length > 0) { - scriptText = `return this.${this._keyValue} === ${this._valueValue}`; - } - else { - scriptText = "return true"; - } + let scriptText = this._scriptValue.length > 0 ? this._scriptValue : + this._keyValue.length > 0 && this._valueValue.length > 0 ? + `return this.${this._keyValue} === ${this._valueValue}` : "return true"; let script = CompileScript(scriptText, { params: { this: Doc.name } }); - if (script.compiled) { - this.props.Document.filterScript = new ScriptField(script); - } - } - - @action - private toggleFlyout = () => { - this._flyout = !this._flyout; + script.compiled && (this.props.Document.filterScript = new ScriptField(script)); } @action private resetFilters = () => { this._keyValue = this._valueValue = ""; this._scriptValue = "return true"; - if (this._keyRef.current) { - this._keyRef.current.value = ""; - } - if (this._valueRef.current) { - this._valueRef.current.value = ""; - } - if (this._scriptRef.current) { - this._scriptRef.current.value = ""; - } + this._keyRef.current && (this._keyRef.current.value = ""); + this._valueRef.current && (this._valueRef.current.value = ""); + this._scriptRef.current && (this._scriptRef.current.value = ""); this.applyFilter(); } - scrollTo(y: number) { - this._mainCont.current && this._mainCont.current.scrollTo({ top: Math.max(y - (this._mainCont.current.offsetHeight / 2), 0), behavior: "auto" }); - } - settingsPanel() { return !this.props.active() ? (null) : - ( -
e.stopPropagation()}> - -
-
- Annotation View Settings -
-
- - -
-
- -
-
- - -
+ (
e.stopPropagation()}> + +
+
+ Annotation View Settings +
+
+ + +
+
+ +
+
+ +
- ); +
); } loaded = (nw: number, nh: number, np: number) => { - if (this.props.Document) { - let doc = this.dataDoc; - doc.numPages = np; - if (doc.nativeWidth && doc.nativeHeight) return; - let oldaspect = NumCast(doc.nativeHeight) / NumCast(doc.nativeWidth, 1); - doc.nativeWidth = nw; - if (doc.nativeHeight) doc.nativeHeight = nw * oldaspect; - else doc.nativeHeight = nh; - let ccv = this.props.ContainingCollectionView; - if (ccv) { - ccv.props.Document.pdfHeight = nh; - } - doc.height = nh * (doc[WidthSym]() / nw); + this.dataDoc.numPages = np; + if (!this.dataDoc.nativeWidth || !this.dataDoc.nativeHeight) { + let oldaspect = NumCast(this.dataDoc.nativeHeight) / NumCast(this.dataDoc.nativeWidth, 1); + this.dataDoc.nativeWidth = nw; + this.dataDoc.nativeHeight = this.dataDoc.nativeHeight ? nw * oldaspect : nh; + this.containingCollectionDocument && (this.containingCollectionDocument.pdfHeight = nh); + this.dataDoc.height = nh * (this.dataDoc[WidthSym]() / nw); } } @action onScroll = (e: React.UIEvent) => { - - if (e.currentTarget) { - this._scrollY = e.currentTarget.scrollTop; - let ccv = this.props.ContainingCollectionView; - if (ccv) { - ccv.props.Document.panTransformType = "None"; - ccv.props.Document.scrollY = this._scrollY; - } + if (e.currentTarget && this.containingCollectionDocument) { + this.containingCollectionDocument.panTransformType = "None"; + this.containingCollectionDocument.scrollY = this._scrollY = e.currentTarget.scrollTop; } } - @computed get fieldExtensionDoc() { return Doc.resolvedFieldDataDoc(this.props.DataDoc ? this.props.DataDoc : this.props.Document, this.props.fieldKey, "true"); } + render() { - // uses mozilla pdf as default const pdfUrl = Cast(this.props.Document.data, PdfField); - if (!(pdfUrl instanceof PdfField)) return
{`pdf, ${this.props.Document.data}, not found`}
; let classname = "pdfBox-cont" + (this.props.active() && !InkingControl.Instance.selectedTool && !this._alt ? "-interactive" : ""); - return ( + return (!(pdfUrl instanceof PdfField) || !this._pdf ? +
{`pdf, ${this.props.Document.data}, not found`}
:
{ - e.stopPropagation(); - }}> - - {/*
*/} + onWheel={(e: React.WheelEvent) => { e.stopPropagation(); }}> + {this.settingsPanel()}
); } - } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From acbe0ced15150d15d81110cd2259b99e942d02e6 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 6 Aug 2019 18:17:48 -0400 Subject: pdf css cleanup --- src/client/views/nodes/PDFBox.scss | 64 +++--------- src/client/views/pdf/Annotation.scss | 5 +- src/client/views/pdf/Annotation.tsx | 2 +- src/client/views/pdf/PDFMenu.tsx | 2 +- src/client/views/pdf/PDFViewer.scss | 186 ++++++++++++++--------------------- src/client/views/pdf/PDFViewer.tsx | 37 +++---- src/client/views/pdf/Page.scss | 31 ++++++ src/client/views/pdf/Page.tsx | 32 +++--- 8 files changed, 161 insertions(+), 198 deletions(-) create mode 100644 src/client/views/pdf/Page.scss (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index e7655d598..a1bab0409 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -1,37 +1,3 @@ -.react-pdf__Page { - transform-origin: left top; - position: absolute; - top: 0; - left: 0; -} - -.react-pdf__Page__textContent span { - user-select: text; -} - -.react-pdf__Document { - position: absolute; -} - -.pdfBox-buttonTray { - position: absolute; - top: 0; - left: 0; - z-index: 25; - pointer-events: all; -} - -.pdfBox-thumbnail { - position: absolute; - width: 100%; -} - -.pdfButton { - pointer-events: all; - width: 100px; - height: 100px; -} - .pdfBox-cont, .pdfBox-cont-interactive { display: flex; @@ -43,26 +9,17 @@ .pdfBox-cont { pointer-events: none; - - .textlayer { - pointer-events: none; - + .pdfPage-textlayer { span { pointer-events: none !important; + user-select: none; } } - - .page-cont { - pointer-events: none; - } } .pdfBox-cont-interactive { pointer-events: all; - display: flex; - flex-direction: row; - - .textlayer { + .pdfPage-textlayer { span { pointer-events: all !important; user-select: text; @@ -70,11 +27,22 @@ } } -.pdfBox-contentContainer { - position: absolute; +.react-pdf__Page { transform-origin: left top; + position: absolute; + top: 0; + left: 0; +} + +.react-pdf__Page__textContent span { + user-select: text; +} + +.react-pdf__Document { + position: absolute; } + .pdfBox-settingsCont { position: absolute; right: 0; diff --git a/src/client/views/pdf/Annotation.scss b/src/client/views/pdf/Annotation.scss index 0ea85d522..817115690 100644 --- a/src/client/views/pdf/Annotation.scss +++ b/src/client/views/pdf/Annotation.scss @@ -1,4 +1,7 @@ -.pdfViewer-annotationBox { +.pdfAnnotation { pointer-events: all; user-select: none; + position: absolute; + background-color: pink; + opacity: 0.1; } \ No newline at end of file diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 9d68a86b8..947f5a2e8 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -130,7 +130,7 @@ class RegionAnnotation extends React.Component { render() { return ( -
void = emptyFunction; - public Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction; + public Highlight: (d: Doc | undefined, color: string) => void = emptyFunction; public Delete: () => void = emptyFunction; public Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction; public AddTag: (key: string, value: string) => boolean = returnFalse; diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss index 41efb0c00..a2f3911c5 100644 --- a/src/client/views/pdf/PDFViewer.scss +++ b/src/client/views/pdf/PDFViewer.scss @@ -1,131 +1,93 @@ -.textLayer { - div { - user-select: text; - } -} -.viewer-button-cont { - position: absolute; - display: flex; - justify-content: space-evenly; - align-items: center; -} - -.viewer-previousPage, -.viewer-nextPage { - background: grey; - font-weight: bold; - opacity: 0.5; - padding: 0 10px; - border-radius: 5px; -} - -.textLayer { - user-select: auto; -} .pdfViewer-viewer { pointer-events:inherit; width: 100%; -} - -.pdfViewer-text { - transform: scale(1.5); - transform-origin: top left; - .page { - .canvasWrapper { - display: none; - } - - .textLayer { - position: relative; - user-select: none; + .pdfViewer-visibleElements { + .pdfPage-cont { + .pdfPage-textLayer { + div { + user-select: text; + } + span { + color: transparent; + position: absolute; + white-space: pre; + cursor: text; + -webkit-transform-origin: 0% 0%; + transform-origin: 0% 0%; + } + } } } -} - -.page-cont { - .textLayer { - user-select: auto; - - div { - user-select: text; - } + .pdfViewer-text { + transform: scale(1.5); + transform-origin: top left; } -} - -.pdfViewer-overlayCont { - position: absolute; - width: 100%; - height: 100px; - background: #121721; - bottom: 0; - display: flex; - justify-content: center; - align-items: center; - padding: 20px; - overflow: hidden; - transition: left .5s; -} -.pdfViewer-overlaySearchBar { - width: 20%; - height: 100%; - font-size: 30px; - padding: 5px; -} - -.pdfViewer-overlayButton { - border-bottom-left-radius: 50%; - display: flex; - justify-content: space-evenly; - align-items: center; - height: 70px; - background: none; - padding: 0; - position: absolute; - - .pdfViewer-overlayButton-arrow { - width: 0; - height: 0; - border-top: 25px solid transparent; - border-bottom: 25px solid transparent; - border-right: 25px solid #121721; - transition: all 0.5s; + .pdfViewer-annotationLayer { + position: absolute; + top: 0; + width: 100%; + pointer-events: none; + .pdfPage-annotationBox { + position: absolute; + background-color: red; + opacity: 0.1; + } } - .pdfViewer-overlayButton-iconCont { + .pdfViewer-overlayCont { + position: absolute; + width: 100%; + height: 100px; background: #121721; - height: 50px; - width: 70px; + bottom: 0; display: flex; justify-content: center; align-items: center; - margin-left: -2px; - border-radius: 3px; + padding: 20px; + overflow: hidden; + transition: left .5s; + .pdfViewer-overlaySearchBar { + width: 20%; + height: 100%; + font-size: 30px; + padding: 5px; + } } -} -.pdfViewer-overlayButton:hover { - background: none; -} + .pdfViewer-overlayButton { + border-bottom-left-radius: 50%; + display: flex; + justify-content: space-evenly; + align-items: center; + height: 70px; + background: none; + padding: 0; + position: absolute; + + .pdfViewer-overlayButton-arrow { + width: 0; + height: 0; + border-top: 25px solid transparent; + border-bottom: 25px solid transparent; + border-right: 25px solid #121721; + transition: all 0.5s; + } -.pdfViewer-annotationBox { - position: absolute; - background-color: red; - opacity: 0.1; -} + .pdfViewer-overlayButton-iconCont { + background: #121721; + height: 50px; + width: 70px; + display: flex; + justify-content: center; + align-items: center; + margin-left: -2px; + border-radius: 3px; + } + } -.pdfViewer-annotationLayer { - position: absolute; - top: 0; - width: 100%; - pointer-events: none; + .pdfViewer-overlayButton:hover { + background: none; + } } - - - -.pdfViewer-pinAnnotation { - background-color: red; - position: absolute; - border-radius: 100%; -} \ No newline at end of file diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 524bb0420..9abb22553 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -427,14 +427,13 @@ export class PDFViewer extends React.Component { if (this._searching) { let container = this._mainCont.current; - let viewer = this._viewer.current; if (!this._pdfFindController) { - if (container && viewer) { + if (container && this._viewer.current) { let simpleLinkService = new SimpleLinkService(); this._pdfViewer = new PDFJSViewer.PDFViewer({ container: container, - viewer: viewer, + viewer: this._viewer.current, linkService: simpleLinkService }); simpleLinkService.setPdf(this.props.pdf); @@ -483,25 +482,23 @@ export class PDFViewer extends React.Component { render() { return (
-
+
{this._visibleElements}
-
-
- {this._annotations.filter(anno => { - if (this._script && this._script.compiled) { - let run = this._script.run({ this: anno }); - if (run.success) { - return run.result; - } +
+ {this._annotations.filter(anno => { + if (this._script && this._script.compiled) { + let run = this._script.run({ this: anno }); + if (run.success) { + return run.result; } - return true; - }).sort((a: Doc, b: Doc) => NumCast(a.y) - NumCast(b.y)) - .map((anno: Doc, index: number) => - - )} -
+ } + return true; + }).sort((a: Doc, b: Doc) => NumCast(a.y) - NumCast(b.y)) + .map((anno: Doc, index: number) => + + )}
e.stopPropagation()} style={{ @@ -509,9 +506,7 @@ export class PDFViewer extends React.Component { left: `${this._searching ? 0 : 100}%` }}> - {/* - */} - e.keyCode === KeyCodes.ENTER ? this.search(this._searchString) : e.keyCode === KeyCodes.BACKSPACE ? e.stopPropagation() : true} placeholder="Search" className="pdfViewer-overlaySearchBar" onChange={this.searchStringChanged} /> + e.keyCode === KeyCodes.ENTER ? this.search(this._searchString) : e.keyCode === KeyCodes.BACKSPACE ? e.stopPropagation() : true} placeholder="Search" onChange={this.searchStringChanged} />
)}
  • +