jquery.accordion.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. * jQuery UI Accordion 1.6
  3. *
  4. * Copyright (c) 2007 Jörn Zaefferer
  5. *
  6. * http://docs.jquery.com/UI/Accordion
  7. *
  8. * Dual licensed under the MIT and GPL licenses:
  9. * http://www.opensource.org/licenses/mit-license.php
  10. * http://www.gnu.org/licenses/gpl.html
  11. *
  12. * Revision: $Id: jquery.accordion.js 4876 2008-03-08 11:49:04Z joern.zaefferer $
  13. *
  14. */
  15. ;(function($) {
  16. // If the UI scope is not available, add it
  17. $.ui = $.ui || {};
  18. $.fn.extend({
  19. accordion: function(options, data) {
  20. var args = Array.prototype.slice.call(arguments, 1);
  21. return this.each(function() {
  22. if (typeof options == "string") {
  23. var accordion = $.data(this, "ui-accordion");
  24. accordion[options].apply(accordion, args);
  25. // INIT with optional options
  26. } else if (!$(this).is(".ui-accordion"))
  27. $.data(this, "ui-accordion", new $.ui.accordion(this, options));
  28. });
  29. },
  30. // deprecated, use accordion("activate", index) instead
  31. activate: function(index) {
  32. return this.accordion("activate", index);
  33. }
  34. });
  35. $.ui.accordion = function(container, options) {
  36. // setup configuration
  37. this.options = options = $.extend({}, $.ui.accordion.defaults, options);
  38. this.element = container;
  39. $(container).addClass("ui-accordion");
  40. if ( options.navigation ) {
  41. var current = $(container).find("a").filter(options.navigationFilter);
  42. if ( current.length ) {
  43. if ( current.filter(options.header).length ) {
  44. options.active = current;
  45. } else {
  46. options.active = current.parent().parent().prev();
  47. current.addClass("current");
  48. }
  49. }
  50. }
  51. // calculate active if not specified, using the first header
  52. options.headers = $(container).find(options.header);
  53. options.active = findActive(options.headers, options.active);
  54. if ( options.fillSpace ) {
  55. var maxHeight = $(container).parent().height();
  56. options.headers.each(function() {
  57. maxHeight -= $(this).outerHeight();
  58. });
  59. var maxPadding = 0;
  60. options.headers.next().each(function() {
  61. maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height());
  62. }).height(maxHeight - maxPadding);
  63. } else if ( options.autoheight ) {
  64. var maxHeight = 0;
  65. options.headers.next().each(function() {
  66. maxHeight = Math.max(maxHeight, $(this).outerHeight());
  67. }).height(maxHeight);
  68. }
  69. options.headers
  70. .not(options.active || "")
  71. .next()
  72. .hide();
  73. options.active.parent().andSelf().addClass(options.selectedClass);
  74. if (options.event)
  75. $(container).bind((options.event) + ".ui-accordion", clickHandler);
  76. };
  77. $.ui.accordion.prototype = {
  78. activate: function(index) {
  79. // call clickHandler with custom event
  80. clickHandler.call(this.element, {
  81. target: findActive( this.options.headers, index )[0]
  82. });
  83. },
  84. enable: function() {
  85. this.options.disabled = false;
  86. },
  87. disable: function() {
  88. this.options.disabled = true;
  89. },
  90. destroy: function() {
  91. this.options.headers.next().css("display", "");
  92. if ( this.options.fillSpace || this.options.autoheight ) {
  93. this.options.headers.next().css("height", "");
  94. }
  95. $.removeData(this.element, "ui-accordion");
  96. $(this.element).removeClass("ui-accordion").unbind(".ui-accordion");
  97. }
  98. }
  99. function scopeCallback(callback, scope) {
  100. return function() {
  101. return callback.apply(scope, arguments);
  102. };
  103. }
  104. function completed(cancel) {
  105. // if removed while animated data can be empty
  106. if (!$.data(this, "ui-accordion"))
  107. return;
  108. var instance = $.data(this, "ui-accordion");
  109. var options = instance.options;
  110. options.running = cancel ? 0 : --options.running;
  111. if ( options.running )
  112. return;
  113. if ( options.clearStyle ) {
  114. options.toShow.add(options.toHide).css({
  115. height: "",
  116. overflow: ""
  117. });
  118. }
  119. $(this).triggerHandler("change.ui-accordion", [options.data], options.change);
  120. }
  121. function toggle(toShow, toHide, data, clickedActive, down) {
  122. var options = $.data(this, "ui-accordion").options;
  123. options.toShow = toShow;
  124. options.toHide = toHide;
  125. options.data = data;
  126. var complete = scopeCallback(completed, this);
  127. // count elements to animate
  128. options.running = toHide.size() == 0 ? toShow.size() : toHide.size();
  129. if ( options.animated ) {
  130. if ( !options.alwaysOpen && clickedActive ) {
  131. $.ui.accordion.animations[options.animated]({
  132. toShow: jQuery([]),
  133. toHide: toHide,
  134. complete: complete,
  135. down: down,
  136. autoheight: options.autoheight
  137. });
  138. } else {
  139. $.ui.accordion.animations[options.animated]({
  140. toShow: toShow,
  141. toHide: toHide,
  142. complete: complete,
  143. down: down,
  144. autoheight: options.autoheight
  145. });
  146. }
  147. } else {
  148. if ( !options.alwaysOpen && clickedActive ) {
  149. toShow.toggle();
  150. } else {
  151. toHide.hide();
  152. toShow.show();
  153. }
  154. complete(true);
  155. }
  156. }
  157. function clickHandler(event) {
  158. var options = $.data(this, "ui-accordion").options;
  159. if (options.disabled)
  160. return false;
  161. // called only when using activate(false) to close all parts programmatically
  162. if ( !event.target && !options.alwaysOpen ) {
  163. options.active.parent().andSelf().toggleClass(options.selectedClass);
  164. var toHide = options.active.next(),
  165. data = {
  166. instance: this,
  167. options: options,
  168. newHeader: jQuery([]),
  169. oldHeader: options.active,
  170. newContent: jQuery([]),
  171. oldContent: toHide
  172. },
  173. toShow = options.active = $([]);
  174. toggle.call(this, toShow, toHide, data );
  175. return false;
  176. }
  177. // get the click target
  178. var clicked = $(event.target);
  179. // due to the event delegation model, we have to check if one
  180. // of the parent elements is our actual header, and find that
  181. if ( clicked.parents(options.header).length )
  182. while ( !clicked.is(options.header) )
  183. clicked = clicked.parent();
  184. var clickedActive = clicked[0] == options.active[0];
  185. // if animations are still active, or the active header is the target, ignore click
  186. if (options.running || (options.alwaysOpen && clickedActive))
  187. return false;
  188. if (!clicked.is(options.header))
  189. return;
  190. // switch classes
  191. options.active.parent().andSelf().toggleClass(options.selectedClass);
  192. if ( !clickedActive ) {
  193. clicked.parent().andSelf().addClass(options.selectedClass);
  194. }
  195. // find elements to show and hide
  196. var toShow = clicked.next(),
  197. toHide = options.active.next(),
  198. //data = [clicked, options.active, toShow, toHide],
  199. data = {
  200. instance: this,
  201. options: options,
  202. newHeader: clicked,
  203. oldHeader: options.active,
  204. newContent: toShow,
  205. oldContent: toHide
  206. },
  207. down = options.headers.index( options.active[0] ) > options.headers.index( clicked[0] );
  208. options.active = clickedActive ? $([]) : clicked;
  209. toggle.call(this, toShow, toHide, data, clickedActive, down );
  210. return false;
  211. };
  212. function findActive(headers, selector) {
  213. return selector != undefined
  214. ? typeof selector == "number"
  215. ? headers.filter(":eq(" + selector + ")")
  216. : headers.not(headers.not(selector))
  217. : selector === false
  218. ? $([])
  219. : headers.filter(":eq(0)");
  220. }
  221. $.extend($.ui.accordion, {
  222. defaults: {
  223. selectedClass: "selected",
  224. alwaysOpen: true,
  225. animated: 'slide',
  226. event: "click",
  227. header: "a",
  228. autoheight: true,
  229. running: 0,
  230. navigationFilter: function() {
  231. return this.href.toLowerCase() == location.href.toLowerCase();
  232. }
  233. },
  234. animations: {
  235. slide: function(options, additions) {
  236. options = $.extend({
  237. easing: "swing",
  238. duration: 300
  239. }, options, additions);
  240. if ( !options.toHide.size() ) {
  241. options.toShow.animate({height: "show"}, options);
  242. return;
  243. }
  244. var hideHeight = options.toHide.height(),
  245. showHeight = options.toShow.height(),
  246. difference = showHeight / hideHeight;
  247. options.toShow.css({ height: 0, overflow: 'hidden' }).show();
  248. options.toHide.filter(":hidden").each(options.complete).end().filter(":visible").animate({height:"hide"},{
  249. step: function(now) {
  250. var current = (hideHeight - now) * difference;
  251. if ($.browser.msie || $.browser.opera) {
  252. current = Math.ceil(current);
  253. }
  254. options.toShow.height( current );
  255. },
  256. duration: options.duration,
  257. easing: options.easing,
  258. complete: function() {
  259. if ( !options.autoheight ) {
  260. options.toShow.css("height", "auto");
  261. }
  262. options.complete();
  263. }
  264. });
  265. },
  266. bounceslide: function(options) {
  267. this.slide(options, {
  268. easing: options.down ? "bounceout" : "swing",
  269. duration: options.down ? 1000 : 200
  270. });
  271. },
  272. easeslide: function(options) {
  273. this.slide(options, {
  274. easing: "easeinout",
  275. duration: 700
  276. })
  277. }
  278. }
  279. });
  280. })(jQuery);