select nav item on hash change (and initial page load)
authorDan Allen <dan@opendevise.com>
Mon, 30 Mar 2020 00:05:58 +0000 (18:05 -0600)
committerDan Allen <dan@opendevise.com>
Mon, 30 Mar 2020 06:21:28 +0000 (00:21 -0600)
- select nav item that points to anchor when hash in window.location changes (or present at initial page load)
- if nav item is not found, but points to a parent of the fragment, select that nav item

preview-src/index.adoc
preview-src/ui-model.yml
src/js/01-nav.js

index d07cf0f..5cc1df7 100644 (file)
@@ -49,6 +49,8 @@ This is an example paragraph.
 [example]
 This is an example paragraph.
 
+=== Some Code
+
 How about some code?
 
 [source,js]
index 87628bc..5cf85ba 100644 (file)
@@ -96,9 +96,12 @@ page:
       - content: Brand&#8217;s Hardware &amp; Software Requirements
         url: /xyz/5.2/index.html
         urlType: internal
-      - content: IDE Integration
-        url: '#'
-        urlType: fragment
+      - content: Cu Solet
+        url: '/xyz/5.2/index.html#cu-solet'
+        urlType: internal
+      - content: English + 中文
+        url: '/xyz/5.2/index.html#english+中文'
+        urlType: internal
     - content: Liber Recusabo
       url: '#liber-recusabo'
       urlType: fragment
index 3d1a8a7..c73a808 100644 (file)
@@ -1,6 +1,8 @@
 ;(function () {
   'use strict'
 
+  var SECT_CLASS_RX = /^sect(\d)$/
+
   var navContainer = document.querySelector('.nav-container')
   var navToggle = document.querySelector('.nav-toggle')
 
@@ -13,6 +15,7 @@
   var nav = navContainer.querySelector('.nav')
 
   var currentPageItem = menuPanel.querySelector('.is-current-page')
+  var originalPageItem = currentPageItem
   if (currentPageItem) {
     activateCurrentPath(currentPageItem)
     scrollItemToMidpoint(menuPanel, currentPageItem.querySelector('.nav-link'))
     if (e.detail > 1) e.preventDefault()
   })
 
+  function onHashChange () {
+    var navLink
+    var hash = window.location.hash
+    if (hash) {
+      if (hash.indexOf('%')) hash = decodeURIComponent(hash)
+      navLink = menuPanel.querySelector('.nav-link[href="' + hash + '"]')
+      if (!navLink) {
+        var targetNode = document.getElementById(hash.slice(1))
+        if (targetNode) {
+          var current = targetNode
+          var ceiling = document.querySelector('article.doc')
+          while ((current = current.parentNode) && current !== ceiling) {
+            var id = current.id
+            // NOTE: look for section heading
+            if (!id && (id = current.className.match(SECT_CLASS_RX))) id = (current.firstElementChild || {}).id
+            if (id && (navLink = menuPanel.querySelector('.nav-link[href="#' + id + '"]'))) break
+          }
+        }
+      }
+    }
+    var navItem
+    if (navLink) {
+      navItem = navLink.parentNode
+    } else if (originalPageItem) {
+      navLink = (navItem = originalPageItem).querySelector('.nav-link')
+    } else {
+      return
+    }
+    if (navItem === currentPageItem) return
+    find(menuPanel, '.nav-item.is-active').forEach(function (el) {
+      el.classList.remove('is-active', 'is-current-path', 'is-current-page')
+    })
+    navItem.classList.add('is-current-page')
+    currentPageItem = navItem
+    activateCurrentPath(navItem)
+    scrollItemToMidpoint(menuPanel, navLink)
+  }
+
+  if (menuPanel.querySelector('.nav-link[href^="#"]')) {
+    if (window.location.hash) onHashChange()
+    window.addEventListener('hashchange', onHashChange)
+  }
+
   function activateCurrentPath (navItem) {
     var ancestorClasses
     var ancestor = navItem.parentNode
   }
 
   function findNextElement (from, selector) {
-    var el
-    if ('nextElementSibling' in from) {
-      el = from.nextElementSibling
-    } else {
-      el = from
-      while ((el = el.nextSibling) && el.nodeType !== 1);
-    }
-    return el && selector ? el[el.matches ? 'matches' : 'msMatchesSelector'](selector) && el : el
+    var el = from.nextElementSibling
+    if (!el) return
+    return selector ? el[el.matches ? 'matches' : 'msMatchesSelector'](selector) && el : el
   }
 })()