diff options
Diffstat (limited to 'src/client/util/DocumentManager.ts')
-rw-r--r-- | src/client/util/DocumentManager.ts | 102 |
1 files changed, 55 insertions, 47 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index c3d78a028..a6816c7f9 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,16 +1,17 @@ -import { action, computed, observable } from 'mobx'; -import { Doc, DocListCastAsync, DocListCast, Opt } from '../../fields/Doc'; +import { action, observable } from 'mobx'; +import { Doc, DocListCast, DocListCastAsync, Opt } from '../../fields/Doc'; import { Id } from '../../fields/FieldSymbols'; import { Cast, NumCast, StrCast } from '../../fields/Types'; +import { returnFalse } from '../../Utils'; +import { DocumentType } from '../documents/DocumentTypes'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { CollectionView } from '../views/collections/CollectionView'; -import { DocumentView, DocFocusFunc } from '../views/nodes/DocumentView'; +import { DocumentView } from '../views/nodes/DocumentView'; import { LinkManager } from './LinkManager'; import { Scripting } from './Scripting'; import { SelectionManager } from './SelectionManager'; -import { DocumentType } from '../documents/DocumentTypes'; -import { TraceMobx } from '../../fields/util'; -import { returnFalse } from '../../Utils'; +import { LinkDocPreview } from '../views/nodes/LinkDocPreview'; +import { FormattedTextBoxComment } from '../views/nodes/formattedText/FormattedTextBoxComment'; export type CreateViewFunc = (doc: Doc, followLinkLocation: string, finished?: () => void) => void; @@ -19,6 +20,7 @@ export class DocumentManager { //global holds all of the nodes (regardless of which collection they're in) @observable public DocumentViews: DocumentView[] = []; + @observable LinkedDocumentViews: { a: DocumentView, b: DocumentView, l: Doc }[] = []; // singleton instance private static _instance: DocumentManager; @@ -32,6 +34,26 @@ export class DocumentManager { private constructor() { } + @action + public AddView = (view: DocumentView) => { + const linksList = DocListCast(view.props.Document.links); + linksList.forEach(link => { + const linkToDoc = link && LinkManager.getOppositeAnchor(link, view.props.Document); + linkToDoc && DocumentManager.Instance.DocumentViews.filter(dv => Doc.AreProtosEqual(dv.props.Document, linkToDoc)).forEach(dv => { + if (dv.props.Document.type !== DocumentType.LINK || dv.props.LayoutTemplateString !== view.props.LayoutTemplateString) { + this.LinkedDocumentViews.push({ a: dv, b: view, l: link }); + } + }); + }); + this.DocumentViews.push(view); + } + public RemoveView = (view: DocumentView) => { + const index = this.DocumentViews.indexOf(view); + index !== -1 && this.DocumentViews.splice(index, 1); + + this.LinkedDocumentViews.slice().forEach(action((pair, i) => pair.a === view || pair.b === view ? this.LinkedDocumentViews.splice(i, 1) : null)); + } + //gets all views public getDocumentViewsById(id: string) { const toReturn: DocumentView[] = []; @@ -88,7 +110,7 @@ export class DocumentManager { public getFirstDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => { const views = this.getDocumentViews(toFind).filter(view => view.props.Document !== originatingDoc); - return views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined); + return views?.find(view => view.ContentDiv?.getBoundingClientRect().width && view.props.focus !== returnFalse) || views?.find(view => view.props.focus !== returnFalse) || (views.length ? views[0] : undefined); } public getDocumentViews(toFind: Doc): DocumentView[] { const toReturn: DocumentView[] = []; @@ -105,39 +127,20 @@ export class DocumentManager { return toReturn; } - @computed - public get LinkedDocumentViews() { - TraceMobx(); - const pairs = DocumentManager.Instance.DocumentViews.reduce((pairs, dv) => { - const linksList = DocListCast(dv.props.Document.links); - pairs.push(...linksList.reduce((pairs, link) => { - const linkToDoc = link && LinkManager.getOppositeAnchor(link, dv.props.Document); - linkToDoc && DocumentManager.Instance.getDocumentViews(linkToDoc).map(docView1 => { - if (dv.props.Document.type !== DocumentType.LINK || dv.props.LayoutTemplateString !== docView1.props.LayoutTemplateString) { - pairs.push({ a: dv, b: docView1, l: link }); - } - }); - return pairs; - }, [] as { a: DocumentView, b: DocumentView, l: Doc }[])); - return pairs; - }, [] as { a: DocumentView, b: DocumentView, l: Doc }[]); - return pairs; - } - - static addRightSplit = (doc: Doc, finished?: () => void) => { + static addView = (doc: Doc, finished?: () => void) => { CollectionDockingView.AddSplit(doc, "right"); finished?.(); } public jumpToDocument = async ( targetDoc: Doc, // document to display willZoom: boolean, // whether to zoom doc to take up most of screen - createViewFunc = DocumentManager.addRightSplit, // how to create a view of the doc if it doesn't exist + createViewFunc = DocumentManager.addView, // how to create a view of the doc if it doesn't exist docContext?: Doc, // context to load that should contain the target linkDoc?: Doc, // link that's being followed closeContextIfNotFound: boolean = false, // after opening a context where the document should be, this determines whether the context should be closed if the Doc isn't actually there originatingDoc: Opt<Doc> = undefined, // doc that initiated the display of the target odoc - finished?: () => void + finished?: () => void, ): Promise<void> => { const getFirstDocView = DocumentManager.Instance.getFirstDocumentView; const focusAndFinish = () => { finished?.(); return false; }; @@ -150,7 +153,7 @@ export class DocumentManager { }; const docView = getFirstDocView(targetDoc, originatingDoc); let annotatedDoc = await Cast(targetDoc.annotationOn, Doc); - if (annotatedDoc && !targetDoc?.isPushpin) { + if (annotatedDoc && annotatedDoc !== originatingDoc?.context && !targetDoc?.isPushpin) { const first = getFirstDocView(annotatedDoc); if (first) { annotatedDoc = first.props.Document; @@ -158,15 +161,23 @@ export class DocumentManager { } } if (docView) { // we have a docView already and aren't forced to create a new one ... just focus on the document. TODO move into view if necessary otherwise just highlight? + const sameContext = annotatedDoc && annotatedDoc === originatingDoc?.context; if (originatingDoc?.isPushpin) { - docView.props.Document.hidden = !docView.props.Document.hidden; + docView.props.focus(docView.props.Document, willZoom, undefined, (didFocus: boolean) => { + if (!didFocus || docView.props.Document.hidden) { + docView.props.Document.hidden = !docView.props.Document.hidden; + } + return focusAndFinish(); + }, sameContext, false);// don't want to focus the container if the source and target are in the same container, so pass 'sameContext' for dontCenter parameter + //finished?.(); } else { docView.select(false); docView.props.Document.hidden && (docView.props.Document.hidden = undefined); - docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish); - highlight(); + // @ts-ignore + docView.props.focus(docView.props.Document, willZoom, undefined, focusAndFinish, sameContext, false); } + highlight(); } else { const contextDocs = docContext ? await DocListCastAsync(docContext.data) : undefined; const contextDoc = contextDocs?.find(doc => Doc.AreProtosEqual(doc, targetDoc)) ? docContext : undefined; @@ -177,7 +188,7 @@ export class DocumentManager { highlight(); } else { // otherwise try to get a view of the context of the target const targetDocContextView = getFirstDocView(targetDocContext); - targetDocContext._scrollY = NumCast(targetDocContext._scrollTop, 0); // this will force PDFs to activate and load their annotations / allow scrolling + targetDocContext._scrollY = targetDocContext._scrollPreviewY = NumCast(targetDocContext._scrollTop, 0); // this will force PDFs to activate and load their annotations / allow scrolling if (targetDocContextView) { // we found a context view and aren't forced to create a new one ... focus on the context first.. targetDocContext._viewTransition = "transform 500ms"; targetDocContextView.props.focus(targetDocContextView.props.Document, willZoom); @@ -192,34 +203,31 @@ export class DocumentManager { if (retryDocView) { // we found the target in the context retryDocView.props.focus(targetDoc, willZoom, undefined, focusAndFinish); // focus on the target in the context highlight(); - } - if (delay > 2500) { + } else if (delay > 1500) { // we didn't find the target, so it must have moved out of the context. Go back to just creating it. if (closeContextIfNotFound) targetDocContextView.props.removeDocument?.(targetDocContextView.props.Document); - // targetDoc.layout && createViewFunc(Doc.BrushDoc(targetDoc), finished); // create a new view of the target + if (targetDoc.layout) { + Doc.SetInPlace(targetDoc, "annotationOn", undefined, false); + createViewFunc(Doc.BrushDoc(targetDoc), finished); // create a new view of the target + } } else { setTimeout(() => findView(delay + 250), 250); } }; findView(0); } - } else { // there's no context view so we need to create one first and try again - createViewFunc(targetDocContext); // so first we create the target, but don't pass finished because we still need to create the target - setTimeout(() => { - const finalDocView = getFirstDocView(targetDoc); - const finalDocContextView = getFirstDocView(targetDocContext); - setTimeout(() => // if not, wait a bit to see if the context can be loaded (e.g., a PDF). wait interval heurisitic tries to guess how we're animating based on what's just become visible - this.jumpToDocument(targetDoc, willZoom, createViewFunc, undefined, linkDoc, true, undefined, finished), // pass true this time for closeContextIfNotFound - finalDocView ? 0 : finalDocContextView ? 250 : 2000); // so call jump to doc again and if the doc isn't found, it will be created. - }, 0); + } else { // there's no context view so we need to create one first and try again when that finishes + createViewFunc(targetDocContext, // after creating the context, this calls the finish function that will retry looking for the target + () => this.jumpToDocument(targetDoc, willZoom, createViewFunc, docContext, linkDoc, true /* if we don't find the target, we want to get rid of the context just created */, undefined, finished)); } } } } public async FollowLink(link: Opt<Doc>, doc: Doc, createViewFunc: CreateViewFunc, zoom = false, currentContext?: Doc, finished?: () => void, traverseBacklink?: boolean) { + LinkDocPreview.TargetDoc = undefined; + FormattedTextBoxComment.linkDoc = undefined; const linkDocs = link ? [link] : DocListCast(doc.links); - SelectionManager.DeselectAll(); const firstDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor1 as Doc, doc) || Doc.AreProtosEqual((linkDoc.anchor1 as Doc).annotationOn as Doc, doc)); // link docs where 'doc' is anchor1 const secondDocs = linkDocs.filter(linkDoc => Doc.AreProtosEqual(linkDoc.anchor2 as Doc, doc) || Doc.AreProtosEqual((linkDoc.anchor2 as Doc).annotationOn as Doc, doc)); // link docs where 'doc' is anchor2 const fwdLinkWithoutTargetView = firstDocs.find(d => DocumentManager.Instance.getDocumentViews(d.anchor2 as Doc).length === 0); |