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.

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