Code Modules — Docs

Nav Module

Nav Module

Overview of Nav Module

Nav Module — Overview Diagram

Not full width? Right click and open the diagram in a new tab to enlarge it.

The Nav Module is easily the most complex in the Sample Website, making this diagram a bit hard to follow. The diagram, as twisted as it is, doesn’t try to capture the different templates used to deliver navigation as a navbar, a linked list, or a flat set of divs.

Screenshot of 404 Page from the Sample Website.

Screenshot of the 404 Page on the Sample Website. Navigation is used in the top navbar and, on this page, in a set of nested links.

The Nav module returns the markup necessary for both desktop and mobile navigation, if they are different. There’s usually navigation near the top of the page and, sometimes, in the footer. The same content requires different markup in different places.

In some use cases, the navigation module can be made to interrogate other modules (i.e. the Blog module) and update automatically when items are added or removed from the other module. The Sample Website demonstrates this feature for both Blog posts and Portfolio items. The maintainer can add a new blog post to the Blog module or a new portfolio item to the high-level-modules module, and, after the next build, the new items will automatically be included in the site’s navigation.

Nav modules tend to become more complex than a normal Markup module. They often use recursion for secondary menus. The example that follows is quite complicated because of this Nav module’s unique requirements.

Fake It Until You Make It

One approach to beginning with Nav modules — or Markup modules generally — is to stuff the desired code whole into the template file. So you might markup the navbar and stick it whole into the appropriate template. Refactoring the Nav module later could split the code using Code Module’s lists, items, and types that make the module flexible and maintainable.

Problem

The Nav module on the Sample Website needs to support three different markup approaches: a Bootstrap header navbar, a flattened group of <a> tags for the Sidebar page, and a nested list of <li> tags for the 404 page.

Additionally, a maintainer should be able to add an item to high-level-modules or to the Blog modules and, without touching the Nav module, have that item appear within the navigation in all of its forms.

Desired Markup Results for Navigation

Desired Result for Navbar

This is markup appropriate for the Bootstrap 5 navbar used in the Sample Website.

Desired Markup for Navbar
<!-- Navigation -->
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-dark fixed-top">
<div class="container">
<a class="navbar-brand" href="index.html">
Code Modules — Sample</a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="about.html">
About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="services.html">
Services</a>
</li>
<li class="nav-item">
<a class="nav-link" href="contact.html">
Contact</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownPortfolio" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Portfolio</a>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownPortfolio">
<li>
<a class="dropdown-item" href="portfolio-1-col.html">
1 Column Portfolio</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-2-col.html">
2 Column Portfolio</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-3-col.html">
3 Column Portfolio</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-4-col.html">
4 Column Portfolio</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item" href="portfolio-markup.html">
Markup Modules</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-page.html">
Page Module</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-nav.html">
Nav Module</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-elements.html">
Elements Module</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-tech.html">
Tech Module</a>
</li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownBlog" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Blog</a>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownBlog">
<li>
<a class="dropdown-item" href="blog-home-1.html">
Blog Home 1</a>
</li>
<li>
<a class="dropdown-item" href="blog-home-2.html">
Blog Home 2</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item" href="blog-sausages.html">
Sausages</a>
</li>
<li>
<a class="dropdown-item" href="blog-buns.html">
Buns</a>
</li>
<li>
<a class="dropdown-item" href="blog-toppings.html">
Toppings</a>
</li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownOther" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Other Pages</a>
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownOther">
<li>
<a class="dropdown-item" href="404.html">
404</a>
</li>
<li>
<a class="dropdown-item" href="faq.html">
FAQ</a>
</li>
<li>
<a class="dropdown-item" href="full-width.html">
Full Width Page</a>
</li>
<li>
<a class="dropdown-item" href="pricing.html">
Pricing Table</a>
</li>
<li>
<a class="dropdown-item" href="sidebar.html">
Sidebar Page</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>

Desired Result for Sidebar Page

The Sidebar page needs a flattened group of <a> tags.

Desired Markup for Sidebar Page
<div class="list-group">
<a class="list-group-item" href="index.html">
Home</a>
<a class="list-group-item" href="about.html">
About</a>
<a class="list-group-item" href="services.html">
Services</a>
<a class="list-group-item" href="contact.html">
Contact</a>
<a class="list-group-item" href="portfolio-1-col.html">
1 Column Portfolio</a>
<a class="list-group-item" href="portfolio-2-col.html">
2 Column Portfolio</a>
<a class="list-group-item" href="portfolio-3-col.html">
3 Column Portfolio</a>
<a class="list-group-item" href="portfolio-4-col.html">
4 Column Portfolio</a>
<a class="list-group-item" href="portfolio-markup.html">
Markup Modules</a>
<a class="list-group-item" href="portfolio-page.html">
Page Module</a>
<a class="list-group-item" href="portfolio-nav.html">
Nav Module</a>
<a class="list-group-item" href="portfolio-elements.html">
Elements Module</a>
<a class="list-group-item" href="portfolio-tech.html">
Tech Module</a>
<a class="list-group-item" href="blog-home-1.html">
Blog Home 1</a>
<a class="list-group-item" href="blog-home-2.html">
Blog Home 2</a>
<a class="list-group-item" href="blog-sausages.html">
Sausages</a>
<a class="list-group-item" href="blog-buns.html">
Buns</a>
<a class="list-group-item" href="blog-toppings.html">
Toppings</a>
<a class="list-group-item" href="404.html">
404</a>
<a class="list-group-item" href="faq.html">
FAQ</a>
<a class="list-group-item" href="full-width.html">
Full Width Page</a>
<a class="list-group-item" href="pricing.html">
Pricing Table</a>
<a class="list-group-item active" href="sidebar.html">
Sidebar Page</a>
</div>
<!-- /.list-group -->

Desired Result for 404 Page

The 404 page needs a nested list of <li> tags.

Desired Markup for 404 Page
<ul>
<li>
<a class="dropdown-item" href="index.html">
Home</a>
</li>
<li>
<a class="dropdown-item" href="about.html">
About</a>
</li>
<li>
<a class="dropdown-item" href="services.html">
Services</a>
</li>
<li>
<a class="dropdown-item" href="contact.html">
Contact</a>
</li>
<li>
Portfolio
<ul>
<li>
<a class="dropdown-item" href="portfolio-1-col.html">
1 Column Portfolio</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-2-col.html">
2 Column Portfolio</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-3-col.html">
3 Column Portfolio</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-4-col.html">
4 Column Portfolio</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-markup.html">
Markup Modules</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-page.html">
Page Module</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-nav.html">
Nav Module</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-elements.html">
Elements Module</a>
</li>
<li>
<a class="dropdown-item" href="portfolio-tech.html">
Tech Module</a>
</li>
</ul>
</li>
<li>
Blog
<ul>
<li>
<a class="dropdown-item" href="blog-home-1.html">
Blog Home 1</a>
</li>
<li>
<a class="dropdown-item" href="blog-home-2.html">
Blog Home 2</a>
</li>
<li>
<a class="dropdown-item" href="blog-sausages.html">
Sausages</a>
</li>
<li>
<a class="dropdown-item" href="blog-buns.html">
Buns</a>
</li>
<li>
<a class="dropdown-item" href="blog-toppings.html">
Toppings</a>
</li>
</ul>
</li>
<li>
Other Pages
<ul>
<li>
<a class="dropdown-item" href="404.html">
404</a>
</li>
<li>
<a class="dropdown-item" href="faq.html">
FAQ</a>
</li>
<li>
<a class="dropdown-item" href="full-width.html">
Full Width Page</a>
</li>
<li>
<a class="dropdown-item" href="pricing.html">
Pricing Table</a>
</li>
<li>
<a class="dropdown-item" href="sidebar.html">
Sidebar Page</a>
</li>
</ul>
</li>
</ul>

This is a list of the files found in the Nav module.

app/modules/nav/
nav/
├── _notes.txt
├── entry.shtml ① ⑩
├── items/
│ ├── blank.shtml
│ ├── secondary/
│ │ ├── about.shtml ⑥
│ │ ├── blog.shtml
│ │ ├── contact.shtml
│ │ ├── home.shtml
│ │ ├── other.shtml ⑧
│ │ ├── portfolio.shtml
│ │ └── services.shtml
│ └── tertiary/
│ ├── blog/
│ │ ├── all-posts.shtml
│ │ ├── home-1.shtml
│ │ └── home-2.shtml
│ ├── other/
│ │ ├── 404.shtml
│ │ ├── faq.shtml
│ │ ├── full-width-page.shtml
│ │ ├── pricing-table.shtml
│ │ └── sidebar-page.shtml ⑬
│ └── portfolio/
│ ├── 1-column.shtml
│ ├── 2-column.shtml
│ ├── 3-column.shtml
│ ├── 4-column.shtml
│ └── all-posts.shtml
├── lists/
│ ├── blog.shtml
│ ├── default-with-home.shtml
│ ├── default.shtml ⑤
│ ├── other.shtml ⑫
│ └── portfolio.shtml
├── templates/
│ ├── default.shtml ②
│ ├── div-links.shtml
│ ├── dropdown-single.shtml
│ ├── dropdown.shtml ⑪
│ ├── parts/
│ │ ├── bottom.shtml ④
│ │ └── top.shtml ③
│ └── ul-links.shtml
└── types/
├── all-blog-posts.shtml
├── all-portfolio-items.shtml
├── dropdown-bare-link.shtml
├── dropdown-divider.shtml
├── dropdown-item-ul.shtml
├── dropdown-item.shtml ⑭
├── dropdown-ul.shtml
├── dropdown.shtml ⑨
├── null.shtml
├── simple-bare.shtml
├── simple-ul.shtml
└── simple.shtml ⑦

Individual Nav Module Files

entry file ① ⑩

app/modules/nav/entry.shtml
1<!-- #bbinclude "/#MODULE#/templates/#TEMPLATE#.shtml"
2#bbincludeoptions#="inline=true"
3#MODULE# = "nav"
4-->
5<!-- end bbinclude -->

Default Template ②

app/modules/nav/templates/default.shtml
1#bbinclude "parts/top.shtml"
2<!-- #bbinclude "/#MODULE#/lists/default.shtml"
3#bbincludeoptions#="inline=true"
4#DROPDOWN-TYPE# = 'dropdown'
5#DROPDOWN-ITEM-TYPE# = 'dropdown-item'
6-->
7<!-- end bbinclude -->
8#bbinclude "parts/bottom.shtml"
parts/top ③
app/modules/nav/templates/parts/top.shtml
1<!-- Navigation -->
2<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-dark fixed-top">
3 <div class="container">
4 <a class="navbar-brand" href="index.html">
5 #NAV-NAME#</a>
6 <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
7 <span class="navbar-toggler-icon"></span>
8 </button>
9 <div class="collapse navbar-collapse" id="navbarResponsive">
10 <ul class="navbar-nav ml-auto">

The #NAV-NAME# variable is a global defined in the app/modules/pages/entry.shtml file.

parts/bottom ④
app/modules/nav/templates/parts/bottom.shtml
1</ul>
2 </div>
3 </div>
4</nav>

In this example, the template top and bottom parts don’t have to be separate files. They could be added to the default.shtml template file itself. It’s a question of taste.

lists/default ⑤

app/modules/nav/lists/default.shtml
1#bbinclude "/#MODULE#/items/secondary/about.shtml"
2#bbinclude "/#MODULE#/items/secondary/services.shtml"
3#bbinclude "/#MODULE#/items/secondary/contact.shtml"
4#bbinclude "/#MODULE#/items/secondary/portfolio.shtml"
5#bbinclude "/#MODULE#/items/secondary/blog.shtml"
6#bbinclude "/#MODULE#/items/secondary/other.shtml"

Items ⑥

The about page navigation item is just a simple link as opposed to a dropdown link. But the #SIMPLE-TYPE# variable is defined elsewhere because simple links need different markup depending on where they are going to be used.

app/modules/nav/items/secondary/about.shtml
1<!-- #bbinclude "/#MODULE#/types/#SIMPLE-TYPE#.shtml"
2#bbincludeoptions#="inline=true"
3#URL# = 'about.html'
4#TEXT# = 'About'
5-->
6<!-- end bbinclude -->

Types ⑦

app/modules/nav/types/simple.shtml
1<li class="nav-item">
2 <a class="nav-link" href="#URL#">
3 #TEXT#</a>
4</li>

The Other page navigation item requires a dropdown. The dropdown has a secondary item and then a series of tertiary items. We can use recursion through the Nav module to get that dropdown list.

Secondary Nav Item — Other ⑧

Note the call is to types/#DROPDOWN-TYPE#.shtml. The #DROPDOWN-TYPE# variable is provided by the calling template — by default, its value is “dropdown”. The “other” list contains the tertiary nav items under the dropdown.

app/modules/nav/items/secondary/other.shtml
1<!-- #bbinclude "/#MODULE#/types/#DROPDOWN-TYPE#.shtml"
2#bbincludeoptions#="inline=true"
3#URL# = '#'
4#TEXT# = 'Other Pages'
5#IDPART# = 'Other'
6#LIST# = 'other'
7-->
8<!-- end bbinclude -->

Types — dropdown.shtml — Calls Nav Module Recursively Using Dropdown Template ⑨

app/modules/nav/types/dropdown.shtml
1<li class="nav-item dropdown">
2 <a class="nav-link dropdown-toggle" href="#URL#" id="navbarDropdown#IDPART#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
3 #TEXT#</a>
4 <ul class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdown#IDPART#">
5<!-- #bbinclude "/nav/entry.shtml"
6#bbincludeoptions#="inline=true"
7#TEMPLATE# = 'dropdown'
8#LIST# = #LIST#
9-->
10<!-- end bbinclude -->
11 </ul>
12</li>

Template — dropdown.shtml — Only for a Single Dropdown ⑪

The #LIST# is defined by the calling file or previously in the chain. In this example, its value is “other”.

app/modules/nav/types/dropdown.shtml
1#bbinclude "/#MODULE#/lists/#LIST#.shtml"
app/modules/nav/lists/other.shtml
1#bbinclude "/#MODULE#/items/tertiary/other/404.shtml"
2#bbinclude "/#MODULE#/items/tertiary/other/faq.shtml"
3#bbinclude "/#MODULE#/items/tertiary/other/full-width-page.shtml"
4#bbinclude "/#MODULE#/items/tertiary/other/pricing-table.shtml"
5#bbinclude "/#MODULE#/items/tertiary/other/sidebar-page.shtml"

Tertiary Nav Item — Sidebar Page ⑬

The #DROPDOWN-ITEM-TYPE# variable, that this item calls, was defined as “dropdown-item” earlier in the chain of calls. Note that #COMMENT# can be used for inline documentation. Each of those tertiary items looks similar to a simple nav link.

app/modules/nav/items/tertiary/other/sidebar-page.shtml
1<!-- #bbinclude "/#MODULE#/types/#DROPDOWN-ITEM-TYPE#.shtml"
2#bbincludeoptions#="inline=true"
3#URL# = 'sidebar.html'
4#TEXT# = 'Sidebar Page'
5#ACTIVE-CLASS# = ' active'
6#COMMENT# = 'Active class only used for type simple-bare which is only used on the sidebar page.'
7-->
8<!-- end bbinclude -->

Tertiary Nav Type — Dropdown Item ⑭

app/modules/nav/types/dropdown-item.shtml
1<li>
2 <a class="dropdown-item" href="#URL#">
3 #TEXT#</a>
4</li>

Interrogating Blog Module for Recent Posts

Tertiary Nav Item — All (Recent) Blog Posts

app/modules/nav/items/tertiary/blog/all-posts.shtml
1#bbinclude "/#MODULE#/types/all-blog-posts.shtml"

Tertiary Nav Type — All (Recent) Blog Posts

The Type file interrogates the Blog module using the nav template. The #DROPDOWN-DIVIDER# variable is either “dropdown-divider” which inserts an <hr> tag for the navbar, or “null” which inserts nothing for the other navigation markup variations.

app/modules/nav/types/all-blog-posts.shtml
1#bbinclude "#DROPDOWN-DIVIDER#.shtml"
2<!-- #bbinclude "/markup/blog/entry.shtml"
3#bbincludeoptions#="inline=true"
4#TEMPLATE# = 'nav'
5-->
6<!-- end bbinclude -->

Inside the Blog module, the nav template uses the “recent” list to construct and return appropriate markup.

Almost the same thing is done to get the “Portfolio” items which appear in navigation from the high-level-modules markup module.