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.

425 lines
12 KiB

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