Reputation: 215
I have a script that should add accordion functionality to a vertical menu. I mainly used code from this blog. The menu I made consists of multiple levels, the example I made in this jsFiddle is only 3 levels deep but I plan on using more (it is a requirement for my client).
When an element has the class "selected", I want only that element and its parents to be shown as soon as the page loads. In the example that element is colored green, but the parents of that element should of course also be shown. When a user selects a different element to expand, it should hide the first one and show the content of the element that has just been clicked.
Please take a look at the example first, and try it out a bit. Then compare it to the below.
This is how the menu should like like in the first place, as soon as the page loads:
- Site 1
- Site 1, page 1
- Site 1, page 2
- Site 1, subsite 1
- Site 1, subsite 1, page 1
- Site 1, subsite 1, page 2
- Site 1, subsite 2
- Site 1, page 3
- Site 2
So as you can see, the only things that should be immediately visible are the elements that contain the class "selected" in the HTML. All the rest should be simply collapsed. Of course, as soon as a user clicks on another subsite, or on Site 1 or Site 2, it should collapse the current one which has "selected", and open up the other element that has been clicked. The behavior it has now is absolutely not what I intended it to be, I've been trying around a lot but no success so far.
I cannot quite manage to see how I could fix this. I've been trying to make it work since last week and I'm still stuck. Therefore I would really appreciate it if someone could take a look and tell me what I'm doing wrong and why it behaves like that.
Some additional information: this menu will be used in a SharePoint 2013 environment, it will replace the SharePoint Quick Launch menu.
Thanks in advance for your time!
EDIT:
In case the jsFiddle becomes unavailable, here is the HTML and JavaScript code.
HTML:
<body>
<div id="sideNavBox">
<ul id="rootMenu" class="static root">
<li class="static level-0 selected"><a class="static menu-item-li" href="#"><span>Site 1</span></a>
<ul class="static level-0-ul selected">
<li class="static level-1"><a class="static menu-item-li" href="#"><span>Site 1, page 1</span></a></li>
<li class="static level-1"><a class="static menu-item-li" href="#"><span>Site 1, page 2</span></a></li>
<li class="static level-1 selected"><a class="static menu-item-li" href="#"><span>Site 1, subsite 1</span></a>
<ul class="static level-1-ul selected">
<li class="static level-2 selected"><a class="static menu-item-li selected" href="#"><span>Site 1, subsite 1, page 1</span></a></li>
<li class="static level-2"><a class="static menu-item-li" href="#"><span>Site 1, subsite 1, page 2</span></a></li>
</ul>
</li>
<li class="static level-1"><a class="static menu-item-li" href="#"><span>Site 1, subsite 2</span></a>
<ul class="static level-1-ul">
<li class="static level-2"><a class="static menu-item-li" href="#"><span>Site 1 subsite 2, page 1</span></a></li>
<li class="static level-2"><a class="static menu-item-li" href="#"><span>Site 1 subsite 2, page 2</span></a></li>
</ul>
</li>
<li class="static level-1"><a class="static menu-item-li" href="#"><span>Site 1, page 3</span></a></li>
</ul>
</li>
<li class="static level-0"><a class="static menu-item-li" href="#"><span>Site 2</span></a>
<ul class="static level-0-ul">
<li class="static level-1"><a class="static menu-item-li" href="#"><span>Site 2, page 1</span></a></li>
<li class="static level-1"><a class="static menu-item-li" href="#"><span>Site 2, subsite 1</span></a>
<ul class="static level-1-ul">
<li class="static level-2"><a class="static menu-item-li" href="#"><span>Site 2, subsite 1, page 1</span></a></li>
</ul>
</li>
<li class="static level-1"><a class="static menu-item-li" href="#"><span>Site 2, subsite 2</span></a>
<ul class="static level-1-ul">
<li class="static level-2"><a class="static menu-item-li" href="#"><span>Site 2, subsite 2, page 1</span></a></li>
<li class="static level-2"><a class="static menu-item-li" href="#"><span>Site 2, subsite 2, page 2</span></a></li>
</ul>
</li>
<li class="static level-1"><a class="static menu-item-li" href="#"><span>Site 2, page 2</span></a></li>
<li class="static level-1"><a class="static menu-item-li" href="#"><span>Site 2, page 3</span></a></li>
</ul>
</li>
</ul>
</div>
JavaScript:
// Set dynamic CSS logic:
if($('#sideNavBox .menu-item-li.selected').length){
// Propagates the selected class, up the three:
$('li.static').removeClass('selected');
$('#sideNavBox .menu-item-li.selected').parents('li.static').addClass('selected');
// Collapses top siblings of selected branch:
$('#sideNavBox .menu-item-li.selected').parents('li.static').last().siblings().find('> ul').hide();
$('#sideNavBox .menu-item-li.selected').parents('li.static').siblings().find('> ul').hide();
}
else {
$('#sideNavBox .root.static > li.static > ul').hide();
}
/* CODE INTENDED FOR COLLAPSING AND EXPANDING THE level-0 AND level-0-ul ELEMENTS */
$('#sideNavBox .root.static > li.static.level-0').each(function(){ // For each element,
if($(this).find('ul').length){ // That has a ul inside it,
$(this).addClass('father').click(function(){ // Add the class 'father' to it.
if($(this).children('ul').css('display') != 'none'){
$(this).removeClass('selected').children('ul').slideUp();
}
else {
/*collapse-siblings*/
$(this).siblings().removeClass('selected').children('ul').slideUp();
/*expand*/
$(this).addClass('selected').children('ul').slideDown();
}
});
}
});
/* SAME CODE AS ABOVE BUT NOW INTENDED FOR COLLAPSING AND EXPANDING THE level-1 AND level-1-ul ELEMENTS */
$('#sideNavBox .root.static > li.static > ul.static > li.static').each(function(){
if($('#sideNavBox .root.static > li.static > ul.static > li.static').find('ul').length){
$(this).addClass('father2').click(function(){
if($(this).children('ul').css('display') != 'none'){
$(this).removeClass('selected').children('ul').slideUp();
}
else {
/*collapse-siblings*/
$(this).siblings().removeClass('selected').children('ul').slideUp();
/*expand*/
$(this).addClass('selected').children('ul').slideDown();
}
});
}
});
/* CODE INTENDED FOR DISABLING DEFAULT LINK BEHAVIOR FOR level-0 AND level-0-ul ELEMENTS */
$('#sideNavBox .root.static > li.static > a.static').click(function(e) {
/*Prevent the link from activating*/
e.preventDefault();
/*Upon clicking header, show contents*/
$('#sideNavBox .root.static > li.static').addClass('selected').children('ul').slideUp();
});
/* CODE INTENDED FOR DISABLING DEFAULT LINK BEHAVIOR BUT NOW FOR level-1 AND level-1-ul ELEMENTS */
$('#sideNavBox .root.static > li.static.level-0 > ul.static.level-0-ul > li.static.level-1 > a.static').click(function(e) {
/*Prevent the link from activating*/
e.preventDefault();
/*Upon clicking header, show contents*/
$('#sideNavBox .root.static > li.static.level-0 > ul.static.level-0-ul > li.static.level-1').addClass('selected');
$('#sideNavBox .root.static > li.static.level-0 > ul.static.level-0-ul > li.static.level-1').children('ul.level-1-ul').slideUp();
});
Upvotes: 2
Views: 4669
Reputation: 344
Here you are my old class mate: http://jsfiddle.net/wxu6f/6/
took some time but at least it's working... I think?
function accordionMe(selector, initalOpeningClass) {
var speedo = 300;
var $this = selector;
var accordionStyle = true; // fancy or not as fancy.. (just set it to true)
// disable all links with # as href, or the page will jump like a chicken on coce
$this.find("li").each(function(){
// Find all these links
if ($(this).find("ul").size() != 0) {
// and disable them if needed
if ($(this).find("a:first").attr('href') == '#') {
$(this).find("a:first").click(function(){ return false; });
}
}
});
// Hide every ul first
$("#rootMenu li>ul").hide();
// Open all items (depending on the class you chose)
$this.find("li."+initalOpeningClass).each(function(){
$(this).parents("ul").slideDown(speedo);
});
// and now.. time for magic
$this.find("li a").click(function(){
if ($(this).parent().find("ul").size() != 0) {
if (accordionStyle) {
if(!$(this).parent().find("ul").is(':visible')){
// get all parents
parents = $(this).parent().parents("ul");
// get all visible ul's'
visible = $this.find("ul:visible");
// Loop through
visible.each(function(visibleIndex){
// check if parent was closed
var close = true;
parents.each(function(parentIndex){
if(parents[parentIndex] == visible[visibleIndex]){
close = false;
return false;
}
});
// if closed, close parent
if(close)
if($(this).parent().find("ul") != visible[visibleIndex])
$(visible[visibleIndex]).slideUp(speedo);
});
}
}
// if the parent was shown at first, hide him and vica versa
if($(this).parent().find("ul:first").is(":visible"))
$(this).parent().find("ul:first").slideUp(speedo);
else
$(this).parent().find("ul:first").slideDown(speedo);
}
}); // einde klik event
}
accordionMe($("#rootMenu"), "selected");
Upvotes: 1
Reputation: 5158
Why not do something as simple as
$("#rootMenu li>a").click(function(e){
var tt = $(this).closest("li");
if(tt.hasClass("selected"))
{
//Collapse all children
tt.removeClass("selected");
$("ul",tt).slideUp(500);
tt.removeClass("selected");
}
else
{
//expand first level ul, a.k.a direct child
$(">ul",tt).slideDown(500);
tt.addClass("selected");
}
});
Upvotes: 1