Ektron Menu? Meet Twitter Bootstrap Support

August 28, 2014

Blog | Development | Ektron Menu? Meet Twitter Bootstrap Support
Ektron Menu? Meet Twitter Bootstrap Support

We recently were asked to update the functionality of a site powered by Ektron CMS. The client wanted Twitter Bootstrap on the front-end. Here’s a simple control taking a menu tree from Ektron, using the Ektron MenuManager API, and building a menu with Twitter Bootstrap markup.

First, create an ASP.NET server control in Visual Studio and define some properties. The most important property is the menu Id. This will be set to whichever menu that you’re trying to load in the control.

//using a predefined menuId based on a menu set up in Ektron
const int _menuId = 123;

We’re going to make the control handle nested menus, so we’ll want to keep track of which level each item is on. To do this, we’ll use an integer variable in our CSS markup.

//property used to determine nested lists level1, level2 etc...
private int _level = 1;

Bootstrap requires that you apply an “active” class on the selected item and every parent/ancestor of that item. In order to achieve that, each item should store its parent id. Later, when we build or interact with the menu, we can verify the parent/child relationship.

//property used to apply "active" class on parent elements
private long _parentId = 0;

When our control loads, pull the menu data from the MenuManager API. Before building your HTML, check that there are menu items to render. Next, create a stub method called PopulateMenuChildren. In the code, pass it your menu items and the Div control. Finally, add the container element to your page through a PlaceHolder control.

protected void Page_Load(object sender, EventArgs e)
{
    var menuManager = new MenuManager();

    //Gets Menu Collection based on menu id
    IMenuData menuData = menuManager.GetTree(_menuId);>
    if (menuData != null && menuData.Items.Count > 0)>
    {
        var div = new HtmlGenericControl("div");
        div.Attributes.Add("class", "nav-container");
        PopulateMenuChildren(menuData.Items, div);
        phContent.Controls.Add(div);
    }
}

Markup for our .ascx file

<asp:PlaceHolder runat="server" ID="phContent" />

The PopulateMenuChildren method is a recursive loop that walks the menu tree and builds it out dynamically. We start the function by creating a new HTML unordered list, applying the class + _level, and then incrementing our level for the next time it comes around. Next we loop through the menuChildren and begin building our list.

We add our new listitem control and then call the GenerateListItem function which adds our link, and link class. Because we want to make sure the nested lists are within our current list item we have to begin crawling the child items. We do a check for child items and if so we loop back over this control. If not, we check to see if we need to set the active class on our current item and then add it to our unordered list.

This pretty much goes on until the tree is exhausted. Hence the infinite loop.

private void PopulateMenuChildren(IEnumerable menuChildren,    HtmlGenericControl rootDiv)
{
   _level++;
    var ul = new HtmlGenericControl("ul");
    ul.Attributes.Add("class", "nav level" + _level); 
    foreach (var md in menuChildren)
    {
        HtmlGenericControl li;
        GenerateListItem(md, out li);
        if (md.Items.Any())
PopulateMenuChildren(md.Items, li); //Checks if md is the selected items parent and sets it to active
if (_parentId == md.Id)
{
li.Attributes.Add("class", "active");
_parentId = md.ParentId;
}
ul.Controls.Add(li);
}
rootDiv.Controls.Add(ul); _level--; }

private void GenerateListItem(IMenuItemData md, out HtmlGenericControl li)
{
li = new HtmlGenericControl("li");
var url = md.Href; //Add "active" class to listitem if href & request url match
if (GetContextUrl.ToLower() == md.Href.ToLower())
{
li.Attributes.Add("class", "active");
_parentId = md.ParentId;
}
var hl = new HyperLink { Text = md.Text, NavigateUrl = url };
li.Controls.Add(hl);
}

The GetContextUrl Property is a helper that I’m using to get the current context url, and comparing it with the Href property of the menuData item. 

With the above implementation in place, a Menu in Ektron can be defined with as many sub menus as desired, as shown in these next two images:

My Menu - http://www.geekhive.com/buzz

 

My SubMenu - http://www.geekhive.com/buzz

 

And finally, the rendered implementation (with the appropriate relevant css styles to make it pop) shows our menu, with each defined sub page in the menu revealed and indented as they are browsed by the user.

Front End - http://geekhive.com/buzz

 

 

 

 

 

Dave Cardine, UX and Creative Director, GeekHive

Dave Cardine

Marketing Technologist
Tags
  • Content Management
  • Ektron
  • Twitter Bootstrap

Recent Work

Check out what else we've been working on