71 lines
2.4 KiB
JavaScript
71 lines
2.4 KiB
JavaScript
"use strict";
|
|
|
|
/** Coordinate CMap routes, parent contexts and browser-history state. */
|
|
export class CmapNavigationController {
|
|
constructor({ navigateToHash, cmapRoute, getEditor, getCurrentMap,
|
|
getParentMap, storage, historyObject = window.history, locationObject = window.location }) {
|
|
this.navigateToHash = navigateToHash;
|
|
this.cmapRoute = cmapRoute;
|
|
this.getEditor = getEditor;
|
|
this.getCurrentMap = getCurrentMap;
|
|
this.getParentMap = getParentMap;
|
|
this.storage = storage;
|
|
this.history = historyObject;
|
|
this.location = locationObject;
|
|
}
|
|
|
|
/** Open a stored CMap through the central hash-navigation contract. */
|
|
open(slug) {
|
|
return this.navigateToHash(this.cmapRoute(slug));
|
|
}
|
|
|
|
/** Remember the active separate-submap root before following a linked CMap. */
|
|
openLinked(record) {
|
|
if (!record?.cmapSlug) return false;
|
|
this.rememberContext();
|
|
this.open(record.cmapSlug).catch((error) => console.error(error));
|
|
return true;
|
|
}
|
|
|
|
/** Return to a source CMap when present, otherwise leave one inline submap level. */
|
|
openParent() {
|
|
const source = this.getParentMap();
|
|
if (source?.slug) {
|
|
this.open(source.slug).catch((error) => console.error(error));
|
|
return true;
|
|
}
|
|
const editor = this.getEditor();
|
|
return Boolean(editor?.openParentMap());
|
|
}
|
|
|
|
requestTransition(action) {
|
|
return this.storage.requestTransition(action);
|
|
}
|
|
|
|
/** Store the active separate-submap context in the current browser history entry. */
|
|
rememberContext() {
|
|
const editor = this.getEditor();
|
|
const current = this.getCurrentMap();
|
|
const root = editor?.activeMapRoot;
|
|
if (!current?.slug || !root) return;
|
|
this.history.replaceState({ ...this.history.state, cmapContext: {
|
|
mapSlug: current.slug,
|
|
rootItemId: Number(root.id)
|
|
} }, "", this.location.href);
|
|
}
|
|
|
|
/**
|
|
* Restore a remembered separate-submap root after browser navigation.
|
|
* post : A consumed context is removed from history state to prevent repeated restoration.
|
|
*/
|
|
async restoreContext(slug) {
|
|
const context = this.history.state?.cmapContext;
|
|
if (!context || context.mapSlug !== slug) return false;
|
|
const editor = this.getEditor();
|
|
const root = editor?.itemRecord(context.rootItemId);
|
|
if (root?.kind === "submap" && root.separateMap) editor.openSubmapMap(root);
|
|
this.history.replaceState({ ...this.history.state, cmapContext: null }, "", this.location.href);
|
|
return true;
|
|
}
|
|
}
|