diff options
Diffstat (limited to 'src/client/views/pdf')
| -rw-r--r-- | src/client/views/pdf/Annotation.tsx | 7 | ||||
| -rw-r--r-- | src/client/views/pdf/GPTPopup/GPTPopup.scss | 11 | ||||
| -rw-r--r-- | src/client/views/pdf/GPTPopup/GPTPopup.tsx | 183 | ||||
| -rw-r--r-- | src/client/views/pdf/PDFViewer.scss | 4 | ||||
| -rw-r--r-- | src/client/views/pdf/PDFViewer.tsx | 59 |
5 files changed, 146 insertions, 118 deletions
diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 1891cfd4c..e8a5235c9 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -50,7 +50,7 @@ interface IAnnotationProps extends FieldViewProps { } @observer export class Annotation extends ObservableReactComponent<IAnnotationProps> { - constructor(props: any) { + constructor(props: IAnnotationProps) { super(props); makeObservable(this); } @@ -58,7 +58,7 @@ export class Annotation extends ObservableReactComponent<IAnnotationProps> { @computed get linkHighlighted() { const found = LinkManager.Instance.getAllDirectLinks(this._props.annoDoc).find(link => { const a1 = Doc.getOppositeAnchor(link, this._props.annoDoc); - return a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, a1)); + return a1 && Doc.GetBrushStatus(DocCast(a1.annotationOn, a1)!); }); return found; } @@ -112,6 +112,7 @@ export class Annotation extends ObservableReactComponent<IAnnotationProps> { outline = () => (this.linkHighlighted ? 'solid 1px lightBlue' : undefined); background = () => (this._props.annoDoc[Highlight] ? 'orange' : StrCast(this._props.annoDoc.backgroundColor)); render() { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const forceRenderHack = [this.background(), this.outline(), this.opacity()]; // forces a re-render when these change -- because RegionAnnotation doesn't do this internally.. return ( <div style={{ display: this._props.annoDoc.textCopied && !Doc.GetBrushHighlightStatus(this._props.annoDoc) ? 'none' : undefined }}> @@ -121,7 +122,7 @@ export class Annotation extends ObservableReactComponent<IAnnotationProps> { .map(([x, y, width, height]) => ( <div key={'' + x + y + width + height} - style={{ pointerEvents: this._props.pointerEvents?.() as any }} + style={{ pointerEvents: this._props.pointerEvents?.() as Property.PointerEvents }} onPointerDown={this.onPointerDown} onContextMenu={this.onContextMenu} onPointerEnter={() => { diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.scss b/src/client/views/pdf/GPTPopup/GPTPopup.scss index 18441f76e..f6fa45221 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.scss +++ b/src/client/views/pdf/GPTPopup/GPTPopup.scss @@ -7,8 +7,15 @@ $highlightedText: #82e0ff; $inputHeight: 60px; $headingHeight: 32px; +.gptPopup-sortBox { + display: block; + max-height: calc(100% - 45px); // leave room for input +} + .gptPopup-summary-box { position: fixed; + padding-left: 10px; + padding-right: 10px; top: 115px; left: 75px; width: 100%; @@ -48,7 +55,6 @@ $headingHeight: 32px; } label { - color: $textgrey; font-size: 12px; font-weight: 400; letter-spacing: 1px; @@ -73,7 +79,6 @@ $headingHeight: 32px; justify-content: center; align-items: center; height: $inputHeight; - background-color: white; width: 100%; pointer-events: all; @@ -87,6 +92,7 @@ $headingHeight: 32px; } .btns-wrapper-gpt { height: 100%; + width: 100%; display: flex; justify-content: center; align-items: center; @@ -97,7 +103,6 @@ $headingHeight: 32px; flex-direction: column; width: 100%; height: 100%; - overflow-y: auto; padding-right: 5px; } diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index 67213382d..568e48edf 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -93,7 +93,7 @@ export class GPTPopup extends ObservableReactComponent<object> { this.onGptResponse = (sortResult: string, questionType: GPTDocCommand, args?: string) => this.processGptResponse(selDoc, this._textToDocMap, sortResult, questionType, args); this.onQuizRandom = () => this.randomlyChooseDoc(selDoc.Document, hasChildDocs()); this._documentDescriptions = Promise.all(hasChildDocs().map(doc => - Doc.getDescription(doc).then(text => this._textToDocMap.set(text.trim(), doc) && `${DescriptionSeperator}${text}${DescriptionSeperator}`) + Doc.getDescription(doc).then(text => this._textToDocMap.set(text.replace(/\n/g, ' ').trim(), doc) && `${DescriptionSeperator}${text}${DescriptionSeperator}`) )).then(docDescriptions => docDescriptions.join()); // prettier-ignore } }, @@ -210,8 +210,8 @@ export class GPTPopup extends ObservableReactComponent<object> { generateFireflyImage = (imgDesc: string) => { const selView = DocumentView.Selected().lastElement(); const selDoc = selView?.Document; - if (selDoc && (selView._props.renderDepth > 1 || selDoc[Doc.LayoutFieldKey(selDoc)] instanceof ImageField)) { - const oldPrompt = StrCast(selDoc.ai_firefly_prompt, StrCast(selDoc.title)); + if (selDoc && (selView._props.renderDepth > 1 || selDoc[Doc.LayoutDataKey(selDoc)] instanceof ImageField)) { + const oldPrompt = StrCast(selDoc.ai_prompt, StrCast(selDoc.title)); const newPrompt = oldPrompt ? `${oldPrompt} ~~~ ${imgDesc}` : imgDesc; return DrawingFillHandler.drawingToImage(selDoc, 100, newPrompt, selDoc) .then(action(() => (this._userPrompt = ''))) @@ -406,70 +406,80 @@ export class GPTPopup extends ObservableReactComponent<object> { scrollToBottom = () => setTimeout(() => this._messagesEndRef.current?.scrollIntoView({ behavior: 'smooth', block: 'end' }), 50); gptMenu = () => ( - <div className="btns-wrapper-gpt"> - <Button - tooltip="Ask Firefly to create images" - text="Ask Firefly" - onClick={() => this.setMode(GPTPopupMode.FIREFLY)} - color={StrCast(Doc.UserDoc().userVariantColor)} - type={Type.TERT} - style={{ - width: '100%', - height: '40%', - textAlign: 'center', - color: '#ffffff', - fontSize: '16px', - marginBottom: '10px', - }} - /> - <Button - tooltip="Ask GPT to sort, tag, define, or filter your Docs!" - text="Ask GPT" - onClick={() => this.setMode(GPTPopupMode.USER_PROMPT)} - color={StrCast(Doc.UserDoc().userVariantColor)} - type={Type.TERT} - style={{ - width: '100%', - height: '40%', - textAlign: 'center', - color: '#ffffff', - fontSize: '16px', - marginBottom: '10px', - }} - /> - <Button - tooltip="Test your knowledge by verifying answers with ChatGPT" - text="Take Quiz" - onClick={() => { - this._conversationArray = ['Define the selected card!']; - this.setMode(GPTPopupMode.QUIZ_RESPONSE); - this.onQuizRandom?.(); - }} - color={StrCast(Doc.UserDoc().userVariantColor)} - type={Type.TERT} - style={{ - width: '100%', - height: '40%', - textAlign: 'center', - color: '#ffffff', - fontSize: '16px', - }} - /> + <div style={{ display: 'flex', maxHeight: 'calc(100% - 32px)', overflow: 'auto' }}> + <div className="btns-wrapper-gpt"> + <Button + tooltip="Ask Firefly to create images" + text="Ask Firefly" + onClick={() => this.setMode(GPTPopupMode.FIREFLY)} + color={SettingsManager.userColor} + background={SettingsManager.userVariantColor} + type={Type.TERT} + style={{ + width: '100%', + height: '40%', + textAlign: 'center', + color: '#ffffff', + fontSize: '16px', + marginBottom: '10px', + }} + /> + <Button + tooltip="Ask GPT to sort, tag, define, or filter your Docs!" + text="Ask GPT" + onClick={() => this.setMode(GPTPopupMode.USER_PROMPT)} + color={SettingsManager.userColor} + background={SettingsManager.userVariantColor} + type={Type.TERT} + style={{ + width: '100%', + height: '40%', + textAlign: 'center', + color: '#ffffff', + fontSize: '16px', + marginBottom: '10px', + }} + /> + <Button + tooltip="Test your knowledge by verifying answers with ChatGPT" + text="Take Quiz" + onClick={() => { + this._conversationArray = ['Define the selected card!']; + this.setMode(GPTPopupMode.QUIZ_RESPONSE); + this.onQuizRandom?.(); + }} + color={SettingsManager.userColor} + background={SettingsManager.userVariantColor} + type={Type.TERT} + style={{ + width: '100%', + height: '40%', + textAlign: 'center', + color: '#ffffff', + fontSize: '16px', + }} + /> + </div> </div> ); callGpt = action((mode: GPTPopupMode) => { this.setGptProcessing(true); + const reset = action(() => { + this.setGptProcessing(false); + this._userPrompt = ''; + this._quizAnswer = ''; + }); switch (mode) { case GPTPopupMode.FIREFLY: this._fireflyArray.push(this._userPrompt); - return this.generateFireflyImage(this._userPrompt).then(action(() => (this._userPrompt = ''))); + return this.generateFireflyImage(this._userPrompt).then(reset); case GPTPopupMode.USER_PROMPT: this._conversationArray.push(this._userPrompt); - return this.generateUserPromptResponse(this._userPrompt).then(action(() => (this._userPrompt = ''))); + return this.generateUserPromptResponse(this._userPrompt).then(reset); case GPTPopupMode.QUIZ_RESPONSE: this._conversationArray.push(this._quizAnswer); - return this.generateQuizAnswerAnalysis(DocumentView.SelectedDocs().lastElement(), this._quizAnswer).then(action(() => (this._quizAnswer = ''))); + return this.generateQuizAnswerAnalysis(DocumentView.SelectedDocs().lastElement(), this._quizAnswer).then(reset); } }); @@ -487,18 +497,20 @@ export class GPTPopup extends ObservableReactComponent<object> { }; gptUserInput = () => ( - <div className="btns-wrapper-gpt"> - <div className="chat-wrapper"> - <div className="chat-bubbles"> - {(this._mode === GPTPopupMode.FIREFLY ? this._fireflyArray : this._conversationArray).map((message, index) => ( - <div key={index} className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}> - {message} - </div> - ))} - {this._gptProcessing && <div className="chat-bubble chat-message">...</div>} - </div> + <div style={{ display: 'flex', maxHeight: 'calc(100% - 32px)', overflow: 'auto' }}> + <div className="btns-wrapper-gpt"> + <div className="chat-wrapper"> + <div className="chat-bubbles"> + {(this._mode === GPTPopupMode.FIREFLY ? this._fireflyArray : this._conversationArray).map((message, index) => ( + <div key={index} className={`chat-bubble ${index % 2 === 1 ? 'user-message' : 'chat-message'}`}> + {message} + </div> + ))} + {this._gptProcessing && <div className="chat-bubble chat-message">...</div>} + </div> - <div ref={this._messagesEndRef} style={{ height: '100px' }} /> + <div ref={this._messagesEndRef} style={{ height: '40px' }} /> + </div> </div> </div> ); @@ -517,6 +529,7 @@ export class GPTPopup extends ObservableReactComponent<object> { onChange={e => onChange(e.target.value)} onKeyDown={e => this.handleKeyPress(e, this._mode)} type="text" + style={{ color: 'black' }} placeholder={placeholder} /> <Button // @@ -524,7 +537,8 @@ export class GPTPopup extends ObservableReactComponent<object> { type={Type.TERT} icon={<AiOutlineSend />} iconPlacement="right" - color={SnappingManager.userVariantColor} + color={SettingsManager.userColor} + background={SettingsManager.userVariantColor} onClick={() => this.callGpt(this._mode)} /> <DictationButton ref={r => (this._askDictation = r)} setInput={onChange} /> @@ -551,7 +565,7 @@ export class GPTPopup extends ObservableReactComponent<object> { </div> </div> <div key={rawSrc[0] + i + 'btn'} className="btn-container"> - <Button text="Save Image" onClick={() => this.transferToImage(rawSrc[1])} color={StrCast(Doc.UserDoc().userColor)} type={Type.TERT} /> + <Button text="Save Image" onClick={() => this.transferToImage(rawSrc[1])} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} type={Type.TERT} /> </div> </> ))} @@ -561,7 +575,8 @@ export class GPTPopup extends ObservableReactComponent<object> { tooltip="Generate Again" onClick={() => this._imgTargetDoc && this.generateImage(this._imageDescription, this._imgTargetDoc, this._addToCollection)} icon={<FontAwesomeIcon icon="redo-alt" size="lg" />} - color={StrCast(Doc.UserDoc().userVariantColor)} + color={SettingsManager.userColor} + background={SettingsManager.userVariantColor} /> )} </div> @@ -603,14 +618,16 @@ export class GPTPopup extends ObservableReactComponent<object> { tooltip="Show originally selected text" // text="Selection" onClick={action(() => (this._showOriginal = true))} - color={StrCast(SettingsManager.userVariantColor)} + color={SettingsManager.userColor} + background={SettingsManager.userVariantColor} type={Type.TERT} /> <Button tooltip="Create a text Doc with this text and link to the text selection" // text="Transfer To Text" onClick={this.transferToText} - color={StrCast(SettingsManager.userVariantColor)} + color={SettingsManager.userColor} + background={SettingsManager.userVariantColor} type={Type.TERT} /> </> @@ -627,14 +644,16 @@ export class GPTPopup extends ObservableReactComponent<object> { } this.generateSummary(this._aiReferenceText); })} - color={StrCast(SettingsManager.userVariantColor)} + color={SettingsManager.userColor} + background={SettingsManager.userVariantColor} type={Type.TERT} /> <Button tooltip="Create Flashcards" // text="Create Flashcards" onClick={this.createFlashcards} - color={StrCast(SettingsManager.userVariantColor)} + color={SettingsManager.userColor} + background={SettingsManager.userVariantColor} type={Type.TERT} /> </> @@ -644,7 +663,7 @@ export class GPTPopup extends ObservableReactComponent<object> { <div className="summarizing"> <span>{this._showOriginal ? 'Creating Cards...' : 'Summarizing'}</span> <ReactLoading type="bubbles" color="#bcbcbc" width={20} height={20} /> - <Button text="Stop Animation" onClick={() => this.setStopAnimatingResponse(true)} color={StrCast(SettingsManager.userVariantColor)} type={Type.TERT} /> + <Button text="Stop Animation" onClick={() => this.setStopAnimatingResponse(true)} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} type={Type.TERT} /> </div> )} </div> @@ -689,19 +708,19 @@ export class GPTPopup extends ObservableReactComponent<object> { placeholder="Ask GPT a question about the data..." id="search-input" className="searchBox-input" - style={{ width: '100%' }} + style={{ width: '100%', color: SnappingManager.userColor }} /> ) : ( <> - <Button tooltip="Transfer to text" text="Transfer To Text" onClick={this.transferToText} color={StrCast(SnappingManager.userVariantColor)} type={Type.TERT} /> - <Button tooltip="Chat with AI" text="Chat with AI" onClick={() => this.setChatEnabled(true)} color={StrCast(SnappingManager.userVariantColor)} type={Type.TERT} /> + <Button tooltip="Transfer to text" text="Transfer To Text" onClick={this.transferToText} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} type={Type.TERT} /> + <Button tooltip="Chat with AI" text="Chat with AI" onClick={() => this.setChatEnabled(true)} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} type={Type.TERT} /> </> ) ) : ( <div className="summarizing"> <span>Summarizing</span> <ReactLoading type="bubbles" color="#bcbcbc" width={20} height={20} /> - <Button text="Stop Animation" onClick={() => this.setStopAnimatingResponse(true)} color={StrCast(SnappingManager.userVariantColor)} type={Type.TERT} /> + <Button text="Stop Animation" onClick={() => this.setStopAnimatingResponse(true)} color={SettingsManager.userColor} background={SettingsManager.userVariantColor} type={Type.TERT} /> </div> )} </div> @@ -718,7 +737,7 @@ export class GPTPopup extends ObservableReactComponent<object> { ); heading = (headingText: string) => ( - <div className="summary-heading"> + <div className="summary-heading" style={{ color: SnappingManager.userBackgroundColor }}> <label className="summary-text">{headingText}</label> {this._gptProcessing ? ( <ReactLoading type="spin" color="#bcbcbc" width={14} height={14} /> @@ -734,7 +753,7 @@ export class GPTPopup extends ObservableReactComponent<object> { onClick={() => this._collectionContext && Doc.setDocFilter(this._collectionContext, 'tags', GPTPopup.ChatTag, 'remove')} /> {[GPTPopupMode.USER_PROMPT, GPTPopupMode.QUIZ_RESPONSE, GPTPopupMode.FIREFLY].includes(this._mode) && ( - <IconButton color={StrCast(SettingsManager.userVariantColor)} tooltip="back" icon={<CgCornerUpLeft size="16px" />} onClick={() => (this._mode = GPTPopupMode.GPT_MENU)} /> + <IconButton color={SettingsManager.userVariantColor} background={SettingsManager.userColor} tooltip="back" icon={<CgCornerUpLeft size="16px" />} onClick={action(() => (this._mode = GPTPopupMode.GPT_MENU))} /> )} </> )} @@ -743,12 +762,12 @@ export class GPTPopup extends ObservableReactComponent<object> { render() { return ( - <div className="gptPopup-summary-box" style={{ display: SnappingManager.ChatVisible ? 'flex' : 'none', overflow: 'auto' }}> + <div className="gptPopup-summary-box" style={{ background: SnappingManager.userColor, color: SnappingManager.userBackgroundColor, display: SnappingManager.ChatVisible ? 'flex' : 'none' }}> {(() => { //prettier-ignore switch (this._mode) { case GPTPopupMode.USER_PROMPT: return this.promptBox("ASK", this._userPrompt, this.setUserPrompt, 'Ask GPT to sort, tag, define, or filter your documents for you!'); - case GPTPopupMode.FIREFLY: return this.promptBox("CREATE", this._userPrompt, this.setUserPrompt, StrCast(DocumentView.Selected().lastElement()?.Document.ai_firefly_prompt, 'Ask Firefly to generate images')); + case GPTPopupMode.FIREFLY: return this.promptBox("CREATE", this._userPrompt, this.setUserPrompt, StrCast(DocumentView.Selected().lastElement()?.Document.ai_prompt, 'Ask Firefly to generate images')); case GPTPopupMode.QUIZ_RESPONSE: return this.promptBox("QUIZ", this._quizAnswer, this.setQuizAnswer, 'Describe/answer the selected document!'); case GPTPopupMode.GPT_MENU: return this.menuBox(); case GPTPopupMode.SUMMARY: return this.summaryBox(); diff --git a/src/client/views/pdf/PDFViewer.scss b/src/client/views/pdf/PDFViewer.scss index 030251762..1aab2b853 100644 --- a/src/client/views/pdf/PDFViewer.scss +++ b/src/client/views/pdf/PDFViewer.scss @@ -29,7 +29,11 @@ .textLayer { opacity: unset; mix-blend-mode: multiply; // bcz: makes text fuzzy! + // all these below fix issues with PDFjs transform: scale(var(--devicePixelRatio)); + --total-scale-factor: var(--scale-factor); // these 3 are used by PDFjs but not defined. why??? + --scale-round-x: 1px; + --scale-round-y: 1px; } [data-main-rotation='90'] { transform: scale(var(--devicePixelRatio)) rotate(90deg) translateY(-100%); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 83b3dffe5..fc2567fbc 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -1,9 +1,10 @@ import { action, computed, IReactionDisposer, makeObservable, observable, ObservableMap, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as Pdfjs from 'pdfjs-dist'; +import { GlobalWorkerOptions } from 'pdfjs-dist/build/pdf.mjs'; import * as PDFJSViewer from 'pdfjs-dist/web/pdf_viewer.mjs'; -import 'pdfjs-dist/webpack.mjs'; // sets the PDF workerSrc import * as React from 'react'; +import ReactLoading from 'react-loading'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, ClientUtils, returnAll, returnFalse, returnNone, returnZero, smoothScroll } from '../../../ClientUtils'; import { CreateLinkToActiveAudio, Doc, DocListCast, Opt } from '../../../fields/Doc'; import { DocData, Height } from '../../../fields/DocSymbols'; @@ -14,6 +15,7 @@ import { TraceMobx } from '../../../fields/util'; import { emptyFunction, numberRange, unimplementedFunction } from '../../../Utils'; import { DocUtils } from '../../documents/DocUtils'; import { SnappingManager } from '../../util/SnappingManager'; +import { Transform } from '../../util/Transform'; import { MarqueeOptionsMenu } from '../collections/collectionFreeForm'; import { CollectionFreeFormView } from '../collections/collectionFreeForm/CollectionFreeFormView'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; @@ -28,12 +30,13 @@ import { AnchorMenu } from './AnchorMenu'; import { Annotation } from './Annotation'; import { GPTPopup } from './GPTPopup/GPTPopup'; import './PDFViewer.scss'; -import ReactLoading from 'react-loading'; -import { Transform } from '../../util/Transform'; +import { DocumentViewProps } from '../nodes/DocumentContentsView'; +if (window?.Worker) GlobalWorkerOptions.workerSrc = 'files/node_modules/pdfjs-dist/build/pdf.worker.min.mjs'; // npm start/etc use copyfiles to copy the worker from the pdfjs-dist package to the public folder +export * from 'pdfjs-dist/build/pdf.mjs'; interface IViewerProps extends FieldViewProps { pdfBox: PDFBox; - Document: Doc; + Doc: Doc; dataDoc: Doc; layoutDoc: Doc; fieldKey: string; @@ -52,7 +55,7 @@ interface IViewerProps extends FieldViewProps { */ @observer export class PDFViewer extends ObservableReactComponent<IViewerProps> { - static _annotationStyle = addStyleSheet(); + static _annotationStyle = addStyleSheet().sheet; constructor(props: IViewerProps) { super(props); @@ -111,8 +114,8 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { () => this._props.layoutDoc._layout_autoHeight, layoutAutoHeight => { if (layoutAutoHeight) { - 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.NativeDimScaling?.() || 1)); + this._props.layoutDoc._nativeHeight = NumCast(this._props.Doc[this._props.fieldKey + '_nativeHeight']); + this._props.setHeight?.(NumCast(this._props.Doc[this._props.fieldKey + '_nativeHeight']) * (this._props.NativeDimScaling?.() || 1)); } } ); @@ -123,7 +126,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { { fireImmediately: true } ); this._disposers.curPage = reaction( - () => Cast(this._props.Document._layout_curPage, 'number', null), + () => Cast(this._props.Doc._layout_curPage, 'number', null), page => page !== undefined && page !== this._pdfViewer?.currentPageNumber && this.gotoPage(page), { fireImmediately: true } ); @@ -131,7 +134,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { componentWillUnmount = () => { Object.values(this._disposers).forEach(disposer => disposer?.()); - document.removeEventListener('copy', this.copy); + document.removeEventListener('copy', this.copy, true); }; copy = (e: ClipboardEvent) => { @@ -143,6 +146,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { e.clipboardData.setData('dash/pdfAnchor', anchor[DocData][Id]); } e.preventDefault(); + e.stopPropagation(); } }; @@ -179,7 +183,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { scrollFocus = (doc: Doc, scrollTop: number, options: FocusViewOptions) => { const mainCont = this._mainCont.current; let focusSpeed: Opt<number>; - if (doc !== this._props.Document && mainCont) { + if (doc !== this._props.Doc && mainCont) { const windowHeight = this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); const scrollTo = ClientUtils.scrollIntoView(scrollTop, doc[Height](), NumCast(this._props.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, this._scrollHeight); if (scrollTo !== undefined && scrollTo !== this._props.layoutDoc._layout_scrollTop) { @@ -214,11 +218,11 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { { fireImmediately: true } ); this._disposers.scroll = reaction( - () => Math.abs(NumCast(this._props.Document._layout_scrollTop)), + () => Math.abs(NumCast(this._props.Doc._layout_scrollTop)), pos => { if (!this._ignoreScroll) { this._showWaiting && this.setupPdfJsViewer(); - const viewTrans = quickScroll?.loc ?? StrCast(this._props.Document._viewTransition); + const viewTrans = quickScroll?.loc ?? StrCast(this._props.Doc._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; @@ -259,16 +263,11 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { } return; } - document.removeEventListener('copy', this.copy); - document.addEventListener('copy', this.copy); + document.removeEventListener('copy', this.copy, true); + document.addEventListener('copy', this.copy, true); const eventBus = new PDFJSViewer.EventBus(); eventBus._on('pagesinit', this.pagesinit); - eventBus._on( - 'pagerendered', - action(() => { - this._showWaiting = false; - }) - ); + eventBus._on('pagerendered',action(() => (this._showWaiting = false))); // prettier-ignore const pdfLinkService = new PDFJSViewer.PDFLinkService({ eventBus }); const pdfFindController = new PDFJSViewer.PDFFindController({ linkService: pdfLinkService, eventBus }); this._pdfViewer = new PDFJSViewer.PDFViewer({ @@ -369,9 +368,9 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { // if alt+left click, drag and annotate this._downX = e.clientX; this._downY = e.clientY; - if ((this._props.Document._freeform_scale || 1) !== 1) return; + if ((this._props.Doc._freeform_scale || 1) !== 1) return; if ((e.button !== 0 || e.altKey) && this._props.isContentActive()) { - this._setPreviewCursor?.(e.clientX, e.clientY, true, false, this._props.Document); + this._setPreviewCursor?.(e.clientX, e.clientY, true, false, this._props.Doc); } if (!e.altKey && e.button === 0 && this._props.isContentActive() && Doc.ActiveTool !== InkTool.Ink) { this._props.select(false); @@ -429,9 +428,9 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { }; addDrawingAnnotation = (drawing: Doc) => { - // drawing[DocData].x = this._props.pdfBox.ScreenToLocalBoxXf().TranslateX + // drawing.x = this._props.pdfBox.ScreenToLocalBoxXf().TranslateX // const scaleX = this._mainCont.current.offsetWidth / boundingRect.width; - drawing.y = NumCast(drawing.y) + NumCast(this._props.Document.layout_scrollTop); + drawing.y = NumCast(drawing.y) + NumCast(this._props.Doc.layout_scrollTop); this._props.addDocument?.(drawing); }; @@ -476,7 +475,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { onClick = (e: React.MouseEvent) => { this._scrollStopper?.(); if (this._setPreviewCursor && e.button === 0 && Math.abs(e.clientX - this._downX) < ClientUtils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < ClientUtils.DRAG_THRESHOLD) { - this._setPreviewCursor(e.clientX, e.clientY, false, false, this._props.Document); + this._setPreviewCursor(e.clientX, e.clientY, false, false, this._props.Doc); } // e.stopPropagation(); // bcz: not sure why this was here. We need to allow the DocumentView to get clicks to process doubleClicks }; @@ -504,7 +503,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { @computed get annotationLayer() { const inlineAnnos = this.inlineTextAnnotations.sort((a, b) => NumCast(a.y) - NumCast(b.y)).filter(anno => !anno.hidden); return ( - <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this._props.Document), transform: `scale(${NumCast(this._props.layoutDoc._freeform_scale, 1)})` }} ref={this._annotationLayer}> + <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this._props.Doc), transform: `scale(${NumCast(this._props.layoutDoc._freeform_scale, 1)})` }} ref={this._annotationLayer}> {inlineAnnos.map(anno => ( <Annotation {...this._props} fieldKey={this._props.fieldKey + '_annotations'} pointerEvents={this.pointerEvents} containerDataDoc={this._props.dataDoc} annoDoc={anno} key={`${anno[Id]}-annotation`} /> ))} @@ -519,7 +518,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); transparentFilter = () => [...this._props.childFilters(), ClientUtils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), ClientUtils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [ClientUtils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => { + childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps & DocumentViewProps>, property: string) => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none'; const isInk = doc.layout_isSvg && !props?.LayoutTemplateString; @@ -595,7 +594,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { onClick={this.onClick} style={{ overflowX: NumCast(this._props.layoutDoc._freeform_scale, 1) !== 1 ? 'scroll' : undefined, - height: !this._props.Document._layout_fitWidth && window.screen.width > 600 ? Doc.NativeHeight(this._props.Document) : `100%`, + height: !this._props.Doc._layout_fitWidth && window.screen.width > 600 ? Doc.NativeHeight(this._props.Doc) : `100%`, }}> {this.pdfViewerDiv} {this.annotationLayer} @@ -604,12 +603,12 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> { {!this._mainCont.current || !this._annotationLayer.current || !this.props.pdfBox.DocumentView ? null : ( <MarqueeAnnotator ref={this._marqueeref} - Document={this._props.Document} + Document={this._props.Doc} getPageFromScroll={this.getPageFromScroll} anchorMenuClick={this._props.anchorMenuClick} scrollTop={0} annotationLayerScaling={() => Pdfjs.PixelsPerInch.PDF_TO_CSS_UNITS} - annotationLayerScrollTop={NumCast(this._props.Document._layout_scrollTop)} + annotationLayerScrollTop={NumCast(this._props.Doc._layout_scrollTop)} addDocument={this.addDocumentWrapper} docView={this.props.pdfBox.DocumentView} screenTransform={this.screenToMarqueeXf} |
