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.

596 lines
19 KiB

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