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.

438 lines
13 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /*
  2. * # Semantic - Accordion
  3. * http://github.com/jlukic/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. module.exports = function(parameters) {
  13. var
  14. $allModules = $(this),
  15. time = new Date().getTime(),
  16. performance = [],
  17. query = arguments[0],
  18. methodInvoked = (typeof query == 'string'),
  19. queryArguments = [].slice.call(arguments, 1),
  20. returnedValue
  21. ;
  22. $allModules
  23. .each(function() {
  24. var
  25. settings = ( $.isPlainObject(parameters) )
  26. ? $.extend(true, {}, module.exports.settings, parameters)
  27. : $.extend({}, module.exports.settings),
  28. className = settings.className,
  29. namespace = settings.namespace,
  30. selector = settings.selector,
  31. error = settings.error,
  32. eventNamespace = '.' + namespace,
  33. moduleNamespace = 'module-' + namespace,
  34. moduleSelector = $allModules.selector || '',
  35. $module = $(this),
  36. $title = $module.find(selector.title),
  37. $content = $module.find(selector.content),
  38. element = this,
  39. instance = $module.data(moduleNamespace),
  40. module
  41. ;
  42. module = {
  43. initialize: function() {
  44. module.debug('Initializing accordion with bound events', $module);
  45. // initializing
  46. $title
  47. .on('click' + eventNamespace, module.event.click)
  48. ;
  49. module.instantiate();
  50. },
  51. instantiate: function() {
  52. instance = module;
  53. $module
  54. .data(moduleNamespace, module)
  55. ;
  56. },
  57. destroy: function() {
  58. module.debug('Destroying previous accordion for', $module);
  59. $module
  60. .removeData(moduleNamespace)
  61. ;
  62. $title
  63. .off(eventNamespace)
  64. ;
  65. },
  66. event: {
  67. click: function() {
  68. module.verbose('Title clicked', this);
  69. var
  70. $activeTitle = $(this),
  71. index = $title.index($activeTitle)
  72. ;
  73. module.toggle(index);
  74. },
  75. resetDisplay: function() {
  76. $(this).css('display', '');
  77. if( $(this).attr('style') == '') {
  78. $(this)
  79. .attr('style', '')
  80. .removeAttr('style')
  81. ;
  82. }
  83. },
  84. resetOpacity: function() {
  85. $(this).css('opacity', '');
  86. if( $(this).attr('style') == '') {
  87. $(this)
  88. .attr('style', '')
  89. .removeAttr('style')
  90. ;
  91. }
  92. }
  93. },
  94. toggle: function(index) {
  95. module.debug('Toggling content content at index', index);
  96. var
  97. $activeTitle = $title.eq(index),
  98. $activeContent = $activeTitle.next($content),
  99. contentIsOpen = $activeContent.is(':visible')
  100. ;
  101. if(contentIsOpen) {
  102. if(settings.collapsible) {
  103. module.close(index);
  104. }
  105. else {
  106. module.debug('Cannot close accordion content collapsing is disabled');
  107. }
  108. }
  109. else {
  110. module.open(index);
  111. }
  112. },
  113. open: function(index) {
  114. var
  115. $activeTitle = $title.eq(index),
  116. $activeContent = $activeTitle.next($content),
  117. $otherSections = module.is.menu()
  118. ? $activeTitle.parent().siblings(selector.item).find(selector.title)
  119. : $activeTitle.siblings(selector.title),
  120. $previousTitle = $otherSections.filter('.' + className.active),
  121. $previousContent = $previousTitle.next($title),
  122. contentIsOpen = ($previousTitle.size() > 0)
  123. ;
  124. if( !$activeContent.is(':animated') ) {
  125. module.debug('Opening accordion content', $activeTitle);
  126. if(settings.exclusive && contentIsOpen) {
  127. $previousTitle
  128. .removeClass(className.active)
  129. ;
  130. $previousContent
  131. .stop()
  132. .children()
  133. .stop()
  134. .animate({
  135. opacity: 0
  136. }, settings.duration, module.event.resetOpacity)
  137. .end()
  138. .slideUp(settings.duration , settings.easing, function() {
  139. $previousContent
  140. .removeClass(className.active)
  141. .children()
  142. ;
  143. $.proxy(module.event.resetDisplay, this)();
  144. })
  145. ;
  146. }
  147. $activeTitle
  148. .addClass(className.active)
  149. ;
  150. $activeContent
  151. .stop()
  152. .children()
  153. .stop()
  154. .animate({
  155. opacity: 1
  156. }, settings.duration)
  157. .end()
  158. .slideDown(settings.duration, settings.easing, function() {
  159. $activeContent
  160. .addClass(className.active)
  161. ;
  162. $.proxy(module.event.resetDisplay, this)();
  163. $.proxy(settings.onOpen, $activeContent)();
  164. $.proxy(settings.onChange, $activeContent)();
  165. })
  166. ;
  167. }
  168. },
  169. close: function(index) {
  170. var
  171. $activeTitle = $title.eq(index),
  172. $activeContent = $activeTitle.next($content)
  173. ;
  174. module.debug('Closing accordion content', $activeContent);
  175. $activeTitle
  176. .removeClass(className.active)
  177. ;
  178. $activeContent
  179. .removeClass(className.active)
  180. .show()
  181. .stop()
  182. .children()
  183. .stop()
  184. .animate({
  185. opacity: 0
  186. }, settings.duration, module.event.resetOpacity)
  187. .end()
  188. .slideUp(settings.duration, settings.easing, function(){
  189. $.proxy(module.event.resetDisplay, this)();
  190. $.proxy(settings.onClose, $activeContent)();
  191. $.proxy(settings.onChange, $activeContent)();
  192. })
  193. ;
  194. },
  195. is: {
  196. menu: function () {
  197. return $module.hasClass(className.menu);
  198. }
  199. },
  200. setting: function(name, value) {
  201. if( $.isPlainObject(name) ) {
  202. $.extend(true, settings, name);
  203. }
  204. else if(value !== undefined) {
  205. settings[name] = value;
  206. }
  207. else {
  208. return settings[name];
  209. }
  210. },
  211. internal: function(name, value) {
  212. module.debug('Changing internal', name, value);
  213. if(value !== undefined) {
  214. if( $.isPlainObject(name) ) {
  215. $.extend(true, module, name);
  216. }
  217. else {
  218. module[name] = value;
  219. }
  220. }
  221. else {
  222. return module[name];
  223. }
  224. },
  225. debug: function() {
  226. if(settings.debug) {
  227. if(settings.performance) {
  228. module.performance.log(arguments);
  229. }
  230. else {
  231. module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
  232. module.debug.apply(console, arguments);
  233. }
  234. }
  235. },
  236. verbose: function() {
  237. if(settings.verbose && settings.debug) {
  238. if(settings.performance) {
  239. module.performance.log(arguments);
  240. }
  241. else {
  242. module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
  243. module.verbose.apply(console, arguments);
  244. }
  245. }
  246. },
  247. error: function() {
  248. module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
  249. module.error.apply(console, arguments);
  250. },
  251. performance: {
  252. log: function(message) {
  253. var
  254. currentTime,
  255. executionTime,
  256. previousTime
  257. ;
  258. if(settings.performance) {
  259. currentTime = new Date().getTime();
  260. previousTime = time || currentTime;
  261. executionTime = currentTime - previousTime;
  262. time = currentTime;
  263. performance.push({
  264. 'Element' : element,
  265. 'Name' : message[0],
  266. 'Arguments' : [].slice.call(message, 1) || '',
  267. 'Execution Time' : executionTime
  268. });
  269. }
  270. clearTimeout(module.performance.timer);
  271. module.performance.timer = setTimeout(module.performance.display, 100);
  272. },
  273. display: function() {
  274. var
  275. title = settings.name + ':',
  276. totalTime = 0
  277. ;
  278. time = false;
  279. clearTimeout(module.performance.timer);
  280. $.each(performance, function(index, data) {
  281. totalTime += data['Execution Time'];
  282. });
  283. title += ' ' + totalTime + 'ms';
  284. if(moduleSelector) {
  285. title += ' \'' + moduleSelector + '\'';
  286. }
  287. if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
  288. console.groupCollapsed(title);
  289. if(console.table) {
  290. console.table(performance);
  291. }
  292. else {
  293. $.each(performance, function(index, data) {
  294. console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
  295. });
  296. }
  297. console.groupEnd();
  298. }
  299. performance = [];
  300. }
  301. },
  302. invoke: function(query, passedArguments, context) {
  303. var
  304. object = instance,
  305. maxDepth,
  306. found,
  307. response
  308. ;
  309. passedArguments = passedArguments || queryArguments;
  310. context = element || context;
  311. if(typeof query == 'string' && object !== undefined) {
  312. query = query.split(/[\. ]/);
  313. maxDepth = query.length - 1;
  314. $.each(query, function(depth, value) {
  315. var camelCaseValue = (depth != maxDepth)
  316. ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
  317. : query
  318. ;
  319. if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
  320. object = object[camelCaseValue];
  321. }
  322. else if( object[camelCaseValue] !== undefined ) {
  323. found = object[camelCaseValue];
  324. return false;
  325. }
  326. else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
  327. object = object[value];
  328. }
  329. else if( object[value] !== undefined ) {
  330. found = object[value];
  331. return false;
  332. }
  333. else {
  334. return false;
  335. }
  336. });
  337. }
  338. if ( $.isFunction( found ) ) {
  339. response = found.apply(context, passedArguments);
  340. }
  341. else if(found !== undefined) {
  342. response = found;
  343. }
  344. if($.isArray(returnedValue)) {
  345. returnedValue.push(response);
  346. }
  347. else if(returnedValue !== undefined) {
  348. returnedValue = [returnedValue, response];
  349. }
  350. else if(response !== undefined) {
  351. returnedValue = response;
  352. }
  353. return found;
  354. }
  355. };
  356. if(methodInvoked) {
  357. if(instance === undefined) {
  358. module.initialize();
  359. }
  360. module.invoke(query);
  361. }
  362. else {
  363. if(instance !== undefined) {
  364. module.destroy();
  365. }
  366. module.initialize();
  367. }
  368. })
  369. ;
  370. return (returnedValue !== undefined)
  371. ? returnedValue
  372. : this
  373. ;
  374. };
  375. module.exports.settings = {
  376. name : 'Accordion',
  377. namespace : 'accordion',
  378. debug : false,
  379. verbose : true,
  380. performance : true,
  381. exclusive : true,
  382. collapsible : true,
  383. duration : 500,
  384. easing : 'easeInOutQuint',
  385. onOpen : function(){},
  386. onClose : function(){},
  387. onChange : function(){},
  388. error: {
  389. method : 'The method you called is not defined'
  390. },
  391. className : {
  392. active : 'active',
  393. menu : 'menu',
  394. },
  395. selector : {
  396. title : '.title',
  397. content : '.content',
  398. menu : '.menu',
  399. item : '.item',
  400. }
  401. };
  402. // Adds easing
  403. $.extend( $.easing, {
  404. easeInOutQuint: function (x, t, b, c, d) {
  405. if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
  406. return c/2*((t-=2)*t*t*t*t + 2) + b;
  407. }
  408. });
  409. })( require("jquery"), window , document );