Collapsible CMS Menus

//Collapsible CMS Menus

Collapsible CMS Menus

R

ecently I worked on a content management system (CMS) deployment for a customer. One of their requirements was to present a collapsible menu structure on a few pages containing links to catalog items, KB articles, etc. The menu piece is simple. ServiceNow provides several ways to construct CMS menus without requiring any code. The less simple part was making a collapsible menu. In this post I’ll explain the solution I came up with to provide a collapsible menu system that leverages the existing menu system in the ServiceNow CMS.

Collapsible Menu Page

The approach I had seen taken in the past with collapsible menus was to leverage some sort of jQuery plugin to pull in the menu items from the database. I considered this approach, but wanted something that was closer to the existing menu setup. I really didn’t want to have to include jQuery and deal with the extra burden of a completely separate library just for this purpose.

What I came up with is a fairly simple solution that overlays the existing menu HTML of a ‘Vertical Blocks’ menu with some javascript that manages the expand/collapse functionality.

Setting up the menu(s)…

The first step is to set up your menus. The only important part of this step for this solution is to make sure your menu is a VERTICAL BLOCKS menu. Other than that, simply create the menu, add sections and items below it, and include any icons you want to use. If you want to have a page with a 2-column menu setup, you’ll need to create a separate menu for each column.
Navigation Menu

Creating the content blocks…

Once you’ve created the menu(s) you need to create a dynamic content block that contains the code to add expand/collapse functionality to the menu. The code below can be used as-is in a dynamic content block in your system.

‘Collapsible Menu Script’ Dynamic Content Block
Name: Collapsible Menu Script
Dynamic content:

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">

<table cellpadding="5">
   <tbody>
      <tr>
         <td id="expandAllImg" onclick="showSectionItems();"><a><img src="images/icons/nav_expandall.gifx"></img><b> Expand all</b></a></td>
         <td id="collapseAllImg" onclick="hideSectionItems();" style="display:none;"><a><img src="images/icons/nav_collapseall.gifx"></img><b> Collapse all</b></a></td>
      </tr>
   </tbody>
</table>

<script>
Event.observe(window, 'load', function() {
  var sections = $$('tr.cms_menu_vertical_blocks_top_section');
   sections.each(function(s) {
      //If subitems
      if(s.next()){
         //Hide the subitems and add the collapse image
         s.next().hide();
         var collapseImg = s.down().insert({
            top: '<a><img src="images/arrows_expand_sm.gifx" alt="Expand" title="Expand" class="collapse_menu_icon"></img></a>'
         });
         collapseImg.down('img').observe('click', toggleSectionItems);
      }
   });
});

function toggleSectionItems(event) {
   var element = event.element();
   if(element.getAttribute('title') == 'Expand'){
      element.title = 'Collapse';
      element.src = 'images/arrows_collapse_sm.gifx';  
      element.alt = 'Collapse';
   }
   else{
      element.title = 'Expand';
      element.src = 'images/arrows_expand_sm.gifx';  
      element.alt = 'Expand';
   }
   element.up('tr.cms_menu_vertical_blocks_top_section').next().fadeToggle();
}

function showSectionItems() {
   var sections = $$('tr.cms_menu_vertical_blocks_top_section');
   sections.each(function(s) {
      //If subitems
      if(s.next()){
         s.next().fadeIn();
      }
   });
   $('collapseAllImg').show();
   $('expandAllImg').hide();
   $$('.collapse_menu_icon').each(function(i) {
      i.title = 'Collapse';
      i.src = 'images/arrows_collapse_sm.gifx';  
      i.alt = 'Collapse';
   });
}

function hideSectionItems() {
   var sections = $$('tr.cms_menu_vertical_blocks_top_section');
   sections.each(function(s) {
      //If subitems
      if(s.next()){
         s.next().fadeOut();
      }
   });
   $('collapseAllImg').hide();
   $('expandAllImg').show();
   $$('.collapse_menu_icon').each(function(i) {
      i.title = 'Expand';
      i.src = 'images/arrows_expand_sm.gifx';  
      i.alt = 'Expand';
   });
}
</script>
</j:jelly>

If you are setting up a 2-column menu page you’ll also want to create a spacer content block so that your menus line up correctly on the page.

‘Collapsible Menu Spacer’ Dynamic Content Block
Name: Collapsible Menu Spacer
Dynamic content:

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
   <div style="margin-top:27px">
   </div>
</j:jelly>

Setting up the page

Finally, you can set up the actual CMS page containing your menu and the content block (or blocks if you’re doing a 2-column menu). The page setup should look something like the screenshot here…
Collapsible Menu Page Setup

If you’ve set everything up correctly you should have a nice menu page with collapsible menus! Each menu section can be expanded individually to show the items underneath it. You can also use the ‘Expand all/Collapse all’ toggle to show and hide all items under all sections on the page.
Collapsible Menu Page

By | 2018-07-09T14:59:58-06:00 August 17th, 2011|Categories: Content management|Tags: , |8 Comments

About the Author:

8 Comments

  1. abhijat August 18, 2011 at 3:13 am - Reply

    Hi Mark,

    I have tried the given script, As a result I am getting that ‘Expand all’ and two menu sections.
    But these menu sections are not related to expand all link.
    How can i make these sections visible only when I click on ‘Expand All’.

    • Mark Stanger August 18, 2011 at 6:09 am - Reply

      The sections will always display. It’s the items underneath each section that will be displayed when you click the ‘Expand all’ link.

      • Andrew May 21, 2014 at 1:42 pm - Reply

        I am having a similar issue to abhijat. I believe I’ve followed instructions correctly, but the page doesn’t allow the menus to expand or collapse. I am talking about the actual view you see when the page loads, not the sections visible in the CMS editor.

  2. Ramsha Almas June 20, 2013 at 11:12 am - Reply

    How would it be possible to make the entire heading (h2) clickable to open up the subitem menu, rather than just the little arrow images?

    • Mark Stanger June 26, 2013 at 6:43 am - Reply

      You just have to target the correct HTML element. I haven’t tested this, but I think you could just adjust this line…

      collapseImg.down(‘img’).observe(‘click’, toggleSectionItems);

      to something like this…

      collapseImg.up(‘tr’).observe(‘click’, toggleSectionItems);

  3. Madeleine Eves August 20, 2014 at 10:50 am - Reply

    Hi,
    This is really great!
    However, we already have a theme for ‘cms_menu_vertical_blocks_top_section’ and it’s not compatible with the dropdown arrows it appears – they just disappear.
    Is there a way that I could use a different div class?
    Thanks,
    Madeleine

    • Mark Stanger August 20, 2014 at 10:57 am - Reply

      You should be able to, you just need to adjust my script to target your HTML structure. It’s impossible for me to predict what that might be though so you’ll probably need to work with someone on your side who has a good understanding of Javascript and CSS.

Leave A Comment