diff options
Diffstat (limited to 'src/client/views/nodes/LinkDocPreview.tsx')
-rw-r--r-- | src/client/views/nodes/LinkDocPreview.tsx | 145 |
1 files changed, 76 insertions, 69 deletions
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx index 198cbe851..4b242649a 100644 --- a/src/client/views/nodes/LinkDocPreview.tsx +++ b/src/client/views/nodes/LinkDocPreview.tsx @@ -1,101 +1,110 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Tooltip } from '@material-ui/core'; -import { action, computed, observable } from 'mobx'; +import { Tooltip } from '@mui/material'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; +import * as React from 'react'; import wiki from 'wikijs'; -import { Doc, DocCastAsync, Opt } from '../../../fields/Doc'; -import { Height, Width } from '../../../fields/DocSymbols'; -import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types'; import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnNone, setupMoveUpEvents } from '../../../Utils'; +import { Doc, Opt } from '../../../fields/Doc'; +import { Cast, DocCast, NumCast, PromiseValue, StrCast } from '../../../fields/Types'; import { DocServer } from '../../DocServer'; -import { Docs } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; +import { Docs } from '../../documents/Documents'; +import { DocumentManager } from '../../util/DocumentManager'; import { DragManager } from '../../util/DragManager'; import { LinkFollower } from '../../util/LinkFollower'; import { LinkManager } from '../../util/LinkManager'; import { SearchUtil } from '../../util/SearchUtil'; import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; -import { DocumentView, DocumentViewSharedProps, OpenWhere } from './DocumentView'; +import { ObservableReactComponent } from '../ObservableReactComponent'; +import { DocumentView, OpenWhere } from './DocumentView'; +import { StyleProviderFuncType } from './FieldView'; import './LinkDocPreview.scss'; -import React = require('react'); -import { DocumentManager } from '../../util/DocumentManager'; + +export class LinkInfo { + private static _instance: Opt<LinkInfo>; + constructor() { + LinkInfo._instance = this; + makeObservable(this); + } + @observable public LinkInfo: Opt<LinkDocPreviewProps> = undefined; + + public static get Instance() { + return LinkInfo._instance ?? new LinkInfo(); + } + public static Clear() { + runInAction(() => LinkInfo.Instance && (LinkInfo.Instance.LinkInfo = undefined)); + } + public static SetLinkInfo(info?: LinkDocPreviewProps) { + runInAction(() => LinkInfo.Instance && (LinkInfo.Instance.LinkInfo = info)); + } +} interface LinkDocPreviewProps { linkDoc?: Doc; linkSrc?: Doc; - docProps: DocumentViewSharedProps; + DocumentView?: () => DocumentView; + styleProvider?: StyleProviderFuncType; location: number[]; hrefs?: string[]; showHeader?: boolean; noPreview?: boolean; } @observer -export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { - @action public static Clear() { - LinkDocPreview.LinkInfo = undefined; - } - @action public static SetLinkInfo(info?: LinkDocPreviewProps) { - LinkDocPreview.LinkInfo !== info && (LinkDocPreview.LinkInfo = info); - } - - static _instance: Opt<LinkDocPreview>; - +export class LinkDocPreview extends ObservableReactComponent<LinkDocPreviewProps> { _infoRef = React.createRef<HTMLDivElement>(); _linkDocRef = React.createRef<HTMLDivElement>(); - @observable public static LinkInfo: Opt<LinkDocPreviewProps>; - @observable _targetDoc: Opt<Doc>; - @observable _markerTargetDoc: Opt<Doc>; - @observable _linkDoc: Opt<Doc>; - @observable _linkSrc: Opt<Doc>; + @observable _targetDoc: Opt<Doc> = undefined; + @observable _markerTargetDoc: Opt<Doc> = undefined; + @observable _linkDoc: Opt<Doc> = undefined; + @observable _linkSrc: Opt<Doc> = undefined; @observable _toolTipText = ''; @observable _hrefInd = 0; - constructor(props: any) { super(props); - LinkDocPreview._instance = this; + makeObservable(this); } - @action init() { - var linkTarget = this.props.linkDoc; - this._linkSrc = this.props.linkSrc; - this._linkDoc = this.props.linkDoc; - const link_anchor_1 = this._linkDoc?.link_anchor_1 as Doc; - const link_anchor_2 = this._linkDoc?.link_anchor_2 as Doc; + @action + init() { + var linkTarget = this._props.linkDoc; + this._linkSrc = this._props.linkSrc; + this._linkDoc = this._props.linkDoc; + const link_anchor_1 = DocCast(this._linkDoc?.link_anchor_1); + const link_anchor_2 = DocCast(this._linkDoc?.link_anchor_2); if (link_anchor_1 && link_anchor_2) { linkTarget = Doc.AreProtosEqual(link_anchor_1, this._linkSrc) || Doc.AreProtosEqual(link_anchor_1?.annotationOn as Doc, this._linkSrc) ? link_anchor_2 : link_anchor_1; } if (linkTarget?.annotationOn && linkTarget?.type !== DocumentType.RTF) { - // want to show annotation embedContainer document if annotation is not text - linkTarget && DocCastAsync(linkTarget.annotationOn).then(action(anno => (this._markerTargetDoc = this._targetDoc = anno))); - } else { - this._markerTargetDoc = this._targetDoc = linkTarget; + linkTarget = DocCast(linkTarget.annotationOn); // want to show annotation embedContainer document if annotation is not text } + this._markerTargetDoc = this._targetDoc = linkTarget; this._toolTipText = ''; this.updateHref(); } - componentDidUpdate(props: any) { - if (props.linkSrc !== this.props.linkSrc || props.linkDoc !== this.props.linkDoc || props.hrefs !== this.props.hrefs) this.init(); + componentDidUpdate(prevProps: Readonly<LinkDocPreviewProps>) { + super.componentDidUpdate(prevProps); + if (prevProps.linkSrc !== this._props.linkSrc || prevProps.linkDoc !== this._props.linkDoc || prevProps.hrefs !== this._props.hrefs) this.init(); } componentDidMount() { this.init(); document.addEventListener('pointerdown', this.onPointerDown, true); } - @action componentWillUnmount() { - LinkDocPreview.SetLinkInfo(undefined); + LinkInfo.Clear(); document.removeEventListener('pointerdown', this.onPointerDown, true); } onPointerDown = (e: PointerEvent) => { - !this._linkDocRef.current?.contains(e.target as any) && LinkDocPreview.Clear(); // close preview when not clicking anywhere other than the info bar of the preview + !this._linkDocRef.current?.contains(e.target as any) && LinkInfo.Clear(); // close preview when not clicking anywhere other than the info bar of the preview }; @action updateHref() { - if (this.props.hrefs?.length) { - const href = this.props.hrefs[this._hrefInd]; + if (this._props.hrefs?.length) { + const href = this._props.hrefs[this._hrefInd]; if (href.indexOf(Doc.localServerPath()) !== 0) { // link to a web page URL -- try to show a preview if (href.startsWith('https://en.wikipedia.org/wiki/')) { @@ -125,7 +134,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { this._markerTargetDoc = linkTarget; this._targetDoc = /*linkTarget?.type === DocumentType.MARKER &&*/ linkTarget?.annotationOn ? Cast(linkTarget.annotationOn, Doc, null) ?? linkTarget : linkTarget; } - if (LinkDocPreview.LinkInfo?.noPreview || this._linkSrc?.followLinkToggle || this._markerTargetDoc?.type === DocumentType.PRES) this.followLink(); + if (LinkInfo.Instance?.LinkInfo?.noPreview || this._linkSrc?.followLinkToggle || this._markerTargetDoc?.type === DocumentType.PRES) this.followLink(); } }) ); @@ -145,9 +154,9 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { action(() => { LinkManager.currentLink = this._linkDoc; LinkManager.currentLinkAnchor = this._linkSrc; - this.props.docProps.DocumentView?.().select(false); - if ((SettingsManager.propertiesWidth ?? 0) < 100) { - SettingsManager.propertiesWidth = 250; + this._props.DocumentView?.().select(false); + if ((SettingsManager.Instance.propertiesWidth ?? 0) < 100) { + SettingsManager.Instance.propertiesWidth = 250; } }) ); @@ -159,7 +168,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { returnFalse, emptyFunction, action(() => { - const nextHrefInd = (this._hrefInd + 1) % (this.props.hrefs?.length || 1); + const nextHrefInd = (this._hrefInd + 1) % (this._props.hrefs?.length || 1); if (nextHrefInd !== this._hrefInd) { this._linkDoc = undefined; this._hrefInd = nextHrefInd; @@ -170,19 +179,19 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { }; followLink = () => { - LinkDocPreview.Clear(); + LinkInfo.Clear(); if (this._linkDoc && this._linkSrc) { LinkFollower.FollowLink(this._linkDoc, this._linkSrc, false); - } else if (this.props.hrefs?.length) { + } else if (this._props.hrefs?.length) { const webDoc = - Array.from(SearchUtil.SearchCollection(Doc.MyFilesystem, this.props.hrefs[0]).keys()).lastElement() ?? - Docs.Create.WebDocument(this.props.hrefs[0], { title: this.props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, data_useCors: true }); + Array.from(SearchUtil.SearchCollection(Doc.MyFilesystem, this._props.hrefs[0]).keys()).lastElement() ?? + Docs.Create.WebDocument(this._props.hrefs[0], { title: this._props.hrefs[0], _nativeWidth: 850, _width: 200, _height: 400, data_useCors: true }); DocumentManager.Instance.showDocument(webDoc, { openLocation: OpenWhere.lightbox, willPan: true, zoomTime: 500, }); - //this.props.docProps?.addDocTab(webDoc, OpenWhere.lightbox); + //this._props.docProps?.addDocTab(webDoc, OpenWhere.lightbox); } }; @@ -190,17 +199,17 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { width = () => { if (!this._targetDoc) return 225; - if (this._targetDoc[Width]() < this._targetDoc?.[Height]()) { - return (Math.min(225, this._targetDoc[Height]()) * this._targetDoc[Width]()) / this._targetDoc[Height](); + if (NumCast(this._targetDoc._width) < NumCast(this._targetDoc._height)) { + return (Math.min(225, NumCast(this._targetDoc._height)) * NumCast(this._targetDoc._width)) / NumCast(this._targetDoc._height); } - return Math.min(225, NumCast(this._targetDoc?.[Width](), 225)); + return Math.min(225, NumCast(this._targetDoc._width, 225)); }; height = () => { if (!this._targetDoc) return 225; - if (this._targetDoc[Width]() > this._targetDoc?.[Height]()) { - return (Math.min(225, this._targetDoc[Width]()) * this._targetDoc[Height]()) / this._targetDoc[Width](); + if (NumCast(this._targetDoc._width) > NumCast(this._targetDoc._height)) { + return (Math.min(225, NumCast(this._targetDoc._width)) * NumCast(this._targetDoc._height)) / NumCast(this._targetDoc._width); } - return Math.min(225, NumCast(this._targetDoc?.[Height](), 225)); + return Math.min(225, NumCast(this._targetDoc._height, 225)); }; @computed get previewHeader() { return !this._linkDoc || !this._markerTargetDoc || !this._targetDoc || !this._linkSrc ? null : ( @@ -218,7 +227,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { </div> <div className="linkDocPreview-buttonBar" style={{ float: 'right' }}> <Tooltip title={<div className="dash-tooltip">Next Link</div>} placement="top"> - <div className="linkDocPreview-button" style={{ background: (this.props.hrefs?.length || 0) <= 1 ? 'gray' : 'green' }} onPointerDown={this.nextHref}> + <div className="linkDocPreview-button" style={{ background: (this._props.hrefs?.length || 0) <= 1 ? 'gray' : 'green' }} onPointerDown={this.nextHref}> <FontAwesomeIcon className="linkDocPreview-fa-icon" icon="chevron-right" color="white" size="sm" /> </div> </Tooltip> @@ -230,7 +239,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { @computed get docPreview() { return (!this._linkDoc || !this._targetDoc || !this._linkSrc) && !this._toolTipText ? null : ( <div className="linkDocPreview-inner"> - {!this.props.showHeader ? null : this.previewHeader} + {!this._props.showHeader ? null : this.previewHeader} <div className="linkDocPreview-preview-wrapper" onPointerDown={e => @@ -240,7 +249,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { (e, down, delta) => { if (Math.abs(e.clientX - down[0]) + Math.abs(e.clientY - down[1]) > 100) { DragManager.StartDocumentDrag([this._infoRef.current!], new DragManager.DocumentDragData([this._targetDoc!]), e.pageX, e.pageY); - LinkDocPreview.Clear(); + LinkInfo.Clear(); return true; } return false; @@ -258,13 +267,12 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { <DocumentView ref={r => { const targetanchor = this._linkDoc && this._linkSrc && LinkManager.getOppositeAnchor(this._linkDoc, this._linkSrc); - targetanchor && this._targetDoc !== targetanchor && r?.props.focus?.(targetanchor, {}); + targetanchor && this._targetDoc !== targetanchor && r?._props.focus?.(targetanchor, {}); }} Document={this._targetDoc!} moveDocument={returnFalse} - rootSelected={returnFalse} - styleProvider={this.props.docProps?.styleProvider} - docViewPath={returnEmptyDoclist} + styleProvider={this._props.styleProvider} + containerViewPath={returnEmptyDoclist} ScreenToLocalTransform={Transform.Identity} isDocumentActive={returnFalse} isContentActive={returnFalse} @@ -285,7 +293,6 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { focus={emptyFunction} whenChildContentsActiveChanged={returnFalse} ignoreAutoHeight={true} // need to ignore layout_autoHeight otherwise layout_autoHeight text boxes will expand beyond the preview panel size. - bringToFront={returnFalse} NativeWidth={Doc.NativeWidth(this._targetDoc) ? () => Doc.NativeWidth(this._targetDoc) : undefined} NativeHeight={Doc.NativeHeight(this._targetDoc) ? () => Doc.NativeHeight(this._targetDoc) : undefined} /> @@ -302,7 +309,7 @@ export class LinkDocPreview extends React.Component<LinkDocPreviewProps> { className="linkDocPreview" ref={this._linkDocRef} onPointerDown={this.followLinkPointerDown} - style={{ borderColor: SettingsManager.userColor, left: this.props.location[0], top: this.props.location[1], width: this.width() + borders, height: this.height() + borders + (this.props.showHeader ? 37 : 0) }}> + style={{ borderColor: SettingsManager.userColor, left: this._props.location[0], top: this._props.location[1], width: this.width() + borders, height: this.height() + borders + (this._props.showHeader ? 37 : 0) }}> {this.docPreview} </div> ); |