| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 | /*! * jQuery Accordion 0.0.1 * (c) 2014 Victor Fernandez <victor@vctrfrnndz.com> * MIT Licensed. */;(function ( $, window, document, undefined ) {    var pluginName = 'accordion',        defaults = {            transitionSpeed: 300,            transitionEasing: 'ease',            controlElement: '[data-control]',            contentElement: '[data-content]',            groupElement: '[data-accordion-group]',            singleOpen: true        };    function Accordion(element, options) {        this.element = element;        this.options = $.extend({}, defaults, options);        this._defaults = defaults;        this._name = pluginName;        this.init();    }    Accordion.prototype.init = function () {        var self = this,            opts = self.options;        var $accordion = $(self.element),            $controls = $accordion.find('> ' + opts.controlElement),            $content =  $accordion.find('> ' + opts.contentElement);        var accordionParentsQty = $accordion.parents('[data-accordion]').length,            accordionHasParent = accordionParentsQty > 0;        var closedCSS = { 'max-height': 0, 'overflow': 'hidden' };        var CSStransitions = supportsTransitions();        function debounce(func, threshold, execAsap) {            var timeout;            return function debounced() {                var obj = this,                    args = arguments;                function delayed() {                    if (!execAsap) func.apply(obj, args);                    timeout = null;                };                if (timeout) clearTimeout(timeout);                else if (execAsap) func.apply(obj, args);                timeout = setTimeout(delayed, threshold || 100);            };        }        function supportsTransitions() {            var b = document.body || document.documentElement,                s = b.style,                p = 'transition';            if (typeof s[p] == 'string') {                return true;            }            var v = ['Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms'];            p = 'Transition';            for (var i=0; i<v.length; i++) {                if (typeof s[v[i] + p] == 'string') {                    return true;                }            }            return false;        }        function requestAnimFrame(cb) {            if(window.requestAnimationFrame){                requestAnimationFrame(cb);            } else if (window.webkitRequestAnimationFrame) {                webkitRequestAnimationFrame(cb);            } else if (window.mozRequestAnimationFrame) {                mozRequestAnimationFrame(cb);            } else {                setTimeout(cb, 1000 / 60);            }        }        function toggleTransition($el, remove) {            if(!remove) {                $content.css({                    '-webkit-transition': 'max-height ' + opts.transitionSpeed + 'ms ' + opts.transitionEasing,                    'transition': 'max-height ' + opts.transitionSpeed + 'ms ' + opts.transitionEasing                });            } else {                $content.css({                    '-webkit-transition': '',                    'transition': ''                });            }        }        function calculateHeight($el) {            var height = 0;            $el.children().each(function() {                height = height + $(this).outerHeight(true);            });            $el.data('oHeight', height);        }        function updateParentHeight($parentAccordion, $currentAccordion, qty, operation) {            var $content = $parentAccordion.filter('.open').find('> [data-content]'),                $childs = $content.find('[data-accordion].open > [data-content]'),                $matched;            if(!opts.singleOpen) {                $childs = $childs.not($currentAccordion.siblings('[data-accordion].open').find('> [data-content]'));            }            $matched = $content.add($childs);            if($parentAccordion.hasClass('open')) {                $matched.each(function() {                    var currentHeight = $(this).data('oHeight');                    switch (operation) {                        case '+':                            $(this).data('oHeight', currentHeight + qty);                            break;                        case '-':                            $(this).data('oHeight', currentHeight - qty);                            break;                        default:                            throw 'updateParentHeight method needs an operation';                    }                    $(this).css('max-height', $(this).data('oHeight'));                });            }        }        function refreshHeight($accordion) {            if($accordion.hasClass('open')) {                var $content = $accordion.find('> [data-content]'),                    $childs = $content.find('[data-accordion].open > [data-content]'),                    $matched = $content.add($childs);                calculateHeight($matched);                $matched.css('max-height', $matched.data('oHeight'));            }        }        function closeAccordion($accordion, $content) {            $accordion.trigger('accordion.close');                        if(CSStransitions) {                if(accordionHasParent) {                    var $parentAccordions = $accordion.parents('[data-accordion]');                    updateParentHeight($parentAccordions, $accordion, $content.data('oHeight'), '-');                }                $content.css(closedCSS);                $accordion.removeClass('open');            } else {                $content.css('max-height', $content.data('oHeight'));                $content.animate(closedCSS, opts.transitionSpeed);                $accordion.removeClass('open');            }        }        function openAccordion($accordion, $content) {            $accordion.trigger('accordion.open');            if(CSStransitions) {                toggleTransition($content);                if(accordionHasParent) {                    var $parentAccordions = $accordion.parents('[data-accordion]');                    updateParentHeight($parentAccordions, $accordion, $content.data('oHeight'), '+');                }                requestAnimFrame(function() {                    $content.css('max-height', $content.data('oHeight'));                });                $accordion.addClass('open');            } else {                $content.animate({                    'max-height': $content.data('oHeight')                }, opts.transitionSpeed, function() {                    $content.css({'max-height': 'none'});                });                $accordion.addClass('open');            }        }        function closeSiblingAccordions($accordion) {            var $accordionGroup = $accordion.closest(opts.groupElement);            var $siblings = $accordion.siblings('[data-accordion]').filter('.open'),                $siblingsChildren = $siblings.find('[data-accordion]').filter('.open');            var $otherAccordions = $siblings.add($siblingsChildren);            $otherAccordions.each(function() {                var $accordion = $(this),                    $content = $accordion.find(opts.contentElement);                closeAccordion($accordion, $content);            });            $otherAccordions.removeClass('open');        }        function toggleAccordion() {            var isAccordionGroup = (opts.singleOpen) ? $accordion.parents(opts.groupElement).length > 0 : false;            calculateHeight($content);            if(isAccordionGroup) {                closeSiblingAccordions($accordion);            }            if($accordion.hasClass('open')) {                closeAccordion($accordion, $content);            } else {                openAccordion($accordion, $content);            }        }        function addEventListeners() {            $controls.on('click', toggleAccordion);                        $controls.on('accordion.toggle', function() {                if(opts.singleOpen && $controls.length > 1) {                    return false;                }                                toggleAccordion();            });                        $controls.on('accordion.refresh', function() {                refreshHeight($accordion);            });            $(window).on('resize', debounce(function() {                refreshHeight($accordion);            }));        }        function setup() {            $content.each(function() {                var $curr = $(this);                if($curr.css('max-height') != 0) {                    if(!$curr.closest('[data-accordion]').hasClass('open')) {                        $curr.css({ 'max-height': 0, 'overflow': 'hidden' });                    } else {                        toggleTransition($curr);                        calculateHeight($curr);                        $curr.css('max-height', $curr.data('oHeight'));                    }                }            });            if(!$accordion.attr('data-accordion')) {                $accordion.attr('data-accordion', '');                $accordion.find(opts.controlElement).attr('data-control', '');                $accordion.find(opts.contentElement).attr('data-content', '');            }        }        setup();        addEventListeners();    };    $.fn[pluginName] = function ( options ) {        return this.each(function () {            if (!$.data(this, 'plugin_' + pluginName)) {                $.data(this, 'plugin_' + pluginName,                new Accordion( this, options ));            }        });    }})( jQuery, window, document );
 |