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.

461 lines
14 KiB

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