aboutsummaryrefslogtreecommitdiff
path: root/src/client/util/DocumentManager.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util/DocumentManager.ts')
-rw-r--r--src/client/util/DocumentManager.ts104
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;