You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

429 lines
13 KiB

10 years ago
  1. /*
  2. * # Semantic - Accordion
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2013 Contributors
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ($, window, document, undefined) {
  12. $.fn.accordion = function(parameters) {
  13. var
  14. $allModules = $(this),
  15. time = new Date().getTime(),
  16. performance = [],
  17. query = arguments[0],
  18. methodInvoked = (typeof query == 'string'),
  19. queryArguments = [].slice.call(arguments, 1),
  20. returnedValue
  21. ;
  22. $allModules
  23. .each(function() {
  24. var
  25. settings = ( $.isPlainObject(parameters) )
  26. ? $.extend(true, {}, $.fn.accordion.settings, parameters)
  27. : $.extend({}, $.fn.accordion.settings),
  28. className = settings.className,
  29. namespace = settings.namespace,
  30. selector = settings.selector,
  31. error = settings.error,
  32. eventNamespace = '.' + namespace,
  33. moduleNamespace = 'module-' + namespace,
  34. moduleSelector = $allModules.selector || '',
  35. $module = $(this),
  36. $title = $module.find(selector.title),
  37. $content = $module.find(selector.content),
  38. element = this,
  39. instance = $module.data(moduleNamespace),
  40. module
  41. ;
  42. module = {
  43. initialize: function() {
  44. module.debug('Initializing accordion with bound events', $module);
  45. // initializing
  46. $title
  47. .on('click' + eventNamespace, module.event.click)
  48. ;
  49. module.instantiate();
  50. },
  51. instantiate: function() {
  52. instance = module;
  53. $module
  54. .data(moduleNamespace, module)
  55. ;
  56. },
  57. destroy: function() {
  58. module.debug('Destroying previous accordion for', $module);
  59. $module
  60. .removeData(moduleNamespace)
  61. ;
  62. $title
  63. .off(eventNamespace)
  64. ;
  65. },
  66. event: {
  67. click: function() {
  68. module.verbose('Title clicked', this);
  69. var
  70. $activeTitle = $(this),
  71. index = $title.index($activeTitle)
  72. ;
  73. module.toggle(index);
  74. },
  75. resetDisplay: function() {
  76. $(this).css('display', '');
  77. if( $(this).attr('style') == '') {
  78. $(this)
  79. .attr('style', '')
  80. .removeAttr('style')
  81. ;
  82. }
  83. },
  84. resetOpacity: function() {
  85. $(this).css('opacity', '');
  86. if( $(this).attr('style') == '') {
  87. $(this)
  88. .attr('style', '')
  89. .removeAttr('style')
  90. ;
  91. }
  92. }
  93. },
  94. toggle: function(index) {
  95. module.debug('Toggling content content at index', index);
  96. var
  97. $activeTitle = $title.eq(index),
  98. $activeContent = $activeTitle.next($content),
  99. contentIsOpen = $activeContent.is(':visible')
  100. ;
  101. if(contentIsOpen) {
  102. if(settings.collapsible) {
  103. module.close(index);
  104. }
  105. else {
  106. module.debug('Cannot close accordion content collapsing is disabled');
  107. }
  108. }
  109. else {
  110. module.open(index);
  111. }
  112. },
  113. open: function(index) {
  114. var
  115. $activeTitle = $title.eq(index),
  116. $activeContent = $activeTitle.next($content),
  117. $previousTitle = $activeTitle.siblings(selector.title).filter('.' + className.active),
  118. $previousContent = $previousTitle.next($title),
  119. contentIsOpen = ($previousTitle.size() > 0)
  120. ;
  121. if( !$activeContent.is(':animated') ) {
  122. module.debug('Opening accordion content', $activeTitle);
  123. if(settings.exclusive && contentIsOpen) {
  124. $previousTitle
  125. .removeClass(className.active)
  126. ;
  127. $previousContent
  128. .stop()
  129. .children()
  130. .stop()
  131. .animate({
  132. opacity: 0
  133. }, settings.duration, module.event.resetOpacity)
  134. .end()
  135. .slideUp(settings.duration , settings.easing, function() {
  136. $previousContent
  137. .removeClass(className.active)
  138. .children()
  139. ;
  140. $.proxy(module.event.resetDisplay, this)();
  141. })
  142. ;
  143. }
  144. $activeTitle
  145. .addClass(className.active)
  146. ;
  147. $activeContent
  148. .stop()
  149. .children()
  150. .stop()
  151. .animate({
  152. opacity: 1
  153. }, settings.duration)
  154. .end()
  155. .slideDown(settings.duration, settings.easing, function() {
  156. $activeContent
  157. .addClass(className.active)
  158. ;
  159. $.proxy(module.event.resetDisplay, this)();
  160. $.proxy(settings.onOpen, $activeContent)();
  161. $.proxy(settings.onChange, $activeContent)();
  162. })
  163. ;
  164. }
  165. },
  166. close: function(index) {
  167. var
  168. $activeTitle = $title.eq(index),
  169. $activeContent = $activeTitle.next($content)
  170. ;
  171. module.debug('Closing accordion content', $activeContent);
  172. $activeTitle
  173. .removeClass(className.active)
  174. ;
  175. $activeContent
  176. .removeClass(className.active)
  177. .show()
  178. .stop()
  179. .children()
  180. .stop()
  181. .animate({
  182. opacity: 0
  183. }, settings.duration, module.event.resetOpacity)
  184. .end()
  185. .slideUp(settings.duration, settings.easing, function(){
  186. $.proxy(module.event.resetDisplay, this)();
  187. $.proxy(settings.onClose, $activeContent)();
  188. $.proxy(settings.onChange, $activeContent)();
  189. })
  190. ;
  191. },
  192. setting: function(name, value) {
  193. module.debug('Changing setting', name, value);
  194. if( $.isPlainObject(name) ) {
  195. $.extend(true, settings, name);
  196. }
  197. else if(value !== undefined) {
  198. settings[name] = value;
  199. }
  200. else {
  201. return settings[name];
  202. }
  203. },
  204. internal: function(name, value) {
  205. module.debug('Changing internal', name, value);
  206. if(value !== undefined) {
  207. if( $.isPlainObject(name) ) {
  208. $.extend(true, module, name);
  209. }
  210. else {
  211. module[name] = value;
  212. }
  213. }
  214. else {
  215. return module[name];
  216. }
  217. },
  218. debug: function() {
  219. if(settings.debug) {
  220. if(settings.performance) {
  221. module.performance.log(arguments);
  222. }
  223. else {
  224. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  225. module.debug.apply(console, arguments);
  226. }
  227. }
  228. },
  229. verbose: function() {
  230. if(settings.verbose && settings.debug) {
  231. if(settings.performance) {
  232. module.performance.log(arguments);
  233. }
  234. else {
  235. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  236. module.verbose.apply(console, arguments);
  237. }
  238. }
  239. },
  240. error: function() {
  241. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  242. module.error.apply(console, arguments);
  243. },
  244. performance: {
  245. log: function(message) {
  246. var
  247. currentTime,
  248. executionTime,
  249. previousTime
  250. ;
  251. if(settings.performance) {
  252. currentTime = new Date().getTime();
  253. previousTime = time || currentTime;
  254. executionTime = currentTime - previousTime;
  255. time = currentTime;
  256. performance.push({
  257. 'Element' : element,
  258. 'Name' : message[0],
  259. 'Arguments' : [].slice.call(message, 1) || '',
  260. 'Execution Time' : executionTime
  261. });
  262. }
  263. clearTimeout(module.performance.timer);
  264. module.performance.timer = setTimeout(module.performance.display, 100);
  265. },
  266. display: function() {
  267. var
  268. title = settings.name + ':',
  269. totalTime = 0
  270. ;
  271. time = false;
  272. clearTimeout(module.performance.timer);
  273. $.each(performance, function(index, data) {
  274. totalTime += data['Execution Time'];
  275. });
  276. title += ' ' + totalTime + 'ms';
  277. if(moduleSelector) {
  278. title += ' \'' + moduleSelector + '\'';
  279. }
  280. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  281. console.groupCollapsed(title);
  282. if(console.table) {
  283. console.table(performance);
  284. }
  285. else {
  286. $.each(performance, function(index, data) {
  287. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  288. });
  289. }
  290. console.groupEnd();
  291. }
  292. performance = [];
  293. }
  294. },
  295. invoke: function(query, passedArguments, context) {
  296. var
  297. object = instance,
  298. maxDepth,
  299. found,
  300. response
  301. ;
  302. passedArguments = passedArguments || queryArguments;
  303. context = element || context;
  304. if(typeof query == 'string' && object !== undefined) {
  305. query = query.split(/[\. ]/);
  306. maxDepth = query.length - 1;
  307. $.each(query, function(depth, value) {
  308. var camelCaseValue = (depth != maxDepth)
  309. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  310. : query
  311. ;
  312. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  313. object = object[camelCaseValue];
  314. }
  315. else if( object[camelCaseValue] !== undefined ) {
  316. found = object[camelCaseValue];
  317. return false;
  318. }
  319. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  320. object = object[value];
  321. }
  322. else if( object[value] !== undefined ) {
  323. found = object[value];
  324. return false;
  325. }
  326. else {
  327. return false;
  328. }
  329. });
  330. }
  331. if ( $.isFunction( found ) ) {
  332. response = found.apply(context, passedArguments);
  333. }
  334. else if(found !== undefined) {
  335. response = found;
  336. }
  337. if($.isArray(returnedValue)) {
  338. returnedValue.push(response);
  339. }
  340. else if(returnedValue !== undefined) {
  341. returnedValue = [returnedValue, response];
  342. }
  343. else if(response !== undefined) {
  344. returnedValue = response;
  345. }
  346. return found;
  347. }
  348. };
  349. if(methodInvoked) {
  350. if(instance === undefined) {
  351. module.initialize();
  352. }
  353. module.invoke(query);
  354. }
  355. else {
  356. if(instance !== undefined) {
  357. module.destroy();
  358. }
  359. module.initialize();
  360. }
  361. })
  362. ;
  363. return (returnedValue !== undefined)
  364. ? returnedValue
  365. : this
  366. ;
  367. };
  368. $.fn.accordion.settings = {
  369. name : 'Accordion',
  370. namespace : 'accordion',
  371. debug : false,
  372. verbose : true,
  373. performance : true,
  374. exclusive : true,
  375. collapsible : true,
  376. duration : 500,
  377. easing : 'easeInOutQuint',
  378. onOpen : function(){},
  379. onClose : function(){},
  380. onChange : function(){},
  381. error: {
  382. method : 'The method you called is not defined'
  383. },
  384. className : {
  385. active : 'active'
  386. },
  387. selector : {
  388. title : '.title',
  389. content : '.content'
  390. }
  391. };
  392. // Adds easing
  393. $.extend( $.easing, {
  394. easeInOutQuint: function (x, t, b, c, d) {
  395. if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
  396. return c/2*((t-=2)*t*t*t*t + 2) + b;
  397. }
  398. });
  399. })( jQuery, window , document );