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.

611 lines
20 KiB

9 years ago
8 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 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
9 years ago
9 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
9 years ago
10 years ago
  1. /*!
  2. * # Semantic UI 2.2.0 - Accordion
  3. * http://github.com/semantic-org/semantic-ui/
  4. *
  5. *
  6. * Copyright 2015 Contributors
  7. * Released under the MIT license
  8. * http://opensource.org/licenses/MIT
  9. *
  10. */
  11. ;(function ($, window, document, undefined) {
  12. "use strict";
  13. window = (typeof window != 'undefined' && window.Math == Math)
  14. ? window
  15. : (typeof self != 'undefined' && self.Math == Math)
  16. ? self
  17. : Function('return this')()
  18. ;
  19. $.fn.accordion = function(parameters) {
  20. var
  21. $allModules = $(this),
  22. time = new Date().getTime(),
  23. performance = [],
  24. query = arguments[0],
  25. methodInvoked = (typeof query == 'string'),
  26. queryArguments = [].slice.call(arguments, 1),
  27. requestAnimationFrame = window.requestAnimationFrame
  28. || window.mozRequestAnimationFrame
  29. || window.webkitRequestAnimationFrame
  30. || window.msRequestAnimationFrame
  31. || function(callback) { setTimeout(callback, 0); },
  32. returnedValue
  33. ;
  34. $allModules
  35. .each(function() {
  36. var
  37. settings = ( $.isPlainObject(parameters) )
  38. ? $.extend(true, {}, $.fn.accordion.settings, parameters)
  39. : $.extend({}, $.fn.accordion.settings),
  40. className = settings.className,
  41. namespace = settings.namespace,
  42. selector = settings.selector,
  43. error = settings.error,
  44. eventNamespace = '.' + namespace,
  45. moduleNamespace = 'module-' + namespace,
  46. moduleSelector = $allModules.selector || '',
  47. $module = $(this),
  48. $title = $module.find(selector.title),
  49. $content = $module.find(selector.content),
  50. element = this,
  51. instance = $module.data(moduleNamespace),
  52. observer,
  53. module
  54. ;
  55. module = {
  56. initialize: function() {
  57. module.debug('Initializing', $module);
  58. module.bind.events();
  59. if(settings.observeChanges) {
  60. module.observeChanges();
  61. }
  62. module.instantiate();
  63. },
  64. instantiate: function() {
  65. instance = module;
  66. $module
  67. .data(moduleNamespace, module)
  68. ;
  69. },
  70. destroy: function() {
  71. module.debug('Destroying previous instance', $module);
  72. $module
  73. .off(eventNamespace)
  74. .removeData(moduleNamespace)
  75. ;
  76. },
  77. refresh: function() {
  78. $title = $module.find(selector.title);
  79. $content = $module.find(selector.content);
  80. },
  81. observeChanges: function() {
  82. if('MutationObserver' in window) {
  83. observer = new MutationObserver(function(mutations) {
  84. module.debug('DOM tree modified, updating selector cache');
  85. module.refresh();
  86. });
  87. observer.observe(element, {
  88. childList : true,
  89. subtree : true
  90. });
  91. module.debug('Setting up mutation observer', observer);
  92. }
  93. },
  94. bind: {
  95. events: function() {
  96. module.debug('Binding delegated events');
  97. $module
  98. .on(settings.on + eventNamespace, selector.trigger, module.event.click)
  99. ;
  100. }
  101. },
  102. event: {
  103. click: function() {
  104. module.toggle.call(this);
  105. }
  106. },
  107. toggle: function(query) {
  108. var
  109. $activeTitle = (query !== undefined)
  110. ? (typeof query === 'number')
  111. ? $title.eq(query)
  112. : $(query).closest(selector.title)
  113. : $(this).closest(selector.title),
  114. $activeContent = $activeTitle.next($content),
  115. isAnimating = $activeContent.hasClass(className.animating),
  116. isActive = $activeContent.hasClass(className.active),
  117. isOpen = (isActive && !isAnimating),
  118. isOpening = (!isActive && isAnimating)
  119. ;
  120. module.debug('Toggling visibility of content', $activeTitle);
  121. if(isOpen || isOpening) {
  122. if(settings.collapsible) {
  123. module.close.call($activeTitle);
  124. }
  125. else {
  126. module.debug('Cannot close accordion content collapsing is disabled');
  127. }
  128. }
  129. else {
  130. module.open.call($activeTitle);
  131. }
  132. },
  133. open: function(query) {
  134. var
  135. $activeTitle = (query !== undefined)
  136. ? (typeof query === 'number')
  137. ? $title.eq(query)
  138. : $(query).closest(selector.title)
  139. : $(this).closest(selector.title),
  140. $activeContent = $activeTitle.next($content),
  141. isAnimating = $activeContent.hasClass(className.animating),
  142. isActive = $activeContent.hasClass(className.active),
  143. isOpen = (isActive || isAnimating)
  144. ;
  145. if(isOpen) {
  146. module.debug('Accordion already open, skipping', $activeContent);
  147. return;
  148. }
  149. module.debug('Opening accordion content', $activeTitle);
  150. settings.onOpening.call($activeContent);
  151. if(settings.exclusive) {
  152. module.closeOthers.call($activeTitle);
  153. }
  154. $activeTitle
  155. .addClass(className.active)
  156. ;
  157. $activeContent
  158. .stop(true, true)
  159. .addClass(className.animating)
  160. ;
  161. if(settings.animateChildren) {
  162. if($.fn.transition !== undefined && $module.transition('is supported')) {
  163. $activeContent
  164. .children()
  165. .transition({
  166. animation : 'fade in',
  167. queue : false,
  168. useFailSafe : true,
  169. debug : settings.debug,
  170. verbose : settings.verbose,
  171. duration : settings.duration
  172. })
  173. ;
  174. }
  175. else {
  176. $activeContent
  177. .children()
  178. .stop(true, true)
  179. .animate({
  180. opacity: 1
  181. }, settings.duration, module.resetOpacity)
  182. ;
  183. }
  184. }
  185. $activeContent
  186. .slideDown(settings.duration, settings.easing, function() {
  187. $activeContent
  188. .removeClass(className.animating)
  189. .addClass(className.active)
  190. ;
  191. module.reset.display.call(this);
  192. settings.onOpen.call(this);
  193. settings.onChange.call(this);
  194. })
  195. ;
  196. },
  197. close: function(query) {
  198. var
  199. $activeTitle = (query !== undefined)
  200. ? (typeof query === 'number')
  201. ? $title.eq(query)
  202. : $(query).closest(selector.title)
  203. : $(this).closest(selector.title),
  204. $activeContent = $activeTitle.next($content),
  205. isAnimating = $activeContent.hasClass(className.animating),
  206. isActive = $activeContent.hasClass(className.active),
  207. isOpening = (!isActive && isAnimating),
  208. isClosing = (isActive && isAnimating)
  209. ;
  210. if((isActive || isOpening) && !isClosing) {
  211. module.debug('Closing accordion content', $activeContent);
  212. settings.onClosing.call($activeContent);
  213. $activeTitle
  214. .removeClass(className.active)
  215. ;
  216. $activeContent
  217. .stop(true, true)
  218. .addClass(className.animating)
  219. ;
  220. if(settings.animateChildren) {
  221. if($.fn.transition !== undefined && $module.transition('is supported')) {
  222. $activeContent
  223. .children()
  224. .transition({
  225. animation : 'fade out',
  226. queue : false,
  227. useFailSafe : true,
  228. debug : settings.debug,
  229. verbose : settings.verbose,
  230. duration : settings.duration
  231. })
  232. ;
  233. }
  234. else {
  235. $activeContent
  236. .children()
  237. .stop(true, true)
  238. .animate({
  239. opacity: 0
  240. }, settings.duration, module.resetOpacity)
  241. ;
  242. }
  243. }
  244. $activeContent
  245. .slideUp(settings.duration, settings.easing, function() {
  246. $activeContent
  247. .removeClass(className.animating)
  248. .removeClass(className.active)
  249. ;
  250. module.reset.display.call(this);
  251. settings.onClose.call(this);
  252. settings.onChange.call(this);
  253. })
  254. ;
  255. }
  256. },
  257. closeOthers: function(index) {
  258. var
  259. $activeTitle = (index !== undefined)
  260. ? $title.eq(index)
  261. : $(this).closest(selector.title),
  262. $parentTitles = $activeTitle.parents(selector.content).prev(selector.title),
  263. $activeAccordion = $activeTitle.closest(selector.accordion),
  264. activeSelector = selector.title + '.' + className.active + ':visible',
  265. activeContent = selector.content + '.' + className.active + ':visible',
  266. $openTitles,
  267. $nestedTitles,
  268. $openContents
  269. ;
  270. if(settings.closeNested) {
  271. $openTitles = $activeAccordion.find(activeSelector).not($parentTitles);
  272. $openContents = $openTitles.next($content);
  273. }
  274. else {
  275. $openTitles = $activeAccordion.find(activeSelector).not($parentTitles);
  276. $nestedTitles = $activeAccordion.find(activeContent).find(activeSelector).not($parentTitles);
  277. $openTitles = $openTitles.not($nestedTitles);
  278. $openContents = $openTitles.next($content);
  279. }
  280. if( ($openTitles.length > 0) ) {
  281. module.debug('Exclusive enabled, closing other content', $openTitles);
  282. $openTitles
  283. .removeClass(className.active)
  284. ;
  285. $openContents
  286. .removeClass(className.animating)
  287. .stop(true, true)
  288. ;
  289. if(settings.animateChildren) {
  290. if($.fn.transition !== undefined && $module.transition('is supported')) {
  291. $openContents
  292. .children()
  293. .transition({
  294. animation : 'fade out',
  295. useFailSafe : true,
  296. debug : settings.debug,
  297. verbose : settings.verbose,
  298. duration : settings.duration
  299. })
  300. ;
  301. }
  302. else {
  303. $openContents
  304. .children()
  305. .stop(true, true)
  306. .animate({
  307. opacity: 0
  308. }, settings.duration, module.resetOpacity)
  309. ;
  310. }
  311. }
  312. $openContents
  313. .slideUp(settings.duration , settings.easing, function() {
  314. $(this).removeClass(className.active);
  315. module.reset.display.call(this);
  316. })
  317. ;
  318. }
  319. },
  320. reset: {
  321. display: function() {
  322. module.verbose('Removing inline display from element', this);
  323. $(this).css('display', '');
  324. if( $(this).attr('style') === '') {
  325. $(this)
  326. .attr('style', '')
  327. .removeAttr('style')
  328. ;
  329. }
  330. },
  331. opacity: function() {
  332. module.verbose('Removing inline opacity from element', this);
  333. $(this).css('opacity', '');
  334. if( $(this).attr('style') === '') {
  335. $(this)
  336. .attr('style', '')
  337. .removeAttr('style')
  338. ;
  339. }
  340. },
  341. },
  342. setting: function(name, value) {
  343. module.debug('Changing setting', name, value);
  344. if( $.isPlainObject(name) ) {
  345. $.extend(true, settings, name);
  346. }
  347. else if(value !== undefined) {
  348. if($.isPlainObject(settings[name])) {
  349. $.extend(true, settings[name], value);
  350. }
  351. else {
  352. settings[name] = value;
  353. }
  354. }
  355. else {
  356. return settings[name];
  357. }
  358. },
  359. internal: function(name, value) {
  360. module.debug('Changing internal', name, value);
  361. if(value !== undefined) {
  362. if( $.isPlainObject(name) ) {
  363. $.extend(true, module, name);
  364. }
  365. else {
  366. module[name] = value;
  367. }
  368. }
  369. else {
  370. return module[name];
  371. }
  372. },
  373. debug: function() {
  374. if(!settings.silent && settings.debug) {
  375. if(settings.performance) {
  376. module.performance.log(arguments);
  377. }
  378. else {
  379. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  380. module.debug.apply(console, arguments);
  381. }
  382. }
  383. },
  384. verbose: function() {
  385. if(!settings.silent && settings.verbose && settings.debug) {
  386. if(settings.performance) {
  387. module.performance.log(arguments);
  388. }
  389. else {
  390. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  391. module.verbose.apply(console, arguments);
  392. }
  393. }
  394. },
  395. error: function() {
  396. if(!settings.silent) {
  397. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  398. module.error.apply(console, arguments);
  399. }
  400. },
  401. performance: {
  402. log: function(message) {
  403. var
  404. currentTime,
  405. executionTime,
  406. previousTime
  407. ;
  408. if(settings.performance) {
  409. currentTime = new Date().getTime();
  410. previousTime = time || currentTime;
  411. executionTime = currentTime - previousTime;
  412. time = currentTime;
  413. performance.push({
  414. 'Name' : message[0],
  415. 'Arguments' : [].slice.call(message, 1) || '',
  416. 'Element' : element,
  417. 'Execution Time' : executionTime
  418. });
  419. }
  420. clearTimeout(module.performance.timer);
  421. module.performance.timer = setTimeout(module.performance.display, 500);
  422. },
  423. display: function() {
  424. var
  425. title = settings.name + ':',
  426. totalTime = 0
  427. ;
  428. time = false;
  429. clearTimeout(module.performance.timer);
  430. $.each(performance, function(index, data) {
  431. totalTime += data['Execution Time'];
  432. });
  433. title += ' ' + totalTime + 'ms';
  434. if(moduleSelector) {
  435. title += ' \'' + moduleSelector + '\'';
  436. }
  437. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  438. console.groupCollapsed(title);
  439. if(console.table) {
  440. console.table(performance);
  441. }
  442. else {
  443. $.each(performance, function(index, data) {
  444. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  445. });
  446. }
  447. console.groupEnd();
  448. }
  449. performance = [];
  450. }
  451. },
  452. invoke: function(query, passedArguments, context) {
  453. var
  454. object = instance,
  455. maxDepth,
  456. found,
  457. response
  458. ;
  459. passedArguments = passedArguments || queryArguments;
  460. context = element || context;
  461. if(typeof query == 'string' && object !== undefined) {
  462. query = query.split(/[\. ]/);
  463. maxDepth = query.length - 1;
  464. $.each(query, function(depth, value) {
  465. var camelCaseValue = (depth != maxDepth)
  466. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  467. : query
  468. ;
  469. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  470. object = object[camelCaseValue];
  471. }
  472. else if( object[camelCaseValue] !== undefined ) {
  473. found = object[camelCaseValue];
  474. return false;
  475. }
  476. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  477. object = object[value];
  478. }
  479. else if( object[value] !== undefined ) {
  480. found = object[value];
  481. return false;
  482. }
  483. else {
  484. module.error(error.method, query);
  485. return false;
  486. }
  487. });
  488. }
  489. if ( $.isFunction( found ) ) {
  490. response = found.apply(context, passedArguments);
  491. }
  492. else if(found !== undefined) {
  493. response = found;
  494. }
  495. if($.isArray(returnedValue)) {
  496. returnedValue.push(response);
  497. }
  498. else if(returnedValue !== undefined) {
  499. returnedValue = [returnedValue, response];
  500. }
  501. else if(response !== undefined) {
  502. returnedValue = response;
  503. }
  504. return found;
  505. }
  506. };
  507. if(methodInvoked) {
  508. if(instance === undefined) {
  509. module.initialize();
  510. }
  511. module.invoke(query);
  512. }
  513. else {
  514. if(instance !== undefined) {
  515. instance.invoke('destroy');
  516. }
  517. module.initialize();
  518. }
  519. })
  520. ;
  521. return (returnedValue !== undefined)
  522. ? returnedValue
  523. : this
  524. ;
  525. };
  526. $.fn.accordion.settings = {
  527. name : 'Accordion',
  528. namespace : 'accordion',
  529. silent : false,
  530. debug : false,
  531. verbose : false,
  532. performance : true,
  533. on : 'click', // event on title that opens accordion
  534. observeChanges : true, // whether accordion should automatically refresh on DOM insertion
  535. exclusive : true, // whether a single accordion content panel should be open at once
  536. collapsible : true, // whether accordion content can be closed
  537. closeNested : false, // whether nested content should be closed when a panel is closed
  538. animateChildren : true, // whether children opacity should be animated
  539. duration : 350, // duration of animation
  540. easing : 'easeOutQuad', // easing equation for animation
  541. onOpening : function(){}, // callback before open animation
  542. onOpen : function(){}, // callback after open animation
  543. onClosing : function(){}, // callback before closing animation
  544. onClose : function(){}, // callback after closing animation
  545. onChange : function(){}, // callback after closing or opening animation
  546. error: {
  547. method : 'The method you called is not defined'
  548. },
  549. className : {
  550. active : 'active',
  551. animating : 'animating'
  552. },
  553. selector : {
  554. accordion : '.accordion',
  555. title : '.title',
  556. trigger : '.title',
  557. content : '.content'
  558. }
  559. };
  560. // Adds easing
  561. $.extend( $.easing, {
  562. easeOutQuad: function (x, t, b, c, d) {
  563. return -c *(t/=d)*(t-2) + b;
  564. }
  565. });
  566. })( jQuery, window, document );