Bumpd Category Selector

by dannygarcia

HTML

<div id="items_wrapper">
    <ul id="items">
        <li class="chosen"><a href="#">Item 1</a></li>
        <li><a href="#">Item 2</a></li>
        <li><a href="#">Item 3</a></li>
        <li><a href="#">Item 4</a></li>
        <li><a href="#">Item 5</a></li>
    </ul>
</div>

SCSS

@mixin transition($data: all 0.3s ease-out) {
  -webkit-transition: $data;  
     -moz-transition: $data;  
      -ms-transition: $data;  
       -o-transition: $data;  
          transition: $data;

}

#items_wrapper {
    position: relative;
    height: 30px;
    overflow: hidden;
    @include transition();
}

#items {
    position: absolute;
    width: 100%;
    background: #999;
    top: 0px;
    @include transition();
}

#items > li, #items > li > a {
    display: block;
    height: 30px;
    line-height: 30px;
    @include transition();
}

#items > .chosen > a {
    color: white;
    background: orange;
    @include transition();
}

JavaScript

// itemSelector();
var itemSelector = (function() {
    // Variables
    var $wrapper = $('#items_wrapper'),    // wrapper div
        $items = $wrapper.find('#items'),  // item ul
        $allItems = $items.find('li'),     // all items
        $chosen = $items.find('.chosen'),  // chosen item (for future ref)
        height = $chosen.height(),         // item height
        open = false;                      // closed by default

    // When the wrapper is clicked:
    $wrapper.bind('click', function() {
        if (!open) {
            // If it's closed, open it.
            $(this).css('height', $allItems.length * height + 'px');
            $items.css('top', '0px');
        } else {
            // If it's open, close it.
            $(this).css('height', '');
        }
        // Sets open to false/true
        open = open ? false : true;
    });

    // When the individual item is clicked:
    $items.find('li').bind('click', function() {
        // Remove the chosen class.
        $allItems.removeClass('chosen');
        // Add the chosen class to the selected item.
        $(this).addClass('chosen');
        // Get the amount of pixels to move.
        var moveAmount = $(this).index() * height;
        // Move it, move it.
        $items.css('top', -moveAmount + 'px');
    });

    return {
        // Returns the chosen element.
        activeItem: function() {
            return $items.find('.chosen');
        },
        
        // Resets to the first item.
        cancel: function() {
            $allItems.removeClass('chosen');
            if (open) {
                $chosen.trigger('click');
            } else {
                $chosen.addClass('chosen');
                $items.css('top',-$chosen.index()*height+'px');
            }
        },
        
        // Returns the status of the selector.
        status: function() {
            return open ? 'open' : 'closed';
        }
    }

})();