| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- ;(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)
|