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.

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