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.

592 lines
18 KiB

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