diff options
Diffstat (limited to 'src/client/views/PreviewCursor.tsx')
-rw-r--r-- | src/client/views/PreviewCursor.tsx | 127 |
1 files changed, 68 insertions, 59 deletions
diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index e3a43d45f..456b753b4 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -1,41 +1,50 @@ -import { action, observable, runInAction } from 'mobx'; +import { action, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, Opt } from '../../fields/Doc'; import { lightOrDark, returnFalse } from '../../Utils'; -import { Docs, DocumentOptions, DocUtils } from '../documents/Documents'; +import { Doc, Opt } from '../../fields/Doc'; +import { DocUtils, Docs, DocumentOptions } from '../documents/Documents'; import { ImageUtils } from '../util/Import & Export/ImageUtils'; import { Transform } from '../util/Transform'; -import { undoBatch, UndoManager } from '../util/UndoManager'; -import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; +import { UndoManager, undoBatch } from '../util/UndoManager'; +import { ObservableReactComponent } from './ObservableReactComponent'; import './PreviewCursor.scss'; +import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; @observer -export class PreviewCursor extends React.Component<{}> { - static _onKeyPress?: (e: KeyboardEvent) => void; - static _getTransform: () => Transform; - static _addDocument: (doc: Doc | Doc[]) => boolean; - static _addLiveTextDoc: (doc: Doc) => void; - static _nudge?: undefined | ((x: number, y: number) => boolean); - static _slowLoadDocuments?: (files: File[] | string, options: DocumentOptions, generatedDocuments: Doc[], text: string, completed: ((doc: Doc[]) => void) | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => Promise<void>; - @observable static _clickPoint = [0, 0]; - @observable public static Visible = false; - public static Doc: Opt<Doc>; +export class PreviewCursor extends ObservableReactComponent<{}> { + static _instance: PreviewCursor; + public static get Instance() { + return PreviewCursor._instance; + } + + _onKeyPress?: (e: KeyboardEvent) => void; + _getTransform?: () => Transform; + _addDocument?: (doc: Doc | Doc[]) => boolean; + _addLiveTextDoc?: (doc: Doc) => void; + _nudge?: undefined | ((x: number, y: number) => boolean); + _slowLoadDocuments?: (files: File[] | string, options: DocumentOptions, generatedDocuments: Doc[], text: string, completed: ((doc: Doc[]) => void) | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => Promise<void>; + @observable _clickPoint: number[] = []; + @observable public Visible = false; + public Doc: Opt<Doc>; constructor(props: any) { super(props); + makeObservable(this); + PreviewCursor._instance = this; + this._clickPoint = observable([0, 0]); document.addEventListener('keydown', this.onKeyPress); document.addEventListener('paste', this.paste, true); } paste = async (e: ClipboardEvent) => { - if (PreviewCursor.Visible && e.clipboardData) { - const newPoint = PreviewCursor._getTransform().transformPoint(PreviewCursor._clickPoint[0], PreviewCursor._clickPoint[1]); - runInAction(() => (PreviewCursor.Visible = false)); + if (this.Visible && e.clipboardData) { + const newPoint = this._getTransform?.().transformPoint(this._clickPoint[0], this._clickPoint[1]); + runInAction(() => (this.Visible = false)); // tests for URL and makes web document const re: any = /^https?:\/\//g; const plain = e.clipboardData.getData('text/plain'); - if (plain) { + if (plain && newPoint) { // tests for youtube and makes video document if (plain.indexOf('www.youtube.com/watch') !== -1) { const batch = UndoManager.StartBatch('youtube upload'); @@ -47,12 +56,12 @@ export class PreviewCursor extends React.Component<{}> { x: newPoint[0], y: newPoint[1], }; - PreviewCursor._slowLoadDocuments?.(plain.split('v=')[1].split('&')[0], options, generatedDocuments, '', undefined, PreviewCursor._addDocument).then(batch.end); + this._slowLoadDocuments?.(plain.split('v=')[1].split('&')[0], options, generatedDocuments, '', undefined, this._addDocument ?? returnFalse).then(batch.end); } else if (re.test(plain)) { const url = plain; - if (url.startsWith(window.location.href)) { + if (!url.startsWith(window.location.href)) { undoBatch(() => - PreviewCursor._addDocument( + this._addDocument?.( Docs.Create.WebDocument(url, { title: url, _width: 500, @@ -70,13 +79,13 @@ export class PreviewCursor extends React.Component<{}> { const strs = docids[0].split(','); // hack! docids[0] is the top left of the selection rectangle const ptx = Number(strs[0].substring((clone ? '__DashCloneId(' : '__DashDocId(').length)); const pty = Number(strs[1].substring(0, strs[1].length - 1)); - Doc.Paste(docids.slice(1), clone, PreviewCursor._addDocument, ptx, pty, newPoint); + this._addDocument && Doc.Paste(docids.slice(1), clone, this._addDocument, ptx, pty, newPoint); e.stopPropagation(); } else { FormattedTextBox.PasteOnLoad = e; if (e.clipboardData.getData('dash/pdfAnchor')) e.preventDefault(); - UndoManager.RunInBatch(() => PreviewCursor._addLiveTextDoc(DocUtils.GetNewTextDoc('', newPoint[0], newPoint[1], 500, undefined, undefined, undefined, 750)), 'paste'); + UndoManager.RunInBatch(() => this._addLiveTextDoc?.(DocUtils.GetNewTextDoc('', newPoint[0], newPoint[1], 500, undefined, undefined, undefined)), 'paste'); } } //pasting in images @@ -84,17 +93,19 @@ export class PreviewCursor extends React.Component<{}> { const re: any = /<img src="(.*?)"/g; const arr: any[] = re.exec(e.clipboardData.getData('text/html')); - undoBatch(() => { - const doc = Docs.Create.ImageDocument(arr[1], { - _width: 300, - title: arr[1], - x: newPoint[0], - y: newPoint[1], - }); - ImageUtils.ExtractExif(doc); - PreviewCursor._addDocument(doc); - })(); - } else if (e.clipboardData.items.length) { + if (newPoint) { + undoBatch(() => { + const doc = Docs.Create.ImageDocument(arr[1], { + _width: 300, + title: arr[1], + x: newPoint[0], + y: newPoint[1], + }); + ImageUtils.ExtractImgInfo(doc); + this._addDocument?.(doc); + })(); + } + } else if (e.clipboardData.items.length && newPoint) { const batch = UndoManager.StartBatch('collection view drop'); const files: File[] = []; Array.from(e.clipboardData.items).forEach(item => { @@ -102,7 +113,7 @@ export class PreviewCursor extends React.Component<{}> { file && files.push(file); }); const generatedDocuments = await DocUtils.uploadFilesToDocs(files, { x: newPoint[0], y: newPoint[1] }); - generatedDocuments.forEach(PreviewCursor._addDocument); + this._addDocument && generatedDocuments.forEach(this._addDocument); batch.end(); } } @@ -135,25 +146,25 @@ export class PreviewCursor extends React.Component<{}> { ) { if ((!e.metaKey && !e.ctrlKey) || (e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 65 && e.keyCode <= 90)) { // /^[a-zA-Z0-9$*^%#@+-=_|}{[]"':;?/><.,}]$/.test(e.key)) { - PreviewCursor.Visible && PreviewCursor._onKeyPress?.(e); - ((!e.ctrlKey && !e.metaKey) || e.key !== 'v') && (PreviewCursor.Visible = false); + this.Visible && this._onKeyPress?.(e); + ((!e.ctrlKey && !e.metaKey) || e.key !== 'v') && (this.Visible = false); } - } else if (PreviewCursor.Visible) { + } else if (this.Visible) { if (e.key === 'ArrowRight') { - PreviewCursor._nudge?.(1 * (e.shiftKey ? 2 : 1), 0) && e.stopPropagation(); + this._nudge?.(1 * (e.shiftKey ? 2 : 1), 0) && e.stopPropagation(); } else if (e.key === 'ArrowLeft') { - PreviewCursor._nudge?.(-1 * (e.shiftKey ? 2 : 1), 0) && e.stopPropagation(); + this._nudge?.(-1 * (e.shiftKey ? 2 : 1), 0) && e.stopPropagation(); } else if (e.key === 'ArrowUp') { - PreviewCursor._nudge?.(0, 1 * (e.shiftKey ? 2 : 1)) && e.stopPropagation(); + this._nudge?.(0, 1 * (e.shiftKey ? 2 : 1)) && e.stopPropagation(); } else if (e.key === 'ArrowDown') { - PreviewCursor._nudge?.(0, -1 * (e.shiftKey ? 2 : 1)) && e.stopPropagation(); + this._nudge?.(0, -1 * (e.shiftKey ? 2 : 1)) && e.stopPropagation(); } } }; //when focus is lost, this will remove the preview cursor @action onBlur = (): void => { - PreviewCursor.Visible = false; + this.Visible = false; }; @action @@ -167,23 +178,21 @@ export class PreviewCursor extends React.Component<{}> { nudge: undefined | ((nudgeX: number, nudgeY: number) => boolean), slowLoadDocuments: (files: File[] | string, options: DocumentOptions, generatedDocuments: Doc[], text: string, completed: ((doc: Doc[]) => void) | undefined, addDocument: (doc: Doc | Doc[]) => boolean) => Promise<void> ) { - this._clickPoint = [x, y]; - this._onKeyPress = onKeyPress; - this._addLiveTextDoc = addLiveText; - this._getTransform = getTransform; - this._addDocument = addDocument || returnFalse; - this._nudge = nudge; - this._slowLoadDocuments = slowLoadDocuments; - this.Visible = true; + const self = PreviewCursor.Instance; + if (self) { + self._clickPoint = [x, y]; + self._onKeyPress = onKeyPress; + self._addLiveTextDoc = addLiveText; + self._getTransform = getTransform; + self._addDocument = addDocument || returnFalse; + self._nudge = nudge; + self._slowLoadDocuments = slowLoadDocuments; + self.Visible = true; + } } render() { - return !PreviewCursor._clickPoint || !PreviewCursor.Visible ? null : ( - <div - className="previewCursor" - onBlur={this.onBlur} - tabIndex={0} - ref={e => e?.focus()} - style={{ color: lightOrDark(PreviewCursor.Doc?.backgroundColor ?? 'white'), transform: `translate(${PreviewCursor._clickPoint[0]}px, ${PreviewCursor._clickPoint[1]}px)` }}> + return !this._clickPoint || !this.Visible ? null : ( + <div className="previewCursor" onBlur={this.onBlur} tabIndex={0} ref={e => e?.focus()} style={{ color: lightOrDark(this.Doc?.backgroundColor ?? 'white'), transform: `translate(${this._clickPoint[0]}px, ${this._clickPoint[1]}px)` }}> I </div> ); |