diff options
Diffstat (limited to 'src/client/util/LinkFollower.ts')
-rw-r--r-- | src/client/util/LinkFollower.ts | 88 |
1 files changed, 32 insertions, 56 deletions
diff --git a/src/client/util/LinkFollower.ts b/src/client/util/LinkFollower.ts index bbfd516da..ba2edb65c 100644 --- a/src/client/util/LinkFollower.ts +++ b/src/client/util/LinkFollower.ts @@ -1,18 +1,15 @@ -import { action, runInAction } from 'mobx'; -import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; -import { CollectionViewType, DocumentType } from '../documents/DocumentTypes'; -import { CollectionDockingView } from '../views/collections/CollectionDockingView'; -import { DocumentDecorations } from '../views/DocumentDecorations'; -import { LightboxView } from '../views/LightboxView'; -import { DocFocusOptions, DocumentViewSharedProps, OpenWhere, OpenWhereMod, ViewAdjustment } from '../views/nodes/DocumentView'; +import { action, observable, runInAction } from 'mobx'; +import { Doc, DocListCast, Field, FieldResult, Opt } from '../../fields/Doc'; +import { ScriptField } from '../../fields/ScriptField'; +import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../fields/Types'; +import { DocumentType } from '../documents/DocumentTypes'; +import { DocFocusOptions, OpenWhere } from '../views/nodes/DocumentView'; import { PresBox } from '../views/nodes/trails'; import { DocumentManager } from './DocumentManager'; import { LinkManager } from './LinkManager'; +import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; import { UndoManager } from './UndoManager'; - -type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void; /* * link doc: * - anchor1: doc @@ -26,59 +23,26 @@ type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => vo * - user defined kvps */ export class LinkFollower { + @observable public static IsFollowing = false; // follows a link - if the target is on screen, it highlights/pans to it. // if the target isn't onscreen, then it will open up the target in the lightbox, or in place // depending on the followLinkLocation property of the source (or the link itself as a fallback); - public static FollowLink = (linkDoc: Opt<Doc>, sourceDoc: Doc, docViewProps: DocumentViewSharedProps, altKey: boolean) => { + public static FollowLink = (linkDoc: Opt<Doc>, sourceDoc: Doc, altKey: boolean) => { const batch = UndoManager.StartBatch('follow link click'); - // open up target if it's not already in view ... - const createViewFunc = (doc: Doc, followLoc: string, finished?: Opt<() => void>) => { - const createTabForTarget = (didFocus: boolean) => - new Promise<ViewAdjustment>(res => { - const where = LightboxView.LightboxDoc ? OpenWhere.inPlace : (StrCast(sourceDoc.followLinkLocation, followLoc) as OpenWhere); - docViewProps.addDocTab(doc, where); - setTimeout(() => { - const targDocView = DocumentManager.Instance.getFirstDocumentView(doc); // get first document view available within the lightbox if that's open, or anywhere otherwise. - if (targDocView) { - targDocView.props.focus(doc, { - willPan: true, - willPanZoom: BoolCast(sourceDoc.followLinkZoom, false), - afterFocus: (didFocus: boolean) => { - finished?.(); - res(ViewAdjustment.resetView); - return new Promise<ViewAdjustment>(res2 => res2(ViewAdjustment.doNothing)); - }, - }); - } else { - finished?.(); - res(where !== OpenWhere.inPlace || BoolCast(sourceDoc.followLinkZoom) ? ViewAdjustment.resetView : ViewAdjustment.doNothing); // for 'inPlace' resetting the initial focus&zoom would negate the zoom into the target - } - }, 100); - }); - - if (!sourceDoc.followLinkZoom) { - createTabForTarget(false); - } else { - // first focus & zoom onto this (the clicked document). Then execute the function to focus on the target - docViewProps.focus(sourceDoc, { willPan: true, willPanZoom: BoolCast(sourceDoc.followLinkZoom, true), zoomTime: 1000, zoomScale: 1, afterFocus: createTabForTarget }); - } - }; - runInAction(() => (DocumentDecorations.Instance.overrideBounds = true)); // turn off decoration bounds while following links since animations may occur, and DocDecorations is based on screenToLocal which is not always an observable value + runInAction(() => (LinkFollower.IsFollowing = true)); // turn off decoration bounds while following links since animations may occur, and DocDecorations is based on screenToLocal which is not always an observable value LinkFollower.traverseLink( linkDoc, sourceDoc, - createViewFunc, - docViewProps.ContainingCollectionDoc, action(() => { batch.end(); - Doc.AddUnHighlightWatcher(action(() => (DocumentDecorations.Instance.overrideBounds = false))); + Doc.AddUnHighlightWatcher(action(() => (LinkFollower.IsFollowing = false))); }), altKey ? true : undefined ); }; - public static traverseLink(link: Opt<Doc>, sourceDoc: Doc, createViewFunc: CreateViewFunc, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) { - const linkDocs = link ? [link] : DocListCast(sourceDoc.links); + public static traverseLink(link: Opt<Doc>, sourceDoc: Doc, finished?: () => void, traverseBacklink?: boolean) { + const linkDocs = link ? [link] : LinkManager.Links(sourceDoc); const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor1 const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, sourceDoc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, sourceDoc)); // link docs where 'doc' is anchor2 const fwdLinkWithoutTargetView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews((d.anchor2 as Doc).type === DocumentType.MARKER ? DocCast((d.anchor2 as Doc).annotationOn) : (d.anchor2 as Doc)).length === 0); @@ -101,16 +65,18 @@ export class LinkFollower { ) as Doc; if (target) { const doFollow = (canToggle?: boolean) => { + const toggleTarget = canToggle && BoolCast(sourceDoc.followLinkToggle); const options: DocFocusOptions = { playAudio: BoolCast(sourceDoc.followLinkAudio), - toggleTarget: canToggle && BoolCast(sourceDoc.followLinkToggle), + toggleTarget, + noSelect: true, willPan: true, - willPanZoom: BoolCast(LinkManager.getOppositeAnchor(linkDoc, target)?.followLinkZoom, false), - zoomTime: NumCast(LinkManager.getOppositeAnchor(linkDoc, target)?.followLinkTransitionTime, 500), + willZoomCentered: BoolCast(sourceDoc.followLinkZoom, false), + zoomTime: NumCast(sourceDoc.followLinkTransitionTime, 500), zoomScale: Cast(sourceDoc.followLinkZoomScale, 'number', null), easeFunc: StrCast(sourceDoc.followLinkEase, 'ease') as any, + openLocation: StrCast(sourceDoc.followLinkLocation, OpenWhere.lightbox) as OpenWhere, effect: sourceDoc, - originatingDoc: sourceDoc, zoomTextSelections: BoolCast(sourceDoc.followLinkZoomText), }; if (target.type === DocumentType.PRES) { @@ -121,9 +87,7 @@ export class LinkFollower { } finished?.(); } else { - const containerDocContext = DocumentManager.GetContextPath(target); - const targetContexts = !sourceDoc.followLinkToOuterContext && containerDocContext.length ? [containerDocContext.lastElement()] : containerDocContext; - DocumentManager.Instance.jumpToDocument(target, options, (doc, finished) => createViewFunc(doc, StrCast(linkDoc.followLinkLocation, OpenWhere.inPlace), finished), targetContexts, allFinished); + DocumentManager.Instance.showDocument(target, options, allFinished); } }; let movedTarget = false; @@ -156,3 +120,15 @@ export class LinkFollower { }); } } + +ScriptingGlobals.add(function followLink(doc: Doc, altKey: boolean) { + SelectionManager.DeselectAll(); + LinkFollower.FollowLink(undefined, doc, altKey); +}); + +export function FollowLinkScript() { + return ScriptField.MakeScript('followLink(this,altKey)', { altKey: 'boolean' }); +} +export function IsFollowLinkScript(field: FieldResult<Field>) { + return ScriptCast(field)?.script.originalScript.includes('followLink('); +} |