Bootstrap Navigation for Office 365 & SharePoint 2013 using jQuery and REST

Introduction

In my last post I talked about making the SharePoint navigation render in a Bootstrap friendly way. I suggested that you could do this by changing the markup of the navigation using an ASP:Repeater to display the nodes. This works great if you’re on an on-prem environment but on Office 365 you cannot use this method because the masterpage cannot contain code blocks. If you haven’t read that it might be worth taking a look at – Bootstrap Responsive Navigation in SharePoint .

This post will demonstrate an Office 365 safe version that use JavaScript, jQuery, and REST to retrieve the navigation from SharePoint’s navigation provider. Once we have that we’ll render that out to the screen client side. With this approach we can use the out of the box Managed Meta Data navigation provider for the navigation, and we can control the exact rendering so that it fits Bootstrap’s model for a navigation bar.

The code can be downloaded directly from my git-hub account – https://github.com/tom-daly/sp2013-bootstrap-nav

Getting Started

It’s very simple to get started you only need to do a few things.

  1. Add the link to the topNavigation.js in your SharePoint masterpage

  1. In the Master Page, add the container below where the navigation will be pushed into. You will need to determine where you want the navigation to go, I’ll have a full example at the very end.

  1. Switch the SharePoint Navigation to use the Managed Meta Data Navigation
    1. In Site Settings
    2. Look and Feel -> Navigation

Once you complete those steps you’ll have your navigation displayed in that container.

Other Details

Changing Rendering

The rendering of the menu is defined in the renderNavigationNodes function. This is currently the format the Bootstrap likes. If you visit the Bootstrap website and take a look at the first example

http://getbootstrap.com/components/#navbar

The red box is exactly what the code is injecting. So you would wrap all that however you want it to appear. Follow the examples there are plenty out there.

2 Level Flyouts

Currently this supports only 2 levels, a top level and 1 flyout. This is just what Bootstrap v3.3.5 supports and that’s what I’m sticking with currently. If you want more levels then it’s up to you to figure that part out. It can be done and there are other 3rd parties implementing 3rd or 4th level flyouts after the fact. The code is recursive and will support as many levels as you have, you just need to handle the front end portion.

The REST Call

The query that I am using can be seen below. The /web/navigation/topbar endpoint – flat out sucks. It won’t show if a node is hidden and it didn’t behave. This is the only one I could get to work reliably.

Changing Target Container

If you want to change where the navigation goes, instead of “#my-top-navigation” then you can edit the topNavigation.js file and at the bottom change the selector to another ID preferably.

Sample Files

I have a few more sample files that might be of use to look at.

Base.css – Sample CSS file (helps with some Bootstrap/SharePoint resets)

Bootstrap.Master – Sample masterpage used in this example. In this sample I create my own header and not s4-titlerow. Using this html structure you’ll get the collapsible navigation that is popular on most web sites.

Conclusion

The whole goal of this script was to have a way for an Office 365 site to use the Bootstrap navigation. Although there are still limitations it’s doable. And you don’t even necessarily need to touch the master page. You could attach the scripts and css via other methods which I won’t go in to. So if you’re an Office 365 purist who doesn’t want to customize the master page you would want to take an approach to this. I hope this helps someone out there. If there are problems with the script you can report the issues through the github page. https://github.com/tom-daly/sp2013-bootstrap-nav/issues

Advertisements

Bootstrap Responsive Navigation in SharePoint

Introduction

Many of my most recent branding projects have all been responsive. Clients are building sites that they want to work on desktops, tablets, & phones. If you’ve ever tried to deal with this request and SharePoint is your platform then you know what a handful this can be. For all my responsive branding projects I always go to Bootstrap. If you don’t know what that is then this article is not for you. We will not going into the details of implementing Bootstrap or the issues / fixes to do that.  If you’re looking for cookie cutter bootstrap in SharePoint then I recommend that you check out Responsive SharePoint.

This article we will simply focus on the navigation. We will be replicating the standard out of the box (OOTB) SharePoint navigation and formatting it in a way that works with Bootstrap 3.0. I’ll provide you with the code snippet and an explanation of how to implement, and what is happening. It should leave you with the functionality of the Bootstrap’s collapsible navigation.

Our main problems with the SharePoint navigation are:

    • SharePoint out of the box navigation is NOT responsive
    • SharePoint out of the box navigation doesn’t work well with touch enabled devices
      • It has hover actions on the navigation, and hover doesn’t work on touch devices

b

Prerequisites

The following need to be reference in your site.

  • jQuery
  • Bootstrap 3.0
  • On-Prem SharePoint environment w/ access to the Masterpage
    • You can see the references these in my master page

SORRY SharePoint Onliner’s and O365’s – this won’t work b/c you can’t use code blocks in the MasterPage

ref

The Navigation Code

You can view the html markup that Bootstrap requires in order to work properly – http://getbootstrap.com/components/#navbar . The OOTB SharePoint navigation does its own thing so it would never work with Bootstrap. In this approach we’ll use the SharePoint top navigation provider but we’ll create our own navigation markup using asp repeaters. The following code will only work for 2 levels deep, it could be modified to work on X number of levels. You would just have to keep nesting repeaters. I am using ASP repeaters in the master page with no code behind in this approach. If you wanted to you could write a user control and simplify what goes into the master page but for me no C# code means less things that could break. There is one minor issue with this approach – see the Known Issues section.

Download Snippet Here

1 <nav class=”navbar navbar-default s4-notdlg noindex s4-noindex”> 2 <div class=”container”> 3 <!– Brand and toggle get grouped for better mobile display –> 4 <div class=”navbar-header”> 5 <button type=”button” class=”navbar-toggle collapsed” data-toggle=”collapse” data-target=”#bs-example-navbar-collapse-1″ aria-expanded=”false”> 6 <span class=”sr-only”>Toggle navigation</span> 7 <span class=”icon-bar”></span> 8 <span class=”icon-bar”></span> 9 <span class=”icon-bar”></span> 10 </button> 11 <SharePoint:SPLinkButton runat=”server” NavigateUrl=”~sitecollection/” ID=”onetidProjectPropertyTitleGraphic” CssClass=”navbar-brand”> 12 <SharePoint:SiteLogoImage name=”onetidHeadbnnr0″ ID=”onetidHeadbnnr2″ LogoImageUrl=”images/logo.png” runat=”server”></SharePoint:SiteLogoImage> 13 </SharePoint:SPLinkButton> 14 </div> 15 16 <div class=”collapse navbar-collapse” id=”bs-example-navbar-collapse-1″> 17 18 <asp:Repeater runat=”server” ID=”TopNavMenu” DataSourceID=”topSiteMap”> 19 <HeaderTemplate> 20 <ul class=”nav navbar-nav navbar-right”> 21 </HeaderTemplate> 22 <ItemTemplate> 23 <li runat=”server” class=”root-node”> 24 <a href=”<%# Eval(“Url”) %>“> 25 <%# Eval(Title) %> 26 </a> 27 </li> 28 <asp:Repeater runat=”server” ID=”FirstLevelNodes” DataSource=”<%# ((SiteMapNode)Container.DataItem).ChildNodes %>”> 29 <ItemTemplate> 30 <!– if has children –> 31 <li runat=”server” visible=”<%# ((SiteMapNode) Container.DataItem).ChildNodes.Count > 0 %>” data-node-count=”<%# ((SiteMapNode)((RepeaterItem)Container.Parent.Parent).DataItem).ChildNodes.Count %>” data-node-index=”<%# Container.ItemIndex %>” class='<%# Container.ItemIndex == ((SiteMapNode)((RepeaterItem)Container.Parent.Parent).DataItem).ChildNodes.Count-1 ? “dropdown last-node nav-node” : (Container.ItemIndex == 0 ? “dropdown first-node nav-node” : “dropdown nav-node”) %>‘> 32 <a href=”<%# Eval(“Url”) %>” class=”dropdown-toggle” data-toggle=”dropdown” role=”button” aria-expanded=”false”> 33 <%# Eval(Title) %> 34 <span class=”caret”></span> 35 </a> 36 <asp:Repeater runat=”server” ID=”ChildMenuRepeater” DataSource=”<%# ((SiteMapNode)Container.DataItem).ChildNodes %>”> 37 <HeaderTemplate> 38 <ul class=”dropdown-menu” role=”menu”> 39 </HeaderTemplate> 40 <ItemTemplate> 41 <li data-node-index=”<%# Container.ItemIndex %>” class=’nav-node’> 42 <a href=”<%# Eval(“Url”) %>“> 43 <%# Eval(Title) %> 44 </a> 45 </li> 46 </ItemTemplate> 47 <FooterTemplate></ul></FooterTemplate> 48 </asp:Repeater> 49 </li> 50 <!– if has zero children –> 51 <li runat=”server” visible=”<%# ((SiteMapNode) Container.DataItem).ChildNodes.Count <= 0 %>” data-node-count=”<%# ((SiteMapNode)((RepeaterItem)Container.Parent.Parent).DataItem).ChildNodes.Count %>” data-node-index=”<%# Container.ItemIndex %>” class='<%# Container.ItemIndex == ((SiteMapNode)((RepeaterItem)Container.Parent.Parent).DataItem).ChildNodes.Count-1 ? “last-node nav-node” : (Container.ItemIndex == 0 ? “first-node nav-node” : “nav-node”) %>‘ > 52 <a href=”<%# Eval(“Url”) %>“> 53 <%# Eval(Title) %> 54 </a> 55 </li> 56 </ItemTemplate> 57 </asp:Repeater> 58 </ItemTemplate> 59 <FooterTemplate> 60 </ul> 61 </FooterTemplate> 62 </asp:Repeater> 63 64 </div> 65 <!– /.navbar-collapse –> 66 67 </div> 68 <!– end container –> 69 </nav> 70 <!– end nav-bar –>

Take a look at how this renders, much better.

render

And when the screen hits the break point. It collapses and you have the mobile friendly menu. The break point is set in the bootstrap CSS (I believe it is 768px). The menu below is also

resp1

And the drop down

resp2

The Code Explained

You can skip this part if you don’t care what the code snippet actually does. I’ll break it down into parts to help you understand so you can make changes to it.

1) It’s up to you to determine where you are going to put the navigation inside your masterpage

In my particular case below I’ve created my own custom header where I put the navbar. I then turn the visibility off on the PlaceHolderTopNavBar (line 543)

ex

2) Looking at just the very high level bootstrap nav html

boot1

3) The Root Level Repeater

The first level I consider the root level. It contains the root navigation node typically “Home”. Below is the best representation of how the data comes back from the topSiteMap navigation provider. Each color is a level. The children of “Home” are the main level. This is similar to the OOTB, you might have seen the first node that isn’t in the navigation provider but just shows up anyway.

nav123 nav1234

Now for the root level. In this screen shot you can see I render the root node then have a second repeater for its children nodes. The html is fairly simple for the first node and gets more involved for the next level.

zerolevel

4) The First Level Repeater

This level gets a bit more interesting because now we have two different classifications of nav nodes, with children and without children. We have to handle each a slight bit different and I’ll explain. If you have children we need to specify a different class to have a drop down. Next it needs a nested repeater to handle the next level (2nd level). If there are no children we can simply just render the navigation node just as we did with the root level. I use the ChildNodes.Count to determine which to hide or show. You might notice that the

  • ’s, line 487 & 507, have some other attributes like data-node-count and data-node-index and are REALLY long.  I’ll explain that in the next section.

level_one

4a) First Level

  • ’s

Let’s examine the first

  • the one with children. They are both the same except for the visible attr. We are going to focus on the following attributes, data-node-count, data-node-index, & class.

data-node-count – is not needed, but this will tell you how many sibling nodes are detected. I used this to help generate the if statements for class.

data-node-index – is not needed, but this will tell you the index of the node in amongst it’s current siblings. I used this to help generate the if statements for class.

a

class – this is basically a fancy edition I added which provides a first-node and last-node class. Again you’ll notice this one has “dropdown” in the class, the other

  • won’t because it doesn’t have children and doesn’t need a drop down.
    • The first node of a set will have the class=“dropdown first-node nav-node”
    • The middle nodes would have the class=”dropdown nav-node”
    • The last node would have the class=”dropdown last-node nav-node”
1 class=’<%# Container.ItemIndex == ((SiteMapNode)((RepeaterItem)Container.Parent.Parent).DataItem).ChildNodes.Count1 ? dropdown last-node nav-node : (Container.ItemIndex == 0 ? dropdown first-node nav-node : dropdown nav-node) %>‘>

5) The Second Level Repeater

The second level repeater code gets a little simpler. This is our last level and we don’t consider if the node has children or not. We just render the value of the node and leave it at that. If you wanted to go 3, 4 or 5 levels essentially it’s just copy what we’ve already done but I wouldn’t go more than 2 levels. Bootstrap 3.0 removed  support for multilevel dropdowns, citing usability issues as the cause.  You would be on your own if you decided to go for more levels. There are 3rd party plugins available to assist Bootstrap 3.0 with multi levels.

second_level

Known Issues

You expected everything to work beautifully, I know! But there is always a gotcha! when it comes to SharePoint.

The only issue with this method is that you loose the selected state of the navigation. This is easily over come with supplemental jQuery. You’re only other alternative is to convert this all to a user control (like I mentioned way earlier) and then in code what page you are on and add a class. I don’t have the reference to this method – but I’m looking. To be posted later.

Here is my jQuery work around – for highlighting the navigation for a selected node.

Download Script Here

1 $(document).ready(function() { 2 var nav = $(.nav); 3 if (nav == null || typeof (nav) == undefined) return; 4 5 /* Match navigation on current page */ 6 var url = window.location.href.toLowerCase(); 7 var decUrl = decodeURI(url); 8 nav.find(li > a).each(function () { 9 10 var href = $(this).attr(href).toLowerCase(); 11 var decHref = decodeURI(href); 12 13 if (decUrl.indexOf(decHref) != 1) { 14 $(this).addClass(active); 15 return false; 16 } 17 }); 18 });

Conclusion

That explains how I was able to utilize the SharePoint out of the box top navigation provider and build a new menu with ASP repeaters to behave responsively and work with Bootstrap 3.0. This is a simple enhancement that I’ve been re-using on many on of my On-Prem responsive projects. Unfortunately this doesn’t not work for SharePoint Online or O365 as the Masterpage does not allow code blocks. I’m curious if that’s with only editing pages by SharePoint designer, but what about deployed through wsp. http://stackoverflow.com/questions/22566589/sharepoint-master-page-asprepeater-tag . I hope to uncover an answer either way. Thanks for reading!

My Favorite JavaScript Libraries and jQuery plugins

These are a few of my favorite and go to JavaScript libraries. These tend to work well in SharePoint with no problem. This is my personal list that I use

Grid

Console Log

Glyphs

Carousel

Cookies

Click Outside

Mutate / Resize

Select Box (supports Multi)

Time / Date

Truncating Text

Layouts (masonry type)

Notify / Alerts

Modal

Scroll Bars

SharePoint Specific

Permanently Removing the Recent Node from Quick Launch for SharePoint 2013

# Update 5/19/2015 – This article is a javascript/css (wsp) based solution.

A reader Håkan Nilsson has suggested a simple solution to permanently hide the Recent node. 

  • Create an empty SharePoint Group
  • In Site Settings -> Look and Feel -> Navigation, Edit the Recent node in Current Navigation
  • Add your blank group to the Audience field.

this method is super easy for an end user to implement without deploying a sandbox solution below. But feel free to continue reading if you are interested in that method. 

Introduction

Yesterday I was tasked to remove the “Recent” node from the quick launch for a customers SharePoint online site. I’ve decided to release the solution in hopes that other people could take advantage of it. The picture below will show you the “Recent” node.

Recent Node

This node was undesired by the user because they wanted to have control over the quick launch navigation. They mentioned that every time they add a new list or library then new items will be added under the “Recent” node. When they go and delete it from the Navigation section in Look & Feel, it will just re-appear when they create a new list or library. Basically they wanted it gone.

Approach

I chose an approach similar to this blog article http://www.jasperoosterveld.com/2013/02/sharepoint-2013-remove-recent-in-quick.html however, I needed it to work on sandbox for o365 and SPO. I also decided to sharpen my JavaScript Client Object model skills and write a small script that will remove the “Recent” node whenever it is created.

I paired this with the jQuery as suggested in the article to hide the “Recent” node. Except I made one modification to it you can see below. I’ve added the id #sideBox to have this only search in the Quick Launch. I explain more about why I remove and hide it in the next section.

this > jQuery(“.ms-core-listMenu-item:contains(‘Recent’)”).parent().hide();

to this > jQuery(“#sideBox .ms-core-listMenu-item:contains(‘Recent’)”).parent().hide();

The Solution

The entire solution & the pre-built .wsp can be downloaded from CodePlex – http://rr.codeplex.com

The sandbox solution is composed of two components:

  1. RemoveRecent.js – JavaScript Client Object Model code which removes the “Recent” node from the quick launch if detected on page refresh.
  2. HideRecent.js – jQuery code to hide the “Recent” node

Why remove and hide?

Since the RemoveRecent.js runs client side there is a case where you may see the “Recent” node. For example you just finished creating a new list and the page refresh. The code to remove the node in RemoveRecent.js is called asynchronously. The list or library is removed from the back end but on the client side is not updated. This could be handled with a refresh but that causes a double refresh once you create a new list and there is a delay between the refreshes. I felt that this created a bad user experience. The answer to that was to also hide the node using HideRecent.js

Hope this may be useful to some of you out there.

Free Floating Quick Launch Navigation for SharePoint 2010 using jQuery

Recently I was asked to make a free floating navigation element, so that when you scroll down the page it would follow. There are many adaptations of this but for standard html websites, but I was unable to find a SharePoint specific one. Until writing this post I just recently noticed an alternate but similar approach here http://blog.muhimbi.com/2009/08/how-to-float-sharepoint-quick-launch.html

Instructions

Download the code snippet from here

Add the script references to the files in the Master Page, or CEWP.

2013-08-18_1932

Once you add that to your pages it’s activated. This is tested to work on standard V4.master.

 

Notes

If you’re quick launch is larger than the view then it will constantly be scrolling down, and you’ll never see the bottom of the quick launch .

Your quick launch must be smaller than the actual view.

I’m using jQuery from the Google hosted API libraries – https://developers.google.com/speed/libraries/devguide#jquery

Here is a look at the actual script

2013-08-18_1934

 

Demo

Customize Table of Contents Web Part: Remove Libraries & Navigation Headers

This article is based off Thomas Sondergaard’s post located here: http://sharepointsharpener.wordpress.com/2011/09/27/quick-fix-remove-libraries-lists-from-toc/

This version is slightly different, I approach it similar but in a different way. That version uses javascript and scans all <A> tags on the page, it did not remove the extra items added from Quick Launch navigation.

My version will remove all the lists and libraries as well as any nodes added from the quick launch navigation, and it specifically targets the table of contents web part only.

Description

Standard Table of Content webpart will display all Items in the site and any additional headings and links added in the Quick Launch.

toc

It pretty much shows everything that’s in the quick launch.

nav

My client had the requirement of a site map type web part for SharePoint Online (o365). So I could not program anything and the Table of Content web part was great because we could sort, but they did not want all this ‘other’ stuff, Libraries & Lists & Navigation Headers, appearing in the site map type webpart. They did want it to appear in the quick launch, so I could not remove it from there. The Table of Content is reading directly from the Quick Launch navigation provider so I was stuck.

Solution

Using jQuery I iterate throught all the headers, then I find which ones are list and libraries.

Lists and Libraries will have an <a> tag which contains ‘BaseType’

Or I check to see if it’s a standard link and remove that. All the automatically generated one would be relative links. And all the ones added to the quick launch we added as absolute.

If the section did not contain a link, then it’s detected as a Header from the quick launch nav provider and I remove that.

Below is the script, I load jQuery via a CDN first. Then I’ll add this to the page in a <script></script> tag. In my actual deployment I added my script to the MasterPage so it would be used site wide.

jQuery(document).ready(function () {

    var url = window.location.pathname;
    jQuery(".toc-layout-main .headermarker").each(function () {

        var result = jQuery(this).find("a").each(function () {
            var href = jQuery(this).attr("href");
            if (href.indexOf('BaseType') != -1) {
                var topNode = jQuery(this).parent().parent().parent().parent();
                if (topNode.hasClass("level-section")) {
                    topNode.hide();
                }
            }
            else if(href.indexOf('http') != -1) {
                var topNode = jQuery(this).parent().parent().parent();
                 if (topNode.hasClass("dfwp-list")) {
                    topNode.hide();
                }
            }
        });

        if (result.length == 0) {
            var topNode = jQuery(this).parent().parent().parent();
            
            if (topNode.hasClass("level-section")) {
                topNode.hide();
            }
        }

    });

});

That’s it. Your final results should look be reduced to only sites and sub sites.

result

Building a custom Navigation Menu using SPServices

In this post we are going to create a 2 tier navigation menu using SPServices. In this scenario we’ll be replacing the current quick launch and putting in our new navigation. This will work with whatever version of SharePoint.

This solution would most likely work with more tiers but the CSS I have provided in the example only accounts for 2 tiers

Things you’ll need

jQuery

SPServices

a Data Source (SharePoint List) – I have specifically configured my list EXACTLY as defined in this way.

2012-04-26_1226

On to the implementation steps

Prior to starting any front end work make sure you have the Custom List as defined above created. I’ve called my list ‘Navigation’

Create a few nodes so that you’ll have some data and know that its working properly.

nodes

After creating the list and some test nodes, make sure that you have resources to the jQuery and SPServices on your site.

I am storing those files on my SiteCollection / js Folder which I created in SharePoint Designer. You can potentially store the files anywhere or get jquery through a Content Delivery Network (CDN) – http://docs.jquery.com/Downloading_jQuery#CDN_Hosted_jQuery

and just recently SPServices is now available through a CDN -http://www.cdnjs.com/#/search/jquery.spservices

I’ve just downloaded the files from the site and I’ll be hosting them in a folder on my Site Collection as I mentioned earlier. Here is a picture of them in their location.

2012-04-26_1531

You might have noticed in that picture the navigation.js. We need to create a blank file as this point called navigation.js this is where the navigation jQuery code will go. You can download that file here.

Once you have that file open it up in a text editor. In the first line set the assignment of the variable “NavigationList” equal to the name of the new list you created. If you are querying a list on another site you would need to specify the WebURL, otherwise leave it blank and it will query the site that the web part is currently on.

Once your are done editing save the list alongside the other .js files.

**NOTE: If you see line 6, this is the object that we will be replacing. You can play around and modify that to potentially go wherever. **

2012-04-26_1557

Next I start off with a generic SharePoint page, and I’ll add a Content Editor Web Part (CEWP). I start off this way because the Content Editor is the easiest way to demo this example. You could embed this into a portion of the master page or some other method.

blank_page

Edit the CEWP properties, click on Source Editor

Add the following information, take special notice to the paths to the files. In this demo I’m on the /sites/tew  , site collection. Adjust that to meet your correct path.

2012-04-26_1544

So above we are linking to a CSS file that we have not yet created (but will). The first JavaScript link is to the jQuery library. The second is to SPServices library. The third to our custom code to create the navigation.

So Save that content in there, hit OK or Save to commit the page.

Now lets add the CSS file. A sample CSS file can be provided here, or you can create your own.

Once you have the correct JS files in place and the CSS in place when you browse or refresh the page you should see the new navigation instead of the quick launch.

Here is a before and after shot.

2012-04-26_16022012-04-26_1603

My files for download again are

The Navigation Script

The Navigation CSS