In Part 1 and Part 2 of this blog post you learned how to convert a Bootstrap theme into a static SCS theme. In this part you will learn how to create navigation menu that will dynamically include links to pages that you added to your site in the Site Builder.
Step 7: Create dynamic navigation menu
In this step you will use Oracle SCS Render API to replace static navigation menu in the page layout files with the menu that is rendered dynamically to display pages that you added to the ‘ModernBusiness’ site in Step 5.
1. Find HTML code that renders navigation in the Bootstrap theme:
<!-- Navigation --> <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation"> … </nav>
2. Replace it with the HTML snippet below. The <ul> tag has no content. You will dynamically generate HTML that renders list of menu items and add it to this tag using its id=”navbar-list”. Another HTML element that needs to be dynamically updated is the<a id=”navbar-brand”> tag in the “navbar-header” <div> tag
<!-- Navigation --> <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation"> <div class="container"> <!-- brand and toggle get grouped for better mobile display --> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a id="navbar-brand" class="navbar-brand" href="index.html">Modern Business</a></div> <!-- collect the nav links, forms, and other content for toggling --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul id="navbar-list" class="nav navbar-nav navbar-right"> <!-- navigation menu goes in here --></ul> </div> </div> </nav>
3. Add a new JavaScript file to the theme that will include code to render navigation dynamically (e.g. create ModernBusinessTheme (<user_name>)/assets/js/navigation.js) and then add the following <script> tag at the bottom of all page layout files to load this file:
<!-- SCS JS libraries --> <script src="_scs_theme_root_/assets/js/navigation.js"></script> <script data-main="/_sitescloud/renderer/renderer.js" src="/_sitescloud/renderer/require.js"></script>
4. To the navigation.js file you need to add JavaScript to generate HTML for the navigation menu that is similar to that in the original Bootstrap theme, but includes page links that are dynamically generated using Oracle SCS Render API.
5. Open navigation.js file in your favorite editor and add the following code:
// render navigation bar... function renderNavbar() { } // must wait for the script to be ready... if (document.addEventListener) { document.addEventListener('scsrenderstart', renderNavbar, false); } else if (document.attachEvent) { document.documentElement.scsrenderstart = 0; document.documentElement.attachEvent('onpropertychange', function(event) { if (event && (event.propertyName == "scsrenderstart")) { renderNavbar(); } }); }
Note: The above code is required to make sure that the renderNavbar() function is called at the right time during SCS page lifecycle.
6. Now add JavaScript that will generate the same HTML as in the Modern Business theme using SCS Render API to generate menu hierarchy dynamically:
// render navigation bar... function renderNavbar() { var id = SCS.navigationRoot; var linkData, navBrand = $("#navbar-brand"); // add link to Home page... if (navBrand) { linkData = SCSRenderAPI.getPageLinkData(id) || {}; if (linkData.href) { $(navBrand).attr("href", linkData.href); } } // build navigation menu... var navList = $("#navbar-list"); // add Home link... $(navList).append(createNavItem(id)); // top level pages... var curID, nodes = SCS.structureMap[id].children; for (var n = 0; n < nodes.length; n++) { curID = nodes[n]; // skip hidden node... if (isNodeHidden(curID)) continue; // add navigstion node... if ((SCS.structureMap[curID].children.length > 0) && !allNodeChildrenAreHidden(curID)) { // add navigation node with childern nodes... navItem = document.createElement("li"); $(navItem).addClass("dropdown"); navLink = document.createElement("a"); $(navLink).addClass("dropdown-toggle"); $(navLink).attr("href", "#"); $(navLink).attr("data-toggle", "dropdown"); $(navLink).attr("data-hover", "dropdown"); $(navLink).attr("data-delay", "0"); $(navLink).attr("data-close-others", "false"); $(navLink).text(SCS.structureMap[curID].name); // add downarroe top level to activate sub-menu... var navLabel = document.createElement("b"); $(navLabel).addClass("caret"); $(navLink).append(navLabel); $(navItem).append(navLink); // sub-menu... var navSubList = document.createElement("ul"); $(navSubList).addClass("dropdown-menu"); var subnodes = SCS.structureMap[curID].children; for(var sub = 0; sub < subnodes.length; sub++) { if (isNodeHidden(subnodes[sub])) continue; // add item in the sub-level navigation menu... $(navSubList).append(createNavItem(subnodes[sub])); } $(navItem).append(navSubList); } else { // add top level node without children... navItem = createNavItem(curID); } // add to the navigation menu... $(navList).append(navItem); } } // returns <li> tag for a navigation menu entry... function createNavItem(id) { var navItem = document.createElement("li"); if ( id ==SCS.navigationCurr ) $(navItem).addClass("active"); var navLink = document.createElement("a"); var linkData = SCSRenderAPI.getPageLinkData(id) || {}; if ( linkData.href ) { $(navLink).attr("href", linkData.href); } if ( linkData.target ) { $(navLink).attr("target", linkData.target); } $(navLink).text(SCS.structureMap[id].name); $(navItem).append(navLink); return navItem; } // returns true if given navigation node is hidden... function isNodeHidden(id) { var navNode, isHidden = false; if (SCS.structureMap) { navNode = SCS.structureMap[id]; if (navNode) { isHidden = (true === navNode.hideInNavigation); } } return isHidden; } // returns true if all children of given navigation node are hidden... function allNodeChildrenAreHidden(id) { var subnodes = SCS.structureMap[id].children, allHidden = ( subnodes.length > 0 ) ? true: false; for( var sub = 0; sub < subnodes.length; sub++ ) { if( !isNodeHidden( subnodes[sub] ) ) { allHidden = false; break; } } return allHidden; }
7. Save navigation.js file.
Note: The above code generates a two-level navigation menu. if you need to use menu that supports more levels, you should extend this code.
Checkpoint 4
At this point you can add new page to your SCS site and see new pages appearing in the navigation menu. In the Part 4 you will learn how to add Breadcrumbs and make pages editable in the Site Builder by adding SCS slots to page layouts in your new theme.