diff options
-rw-r--r-- | src/client/util/DocumentManager.ts | 26 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 30 | ||||
-rw-r--r-- | src/client/views/nodes/FieldView.tsx | 3 |
3 files changed, 37 insertions, 22 deletions
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 5a6ce528f..a893fe627 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -18,6 +18,7 @@ import { PresBox } from '../views/nodes/trails'; import { ScriptingGlobals } from './ScriptingGlobals'; import { SelectionManager } from './SelectionManager'; +type childIterator = { viewSpec: Opt<Doc>; childDocView: Opt<DocumentView>; focused: boolean; contextPath: Doc[] }; export class DocumentManager { // eslint-disable-next-line no-use-before-define private static _instance: DocumentManager; @@ -221,7 +222,9 @@ export class DocumentManager { public showDocumentView = async (targetDocView: DocumentView, options: FocusViewOptions) => { const docViewPath = [...(targetDocView.containerViewPath?.() ?? []), targetDocView]; const rootContextView = docViewPath.shift(); - await (rootContextView && this.focusViewsInPath(rootContextView, options, async () => ({ childDocView: docViewPath.shift(), viewSpec: undefined, focused: false }))); + const iterator = () => ({ childDocView: docViewPath.shift(), viewSpec: undefined, focused: false, contextPath: docViewPath.map(dv => dv.Document) }); + options.contextPath = docViewPath.map(dv => dv.Document); + await (rootContextView && this.focusViewsInPath(rootContextView, options, iterator)); if (options.toggleTarget && (!options.didMove || targetDocView.Document.hidden)) targetDocView.Document.hidden = !targetDocView.Document.hidden; else if (options.openLocation?.startsWith(OpenWhere.toggle) && !options.didMove && rootContextView) DocumentViewInternal.addDocTabFunc(rootContextView.Document, options.openLocation); }; @@ -269,14 +272,17 @@ export class DocumentManager { }); } } - docContextPath.shift(); - const childViewIterator = async (docView: DocumentView) => { - const innerDoc = docContextPath.shift(); - const viewSpec = innerDoc?.isGroup ? (docContextPath[0] ?? innerDoc) : innerDoc; - return { focused: false, viewSpec: viewSpec, childDocView: innerDoc && !innerDoc.layout_unrendered ? (await docView.ComponentView?.getView?.(innerDoc, options)) ?? this.getDocumentView(innerDoc) : undefined }; - }; if (rootContextView) { + const childViewIterator = async (docView: DocumentView): Promise<childIterator> => { + const innerDoc = docContextPath.shift(); + const childDocView = innerDoc && !innerDoc.layout_unrendered + ? (await docView.ComponentView?.getView?.(innerDoc, options)) ?? this.getDocumentView(innerDoc): + undefined; // prettier-ignore + return { focused: false, viewSpec: innerDoc, childDocView, contextPath: docContextPath }; + }; + docContextPath.shift(); + options.contextPath = docContextPath; const target = await this.focusViewsInPath(rootContextView, options, childViewIterator); if (target) { this.restoreDocView(target.viewSpec, target.docView, options, target.contextView ?? target.docView, targetDoc); @@ -290,7 +296,7 @@ export class DocumentManager { focusViewsInPath = async ( docViewIn: DocumentView, // optionsIn: FocusViewOptions, - iterator: (docView: DocumentView) => Promise<{ viewSpec: Opt<Doc>; childDocView: Opt<DocumentView>; focused: boolean }> + iterator: (docView: DocumentView) => childIterator | Promise<childIterator> ) => { let contextView: DocumentView | undefined; // view containing context that contains target let focused = false; @@ -311,12 +317,14 @@ export class DocumentManager { const nextFocus = docView._props.focus(anchor, options); // focus the view within its container focused = focused || nextFocus !== undefined; // keep track of whether focusing on a view needed to actually change anything // eslint-disable-next-line no-await-in-loop - const { childDocView, viewSpec } = await iterator(docView); + const { childDocView, viewSpec, contextPath } = await iterator(docView); if (!childDocView) return { viewSpec: viewSpec ?? docView.Document, docView, contextView, focused }; contextView = !childDocView.Document.layout_unrendered ? childDocView : docView; docView = childDocView; anchor = viewSpec ?? docView.Document; + options.contextPath = contextPath; } + options.contextPath = undefined; return undefined; }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8a859a3fd..986c1e357 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -310,7 +310,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection } focusOnPoint = (options: FocusViewOptions) => { - const {pointFocus, zoomTime, didMove} = options; + const { pointFocus, zoomTime, didMove } = options; if (!this.Document.isGroup && pointFocus && !didMove) { const dfltScale = this.isAnnotationOverlay ? 1 : 0.5; if (this.layoutDoc[this.scaleFieldKey] !== dfltScale) { @@ -322,6 +322,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return undefined; }; + /** + * Focusing on a member of a group - + * Since groups can't pan and zoom like regular collections, this method focuses on a Doc in a group by + * focusing on the group with an additional transformation to force the final focus to be on the center of the group item. + * @param anchor + * @param options + * @returns + */ groupFocus = (anchor: Doc, options: FocusViewOptions) => { if (options.pointFocus) return this.focusOnPoint(options); options.docTransform = new Transform(NumCast(anchor.x) + NumCast(anchor._width)/2 - NumCast(this.layoutDoc[this.panXFieldKey]), @@ -331,19 +339,17 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection return res; }; - focus = (anchor: Doc, options: FocusViewOptions) => { + focus = (anchor: Doc, options: FocusViewOptions): any => { + if (anchor.isGroup && !options.docTransform && options.contextPath?.length) { + // don't focus on group if there's a context path because we're about to focus on a group item + // which will override any group focus. (If we allowed the group to focus, it would mark didMove even if there were no net movement) + return undefined; + } if (this._lightboxDoc) return undefined; if (options.pointFocus) return this.focusOnPoint(options); - if (anchor === this.Document) { - // if (options.willZoomCentered && options.zoomScale) { - // this.fitContentOnce(); - // options.didMove = true; - // } - } - // prettier-ignore - if (anchor.type !== DocumentType.CONFIG && - !DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]).includes(anchor) && // - !this.childLayoutPairs.map(pair => pair.layout).includes(anchor)) { + const anchorInCollection = DocListCast(this.Document[this.fieldKey ?? Doc.LayoutFieldKey(this.Document)]).includes(anchor); + const anchorInChildViews = this.childLayoutPairs.map(pair => pair.layout).includes(anchor); + if (anchor.type !== DocumentType.CONFIG && !anchorInCollection && !anchorInChildViews) { return undefined; } const xfToCollection = options?.docTransform ?? Transform.Identity(); diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 52dc632ae..ab0850790 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -30,7 +30,8 @@ export interface FocusViewOptions { zoomTextSelections?: boolean; // whether to display a zoomed overlay of anchor text selections toggleTarget?: boolean; // whether to toggle target on and off easeFunc?: 'linear' | 'ease'; // transition method for scrolling - pointFocus?: {X:number, Y: number }; // clientX and clientY coordinates to focus on instead of a document target (used by explore mode) + pointFocus?: { X: number; Y: number }; // clientX and clientY coordinates to focus on instead of a document target (used by explore mode) + contextPath?: Doc[]; // path of inner documents that will also be focused } export type FocusFuncType = (doc: Doc, options: FocusViewOptions) => Opt<number>; // eslint-disable-next-line no-use-before-define |