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.

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