aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/pdf/PDFViewer.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/pdf/PDFViewer.tsx')
-rw-r--r--src/client/views/pdf/PDFViewer.tsx455
1 files changed, 249 insertions, 206 deletions
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 510c5c385..837734edf 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -1,36 +1,35 @@
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from "mobx";
-import { observer } from "mobx-react";
-import * as Pdfjs from "pdfjs-dist";
-import "pdfjs-dist/web/pdf_viewer.css";
-import { Doc, DocListCast, Field, HeightSym, Opt } from "../../../fields/Doc";
-import { Id } from "../../../fields/FieldSymbols";
-import { InkTool } from "../../../fields/InkField";
-import { Cast, NumCast, StrCast } from "../../../fields/Types";
-import { TraceMobx } from "../../../fields/util";
-import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, returnFalse, smoothScroll, Utils } from "../../../Utils";
-import { DocUtils } from "../../documents/Documents";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { SelectionManager } from "../../util/SelectionManager";
-import { SharingManager } from "../../util/SharingManager";
-import { SnappingManager } from "../../util/SnappingManager";
-import { MarqueeOptionsMenu } from "../collections/collectionFreeForm";
-import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView";
-import { MarqueeAnnotator } from "../MarqueeAnnotator";
-import { DocumentViewProps } from "../nodes/DocumentView";
-import { FieldViewProps } from "../nodes/FieldView";
-import { LinkDocPreview } from "../nodes/LinkDocPreview";
-import { StyleProp } from "../StyleProvider";
-import { AnchorMenu } from "./AnchorMenu";
-import { Annotation } from "./Annotation";
-import "./PDFViewer.scss";
-import React = require("react");
-const PDFJSViewer = require("pdfjs-dist/web/pdf_viewer");
-const pdfjsLib = require("pdfjs-dist");
-const _global = (window /* browser */ || global /* node */) as any;
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from 'mobx';
+import { observer } from 'mobx-react';
+import * as Pdfjs from 'pdfjs-dist';
+import 'pdfjs-dist/web/pdf_viewer.css';
+import { Doc, DocListCast, Field, HeightSym, Opt } from '../../../fields/Doc';
+import { Id } from '../../../fields/FieldSymbols';
+import { InkTool } from '../../../fields/InkField';
+import { Cast, NumCast, StrCast } from '../../../fields/Types';
+import { TraceMobx } from '../../../fields/util';
+import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, OmitKeys, smoothScroll, Utils } from '../../../Utils';
+import { DocUtils } from '../../documents/Documents';
+import { SelectionManager } from '../../util/SelectionManager';
+import { SharingManager } from '../../util/SharingManager';
+import { SnappingManager } from '../../util/SnappingManager';
+import { MarqueeOptionsMenu } from '../collections/collectionFreeForm';
+import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView';
+import { MarqueeAnnotator } from '../MarqueeAnnotator';
+import { DocumentViewProps } from '../nodes/DocumentView';
+import { FieldViewProps } from '../nodes/FieldView';
+import { LinkDocPreview } from '../nodes/LinkDocPreview';
+import { StyleProp } from '../StyleProvider';
+import { AnchorMenu } from './AnchorMenu';
+import { Annotation } from './Annotation';
+import './PDFViewer.scss';
+import React = require('react');
+const PDFJSViewer = require('pdfjs-dist/web/pdf_viewer');
+const pdfjsLib = require('pdfjs-dist');
+const _global = (window /* browser */ || global) /* node */ as any;
//pdfjsLib.GlobalWorkerOptions.workerSrc = `/assets/pdf.worker.js`;
// The workerSrc property shall be specified.
-pdfjsLib.GlobalWorkerOptions.workerSrc = "https://unpkg.com/pdfjs-dist@2.14.305/build/pdf.worker.js";
+pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://unpkg.com/pdfjs-dist@2.14.305/build/pdf.worker.js';
interface IViewerProps extends FieldViewProps {
Document: Doc;
@@ -53,7 +52,7 @@ interface IViewerProps extends FieldViewProps {
@observer
export class PDFViewer extends React.Component<IViewerProps> {
static _annotationStyle: any = addStyleSheet();
- @observable private _pageSizes: { width: number, height: number }[] = [];
+ @observable private _pageSizes: { width: number; height: number }[] = [];
@observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
@observable private _marqueeing: number[] | undefined;
@observable private _textSelecting = true;
@@ -70,7 +69,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
private _viewer: React.RefObject<HTMLDivElement> = React.createRef();
public _getAnchor: (savedAnnotations?: ObservableMap<number, HTMLDivElement[]>) => Opt<Doc> = () => undefined;
_mainCont: React.RefObject<HTMLDivElement> = React.createRef();
- private _selectionText: string = "";
+ private _selectionText: string = '';
private _downX: number = 0;
private _downY: number = 0;
private _lastSearch = false;
@@ -82,69 +81,80 @@ export class PDFViewer extends React.Component<IViewerProps> {
@observable isAnnotating = false;
// key where data is stored
@computed get allAnnotations() {
- return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + "-annotations"]), this.props.docFilters(), this.props.docRangeFilters(), undefined);
+ return DocUtils.FilterDocs(DocListCast(this.props.dataDoc[this.props.fieldKey + '-annotations']), this.props.docFilters(), this.props.docRangeFilters(), undefined);
+ }
+ @computed get inlineTextAnnotations() {
+ return this.allAnnotations.filter(a => a.textInlineAnnotations);
}
- @computed get inlineTextAnnotations() { return this.allAnnotations.filter(a => a.textInlineAnnotations); }
componentDidMount = async () => {
- runInAction(() => this._showWaiting = true);
+ runInAction(() => (this._showWaiting = true));
this.setupPdfJsViewer();
- this._mainCont.current?.addEventListener("scroll", e => (e.target as any).scrollLeft = 0);
+ this._mainCont.current?.addEventListener('scroll', e => ((e.target as any).scrollLeft = 0));
- this._disposers.autoHeight = reaction(() => this.props.layoutDoc._autoHeight,
+ this._disposers.autoHeight = reaction(
+ () => this.props.layoutDoc._autoHeight,
autoHeight => {
if (autoHeight) {
- this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]);
- this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + "-nativeHeight"]) * (this.props.scaling?.() || 1));
+ this.props.layoutDoc._nativeHeight = NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']);
+ this.props.setHeight?.(NumCast(this.props.Document[this.props.fieldKey + '-nativeHeight']) * (this.props.scaling?.() || 1));
}
- });
+ }
+ );
- this._disposers.selected = reaction(() => this.props.isSelected(),
+ this._disposers.selected = reaction(
+ () => this.props.isSelected(),
selected => {
// if (!selected) {
// Array.from(this._savedAnnotations.values()).forEach(v => v.forEach(a => a.remove()));
// Array.from(this._savedAnnotations.keys()).forEach(k => this._savedAnnotations.set(k, []));
// }
- (SelectionManager.Views().length === 1) && this.setupPdfJsViewer();
+ SelectionManager.Views().length === 1 && this.setupPdfJsViewer();
},
- { fireImmediately: true });
- this._disposers.curPage = reaction(() => Cast(this.props.Document._curPage, "number", null),
- (page) => page !== undefined && page !== this._pdfViewer?.currentPageNumber && this.gotoPage(page),
{ fireImmediately: true }
);
- }
+ this._disposers.curPage = reaction(
+ () => Cast(this.props.Document._curPage, 'number', null),
+ page => page !== undefined && page !== this._pdfViewer?.currentPageNumber && this.gotoPage(page),
+ { fireImmediately: true }
+ );
+ };
componentWillUnmount = () => {
Object.values(this._disposers).forEach(disposer => disposer?.());
- document.removeEventListener("copy", this.copy);
- }
+ document.removeEventListener('copy', this.copy);
+ };
copy = (e: ClipboardEvent) => {
if (this.props.isContentActive() && e.clipboardData) {
- e.clipboardData.setData("text/plain", this._selectionText);
+ e.clipboardData.setData('text/plain', this._selectionText);
e.preventDefault();
}
- }
+ };
@action
initialLoad = async () => {
if (this._pageSizes.length === 0) {
- this._pageSizes = Array<{ width: number, height: number }>(this.props.pdf.numPages);
- await Promise.all(this._pageSizes.map((val, i) =>
- this.props.pdf.getPage(i + 1).then(action((page: Pdfjs.PDFPageProxy) => {
- const page0or180 = page.rotate === 0 || page.rotate === 180;
- this._pageSizes.splice(i, 1, {
- width: (page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1]),
- height: (page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0])
- });
- if (i === this.props.pdf.numPages - 1) {
- this.props.loaded?.(page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1],
- page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0], this.props.pdf.numPages);
- }
- }))));
- this.props.Document.scrollHeight = this._pageSizes.reduce((size, page) => size + page.height, 0) * 96 / 72;
+ this._pageSizes = Array<{ width: number; height: number }>(this.props.pdf.numPages);
+ await Promise.all(
+ this._pageSizes.map((val, i) =>
+ this.props.pdf.getPage(i + 1).then(
+ action((page: Pdfjs.PDFPageProxy) => {
+ const page0or180 = page.rotate === 0 || page.rotate === 180;
+ this._pageSizes.splice(i, 1, {
+ width: page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1],
+ height: page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0],
+ });
+ if (i === this.props.pdf.numPages - 1) {
+ this.props.loaded?.(page.view[page0or180 ? 2 : 3] - page.view[page0or180 ? 0 : 1], page.view[page0or180 ? 3 : 2] - page.view[page0or180 ? 1 : 0], this.props.pdf.numPages);
+ }
+ })
+ )
+ )
+ );
+ this.props.Document.scrollHeight = (this._pageSizes.reduce((size, page) => size + page.height, 0) * 96) / 72;
}
- }
+ };
// scrolls to focus on a nested annotation document. if this is part a link preview then it will jump to the scroll location,
// otherwise it will scroll smoothly.
@@ -153,7 +163,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
let focusSpeed: Opt<number>;
if (doc !== this.props.rootDoc && mainCont) {
const windowHeight = this.props.PanelHeight() / (this.props.scaling?.() || 1);
- const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, .1 * windowHeight, NumCast(this.props.Document.scrollHeight));
+ const scrollTo = doc.unrendered ? NumCast(doc.y) : Utils.scrollIntoView(NumCast(doc.y), doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, NumCast(this.props.Document.scrollHeight));
if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) {
focusSpeed = 500;
@@ -165,10 +175,10 @@ export class PDFViewer extends React.Component<IViewerProps> {
this._initialScroll = NumCast(this.props.layoutDoc._scrollTop);
}
return focusSpeed;
- }
+ };
crop = (region: Doc | undefined, addCrop?: boolean) => {
return this.props.crop(region, addCrop);
- }
+ };
@action
setupPdfJsViewer = async () => {
@@ -179,18 +189,18 @@ export class PDFViewer extends React.Component<IViewerProps> {
await this.initialLoad();
this.createPdfViewer();
- }
+ };
pagesinit = () => {
if (this._pdfViewer._setDocumentViewerElement?.offsetParent) {
- runInAction(() => this._pdfViewer.currentScaleValue = this.props.layoutDoc._viewScale = 1);
+ runInAction(() => (this._pdfViewer.currentScaleValue = this.props.layoutDoc._viewScale = 1));
this.gotoPage(NumCast(this.props.Document._curPage, 1));
}
- document.removeEventListener("pagesinit", this.pagesinit);
- var quickScroll: string | undefined = this._initialScroll ? this._initialScroll.toString() : "";
+ document.removeEventListener('pagesinit', this.pagesinit);
+ var quickScroll: string | undefined = this._initialScroll ? this._initialScroll.toString() : '';
this._disposers.scroll = reaction(
() => Math.abs(NumCast(this.props.Document._scrollTop)),
- (pos) => {
+ pos => {
if (!this._ignoreScroll) {
this._showWaiting && this.setupPdfJsViewer();
const viewTrans = quickScroll ?? StrCast(this.props.Document._viewTransition);
@@ -199,10 +209,13 @@ export class PDFViewer extends React.Component<IViewerProps> {
const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
this._forcedScroll = true;
if (duration) {
- setTimeout(() => {
- this._mainCont.current && smoothScroll(duration, this._mainCont.current, pos);
- setTimeout(() => this._forcedScroll = false, duration);
- }, this._mainCont.current ? 0 : 250); // wait for mainCont and try again to scroll
+ setTimeout(
+ () => {
+ this._mainCont.current && smoothScroll(duration, this._mainCont.current, pos);
+ setTimeout(() => (this._forcedScroll = false), duration);
+ },
+ this._mainCont.current ? 0 : 250
+ ); // wait for mainCont and try again to scroll
} else {
this._mainCont.current?.scrollTo({ top: pos });
this._forcedScroll = false;
@@ -216,23 +229,27 @@ export class PDFViewer extends React.Component<IViewerProps> {
this._mainCont.current?.scrollTo({ top: Math.abs(this._initialScroll || 0) });
this._initialScroll = undefined;
}
- }
+ };
createPdfViewer() {
- if (!this._mainCont.current) { // bcz: I don't think this is ever triggered or needed
- console.log("PDFViewer- I guess we got here");
+ if (!this._mainCont.current) {
+ // bcz: I don't think this is ever triggered or needed
+ console.log('PDFViewer- I guess we got here');
if (this._retries < 5) {
this._retries++;
- console.log("PDFViewer- retry num:" + this._retries);
+ console.log('PDFViewer- retry num:' + this._retries);
setTimeout(() => this.createPdfViewer(), 1000);
}
return;
}
- document.removeEventListener("copy", this.copy);
- document.addEventListener("copy", this.copy);
+ document.removeEventListener('copy', this.copy);
+ document.addEventListener('copy', this.copy);
const eventBus = new PDFJSViewer.EventBus(true);
- eventBus._on("pagesinit", this.pagesinit);
- eventBus._on("pagerendered", action(() => this._showWaiting = false));
+ eventBus._on('pagesinit', this.pagesinit);
+ eventBus._on(
+ 'pagerendered',
+ action(() => (this._showWaiting = false))
+ );
const pdfLinkService = new PDFJSViewer.PDFLinkService({ eventBus });
const pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService, eventBus });
this._pdfViewer = new PDFJSViewer.PDFViewer({
@@ -240,31 +257,30 @@ export class PDFViewer extends React.Component<IViewerProps> {
viewer: this._viewer.current,
linkService: pdfLinkService,
findController: pdfFindController,
- renderer: "canvas",
- eventBus
+ renderer: 'canvas',
+ eventBus,
});
pdfLinkService.setViewer(this._pdfViewer);
pdfLinkService.setDocument(this.props.pdf, null);
this._pdfViewer.setDocument(this.props.pdf);
}
-
@action
prevAnnotation = () => {
this.Index = Math.max(this.Index - 1, 0);
this.scrollToAnnotation(this.allAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y))[this.Index]);
- }
+ };
@action
nextAnnotation = () => {
this.Index = Math.min(this.Index + 1, this.allAnnotations.length - 1);
this.scrollToAnnotation(this.allAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y))[this.Index]);
- }
+ };
@action
gotoPage = (p: number) => {
this._pdfViewer?.scrollPageIntoView({ pageNumber: Math.min(Math.max(1, p), this._pageSizes.length) });
- }
+ };
@action
scrollToAnnotation = (scrollToAnnotation: Doc) => {
@@ -272,7 +288,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
this.scrollFocus(scrollToAnnotation, true);
Doc.linkFollowHighlight(scrollToAnnotation);
}
- }
+ };
@observable private _scrollTimer: any;
@@ -289,7 +305,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
this._scrollTimer = undefined;
}, 200);
}
- }
+ };
// get the page index that the vertical offset passed in is on
getPageFromScroll = (vOffset: number) => {
@@ -299,7 +315,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
currOffset -= this._pageSizes[index++].height;
}
return index;
- }
+ };
@action
search = (searchString: string, bwd?: boolean, clear: boolean = false) => {
@@ -308,22 +324,21 @@ export class PDFViewer extends React.Component<IViewerProps> {
findPrevious: bwd,
highlightAll: true,
phraseSearch: true,
- query: searchString
+ query: searchString,
};
if (clear) {
- this._pdfViewer?.findController.executeCommand('reset', { query: "" });
+ this._pdfViewer?.findController.executeCommand('reset', { query: '' });
} else if (!searchString) {
bwd ? this.prevAnnotation() : this.nextAnnotation();
} else if (this._pdfViewer?.pageViewsReady) {
this._pdfViewer.findController.executeCommand('findagain', findOpts);
- }
- else if (this._mainCont.current) {
+ } else if (this._mainCont.current) {
const executeFind = () => this._pdfViewer.findController.executeCommand('find', findOpts);
- this._mainCont.current.addEventListener("pagesloaded", executeFind);
- this._mainCont.current.addEventListener("pagerendered", executeFind);
+ this._mainCont.current.addEventListener('pagesloaded', executeFind);
+ this._mainCont.current.addEventListener('pagerendered', executeFind);
}
return true;
- }
+ };
@action
onPointerDown = (e: React.PointerEvent): void => {
@@ -340,24 +355,27 @@ export class PDFViewer extends React.Component<IViewerProps> {
if ((e.button !== 0 || e.altKey) && this.props.isContentActive(true)) {
this._setPreviewCursor?.(e.clientX, e.clientY, true, false);
}
- if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.ActiveTool)) {
+ if (!e.altKey && e.button === 0 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
this.props.select(false);
MarqueeAnnotator.clearAnnotations(this._savedAnnotations);
this._marqueeing = [e.clientX, e.clientY];
this.isAnnotating = true;
- if (e.target && ((e.target as any).className.includes("endOfContent") || ((e.target as any).parentElement.className !== "textLayer"))) {
+ if (e.target && ((e.target as any).className.includes('endOfContent') || (e.target as any).parentElement.className !== 'textLayer')) {
this._textSelecting = false;
- document.addEventListener("pointermove", this.onSelectMove); // need this to prevent document from being dragged if stopPropagation doesn't get called
+ document.addEventListener('pointermove', this.onSelectMove); // need this to prevent document from being dragged if stopPropagation doesn't get called
} else {
// if textLayer is hit, then we select text instead of using a marquee so clear out the marquee.
- setTimeout(action(() => this._marqueeing = undefined), 100); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it.
-
- this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, "htmlAnnotation", { "pointer-events": "none" });
- document.addEventListener("pointerup", this.onSelectEnd);
- document.addEventListener("pointermove", this.onSelectMove);
+ setTimeout(
+ action(() => (this._marqueeing = undefined)),
+ 100
+ ); // bcz: hack .. anchor menu is setup within MarqueeAnnotator so we need to at least create the marqueeAnnotator even though we aren't using it.
+
+ this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, 'htmlAnnotation', { 'pointer-events': 'none' });
+ document.addEventListener('pointerup', this.onSelectEnd);
+ document.addEventListener('pointermove', this.onSelectMove);
}
}
- }
+ };
@action
finishMarquee = (x?: number, y?: number) => {
@@ -365,8 +383,8 @@ export class PDFViewer extends React.Component<IViewerProps> {
this.isAnnotating = false;
this._marqueeing = undefined;
this._textSelecting = true;
- document.removeEventListener("pointermove", this.onSelectMove);
- }
+ document.removeEventListener('pointermove', this.onSelectMove);
+ };
onSelectMove = (e: PointerEvent) => e.stopPropagation();
@@ -375,15 +393,15 @@ export class PDFViewer extends React.Component<IViewerProps> {
this.isAnnotating = false;
clearStyleSheetRules(PDFViewer._annotationStyle);
this.props.select(false);
- document.removeEventListener("pointermove", this.onSelectMove);
- document.removeEventListener("pointerup", this.onSelectEnd);
+ document.removeEventListener('pointermove', this.onSelectMove);
+ document.removeEventListener('pointerup', this.onSelectEnd);
const sel = window.getSelection();
- if (sel?.type === "Range") {
+ if (sel?.type === 'Range') {
this.createTextAnnotation(sel, sel.getRangeAt(0));
AnchorMenu.Instance.jumpTo(e.clientX, e.clientY);
}
- }
+ };
@action
createTextAnnotation = (sel: Selection, selRange: Range) => {
@@ -395,41 +413,41 @@ export class PDFViewer extends React.Component<IViewerProps> {
if (rect && rect.width !== this._mainCont.current.clientWidth && rect.width) {
const scaleX = this._mainCont.current.offsetWidth / boundingRect.width;
const pdfScale = NumCast(this.props.layoutDoc._viewScale, 1);
- const annoBox = document.createElement("div");
- annoBox.className = "marqueeAnnotator-annotationBox";
+ const annoBox = document.createElement('div');
+ annoBox.className = 'marqueeAnnotator-annotationBox';
// transforms the positions from screen onto the pdf div
- annoBox.style.top = ((rect.top - boundingRect.top) * scaleX / pdfScale + this._mainCont.current.scrollTop).toString();
- annoBox.style.left = ((rect.left - boundingRect.left) * scaleX / pdfScale).toString();
- annoBox.style.width = (rect.width * this._mainCont.current.offsetWidth / boundingRect.width / pdfScale).toString();
- annoBox.style.height = (rect.height * this._mainCont.current.offsetHeight / boundingRect.height / pdfScale).toString();
+ annoBox.style.top = (((rect.top - boundingRect.top) * scaleX) / pdfScale + this._mainCont.current.scrollTop).toString();
+ annoBox.style.left = (((rect.left - boundingRect.left) * scaleX) / pdfScale).toString();
+ annoBox.style.width = ((rect.width * this._mainCont.current.offsetWidth) / boundingRect.width / pdfScale).toString();
+ annoBox.style.height = ((rect.height * this._mainCont.current.offsetHeight) / boundingRect.height / pdfScale).toString();
this._annotationLayer.current && MarqueeAnnotator.previewNewAnnotation(this._savedAnnotations, this._annotationLayer.current, annoBox, this.getPageFromScroll(rect.top));
}
}
}
- this._selectionText = selRange.cloneContents().textContent || "";
+ this._selectionText = selRange.cloneContents().textContent || '';
// clear selection
- if (sel.empty) { // Chrome
+ if (sel.empty) {
+ // Chrome
sel.empty();
- } else if (sel.removeAllRanges) { // Firefox
+ } else if (sel.removeAllRanges) {
+ // Firefox
sel.removeAllRanges();
}
- }
+ };
scrollXf = () => {
return this._mainCont.current ? this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.layoutDoc._scrollTop)) : this.props.ScreenToLocalTransform();
- }
+ };
onClick = (e: React.MouseEvent) => {
- if (this._setPreviewCursor && e.button === 0 &&
- Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
- Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
+ if (this._setPreviewCursor && e.button === 0 && Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) {
this._setPreviewCursor(e.clientX, e.clientY, false, false);
}
// e.stopPropagation(); // bcz: not sure why this was here. We need to allow the DocumentView to get clicks to process doubleClicks
- }
+ };
- setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => this._setPreviewCursor = func;
+ setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean) => void) => (this._setPreviewCursor = func);
@action
onZoomWheel = (e: React.WheelEvent) => {
@@ -437,52 +455,59 @@ export class PDFViewer extends React.Component<IViewerProps> {
e.stopPropagation();
if (e.ctrlKey) {
const curScale = Number(this._pdfViewer.currentScaleValue);
- this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - curScale * e.deltaY / 1000));
+ this._pdfViewer.currentScaleValue = Math.max(1, Math.min(10, curScale - (curScale * e.deltaY) / 1000));
this.props.layoutDoc._viewScale = Number(this._pdfViewer.currentScaleValue);
}
}
- }
+ };
- pointerEvents = () => this.props.isContentActive() && this.props.pointerEvents?.() !== "none" && !MarqueeOptionsMenu.Instance.isShown() ? "all" : SnappingManager.GetIsDragging() ? undefined : "none";
+ pointerEvents = () => (this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' && !MarqueeOptionsMenu.Instance.isShown() ? 'all' : SnappingManager.GetIsDragging() ? undefined : 'none');
@computed get annotationLayer() {
- return <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.props.Document), transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})` }} ref={this._annotationLayer}>
- {this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).map(anno =>
- <Annotation {...this.props} fieldKey={this.props.fieldKey + "-annotations"} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.props.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />)}
- </div>;
+ return (
+ <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this.props.Document), transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})` }} ref={this._annotationLayer}>
+ {this.inlineTextAnnotations
+ .sort((a, b) => NumCast(a.y) - NumCast(b.y))
+ .map(anno => (
+ <Annotation {...this.props} fieldKey={this.props.fieldKey + '-annotations'} pointerEvents={this.pointerEvents} showInfo={this.showInfo} dataDoc={this.props.dataDoc} anno={anno} key={`${anno[Id]}-annotation`} />
+ ))}
+ </div>
+ );
}
@computed get overlayInfo() {
- return !this._overlayAnnoInfo ? (null) :
+ return !this._overlayAnnoInfo ? null : (
<div className="pdfViewerDash-overlayAnno" style={{ top: NumCast(this._overlayAnnoInfo.y), left: NumCast(this._overlayAnnoInfo.x) }}>
<div className="pdfViewerDash-overlayAnno" style={{ right: -50, background: SharingManager.Instance.users.find(users => users.user.email === this._overlayAnnoInfo!.author)?.userColor }}>
- {this._overlayAnnoInfo.author + " " + Field.toString(this._overlayAnnoInfo.creationDate as Field)}
+ {this._overlayAnnoInfo.author + ' ' + Field.toString(this._overlayAnnoInfo.creationDate as Field)}
</div>
- </div>;
+ </div>
+ );
}
- showInfo = action((anno: Opt<Doc>) => this._overlayAnnoInfo = anno);
+ showInfo = action((anno: Opt<Doc>) => (this._overlayAnnoInfo = anno));
overlayTransform = () => this.scrollXf().scale(1 / NumCast(this.props.layoutDoc._viewScale, 1));
panelWidth = () => this.props.PanelWidth() / (this.props.scaling?.() || 1); // (this.Document.scrollHeight || Doc.NativeHeight(this.Document) || 0);
panelHeight = () => this.props.PanelHeight() / (this.props.scaling?.() || 1); // () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : Doc.NativeWidth(this.Document);
- basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter("textInlineAnnotations")];
+ basicFilter = () => [...this.props.docFilters(), Utils.PropUnsetFilter('textInlineAnnotations')];
transparentFilter = () => [...this.props.docFilters(), Utils.IsTransparentFilter()];
opaqueFilter = () => [...this.props.docFilters(), Utils.IsOpaqueFilter()];
- childStyleProvider = (doc: (Doc | undefined), props: Opt<DocumentViewProps>, property: string): any => {
+ childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
if (doc instanceof Doc && property === StyleProp.PointerEvents) {
- if (doc.textInlineAnnotations) return "none";
- return "all";
+ if (doc.textInlineAnnotations) return 'none';
+ return 'all';
}
return this.props.styleProvider?.(doc, props, property);
- }
+ };
- renderAnnotations = (docFilters?: () => string[], dontRender?: boolean) =>
- <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
+ renderAnnotations = (docFilters?: () => string[], dontRender?: boolean) => (
+ <CollectionFreeFormView
+ {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit}
isAnnotationOverlay={true}
- fieldKey={this.props.fieldKey + "-annotations"}
+ fieldKey={this.props.fieldKey + '-annotations'}
setPreviewCursor={this.setPreviewCursor}
PanelHeight={this.panelHeight}
PanelWidth={this.panelWidth}
- dropAction={"alias"}
+ dropAction={'alias'}
select={emptyFunction}
ContentScaling={this.contentZoom}
bringToFront={emptyFunction}
@@ -493,70 +518,88 @@ export class PDFViewer extends React.Component<IViewerProps> {
ScreenToLocalTransform={this.overlayTransform}
renderDepth={this.props.renderDepth + 1}
/>
- @computed get overlayTransparentAnnotations() { return this.renderAnnotations(this.transparentFilter, false); }
- @computed get overlayOpaqueAnnotations() { return this.renderAnnotations(this.opaqueFilter, false); }
+ );
+ @computed get overlayTransparentAnnotations() {
+ return this.renderAnnotations(this.transparentFilter, false);
+ }
+ @computed get overlayOpaqueAnnotations() {
+ return this.renderAnnotations(this.opaqueFilter, false);
+ }
@computed get overlayClickableAnnotations() {
- return <div style={{ height: NumCast(this.props.rootDoc.scrollHeight) }}>
- {this.renderAnnotations(undefined, true)}
- </div>;
+ return <div style={{ height: NumCast(this.props.rootDoc.scrollHeight) }}>{this.renderAnnotations(undefined, true)}</div>;
}
@computed get overlayLayer() {
- return <div style={{ pointerEvents: SnappingManager.GetIsDragging() ? "all" : "none" }}>
- <div className="pdfViewerDash-overlay"
- style={{
- pointerEvents: SnappingManager.GetIsDragging() ? "all" : "none",
- mixBlendMode: "multiply",
- transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})`
- }}>
- {this.overlayTransparentAnnotations}
- </div>
- <div className="pdfViewerDash-overlay"
- style={{
- pointerEvents: SnappingManager.GetIsDragging() ? "all" : "none",
- mixBlendMode: this.allAnnotations.some(anno => anno.mixBlendMode) ? "hard-light" : undefined,
- transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})`
- }}>
- {this.overlayOpaqueAnnotations}
- {this.overlayClickableAnnotations}
+ return (
+ <div style={{ pointerEvents: SnappingManager.GetIsDragging() ? 'all' : 'none' }}>
+ <div
+ className="pdfViewerDash-overlay"
+ style={{
+ pointerEvents: SnappingManager.GetIsDragging() ? 'all' : 'none',
+ mixBlendMode: 'multiply',
+ transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})`,
+ }}>
+ {this.overlayTransparentAnnotations}
+ </div>
+ <div
+ className="pdfViewerDash-overlay"
+ style={{
+ pointerEvents: SnappingManager.GetIsDragging() ? 'all' : 'none',
+ mixBlendMode: this.allAnnotations.some(anno => anno.mixBlendMode) ? 'hard-light' : undefined,
+ transform: `scale(${NumCast(this.props.layoutDoc._viewScale, 1)})`,
+ }}>
+ {this.overlayOpaqueAnnotations}
+ {this.overlayClickableAnnotations}
+ </div>
</div>
- </div>;
+ );
}
@computed get pdfViewerDiv() {
- return <div className={"pdfViewerDash-text" + (this.props.pointerEvents?.() !== "none" && this._textSelecting && this.props.isContentActive() ? "-selected" : "")} ref={this._viewer} />;
+ return <div className={'pdfViewerDash-text' + (this.props.pointerEvents?.() !== 'none' && this._textSelecting && this.props.isContentActive() ? '-selected' : '')} ref={this._viewer} />;
+ }
+ @computed get contentScaling() {
+ return this.props.ContentScaling?.() || 1;
}
- @computed get contentScaling() { return this.props.ContentScaling?.() || 1; }
contentZoom = () => NumCast(this.props.layoutDoc._viewScale, 1);
savedAnnotations = () => this._savedAnnotations;
render() {
TraceMobx();
- return <div className="pdfViewer-content">
- <div className={`pdfViewerDash${this.props.isContentActive() && this.props.pointerEvents?.() !== "none" ? "-interactive" : ""}`} ref={this._mainCont}
- onScroll={this.onScroll} onWheel={this.onZoomWheel} onPointerDown={this.onPointerDown} onClick={this.onClick}
- style={{
- overflowX: NumCast(this.props.layoutDoc._viewScale, 1) !== 1 ? "scroll" : undefined,
- height: !this.props.Document._fitWidth && (window.screen.width > 600) ? Doc.NativeHeight(this.props.Document) : `${100 / this.contentScaling}%`,
- transform: `scale(${this.contentScaling})`
- }} >
- {this.pdfViewerDiv}
- {this.annotationLayer}
- {this.overlayLayer}
- {this.overlayInfo}
- {this._showWaiting ? <img className="pdfViewerDash-waiting" src={"/assets/loading.gif"} /> : (null)}
- {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? (null) :
- <MarqueeAnnotator rootDoc={this.props.rootDoc}
- getPageFromScroll={this.getPageFromScroll}
- anchorMenuClick={this.props.anchorMenuClick}
- scrollTop={0}
- down={this._marqueeing}
- addDocument={(doc: Doc | Doc[]) => this.props.addDocument!(doc)}
- docView={this.props.docViewPath().lastElement()}
- finishMarquee={this.finishMarquee}
- savedAnnotations={this.savedAnnotations}
- annotationLayer={this._annotationLayer.current}
- mainCont={this._mainCont.current}
- anchorMenuCrop={this._textSelecting ? undefined : this.crop}
- />}
+ return (
+ <div className="pdfViewer-content">
+ <div
+ className={`pdfViewerDash${this.props.isContentActive() && this.props.pointerEvents?.() !== 'none' ? '-interactive' : ''}`}
+ ref={this._mainCont}
+ onScroll={this.onScroll}
+ onWheel={this.onZoomWheel}
+ onPointerDown={this.onPointerDown}
+ onClick={this.onClick}
+ style={{
+ overflowX: NumCast(this.props.layoutDoc._viewScale, 1) !== 1 ? 'scroll' : undefined,
+ height: !this.props.Document._fitWidth && window.screen.width > 600 ? Doc.NativeHeight(this.props.Document) : `${100 / this.contentScaling}%`,
+ transform: `scale(${this.contentScaling})`,
+ }}>
+ {this.pdfViewerDiv}
+ {this.annotationLayer}
+ {this.overlayLayer}
+ {this.overlayInfo}
+ {this._showWaiting ? <img className="pdfViewerDash-waiting" src={'/assets/loading.gif'} /> : null}
+ {!this._marqueeing || !this._mainCont.current || !this._annotationLayer.current ? null : (
+ <MarqueeAnnotator
+ rootDoc={this.props.rootDoc}
+ getPageFromScroll={this.getPageFromScroll}
+ anchorMenuClick={this.props.anchorMenuClick}
+ scrollTop={0}
+ down={this._marqueeing}
+ addDocument={(doc: Doc | Doc[]) => this.props.addDocument!(doc)}
+ docView={this.props.docViewPath().lastElement()}
+ finishMarquee={this.finishMarquee}
+ savedAnnotations={this.savedAnnotations}
+ annotationLayer={this._annotationLayer.current}
+ mainCont={this._mainCont.current}
+ anchorMenuCrop={this._textSelecting ? undefined : this.crop}
+ />
+ )}
+ </div>
</div>
- </div>;
+ );
}
-} \ No newline at end of file
+}