diff options
Diffstat (limited to 'src/client/util/DocumentManager.ts')
-rw-r--r-- | src/client/util/DocumentManager.ts | 104 |
1 files changed, 48 insertions, 56 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 7fef5cc79..a38a330da 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,6 +1,7 @@ +import { Howl } from 'howler'; import { action, computed, makeObservable, observable, ObservableSet, observe } from 'mobx'; -import { Doc, DocListCast, Opt } from '../../fields/Doc'; -import { AclAdmin, AclEdit, Animation } from '../../fields/DocSymbols'; +import { Doc, Opt } from '../../fields/Doc'; +import { AclAdmin, AclEdit, Animation, DocData } from '../../fields/DocSymbols'; import { Id } from '../../fields/FieldSymbols'; import { listSpec } from '../../fields/Schema'; import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types'; @@ -10,13 +11,13 @@ import { CollectionViewType } from '../documents/DocumentTypes'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { TabDocView } from '../views/collections/TabDocView'; import { LightboxView } from '../views/LightboxView'; -import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; +import { DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView'; +import { FocusViewOptions } from '../views/nodes/FieldView'; import { KeyValueBox } from '../views/nodes/KeyValueBox'; import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox'; import { PresBox } from '../views/nodes/trails'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; -import { Howl } from 'howler'; export class DocumentManager { private static _instance: DocumentManager; @@ -27,10 +28,8 @@ export class DocumentManager { //global holds all of the nodes (regardless of which collection they're in) @observable _documentViews = new Set<DocumentView>(); @observable.shallow public CurrentlyLoading: Doc[] = []; - @observable.shallow public LinkAnchorBoxViews: DocumentView[] = []; - @observable.shallow public LinkedDocumentViews: { a: DocumentView; b: DocumentView; l: Doc }[] = []; @computed public get DocumentViews() { - return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.IsLightboxDocView(view.docViewPath))); + return Array.from(this._documentViews).filter(view => !(view.ComponentView instanceof KeyValueBox) && (!LightboxView.LightboxDoc || LightboxView.Contains(view))); } public AddDocumentView(dv: DocumentView) { this._documentViews.add(dv); @@ -89,37 +88,14 @@ export class DocumentManager { @action public AddView = (view: DocumentView) => { - if (view._props.LayoutTemplateString?.includes(KeyValueBox.name)) return; - if (view._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { - const viewAnchorIndex = view._props.LayoutTemplateString.includes('link_anchor_2') ? 'link_anchor_2' : 'link_anchor_1'; - const link = view.Document; - this.LinkAnchorBoxViews?.filter(dv => Doc.AreProtosEqual(dv.Document, link) && !dv._props.LayoutTemplateString?.includes(viewAnchorIndex)).forEach(otherView => - this.LinkedDocumentViews.push({ - a: viewAnchorIndex === 'link_anchor_2' ? otherView : view, - b: viewAnchorIndex === 'link_anchor_2' ? view : otherView, - l: link, - }) - ); - this.LinkAnchorBoxViews.push(view); - } else { + if (!view._props.LayoutTemplateString?.includes(KeyValueBox.name) && + !view._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { this.AddDocumentView(view); - } - this.callAddViewFuncs(view); + this.callAddViewFuncs(view); + } // prettier-ignore }; public RemoveView = action((view: DocumentView) => { - this.LinkedDocumentViews.slice().forEach( - action(pair => { - if (pair.a === view || pair.b === view) { - const li = this.LinkedDocumentViews.indexOf(pair); - li !== -1 && this.LinkedDocumentViews.splice(li, 1); - } - }) - ); - - if (view._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { - const index = this.LinkAnchorBoxViews.indexOf(view); - this.LinkAnchorBoxViews.splice(index, 1); - } else { + if (!view._props.LayoutTemplateString?.includes(KeyValueBox.name) && !view._props.LayoutTemplateString?.includes(LinkAnchorBox.name)) { this.DeleteDocumentView(view); } SelectionManager.DeselectView(view); @@ -135,7 +111,7 @@ export class DocumentManager { }); if (toReturn.length === 0) { DocumentManager.Instance.DocumentViews.forEach(view => { - if (Doc.GetProto(view.Document)?.[Id] === id) { + if (view.Document[DocData]?.[Id] === id) { toReturn.push(view); } }); @@ -153,15 +129,15 @@ export class DocumentManager { return passes.reduce( (toReturn, pass) => toReturn ?? - docViewArray.filter(view => view.Document === target).find(view => !pass || view._props.docViewPath().lastElement() === preferredCollection) ?? - docViewArray.filter(view => Doc.AreProtosEqual(view.Document, target)).find(view => !pass || view._props.docViewPath().lastElement() === preferredCollection), + docViewArray.filter(view => view.Document === target).find(view => !pass || view.containerViewPath?.().lastElement() === preferredCollection) ?? + docViewArray.filter(view => Doc.AreProtosEqual(view.Document, target)).find(view => !pass || view.containerViewPath?.().lastElement() === preferredCollection), undefined as Opt<DocumentView> ); } public getLightboxDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => { const views: DocumentView[] = []; - DocumentManager.Instance.DocumentViews.forEach(view => LightboxView.IsLightboxDocView(view.docViewPath) && Doc.AreProtosEqual(view.Document, toFind) && views.push(view)); + DocumentManager.Instance.DocumentViews.forEach(view => LightboxView.Contains(view) && Doc.AreProtosEqual(view.Document, toFind) && views.push(view)); 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 getFirstDocumentView = (toFind: Doc, originatingDoc: Opt<Doc> = undefined): DocumentView | undefined => { @@ -179,8 +155,8 @@ export class DocumentManager { toFindIn; const toReturn: DocumentView[] = []; - const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.IsLightboxDocView(view.docViewPath)); - const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.IsLightboxDocView(view.docViewPath)); + const docViews = DocumentManager.Instance.DocumentViews.filter(view => !LightboxView.Contains(view)); + const lightViews = DocumentManager.Instance.DocumentViews.filter(view => LightboxView.Contains(view)); // heuristic to return the "best" documents first: // choose a document in the lightbox first @@ -224,7 +200,7 @@ export class DocumentManager { } public static removeOverlayViews() { - DocumentManager._overlayViews?.forEach(action(view => (view.textHtmlOverlay = undefined))); + DocumentManager._overlayViews?.forEach(view => view.setTextHtmlOverlay(undefined, undefined)); DocumentManager._overlayViews?.clear(); } static _overlayViews = new ObservableSet<DocumentView>(); @@ -233,11 +209,25 @@ export class DocumentManager { finished?.(); }; + public static LinkCommonAncestor(linkDoc: Doc) { + const anchor = (which: number) => { + const anch = DocCast(linkDoc['link_anchor_' + which]); + const anchor = anch?.layout_unrendered ? DocCast(anch.annotationOn) : anch; + return DocumentManager.Instance.getDocumentView(anchor); + }; + const anchor1 = anchor(1); + const anchor2 = anchor(2); + return anchor1 + ?.docViewPath() + .reverse() + .find(ancestor => anchor2?.docViewPath().includes(ancestor)); + } + // shows a documentView by: // traverses down through the viewPath of contexts to the view: // focusing on each context - public showDocumentView = async (targetDocView: DocumentView, options: DocFocusOptions) => { - const docViewPath = targetDocView.docViewPath.slice(); + public showDocumentView = async (targetDocView: DocumentView, options: FocusViewOptions) => { + const docViewPath = [...(targetDocView.containerViewPath?.() ?? []), targetDocView]; let rootContextView = docViewPath.shift(); await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined, focused: false }))); if (options.toggleTarget && (!options.didMove || targetDocView.Document.hidden)) targetDocView.Document.hidden = !targetDocView.Document.hidden; @@ -252,12 +242,17 @@ export class DocumentManager { // and finally restoring the targetDoc to the viewSpec specified by the last document which may either be the targetDoc, or a viewSpec that describes the targetDoc configuration public showDocument = async ( targetDoc: Doc, // document to display - options: DocFocusOptions, // options for how to navigate to target + options: FocusViewOptions, // options for how to navigate to target finished?: (changed: boolean) => void // func called after focusing on target with flag indicating whether anything needed to be done. ) => { Doc.RemoveDocFromList(Doc.MyRecentlyClosed, undefined, targetDoc); const docContextPath = DocumentManager.GetContextPath(targetDoc, true); if (docContextPath.some(doc => doc.hidden)) options.toggleTarget = false; + const tabView = Array.from(TabDocView._allTabs).find(view => view._document === docContextPath[0]); + if (!tabView?._activated && tabView?._document) { + options.toggleTarget = false; + TabDocView.Activate(tabView?._document); + } let rootContextView = docContextPath.length && (await new Promise<DocumentView>(res => { @@ -274,7 +269,7 @@ export class DocumentManager { // even if we found the document view, if the target is a lightbox, we try to open it in the lightbox to preserve lightbox semantics (eg, there's only one active doc in the lightbox) const target = DocCast(targetDoc.annotationOn, targetDoc); const contextView = this.getDocumentView(DocCast(target.embedContainer)); - if (contextView?.docView?._componentView?.addDocTab?.(target, OpenWhere.lightbox)) { + if (contextView?.ComponentView?.addDocTab?.(target, OpenWhere.lightbox)) { await new Promise<void>(waitres => setTimeout(() => waitres())); } } @@ -293,7 +288,7 @@ export class DocumentManager { focusViewsInPath = async ( docView: DocumentView, // - options: DocFocusOptions, + options: FocusViewOptions, iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt<Doc>; childDocView: Opt<DocumentView>; focused: boolean }> ) => { let contextView: DocumentView | undefined; // view containing context that contains target @@ -313,7 +308,7 @@ export class DocumentManager { }; @action - restoreDocView(viewSpec: Opt<Doc>, docView: DocumentView, options: DocFocusOptions, contextView: Opt<DocumentView>, targetDoc: Doc) { + restoreDocView(viewSpec: Opt<Doc>, docView: DocumentView, options: FocusViewOptions, contextView: Opt<DocumentView>, targetDoc: Doc) { if (viewSpec && docView) { //if (docView.ComponentView instanceof FormattedTextBox) //viewSpec !== docView.Document && @@ -327,24 +322,21 @@ export class DocumentManager { if (options.zoomTextSelections && Doc.UnhighlightTimer && contextView && targetDoc.text_html) { // if the docView is a text anchor, the contextView is the PDF/Web/Text doc - contextView.htmlOverlayEffect = options.effect; - contextView.textHtmlOverlayTime = options.zoomTime; - contextView.textHtmlOverlay = StrCast(targetDoc.text_html); + contextView.setTextHtmlOverlay(StrCast(targetDoc.text_html), options.effect); DocumentManager._overlayViews.add(contextView); } Doc.AddUnHighlightWatcher(() => { docView.Document[Animation] = undefined; DocumentManager.removeOverlayViews(); - contextView && (contextView.htmlOverlayEffect = undefined); }); } } } -export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) { +export function DocFocusOrOpen(doc: Doc, options: FocusViewOptions = { willZoomCentered: true, zoomScale: 0, openLocation: OpenWhere.toggleRight }, containingDoc?: Doc) { const func = () => { const cv = DocumentManager.Instance.getDocumentView(containingDoc); const dv = DocumentManager.Instance.getDocumentView(doc, cv); - if (dv && (!containingDoc || dv._props.docViewPath().lastElement()?.Document === containingDoc)) { + if (dv && (!containingDoc || dv.containerViewPath?.().lastElement()?.Document === containingDoc)) { DocumentManager.Instance.showDocumentView(dv, options).then(() => dv && Doc.linkFollowHighlight(dv.Document)); } else { const container = DocCast(containingDoc ?? doc.embedContainer ?? Doc.BestEmbedding(doc)); @@ -357,8 +349,8 @@ export function DocFocusOrOpen(doc: Doc, options: DocFocusOptions = { willZoomCe }); } }; - if (Doc.IsDataProto(doc) && DocListCast(doc.proto_embeddings).some(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))) { - doc = DocListCast(doc.proto_embeddings).find(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))!; + if (Doc.IsDataProto(doc) && Doc.GetEmbeddings(doc).some(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))) { + doc = Doc.GetEmbeddings(doc).find(embed => embed.hidden && [AclAdmin, AclEdit].includes(GetEffectiveAcl(embed)))!; } if (doc.hidden) { doc.hidden = false; |