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.

584 lines
18 KiB

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