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.

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