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