PageSourceSearch

https://pressthink.org/j/rosen-archive/frontend/services/router.js?v=3.8.36

js pressthink.org collected 2026-10-02 04:26:10 UTC 3,570 bytes, 103 lines download raw bytes

1// Hash-based router for the archive SPA: the window-touching navigation layer.
2//
3// The route vocabulary (ROUTES / DEFAULT_ROUTE) is owned by viewState.js, the
4// single source of truth for view state called for in issue #133. This module
5// imports it rather than keeping a second copy — two hand-maintained ROUTES
6// objects could silently drift — and re-exports ROUTES so existing importers
7// (App.js) keep working unchanged. The pure URL serialisation lives in
8// viewState.js too; what remains here is the imperative, window-bound
9// navigation helpers.
10
11import { ROUTES, DEFAULT_ROUTE, parseViewState } from './viewState.js?v=3.8.36';
12import { parseRecordId, setRecordParam } from '../utils/recordDeepLink.js?v=3.8.36';
13
14export { ROUTES };
15
16/**
17 * Read the current hash and return the matching route name.
18 * Falls back to 'archive' for unknown or empty hashes.
19 */
20export function getCurrentRoute() {
21  return parseViewState(window.location.href).route || DEFAULT_ROUTE;
22}
23
24/**
25 * Read the optional in-shell desktop app id from the current URL.
26 */
27export function getDesktopAppIdFromUrl() {
28  const state = parseViewState(window.location.href);
29  return state.route === ROUTES.desktop ? state.routeParams.desktopAppId || null : null;
30}
31
32/**
33 * Read the optional selected entity from a canonical entity route.
34 */
35export function getEntityIdFromUrl() {
36  return parseViewState(window.location.href).routeParams.entityId || null;
37}
38
39/**
40 * Navigate to a route by updating the hash.
41 * Optionally sets a ?record=ID query parameter and canonical entity context.
42 */
43export function navigateTo(route, recordId, entityId) {
44  const url = new URL(window.location.href);
45
46  // Clean up legacy query params
47  url.searchParams.delete('view');
48  if (route === ROUTES.entities && entityId !== undefined) {
49    if (/^[A-Za-z0-9_.:-]+$/.test(entityId || '')) url.searchParams.set('entity', entityId);
50    else url.searchParams.delete('entity');
51  } else if (route !== ROUTES.entities) {
52    url.searchParams.delete('entity');
53  }
54
55  setRecordParam(url.searchParams, recordId);
56
57  url.hash = route === DEFAULT_ROUTE ? '' : route;
58  window.history.pushState({}, '', url);
59  window.dispatchEvent(new HashChangeEvent('hashchange'));
60}
61
62/**
63 * Navigate within the desktop shell while keeping the app id in the hash.
64 */
65export function navigateToDesktop(appId = null, entityId) {
66  if (appId !== null && (
67    typeof appId !== 'string' || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(appId)
68  )) {
69    throw new TypeError('Desktop app id must be a lowercase URL-safe id');
70  }
71
72  const url = new URL(window.location.href);
73  url.searchParams.delete('view');
74  if (appId === 'entities' && entityId !== undefined) {
75    if (/^[A-Za-z0-9_.:-]+$/.test(entityId || '')) url.searchParams.set('entity', entityId);
76    else url.searchParams.delete('entity');
77  } else if (appId !== 'entities') {
78    url.searchParams.delete('entity');
79  }
80  setRecordParam(url.searchParams, null);
81  url.hash = appId ? `${ROUTES.desktop}/${appId}` : ROUTES.desktop;
82  window.history.pushState({}, '', url);
83  window.dispatchEvent(new HashChangeEvent('hashchange'));
84}
85
86/**
87 * Read ?record= from the current URL.
88 */
89export function getRecordIdFromUrl() {
90  return parseRecordId(window.location.search);
91}
92
93/**
94 * Migrate legacy ?view= URLs to hash routes.
95 * Call once on app init.
96 */
97export function migrateLegacyUrl() {
98  const params = new URLSearchParams(window.location.search);
99  const view = params.get('view');
100  if (view === 'dissertation' || view === 'about') {
101    navigateTo(ROUTES[view]);
102  }
103}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.