Move navigation from _menu.json files in each navigation-parent directory to a naviga...
[ndcode_site.git] / _lib / navbar.jst
index 02bbab5..318c6f1 100644 (file)
@@ -1,6 +1,10 @@
 let assert = require('assert')
 let XDate = require('xdate')
 
+let arrays_equal =
+  (a, b) =>
+    a.length === b.length && a.every((value, index) => value === b[index])
 return async (env, head, body, scripts) => {
   //let cart = await _require('/online_store/cart.jst')
   let fa_arrow_circle_left = await env.site.get_min_svg('/_svg/fa_arrow-circle-left.svg')
@@ -13,26 +17,52 @@ return async (env, head, body, scripts) => {
   let icon_cross = await env.site.get_min_svg('/_svg/icon_cross.svg')
   //let icon_tick = await env.site.get_min_svg('/_svg/icon_tick.svg')
   let logo_large = await env.site.get_min_svg('/_svg/logo_large.svg')
-  let menu = await env.site.get_menu('/_menu.json')
   let page = await _require('/_lib/page.jst')
 
   // initialize env.cart
   //await cart(env)
 
+  // compute breadcrumbs from directories of the path
+  let component_names = env.parsed_url.pathname.split('/')
+  assert(component_names.length >= 2)
+  assert(component_names[0].length === 0)
+  assert(component_names[component_names.length - 1].length)
+  component_names = component_names.slice(1, -1)
+
   let transaction = await env.site.database.Transaction()
   let signed_in_as
   let site_title, copyright
+  let component_titles // collects breadcrumb titles for current page
+  let menu_names, menu_titles // collects top level of menu for the navbar
   let feedback_draft
   try {
-    let root = await transaction.get({})
+    let root = await transaction.get()
 
     let session = await get_session(env, root)
     signed_in_as = await session.get_json('signed_in_as')
 
-    let globals = await root.get('globals', {})
+    let globals = await root.get('globals')
     site_title = await globals.get_json('site_title')
     copyright = await globals.get_json('copyright')
 
+    let navigation = await root.get('navigation')
+
+    let p = navigation
+    component_titles = [await p.get_json('title')] // Home
+    for (let i = 0; i < component_names.length; ++i) {
+      let children = await p.get('children')
+      p = await children.get(component_names[i])
+      component_titles.push(await p.get_json('title'))
+    }
+
+    menu_names = await navigation.get_json('menu')
+    let children = await navigation.get('children')
+    menu_titles = [await navigation.get_json('title')] // Home
+    for (let i = 0; i < menu_names.length; ++i) {
+      let child = await children.get(menu_names[i])
+      menu_titles.push(await child.get('title'))
+    }
+
     feedback_draft = await session.get_json('feedback_draft')
     if (feedback_draft === undefined || env.now >= feedback_draft.expires)
       feedback_draft = null
@@ -41,21 +71,32 @@ return async (env, head, body, scripts) => {
     transaction.rollback()
   }
 
+  // save breadcrumbs and their titles for breadcrumbs.jst
+  // note: component_titles.length === component_names.length + 1
+  // component_titles[0] corresponds to /, is 'Home' or similar
+  // component_titles[i] corresponds to component_names[i - 1], i >= 1
+  env.component_names = component_names
+  env.component_titles = component_titles
+  console.log('cn', component_names)
+  console.log('ct', component_titles)
+
+  // note: menu_titles.length === menu_names.length + 1
+  // menu_titles[0] corresponds to /, is 'Home' or similar
+  // menu_titles[i] corresponds to menu_names[i - 1], i >= 1a
+  // (navbar has Home appearing at same level as its immediate children)
+  console.log('mn', menu_names)
+  console.log('mt', menu_titles)
+
   await page(
     env,
     // head
     async _out => {
-      // extract top-level directory name
-      assert(env.parsed_url.pathname.slice(0, 1) === '/')
-      let index = env.parsed_url.pathname.indexOf('/', 1)
-      let dir = index === -1 ? '' : env.parsed_url.pathname.slice(1, index)
-
       title {
         `${site_title}: ${
-          dir.length === 0 ?
-            'Home' :
-            menu.entries[menu.index[dir]].name
-          }`
+          component_titles[
+            component_names.length >= 2 ? 1 : component_names.length
+          ]
+        }`
       }
 
       await head(_out)
@@ -139,33 +180,34 @@ return async (env, head, body, scripts) => {
           }
           div.collapse.navbar-collapse#navbarSupportedContent {
             ul.navbar-nav.mr-auto {
-              if (dir.length === 0)
-                li.nav-item.active {
-                  a.nav-link(href="/index.html") {
-                    'Home'
-                    span.sr-only {' (current)'}
-                  }
-                }
-              else
-                li.nav-item {
-                  a.nav-link(href="/index.html") {'Home'}
-                }
-              let entries = menu.entries
-              for (let i = 0; i < entries.length; ++i)
-                if (entries[i].navbar)
-                  if (entries[i].dir === dir)
-                    li.nav-item.active {
-                      a.nav-link(href=`/${entries[i].dir}/index.html`) {
-                        `${entries[i].name}`
-                        span.sr-only {' (current)'}
-                      }
+              // the active entry in the navbar bar is based on which top-level
+              // page we are under, even if we are not directly on that page
+              // but one of its children, this may be unexpected as the active
+              // entry does not highlight on hover, but you can still click it;
+              // we determine here the path to the corresponding top-level page
+              let component_prefix = component_names.slice(0, 1)
+
+              for (let i = 0; i < menu_titles.length; ++i) {
+                // construct path to the top-level page about to be described
+                let menu_prefix =
+                  i == 0 ? [] : [menu_names[i - 1]]
+                let menu_prefix_path =
+                  menu_prefix.map(name => '/' + name).join('') + '/index.html'
+
+                if (arrays_equal(menu_prefix, component_prefix))
+                  li.nav-item.active {
+                    a.nav-link(href=menu_prefix_path) {
+                      `${menu_titles[i]}`
+                      span.sr-only {' (current)'}
                     }
-                  else
-                    li.nav-item {
-                      a.nav-link(href=`/${entries[i].dir}/index.html`) {
-                        `${entries[i].name}`
-                      }
+                  }
+                else
+                  li.nav-item {
+                    a.nav-link(href=menu_prefix_path) {
+                      `${menu_titles[i]}`
                     }
+                  }
+              }
               //li.nav-item.dropdown {
               //  a.nav-link.dropdown-toggle#navbarDropdown(href="#" role="button" data-toggle="dropdown" aria-expanded="false") {
               //    'Dropdown'