user1184100
user1184100

Reputation: 6894

How to have accordion type of menu?

I'm creating a folder view type of plugin and i've put my code in jsfiddle...

http://jsfiddle.net/masnR/1/ Basically i'm trying to have accordion type in this...

When i click on Folder2, folder1 should collapse and only folder2 should be visible and expanded.

How can i go ahead with this.. ?

Upvotes: 0

Views: 112

Answers (2)

ShadowScripter
ShadowScripter

Reputation: 7369

Before I give you the solution

I can tell you right now, your HTML structuring is not very consistent Mr/Mrs!

Your top node link is not contained in an li and is treated differently. All nodes should have the same structure for easy traversing.

I would urge you to consider using a classic setup that looks like this

<div class='container'>
    <ul>
        <li>
            <a href='#'>Folder 1</a>
            <ul>
                <li>Sub item 1</li>
                <li>Sub item 2</li>
                <li>
                    <a href='#'>Sub Folder 1</a>
                    <ul>
                        <li>Sub item 1</li>
                        <li>Sub item 2</li>
                        <li>Sub item 3</li>
                    </ul>
                </li>
            </ul>
        </li>
        <!-- ... -->
    </ul>
</div>

This is much more consistent, and it is easier to traverse... also it is very aesthetically pleasing... ;)

Your javascript code is inefficient. Instead of collapsing each li, consider collapsing the ul instead. I also had a hard time deciphering what the code was trying to do, as I believe everyone has, which is why you haven't gotten many answers.
Consider adding comments or making your code "cleaner" to look at. It is for everyone's sake, including your own.


Example

I have created this example for you to take a look at. These menus are very common, so you can expect many other plugins to have a similar markup/functionality.

It utilizes the same HTML structure as previously mentioned.

Example | Code

$(document).ready(function () {
    $('.fileview').fileview({
        bAnimate: false //I don't like animations to be honest ;)
    });
});

$.fn.fileview = function(options) {
    var config = {
        sCollapseClass: "collapse",
        sUncollapseClass: "uncollapse",
        sSelectedClass: "selected",
        bCollapseAll: true,
        bCollapseAdjacent: true,
        bStartCollapsed: true,
        bAnimate: true,
        iAnimationTime: 250
    };

    $.extend(config, options);

    //Collapse link & list
    function collapse($link, $list){
        //Remove the uncollapse class and add the collapse class to link and list
        $($link).removeClass(config.sUncollapseClass)
                .addClass(config.sCollapseClass);
        $($list).removeClass(config.sUncollapseClass)
                .addClass(config.sCollapseClass);

        //Animate?
        if(config.bAnimate){
            $list.slideUp(config.iAnimationTime);
        }else{
            $($list).hide();  
        }

        //Collapse nested lists?
        if(config.bCollapseAll){
            $("ul."+config.sUncollapseClass, $list).each(function(){
                collapse($(this).prev(), $(this));
            });
        }
    }

    //Uncollapse link & list
    function uncollapse($link, $list){

        //Remove the collapse class and add the uncollapse class to link and list
        $link.removeClass(config.sCollapseClass)
             .addClass(config.sUncollapseClass);
        $list.removeClass(config.sCollapseClass)
             .addClass(config.sUncollapseClass);

        //Animate?
        if(config.bAnimate){
            $list.slideDown(config.iAnimationTime);
        }else{
            $list.show();
        }

        //Collapse adjacent nodes?
        if(config.bCollapseAdjacent){
            $link.closest("li").siblings("li").each(function(){
                collapse($(this).children(":nth-child(1)"), $(this).children(":nth-child(2)"));
            });
        }  
    }

    //Select node
    function select(link, context){
        if(config.sSelectedClass == "" || $(link).hasClass(config.sSelectedClass)) return;

        $("."+config.sSelectedClass, context).removeClass(config.sSelectedClass);
        $(link).addClass(config.sSelectedClass);
    }

    //Start collapsed?
    if(config.bStartCollapsed === true){
        $("a, ul", $(this).children()).each(function(){
            if(!$(this).hasClass(config.sUncollapseClass))
                $(this).addClass(config.sCollapseClass);
        });
    }else if(config.bStartCollapsed === false){
        $("a, ul", $(this).children()).each(function(){
            if(!$(this).hasClass(config.sCollapseClass))
                $(this).addClass(config.sUncollapseClass);
        });
    }

    //Hide collapse class list nodes
    $("ul."+config.sCollapseClass, this).hide();

    this.each(function(){
        var _self = this;

        //Collapse/Uncollapse for list items that have a ul child
        $("li > ul", this).each(function(){
            var $_this = $(this),
                $link = $(this).siblings("a");

            $link.click(function(){
                if($_this.hasClass(config.sCollapseClass)){
                    uncollapse($link, $_this);
                }else{
                    collapse($link, $_this);
                }
            });
        });

        //Select event
        $("a", this).click(function(){
            select(this, _self);
        });

    });    
};

The solution

There seem to be other issues with your code, but this is how I'd do it with the current markup.

Example | Code

function showElement(element){
    element.addClass(config.collapseElementClass);
    element.removeClass(config.expandElementClass);
    element['siblings']()[displayEffectShow]();
    element.html(htmlCollapse);

    //Select all the li siblings
    var $siblings = element.closest("li").siblings("li");

    //Check if there were no siblings, which would indicate that we're at the top node
    if($siblings.length == 0)
        $siblings = element.closest("ul").siblings("ul");

    //Hide all the siblings
    $siblings.each(function(){
        hideElement($("a", this));
    });
}

Upvotes: 1

Frank van Wijk
Frank van Wijk

Reputation: 3252

The accordion animation effect can be made with a slideUp and a slideDown. Both are supported by jQuery. But it's easier to use jQuery accordion.

Upvotes: 1

Related Questions