If you use term driven navigation to manage all the pages on your subsites, and you have a lot of pages for a certain subsite, then your navigation might turn out to be quite long. In situations like this, it might as well come in handy to have an accordion menu that just collapses or expands its contents (terms) upon click. I'm going to use jQuery and JavaScript for this.
Of course, it would also be important that terms having underlaying terms can't act as a link (the link behind them, if any, shouldn't activate and open a new page). Terms that have underlaying terms should expand and show their underlaying terms.
Here's a screenshot of a term driven navigation with all the terms and underlaying terms visible, no accordion used yet:
What we want is a navigation that looks like this:
=>
|
=>
|
|
So basically you have all the categories (the top terms) collapsed. Upon clicking on a term that has underlaying terms, it should expand and show the underlaying terms of that term you just clicked on. And so on.
In the example above, when you open the second category, the underlaying terms expand. In here, there is another term that has underlaying terms, which I named the subcategory. You can once again click on this one and it will expand, showing its respective underlaying terms. If a term no longer has underlaying terms, it cannot expand and it just opens the page.
And now the real work.
You will need to create a JavaScript file (or just add the code in an existing script file if you already use scripts on your site) and make sure to add it to your master page. Mine is named "script.js" and its path is "
~sitecollection/Style Library/Scripts/script.js". You will also need jQuery, so make sure you have that as well. My jQuery file its path is "
~sitecollection/Style Library/Scripts/jquery-1.10.2.min.js".
To correctly make a reference to your scripts, you must add them to your master page. I'm using a HTML master page. Edit your master page in advanced edit mode and add the reference code after the "
ScriptLink" lines. The code below has five ScriptLink references (references to default SharePoint scripts), the code you must add has to be after those scripts.
// The following five lines are already in your master page
<!--SPM:<SharePoint:ScriptLink language="javascript" name="core.js"
OnDemand="true" runat="server" Localizable="false"/>-->
<!--SPM:<SharePoint:ScriptLink language="javascript" name="menu.js"
OnDemand="true" runat="server" Localizable="false"/>-->
<!--SPM:<SharePoint:ScriptLink language="javascript" name="callout.js"
OnDemand="true" runat="server" Localizable="false"/>-->
<!--SPM:<SharePoint:ScriptLink language="javascript" name="sharing.js"
OnDemand="true" runat="server" Localizable="false"/>-->
<!--SPM:<SharePoint:ScriptLink language="javascript" name="suitelinks.js"
OnDemand="true" runat="server" Localizable="false"/>-->
// Now use these following two lines to reference to your JavaScript
// files, with first referencing to the jQuery script and then your
// own script.
<!--SPM:<SharePoint:ScriptLink language="javascript" ID="scriptLink1"
runat="server" OnDemand="false" Localizable="false"
name="~sitecollection/Style Library/Scripts/jquery-1.10.2.min.js"/>-->
<!--SPM:<SharePoint:ScriptLink language="javascript" ID="scriptLink2"
runat="server" OnDemand="false" Localizable="false"
name="~sitecollection/Style Library/Scripts/scripts.js"/>-->
Now that you have correctly made a reference to the jQuery script and your own script, you can save the master page (for now, since we'll add some more later).
Let's start with the script.
This is what the code in my script.js file looks like. I will try to add comments in the code.
function accordionMe(selector, initalOpeningClass) {
var speedo = 300;
var $this = selector;
var accordionStyle = true;
// First of all, hide all ul's:
$this.find("li>ul").hide();
// Then for each li you find in that ul,
$this.find("li").each(function(){
// that isn't empty,
if ($(this).find("ul").size() != 0) {
// find all the ones at the top,
if ($(this).find("a:first")) {
// and make sure it won't do anything on click.
$(this).find("a:first").click(function(){ return false; });
// Optional: if you want to style the non-clickable links,
// then uncomment the code below.
//$(this).find("a:first").addClass("no-click");
}
}
});
// Open all items.
$this.find("li."+initalOpeningClass).each(function(){
$(this).parents("ul").slideDown(speedo);
});
// Execute this function on click of li with an a tag.
$this.find("li a").click(function(){
if ($(this).parent().find("ul").size() != 0) {
if (accordionStyle) {
if(!$(this).parent().find("ul").is(':visible')){
// Fetch all parents.
parents = $(this).parent().parents("ul");
// Fetch all visible ul's.
visible = $this.find("ul:visible");
// Loop through.
visible.each(function(visibleIndex){
var close = true;
// Check if the parent is closed.
parents.each(function(parentIndex){
if(parents[parentIndex] == visible[visibleIndex]){
close = false;
return false;
}
});
// If closed, slide the content of the ul up
// (so collapse).
if(close){
if($(this).parent().find("ul") !=
visible[visibleIndex]){
$(visible[visibleIndex]).slideUp(speedo);
}
}
});
}
}
if($(this).parent().find("ul:first").is(":visible")) {
$(this).parent().find("ul:first").slideUp(speedo);
}
else {
$(this).parent().find("ul:first").slideDown(speedo);
}
}
});
}
There you have it, your code is done! Now all we need to do is make sure it will execute the function as soon as a page is loaded. We need to get back to our master page for this. So open your master page again (in advanced edit mode) and
find the following piece of code:
<script type="text/javascript">
//<![CDATA[
var g_pageLoadAnimationParams = { elementSlideIn : "sideNavBox",
elementSlideInPhase2 : "contentBox" };
//]]>
</script>
We
will not change that part, but we will have to paste some code underneath it. Here's the code:
<script type="text/javascript">
//<![CDATA[
var g_pageLoadAnimationParams = { elementSlideIn : "sideNavBox",
elementSlideInPhase2 : "contentBox" };
$(function runOnInitLoad() {
accordionMe(jQuery("#zz9_RootAspMenu"), "selected");
accordionMe(jQuery("#zz10_RootAspMenu"), "selected");
accordionMe(jQuery("#zz11_RootAspMenu"), "selected");
accordionMe(jQuery("#zz12_RootAspMenu"), "selected");
accordionMe(jQuery("#zz13_RootAspMenu"), "selected");
accordionMe(jQuery("#zz14_RootAspMenu"), "selected");
accordionMe(jQuery("#zz15_RootAspMenu"), "selected");
accordionMe(jQuery("#zz16_RootAspMenu"), "selected");
runThisCode();
moveScroller();
setCustomFontName('#fseaFont-1-1-Menu');
});
ExecuteOrDelayUntilScriptLoaded(function() { runOnInitLoad(); },
"init.js");
//]]>
</script>
The reason that I use the function on so many different ID's is because these menu ID's get used often, spread across the site. These are just all the ones I needed, so I added them all. Feel free to add/remove some.
After you have saved your master page, checked it in and published it as a major version (and don't forget to check in and publish your scripts as well), we're all done! You now should have a nice accordion menu, sliding up and down as you click on it. :) Enjoy!
PS.: I would like to express my thanks to Mathias Bosman, who seriously helped me with this (basically, he made the whole script work). Thanks Mathias!