Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

jquery.accordion.js 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. ;(function ($, window, document, undefined) {
  2. var pluginName = 'accordion',
  3. defaults = {
  4. transitionSpeed: 300,
  5. transitionEasing: 'ease',
  6. controlElement: '[data-control]',
  7. contentElement: '[data-content]',
  8. groupElement: '[data-accordion-group]',
  9. singleOpen: true,
  10. }
  11. function Accordion(element, options) {
  12. this.element = element
  13. this.options = $.extend({}, defaults, options)
  14. this._defaults = defaults
  15. this._name = pluginName
  16. this.init()
  17. }
  18. Accordion.prototype.init = function () {
  19. var self = this,
  20. opts = self.options
  21. var $accordion = $(self.element),
  22. $controls = $accordion.find('> ' + opts.controlElement),
  23. $content = $accordion.find('> ' + opts.contentElement)
  24. var accordionParentsQty = $accordion.parents('[data-accordion]').length,
  25. accordionHasParent = accordionParentsQty > 0
  26. var closedCSS = { 'max-height': 0, overflow: 'hidden' }
  27. var CSStransitions = supportsTransitions()
  28. function debounce(func, threshold, execAsap) {
  29. var timeout
  30. return function debounced() {
  31. var obj = this,
  32. args = arguments
  33. function delayed() {
  34. if (!execAsap) func.apply(obj, args)
  35. timeout = null
  36. }
  37. if (timeout) clearTimeout(timeout)
  38. else if (execAsap) func.apply(obj, args)
  39. timeout = setTimeout(delayed, threshold || 100)
  40. }
  41. }
  42. function supportsTransitions() {
  43. var b = document.body || document.documentElement,
  44. s = b.style,
  45. p = 'transition'
  46. if (typeof s[p] == 'string') {
  47. return true
  48. }
  49. var v = ['Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms']
  50. p = 'Transition'
  51. for (var i = 0; i < v.length; i++) {
  52. if (typeof s[v[i] + p] == 'string') {
  53. return true
  54. }
  55. }
  56. return false
  57. }
  58. function requestAnimFrame(cb) {
  59. if (window.requestAnimationFrame) {
  60. requestAnimationFrame(cb)
  61. } else if (window.webkitRequestAnimationFrame) {
  62. webkitRequestAnimationFrame(cb)
  63. } else if (window.mozRequestAnimationFrame) {
  64. mozRequestAnimationFrame(cb)
  65. } else {
  66. setTimeout(cb, 1000 / 60)
  67. }
  68. }
  69. function toggleTransition($el, remove) {
  70. if (!remove) {
  71. $content.css({
  72. '-webkit-transition':
  73. 'max-height ' +
  74. opts.transitionSpeed +
  75. 'ms ' +
  76. opts.transitionEasing,
  77. transition:
  78. 'max-height ' +
  79. opts.transitionSpeed +
  80. 'ms ' +
  81. opts.transitionEasing,
  82. })
  83. } else {
  84. $content.css({
  85. '-webkit-transition': '',
  86. transition: '',
  87. })
  88. }
  89. }
  90. function calculateHeight($el) {
  91. var height = 0
  92. $el.children().each(function () {
  93. height = height + $(this).outerHeight(true)
  94. })
  95. $el.data('oHeight', height)
  96. }
  97. function updateParentHeight(
  98. $parentAccordion,
  99. $currentAccordion,
  100. qty,
  101. operation
  102. ) {
  103. var $content = $parentAccordion.filter('.open').find('> [data-content]'),
  104. $childs = $content.find('[data-accordion].open > [data-content]'),
  105. $matched
  106. if (!opts.singleOpen) {
  107. $childs = $childs.not(
  108. $currentAccordion
  109. .siblings('[data-accordion].open')
  110. .find('> [data-content]')
  111. )
  112. }
  113. $matched = $content.add($childs)
  114. if ($parentAccordion.hasClass('open')) {
  115. $matched.each(function () {
  116. var currentHeight = $(this).data('oHeight')
  117. switch (operation) {
  118. case '+':
  119. $(this).data('oHeight', currentHeight + qty)
  120. break
  121. case '-':
  122. $(this).data('oHeight', currentHeight - qty)
  123. break
  124. default:
  125. throw 'updateParentHeight method needs an operation'
  126. }
  127. $(this).css('max-height', $(this).data('oHeight'))
  128. })
  129. }
  130. }
  131. function refreshHeight($accordion) {
  132. if ($accordion.hasClass('open')) {
  133. var $content = $accordion.find('> [data-content]'),
  134. $childs = $content.find('[data-accordion].open > [data-content]'),
  135. $matched = $content.add($childs)
  136. calculateHeight($matched)
  137. $matched.css('max-height', $matched.data('oHeight'))
  138. }
  139. }
  140. function closeAccordion($accordion, $content) {
  141. $accordion.trigger('accordion.close')
  142. if (CSStransitions) {
  143. if (accordionHasParent) {
  144. var $parentAccordions = $accordion.parents('[data-accordion]')
  145. updateParentHeight(
  146. $parentAccordions,
  147. $accordion,
  148. $content.data('oHeight'),
  149. '-'
  150. )
  151. }
  152. $content.css(closedCSS)
  153. $accordion.removeClass('open')
  154. } else {
  155. $content.css('max-height', $content.data('oHeight'))
  156. $content.animate(closedCSS, opts.transitionSpeed)
  157. $accordion.removeClass('open')
  158. }
  159. }
  160. function openAccordion($accordion, $content) {
  161. $accordion.trigger('accordion.open')
  162. if (CSStransitions) {
  163. toggleTransition($content)
  164. if (accordionHasParent) {
  165. var $parentAccordions = $accordion.parents('[data-accordion]')
  166. updateParentHeight(
  167. $parentAccordions,
  168. $accordion,
  169. $content.data('oHeight'),
  170. '+'
  171. )
  172. }
  173. requestAnimFrame(function () {
  174. $content.css('max-height', $content.data('oHeight'))
  175. })
  176. $accordion.addClass('open')
  177. } else {
  178. $content.animate(
  179. {
  180. 'max-height': $content.data('oHeight'),
  181. },
  182. opts.transitionSpeed,
  183. function () {
  184. $content.css({ 'max-height': 'none' })
  185. }
  186. )
  187. $accordion.addClass('open')
  188. }
  189. }
  190. function closeSiblingAccordions($accordion) {
  191. var $accordionGroup = $accordion.closest(opts.groupElement)
  192. var $siblings = $accordion.siblings('[data-accordion]').filter('.open'),
  193. $siblingsChildren = $siblings.find('[data-accordion]').filter('.open')
  194. var $otherAccordions = $siblings.add($siblingsChildren)
  195. $otherAccordions.each(function () {
  196. var $accordion = $(this),
  197. $content = $accordion.find(opts.contentElement)
  198. closeAccordion($accordion, $content)
  199. })
  200. $otherAccordions.removeClass('open')
  201. }
  202. function toggleAccordion() {
  203. var isAccordionGroup = opts.singleOpen
  204. ? $accordion.parents(opts.groupElement).length > 0
  205. : false
  206. calculateHeight($content)
  207. if (isAccordionGroup) {
  208. closeSiblingAccordions($accordion)
  209. }
  210. if ($accordion.hasClass('open')) {
  211. closeAccordion($accordion, $content)
  212. } else {
  213. openAccordion($accordion, $content)
  214. }
  215. }
  216. function addEventListeners() {
  217. $controls.on('click', toggleAccordion)
  218. $controls.on('accordion.toggle', function () {
  219. if (opts.singleOpen && $controls.length > 1) {
  220. return false
  221. }
  222. toggleAccordion()
  223. })
  224. $controls.on('accordion.refresh', function () {
  225. refreshHeight($accordion)
  226. })
  227. $(window).on(
  228. 'resize',
  229. debounce(function () {
  230. refreshHeight($accordion)
  231. })
  232. )
  233. }
  234. function setup() {
  235. $content.each(function () {
  236. var $curr = $(this)
  237. if ($curr.css('max-height') != 0) {
  238. if (!$curr.closest('[data-accordion]').hasClass('open')) {
  239. $curr.css({ 'max-height': 0, overflow: 'hidden' })
  240. } else {
  241. toggleTransition($curr)
  242. calculateHeight($curr)
  243. $curr.css('max-height', $curr.data('oHeight'))
  244. }
  245. }
  246. })
  247. if (!$accordion.attr('data-accordion')) {
  248. $accordion.attr('data-accordion', '')
  249. $accordion.find(opts.controlElement).attr('data-control', '')
  250. $accordion.find(opts.contentElement).attr('data-content', '')
  251. }
  252. }
  253. setup()
  254. addEventListeners()
  255. }
  256. $.fn[pluginName] = function (options) {
  257. return this.each(function () {
  258. if (!$.data(this, 'plugin_' + pluginName)) {
  259. $.data(this, 'plugin_' + pluginName, new Accordion(this, options))
  260. }
  261. })
  262. }
  263. })(jQuery, window, document)