diff options
Diffstat (limited to 'src/client/views/pdf')
| -rw-r--r-- | src/client/views/pdf/AnchorMenu.tsx | 3 | ||||
| -rw-r--r-- | src/client/views/pdf/Annotation.tsx | 8 | ||||
| -rw-r--r-- | src/client/views/pdf/PDFViewer.scss | 12 | ||||
| -rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 54 |
4 files changed, 49 insertions, 28 deletions
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index ee2ae10a7..265328036 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -210,14 +210,13 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> { </button> </Tooltip> ), - //NOTE: link popup is currently in progress <Tooltip key="link" title={<div className="dash-tooltip">{'Find document to link to selected text'}</div>}> <button className="antimodeMenu-button link" onPointerDown={this.toggleLinkPopup} style={{}}> <FontAwesomeIcon style={{ position: 'absolute', transform: 'scale(1.5)' }} icon={'search'} size="lg" /> <FontAwesomeIcon style={{ position: 'absolute', transform: 'scale(0.5)', transformOrigin: 'top left', top: 12, left: 12 }} icon={'link'} size="lg" /> </button> </Tooltip>, - <LinkPopup key="popup" showPopup={this._showLinkPopup} linkFrom={this.onMakeAnchor} />, + <LinkPopup key="popup" showPopup={this._showLinkPopup} linkCreateAnchor={this.onMakeAnchor} />, AnchorMenu.Instance.StartCropDrag === unimplementedFunction ? ( <></> ) : ( diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index ee418a02f..7069ff399 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -22,7 +22,7 @@ interface IAnnotationProps extends FieldViewProps { export class Annotation extends React.Component<IAnnotationProps> { render() { return ( - <div> + <div style={{ display: this.props.anno.textCopied && !Doc.isBrushedHighlightedDegree(this.props.anno) ? 'none' : undefined }}> {DocListCast(this.props.anno.textInlineAnnotations).map(a => ( <RegionAnnotation pointerEvents={this.props.pointerEvents} {...this.props} document={a} key={a[Id]} /> ))} @@ -52,12 +52,12 @@ class RegionAnnotation extends React.Component<IRegionAnnotationProps> { }; @undoBatch - pinToPres = () => this.props.pinToPres(this.annoTextRegion); + pinToPres = () => this.props.pinToPres(this.annoTextRegion, {}); @undoBatch - makePushpin = () => (this.annoTextRegion.isPushpin = !this.annoTextRegion.isPushpin); + makePushpin = () => (this.annoTextRegion.followLinkToggle = !this.annoTextRegion.followLinkToggle); - isPushpin = () => BoolCast(this.annoTextRegion.isPushpin); + isPushpin = () => BoolCast(this.annoTextRegion.followLinkToggle); @action onPointerDown = (e: React.PointerEvent) => { diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss index 822af6a68..470aa3eb1 100644 --- a/src/client/views/pdf/PDFViewer.scss +++ b/src/client/views/pdf/PDFViewer.scss @@ -27,14 +27,14 @@ opacity: unset; mix-blend-mode: multiply; // bcz: makes text fuzzy! - span { - padding-right: 5px; - padding-bottom: 4px; - } + // span { + // padding-right: 5px; + // padding-bottom: 4px; + // } } .textLayer ::selection { - background: #ACCEF7; + background: #accef7; } // should match the backgroundColor in createAnnotation() @@ -111,4 +111,4 @@ .pdfViewerDash-interactive { pointer-events: all; -}
\ No newline at end of file +} diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 5c10c7cef..f95d5ac2e 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -16,7 +16,7 @@ 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 { DocFocusOptions, DocumentViewProps } from '../nodes/DocumentView'; import { FieldViewProps } from '../nodes/FieldView'; import { LinkDocPreview } from '../nodes/LinkDocPreview'; import { StyleProp } from '../StyleProvider'; @@ -68,16 +68,22 @@ export class PDFViewer extends React.Component<IViewerProps> { private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; 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 _selectionContent: DocumentFragment | undefined; private _downX: number = 0; private _downY: number = 0; private _lastSearch = false; private _viewerIsSetup = false; private _ignoreScroll = false; - private _initialScroll: Opt<number>; + private _initialScroll: { loc: Opt<number>; easeFunc: 'linear' | 'ease' | undefined } | undefined; private _forcedScroll = true; + get _getAnchor() { + return AnchorMenu.Instance?.GetAnchor; + } + + selectionText = () => this._selectionText; + selectionContent = () => this._selectionContent; @observable isAnnotating = false; // key where data is stored @@ -129,6 +135,11 @@ export class PDFViewer extends React.Component<IViewerProps> { copy = (e: ClipboardEvent) => { if (this.props.isContentActive() && e.clipboardData) { e.clipboardData.setData('text/plain', this._selectionText); + const anchor = this._getAnchor(); + if (anchor) { + anchor.textCopied = true; + e.clipboardData.setData('dash/pdfAnchor', anchor[Id]); + } e.preventDefault(); } }; @@ -157,21 +168,23 @@ export class PDFViewer extends React.Component<IViewerProps> { } }; + _scrollStopper: undefined | (() => void); + // 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. - scrollFocus = (doc: Doc, smooth: boolean) => { + scrollFocus = (doc: Doc, scrollTop: number, options: DocFocusOptions) => { const mainCont = this._mainCont.current; let focusSpeed: Opt<number>; if (doc !== this.props.rootDoc && mainCont) { const windowHeight = this.props.PanelHeight() / (this.props.NativeDimScaling?.() || 1); - 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)); + const scrollTo = doc.unrendered ? scrollTop : Utils.scrollIntoView(scrollTop, doc[HeightSym](), NumCast(this.props.layoutDoc._scrollTop), windowHeight, 0.1 * windowHeight, NumCast(this.props.Document.scrollHeight)); if (scrollTo !== undefined && scrollTo !== this.props.layoutDoc._scrollTop) { - if (!this._pdfViewer) this._initialScroll = scrollTo; - else if (smooth) smoothScroll((focusSpeed = NumCast(doc.focusSpeed, 500)), mainCont, scrollTo); + if (!this._pdfViewer) this._initialScroll = { loc: scrollTo, easeFunc: options.easeFunc }; + else if (!options.instant) this._scrollStopper = smoothScroll((focusSpeed = options.zoomTime ?? 500), mainCont, scrollTo, options.easeFunc, this._scrollStopper); else this._mainCont.current?.scrollTo({ top: Math.abs(scrollTo || 0) }); } } else { - this._initialScroll = NumCast(this.props.layoutDoc._scrollTop); + this._initialScroll = { loc: NumCast(this.props.layoutDoc._scrollTop), easeFunc: options.easeFunc }; } return focusSpeed; }; @@ -195,13 +208,18 @@ export class PDFViewer extends React.Component<IViewerProps> { this.gotoPage(NumCast(this.props.Document._curPage, 1)); } document.removeEventListener('pagesinit', this.pagesinit); - var quickScroll: string | undefined = this._initialScroll ? this._initialScroll.toString() : ''; + var quickScroll: { loc?: string; easeFunc?: 'ease' | 'linear' } | undefined = { loc: this._initialScroll ? this._initialScroll.loc?.toString() : '', easeFunc: this._initialScroll ? this._initialScroll.easeFunc : undefined }; + this._disposers.scale = reaction( + () => NumCast(this.props.layoutDoc._viewScale, 1), + scale => (this._pdfViewer.currentScaleValue = scale), + { fireImmediately: true } + ); this._disposers.scroll = reaction( () => Math.abs(NumCast(this.props.Document._scrollTop)), pos => { if (!this._ignoreScroll) { this._showWaiting && this.setupPdfJsViewer(); - const viewTrans = quickScroll ?? StrCast(this.props.Document._viewTransition); + const viewTrans = quickScroll?.loc ?? StrCast(this.props.Document._viewTransition); const durationMiliStr = viewTrans.match(/([0-9]*)ms/); const durationSecStr = viewTrans.match(/([0-9.]*)s/); const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0; @@ -209,7 +227,7 @@ export class PDFViewer extends React.Component<IViewerProps> { if (duration) { setTimeout( () => { - this._mainCont.current && smoothScroll(duration, this._mainCont.current, pos); + this._mainCont.current && (this._scrollStopper = smoothScroll(duration, this._mainCont.current, pos, this._initialScroll?.easeFunc ?? 'ease', this._scrollStopper)); setTimeout(() => (this._forcedScroll = false), duration); }, this._mainCont.current ? 0 : 250 @@ -224,7 +242,7 @@ export class PDFViewer extends React.Component<IViewerProps> { ); quickScroll = undefined; if (this._initialScroll !== undefined && this._mainCont.current) { - this._mainCont.current?.scrollTo({ top: Math.abs(this._initialScroll || 0) }); + this._mainCont.current?.scrollTo({ top: Math.abs(this._initialScroll?.loc || 0) }); this._initialScroll = undefined; } }; @@ -283,7 +301,7 @@ export class PDFViewer extends React.Component<IViewerProps> { @action scrollToAnnotation = (scrollToAnnotation: Doc) => { if (scrollToAnnotation) { - this.scrollFocus(scrollToAnnotation, true); + this.scrollFocus(scrollToAnnotation, NumCast(scrollToAnnotation.y), { zoomTime: 500 }); Doc.linkFollowHighlight(scrollToAnnotation); } }; @@ -358,7 +376,8 @@ export class PDFViewer extends React.Component<IViewerProps> { 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')) { + const target = e.target as any; + if (e.target && (target.className.includes('endOfContent') || (target.parentElement.className !== 'textLayer' && target.parentElement.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 } else { @@ -377,7 +396,6 @@ export class PDFViewer extends React.Component<IViewerProps> { @action finishMarquee = (x?: number, y?: number) => { - this._getAnchor = AnchorMenu.Instance?.GetAnchor; this.isAnnotating = false; this._marqueeing = undefined; this._textSelecting = true; @@ -422,7 +440,8 @@ export class PDFViewer extends React.Component<IViewerProps> { } } } - this._selectionText = selRange.cloneContents().textContent || ''; + this._selectionContent = selRange.cloneContents(); + this._selectionText = this._selectionContent?.textContent || ''; // clear selection if (sel.empty) { @@ -439,6 +458,7 @@ export class PDFViewer extends React.Component<IViewerProps> { }; onClick = (e: React.MouseEvent) => { + this._scrollStopper?.(); 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); } @@ -466,6 +486,7 @@ export class PDFViewer extends React.Component<IViewerProps> { <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)) + .filter(anno => !anno.hidden) .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`} /> ))} @@ -574,6 +595,7 @@ export class PDFViewer extends React.Component<IViewerProps> { docView={this.props.docViewPath().lastElement()} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} + selectionText={this.selectionText} annotationLayer={this._annotationLayer.current} mainCont={this._mainCont.current} anchorMenuCrop={this._textSelecting ? undefined : this.crop} |
