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.

613 lines
20 KiB

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