« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/static/js/client/hash-link.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/static/js/client/hash-link.js')
-rw-r--r--src/static/js/client/hash-link.js58
1 files changed, 57 insertions, 1 deletions
diff --git a/src/static/js/client/hash-link.js b/src/static/js/client/hash-link.js
index 27035e29..e82e06c5 100644
--- a/src/static/js/client/hash-link.js
+++ b/src/static/js/client/hash-link.js
@@ -1,6 +1,7 @@
 /* eslint-env browser */
 
-import {filterMultipleArrays, stitchArrays} from '../../shared-util/sugar.js';
+import {filterMultipleArrays, stitchArrays, unique}
+  from '../../shared-util/sugar.js';
 
 import {dispatchInternalEvent} from '../client-util.js';
 
@@ -11,6 +12,9 @@ export const info = {
   hrefs: null,
   targets: null,
 
+  details: null,
+  detailsIDs: null,
+
   state: {
     highlightedTarget: null,
     scrollingAfterClick: false,
@@ -40,6 +44,19 @@ export function getPageReferences() {
     info.hrefs,
     info.targets,
     (_link, _href, target) => target);
+
+  info.details =
+    unique([
+      ...document.querySelectorAll('details[id]'),
+      ...
+        Array.from(document.querySelectorAll('summary[id]'))
+          .map(summary => summary.closest('details')),
+    ]);
+
+  info.detailsIDs =
+    info.details.map(details =>
+      details.id ||
+      details.querySelector('summary').id);
 }
 
 function processScrollingAfterHashLinkClicked() {
@@ -60,6 +77,15 @@ function processScrollingAfterHashLinkClicked() {
   }, 200);
 }
 
+export function mutatePageContent() {
+  if (location.hash.length > 1) {
+    const target = document.getElementById(location.hash.slice(1));
+    if (target) {
+      expandDetails(target);
+    }
+  }
+}
+
 export function addPageListeners() {
   // Instead of defining a scroll offset (to account for the sticky heading)
   // in JavaScript, we interface with the CSS property 'scroll-margin-top'.
@@ -94,6 +120,8 @@ export function addPageListeners() {
         return;
       }
 
+      expandDetails(target);
+
       // Hide skipper box right away, so the layout is updated on time for the
       // math operations coming up next.
       const skipper = document.getElementById('skippers');
@@ -143,4 +171,32 @@ export function addPageListeners() {
       state.highlightedTarget = null;
     });
   }
+
+  stitchArrays({
+    details: info.details,
+    id: info.detailsIDs,
+  }).forEach(({details, id}) => {
+      details.addEventListener('toggle', () => {
+        if (!details.open) {
+          detractHash(id);
+        }
+      });
+    });
+}
+
+function expandDetails(target) {
+  if (target.nodeName === 'SUMMARY') {
+    const details = target.closest('details');
+    if (details) {
+      details.open = true;
+    }
+  } else if (target.nodeName === 'DETAILS') {
+    details.open = true;
+  }
+}
+
+function detractHash(id) {
+  if (location.hash === '#' + id) {
+    history.pushState({}, undefined, location.href.replace(/#.*$/, ''));
+  }
 }