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.

610 lines
20 KiB

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