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.

423 lines
12 KiB

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