1;(function ( $, window, undefined ) { 2 3 /** Default settings */ 4 var defaults = { 5 active: null, 6 event: 'click', 7 disabled: [], 8 collapsible: 'accordion', 9 startCollapsed: false, 10 rotate: false, 11 setHash: false, 12 animation: 'default', 13 animationQueue: false, 14 duration: 500, 15 fluidHeight: true, 16 scrollToAccordion: true, 17 scrollToAccordionOnLoad: false, 18 scrollToAccordionOffset: 0, 19 accordionTabElement: '<div></div>', 20 accordionAnchorHTML: '', 21 click: function(){}, 22 activate: function(){}, 23 deactivate: function(){}, 24 load: function(){}, 25 activateState: function(){}, 26 classes: { 27 stateDefault: 'r-tabs-state-default', 28 stateActive: 'r-tabs-state-active', 29 stateDisabled: 'r-tabs-state-disabled', 30 stateExcluded: 'r-tabs-state-excluded', 31 container: 'r-tabs', 32 ul: 'r-tabs-nav', 33 tab: 'r-tabs-tab', 34 anchor: 'r-tabs-anchor', 35 panel: 'r-tabs-panel', 36 accordionTitle: 'r-tabs-accordion-title', 37 elements: '.ue-element', 38 activeElements: '.ue-element.active', 39 containerPanel: '.tab-container' 40 } 41 }; 42 43 /** 44 * Responsive Tabs 45 * @constructor 46 * @param {object} element - The HTML element the validator should be bound to 47 * @param {object} options - An option map 48 */ 49 function ResponsiveContentTabs(element, options) { 50 this.element = element; // Selected DOM element 51 this.$element = $(element); // Selected jQuery element 52 53 this.tabs = []; // Create tabs array 54 this.state = ''; // Define the plugin state (tabs/accordion) 55 this.rotateInterval = 0; // Define rotate interval 56 this.$queue = $({}); 57 58 // Extend the defaults with the passed options 59 this.options = $.extend( {}, defaults, options); 60 61 this.init(); 62 } 63 64 65 /** 66 * This function initializes the tab plugin 67 */ 68 ResponsiveContentTabs.prototype.init = function () { 69 var _this = this; 70 71 // Load all the elements 72 this.tabs = this._loadElements(); 73 this._loadClasses(); 74 this._loadEvents(); 75 76 // Window resize bind to check state 77 $(window).on('resize', function(e) { 78 _this._setState(e); 79 if(_this.options.fluidHeight !== true) { 80 _this._equaliseHeights(); 81 } 82 }); 83 84 // Hashchange event 85 $(window).on('hashchange', function(e) { 86 setTimeout(function() { 87 var tabRef = _this._getTabRefBySelector(window.location.hash); 88 var oTab = _this._getTab(tabRef); 89 if(tabRef >= 0 && !oTab._ignoreHashChange && !oTab.disabled) { 90 _this._openTab(e, _this._getTab(tabRef), true); 91 } 92 if(oTab) oTab._ignoreHashChange = false; // Reset it 93 }, 20); 94 }); 95 96 // Start rotate event if rotate option is defined 97 if(this.options.rotate !== false) { 98 this.startRotation(); 99 } 100 101 // Set fluid height 102 if(this.options.fluidHeight !== true) { 103 _this._equaliseHeights(); 104 } 105 106 // -------------------- 107 // Define plugin events 108 // 109 110 // Activate: this event is called when a tab is selected 111 this.$element.bind('tabs-click', function(e, oTab) { 112 _this.options.click.call(this, e, oTab); 113 }); 114 115 // Activate: this event is called when a tab is selected 116 this.$element.bind('tabs-activate', function(e, oTab) { 117 _this.options.activate.call(this, e, oTab); 118 119 //add active class to tab if it wasn't added 120 if(oTab.tab.hasClass(_this.options.classes.stateActive) == false){ 121 oTab.tab.addClass(_this.options.classes.stateActive); 122 } 123 }); 124 125 // Deactivate: this event is called when a tab is closed 126 this.$element.bind('tabs-deactivate', function(e, oTab) { 127 _this.options.deactivate.call(this, e, oTab); 128 129 //remove active class from tab if it wasn't removed 130 if(oTab.tab.hasClass(_this.options.classes.stateActive) == true){ 131 oTab.tab.removeClass(_this.options.classes.stateActive); 132 } 133 }); 134 // Activate State: this event is called when the plugin switches states 135 this.$element.bind('tabs-activate-state', function(e, state) { 136 _this.options.activateState.call(this, e, state); 137 }); 138 139 // Load: this event is called when the plugin has been loaded 140 this.$element.bind('tabs-load', function(e) { 141 var startTab; 142 143 _this._setState(e); // Set state 144 145 var isDesktopBeakpoint = window.matchMedia("(min-width: " + _this.options.breakpoint + "px)"); 146 147 function openFirstItem(){ 148 149 startTab = _this._getStartTab(); 150 151 // Open the initial tab 152 _this._openTab(e, startTab); // Open first tab 153 154 // Call the callback function 155 _this.options.load.call(this, e, startTab); // Call the load callback 156 } 157 158 // Check if the panel should be collapsed on load 159 if(_this.options.startCollapsed == 'none' && !(_this.options.startCollapsed === 'accordion' && _this.state === 'accordion')) 160 openFirstItem(); 161 162 // Check if the panel should be collapsed on load 163 if(_this.options.startCollapsed == 'mobile' && !(_this.options.startCollapsed === 'accordion' && _this.state === 'accordion')) { 164 165 if(isDesktopBeakpoint.matches == true) 166 openFirstItem(); 167 168 } 169 170 if(window.location.hash && _this.options.startCollapsed != 'none' && _this.options.setHash == true){ 171 172 var tabRef = _this._getTabRefBySelector(window.location.hash); 173 startTab = _this._getTab(tabRef); 174 175 if(tabRef >= 0 && !startTab.disabled) 176 openFirstItem(); 177 } 178 179 }); 180 // Trigger loaded event 181 this.$element.trigger('tabs-load'); 182 }; 183 184 // 185 // PRIVATE FUNCTIONS 186 // 187 188 /** 189 * This function loads the tab elements and stores them in an array 190 * @returns {Array} Array of tab elements 191 */ 192 ResponsiveContentTabs.prototype._loadElements = function() { 193 var _this = this; 194 var $ul = this.$element.children('ul:first'); 195 var tabs = []; 196 var id = 0; 197 198 // Add the classes to the basic html elements 199 this.$element.addClass(_this.options.classes.container); // Tab container 200 $ul.addClass(_this.options.classes.ul); // List container 201 202 // Get tab buttons and store their data in an array 203 $('li', $ul).each(function() { 204 var $tab = $(this);
205 var isExcluded = $tab.hasClass(_this.options.classes.stateExcluded); 206 var $anchor, $panel, $accordionTab, $accordionAnchor, panelSelector; 207 208 // Check if the tab should be excluded 209 if(!isExcluded) { 210 211 $anchor = $('a', $tab); 212 panelSelector = $anchor.attr('data-content-id'); 213 panelSelectorId = $anchor.attr('data-hash-id'); 214 $panel = $("#"+panelSelector); 215 $accordionTab = $(_this.options.accordionTabElement).insertBefore($panel); 216 $accordionAnchor = $('<a></a>').attr('href', panelSelector).attr("data-e-disable-page-transition", true).attr("rel", "nofollow").html("<div class='uc-tabs-accordion-title'>" +$anchor.html()+"</div>").appendTo($accordionTab); 217 218 if(_this.options.accordionAnchorHTML) 219 $accordionAnchor.append(_this.options.accordionAnchorHTML); 220 221 var oTab = { 222 _ignoreHashChange: false, 223 id: id, 224 disabled: ($.inArray(id, _this.options.disabled) !== -1), 225 tab: $(this), 226 anchor: $('a', $tab), 227 panel: $panel, 228 selector: panelSelectorId, 229 accordionTab: $accordionTab, 230 accordionAnchor: $accordionAnchor, 231 active: false 232 }; 233 234 // 1up the ID 235 id++; 236 // Add to tab array 237 tabs.push(oTab); 238 } 239 }); 240 return tabs; 241 }; 242 243 244 /** 245 * This function adds classes to the tab elements based on the options 246 */ 247 ResponsiveContentTabs.prototype._loadClasses = function() { 248 for (var i=0; i<this.tabs.length; i++) { 249 this.tabs[i].tab.addClass(this.options.classes.stateDefault).addClass(this.options.classes.tab); 250 this.tabs[i].anchor.addClass(this.options.classes.anchor); 251 this.tabs[i].panel.addClass(this.options.classes.stateDefault).addClass(this.options.classes.panel); 252 this.tabs[i].accordionTab.addClass(this.options.classes.accordionTitle); 253 this.tabs[i].accordionAnchor.addClass(this.options.classes.anchor); 254 if(this.tabs[i].disabled) { 255 this.tabs[i].tab.removeClass(this.options.classes.stateDefault).addClass(this.options.classes.stateDisabled); 256 this.tabs[i].accordionTab.removeClass(this.options.classes.stateDefault).addClass(this.options.classes.stateDisabled); 257 } 258 } 259 }; 260 261 /** 262 * This function adds events to the tab elements 263 */ 264 ResponsiveContentTabs.prototype._loadEvents = function() { 265 var _this = this; 266 267 // Define activate event on a tab element 268 var fActivate = function(e) { 269 var current = _this._getCurrentTab(); // Fetch current tab 270 var activatedTab = e.data.tab; 271 e.preventDefault(); 272 273 // Trigger click event for whenever a tab is clicked/touched even if the tab is disabled 274 activatedTab.tab.trigger('tabs-click', activatedTab); 275 276 // Make sure this tab isn't disabled 277 if(!activatedTab.disabled) { 278 279 // Check if hash has to be set in the URL location 280 if(_this.options.setHash) { 281 // Set the hash using the history api if available to tackle Chromes repaint bug on hash change 282 if(history.pushState) { 283 history.pushState(null, null, window.location.origin + window.location.pathname + window.location.search + activatedTab.selector); 284 } else { 285 // Otherwise fallback to the hash update for sites that don't support the history api 286 window.location.hash = activatedTab.selector; 287 } 288 } 289 290 e.data.tab._ignoreHashChange = true; 291 292 // Check if the activated tab isnt the current one or if its collapsible. If not, do nothing 293 if(current !== activatedTab || _this._isCollapisble()) { 294 // The activated tab is either another tab of the current one. If it's the current tab it is collapsible 295 // Either way, the current tab can be closed 296 //if closeCurrent is false, state is tabs and current == activatedTab do not close
297 if(_this.options.closeCurrent === false && _this.getState() === 'tabs' && current === activatedTab) { 298 }else 299 _this._closeTab(e, current); 300 301 // Check if the activated tab isnt the current one or if it isnt collapsible 302 if(current !== activatedTab || !_this._isCollapisble()) { 303 _this._openTab(e, activatedTab, false, true); 304 } 305 } 306 } 307 }; 308 309 // Loop tabs 310 for (var i=0; i<this.tabs.length; i++) { 311 // Add activate function to the tab and accordion selection element 312 this.tabs[i].anchor.on(_this.options.event, {tab: _this.tabs[i]}, fActivate); 313 this.tabs[i].accordionAnchor.on(_this.options.event, {tab: _this.tabs[i]}, fActivate); 314 315 this.tabs[i].anchor.on("ucclick", {tab: _this.tabs[i]}, fActivate); 316 this.tabs[i].accordionAnchor.on("ucclick", {tab: _this.tabs[i]}, fActivate); 317 318 } 319 }; 320 321 /** 322 * This function gets the tab that should be opened at start 323 * @returns {Object} Tab object 324 */ 325 ResponsiveContentTabs.prototype._getStartTab = function() { 326 var tabRef = this._getTabRefBySelector(window.location.hash); 327 var startTab; 328 329 // Check if the page has a hash set that is linked to a tab 330 if(tabRef >= 0 && !this._getTab(tabRef).disabled) { 331 // If so, set the current tab to the linked tab 332 startTab = this._getTab(tabRef); 333 } else if(this.options.active > 0 && !this._getTab(this.options.active).disabled) { 334 startTab = this._getTab(this.options.active); 335 } else { 336 // If not, just get the first one 337 startTab = this._getTab(0); 338 } 339 340 return startTab; 341 }; 342 343 /** 344 * This function sets the current state of the plugin 345 * @param {Event} e - The event that triggers the state change 346 */ 347 ResponsiveContentTabs.prototype._setState = function(e) { 348 var $ul = $('ul:first', this.$element); 349 var oldState = this.state; 350 var startCollapsedIsState = (typeof this.options.startCollapsed === 'string'); 351 var startTab; 352 353 // The state is based on the visibility of the tabs list 354 if($ul.is(':visible')){ 355 // Tab list is visible, so the state is 'tabs' 356 this.state = 'tabs'; 357 358 } else { 359 // Tab list is invisible, so the state is 'accordion' 360 361 this.state = 'accordion'; 362 363 } 364 365 // If the new state is different from the old state 366 if(this.state !== oldState) { 367 // If so, the state activate trigger must be called 368 this.$element.trigger('tabs-activate-state', {oldState: oldState, newState: this.state}); 369 370 // Check if the state switch should open a tab 371 if(oldState && startCollapsedIsState && this.options.startCollapsed !== this.state && this._getCurrentTab() === undefined) { 372 // Get initial tab 373 startTab = this._getStartTab(e); 374 // Open the initial tab 375 this._openTab(e, startTab); // Open first tab 376 } 377 } 378 379 }; 380 381 /** 382 * This function opens a tab 383 * @param {Event} e - The event that triggers the tab opening 384 * @param {Object} oTab - The tab object that should be opened 385 * @param {Boolean} closeCurrent - Defines if the current tab should be closed 386 * @param {Boolean} stopRotation - Defines if the tab rotation loop should be stopped 387 */ 388 ResponsiveContentTabs.prototype._openTab = function(e, oTab, closeCurrent, stopRotation) { 389 //protection from synced parent invisible elementor container 390 var objHiddenParentDesktop = jQuery(oTab.accordionTab).parents('.elementor-hidden-desktop'); 391 var objHiddenParentTablet = jQuery(oTab.accordionTab).parents('.elementor-hidden-tablet'); 392 var objHiddenParentMobile = jQuery(oTab.accordionTab).parents('.elementor-hidden-mobile'); 393 var dataDeviceMode = jQuery('body').attr("data-elementor-device-mode"); 394 395 // if(objHiddenParentDesktop.length >= 1 && objHiddenParentDesktop.is(':visible') == false && dataDeviceMode == 'desktop') 396 // return(false); 397 398 // if(objHiddenParentTablet.length >= 1 && objHiddenParentTablet.is(':visible') == false && dataDeviceMode == 'tablet') 399 // return(false); 400 401 // if(objHiddenParentTablet.length >= 1 && objHiddenParentMobile.is(':visible') == false && dataDeviceMode == 'mobile') 402 // return(false); 403 404 var _this = this; 405 var scrollOffset; 406 // Check if the current tab has to be closed 407 if(closeCurrent || _this.options.closeCurrent === true) { 408 this._closeTab(e, this._getCurrentTab()); 409 } 410 411 // Check if the rotation has to be stopped when activated 412 if(stopRotation && this.rotateInterval > 0) { 413 this.stopRotation(); 414 } 415 416 if(oTab == undefined) 417 return(false) 418 419 // Set this tab to active 420 oTab.active = true; 421 // Set active classes to the tab button and accordion tab button 422
423 if(_this.getState() === 'tabs'){ 424 oTab.tab.removeClass(_this.options.classes.stateDefault).addClass(_this.options.classes.stateActive); 425 } 426 427 if(_this.getState() === 'accordion'){ 428 oTab.accordionTab.removeClass(_this.options.classes.stateDefault).addClass(_this.options.classes.stateActive); 429 } 430 431 // Run panel transiton 432 _this._doTransition(oTab.panel, _this.options.animation, 'open', function() { 433 var scrollOnLoad = (e.type !== 'tabs-load' || _this.options.scrollToAccordionOnLoad); 434 435 // When finished, set active class to the panel 436 oTab.panel.removeClass(_this.options.classes.stateDefault).addClass(_this.options.classes.stateActive); 437 438 // And if enabled and state is accordion, scroll to the accordion tab 439 if(_this.getState() === 'accordion' && _this.options.scrollToAccordion && (!_this._isInView(oTab.accordionTab) || _this.options.animation !== 'default') && scrollOnLoad) { 440 441 // Add offset element's height to scroll position 442 scrollOffset = oTab.accordionTab.offset().top - _this.options.scrollToAccordionOffset; 443 444 // Check if the animation option is enabled, and if the duration isn't 0 445 if(_this.options.animation !== 'default' && _this.options.duration > 0) { 446 // If so, set scrollTop with animate and use the 'animation' duration 447 $('html, body').animate({ 448 scrollTop: scrollOffset 449 }, _this.options.duration); 450 } else { 451 // If not, just set scrollTop 452 $('html, body').scrollTop(scrollOffset); 453 } 454 } 455 }); 456 457 this.$element.trigger('tabs-activate', oTab); 458 459 // show/hide elements by id 460 461 var elements = defaults.classes.elements; 462 463 if(jQuery(elements).length < 0){ 464 return true 465 } 466 467 var objTabs = this.$element; 468 var container = defaults.classes.containerPanel; 469 var parentElement = jQuery(elements).parents(container); 470 var elementParentIndex; 471 var elementParentArray = []; 472 473 parentElement.each(function(){ 474 elementParentIndex = Math.floor(jQuery(this).index() / 2); 475 elementParentArray.push(elementParentIndex); 476 }); 477 478 // hide container when tab with elements to show is clicked 479 480 function hideContainer(){ 481 jQuery(elements).parents(container).hide(); 482 } 483 484 if(elementParentIndex == 0){ 485 hideContainer(); 486 } 487 488 var elementsId; 489 var currentTabIndex = jQuery(oTab.tab[0]).index(); 490 491 // hide all elements 492 493 jQuery(elements).each(function(){ 494 495 elementsId = jQuery(this).data('id'); 496 var elementsIdArray = elementsId.split(','); 497 498 elementsIdArray.forEach(function(value){ 499 var element = jQuery("#" + value); 500 element.hide(); 501 502 // show elements if in editor and debug mode is true 503 504 var dataDebug = _this.$element.data("debug"); 505 var dataEditor = _this.$element.data("editor"); 506 507 if(dataEditor == "yes" && dataDebug == true){ 508 element.show(); 509 element.css({"border": "3px solid red"}); 510 }else{ 511 element.css({"border": "none"}); 512 } 513 }); 514 }); 515 516 // find active elements 517 objTabs.find(container).find(elements).removeClass('active'); 518 objTabs.find(container).eq(currentTabIndex).find(elements).addClass('active'); 519 520 var activeElements = jQuery(defaults.classes.activeElements); 521 522 // show active elements 523 524 jQuery(activeElements).each(function(){ 525 526 elementsId = jQuery(this).data('id'); 527 var elementsIdArray = elementsId.split(','); 528 529 elementsIdArray.forEach(function(value){ 530 var element = jQuery("#" + value); 531 532 elementParentArray.forEach(function(index, value){ 533 534 if(currentTabIndex == index){ 535 element.show(); 536 hideContainer(); 537 } 538 }); 539 }); 540 }); 541 }; 542 543 /** 544 * This function closes a tab 545 * @param {Event} e - The event that is triggered when a tab is closed 546 * @param {Object} oTab - The tab object that should be closed 547 */ 548 ResponsiveContentTabs.prototype._closeTab = function(e, oTab) { 549 550 var _this = this; 551 var doQueueOnState = typeof _this.options.animationQueue === 'string'; 552 var doQueue; 553 554 if(oTab !== undefined) {
555 if(doQueueOnState && _this.getState() === _this.options.animationQueue) { 556 doQueue = true; 557 } else if(doQueueOnState) { 558 doQueue = false; 559 } else { 560 doQueue = _this.options.animationQueue; 561 } 562 563 // Deactivate tab 564 oTab.active = false; 565 // Set default class to the tab button 566 if(_this.getState() === 'tabs'){ 567 oTab.tab.removeClass(_this.options.classes.stateActive).addClass(_this.options.classes.stateDefault); 568 } 569 570 if(_this.getState() === 'accordion'){ 571 oTab.accordionTab.removeClass(_this.options.classes.stateActive).addClass(_this.options.classes.stateDefault); 572 } 573 574 // Run panel transition 575 _this._doTransition(oTab.panel, _this.options.animation, 'close', function() { 576 // Set default class to the accordion tab button and tab panel 577 oTab.accordionTab.removeClass(_this.options.classes.stateActive).addClass(_this.options.classes.stateDefault); 578 oTab.panel.removeClass(_this.options.classes.stateActive).addClass(_this.options.classes.stateDefault); 579 }, !doQueue); 580 581 this.$element.trigger('tabs-deactivate', oTab); 582 } 583 }; 584 585 /** 586 * This function runs an effect on a panel 587 * @param {Element} panel - The HTML element of the tab panel 588 * @param {String} method - The transition method reference 589 * @param {String} state - The state (open/closed) that the panel should transition to 590 * @param {Function} callback - The callback function that is called after the transition 591 * @param {Boolean} dequeue - Defines if the event queue should be dequeued after the transition 592 */ 593 ResponsiveContentTabs.prototype._doTransition = function(panel, method, state, callback, dequeue) { 594 var effect; 595 var _this = this; 596 597 // Get effect based on method 598 switch(method) { 599 case 'slide': 600 effect = (state === 'open') ? 'slideDown' : 'slideUp'; 601 break; 602 case 'fade': 603 effect = (state === 'open') ? 'fadeIn' : 'fadeOut'; 604 break; 605 default: 606 effect = (state === 'open') ? 'show' : 'hide'; 607 // When default is used, set the duration to 0 608 _this.options.duration = 0; 609 break; 610 } 611 612 // Add the transition to a custom queue 613 this.$queue.queue('responsive-tabs',function(next){ 614 // Run the transition on the panel 615 panel[effect]({ 616 duration: _this.options.duration, 617 complete: function() { 618 // Call the callback function 619 callback.call(panel, method, state); 620 // Run the next function in the queue 621 next(); 622 } 623 }); 624 }); 625 626 // When the panel is openend, dequeue everything so the animation starts 627 if(state === 'open' || dequeue) { 628 this.$queue.dequeue('responsive-tabs'); 629 } 630 631 }; 632 633 /** 634 * This function returns the collapsibility of the tab in this state 635 * @returns {Boolean} The collapsibility of the tab 636 */ 637 ResponsiveContentTabs.prototype._isCollapisble = function() { 638 return (typeof this.options.collapsible === 'boolean' && this.options.collapsible) || (typeof this.options.collapsible === 'string' && this.options.collapsible === this.getState()); 639 }; 640 641 /** 642 * This function returns a tab by numeric reference 643 * @param {Integer} numRef - Numeric tab reference 644 * @returns {Object} Tab object 645 */ 646 ResponsiveContentTabs.prototype._getTab = function(numRef) { 647 return this.tabs[numRef]; 648 }; 649 650 /** 651 * This function returns the numeric tab reference based on a hash selector 652 * @param {String} selector - Hash selector 653 * @returns {Integer} Numeric tab reference 654 */ 655 ResponsiveContentTabs.prototype._getTabRefBySelector = function(selector) { 656 // Loop all tabs 657 658 for (var i=0; i<this.tabs.length; i++) { 659 // Check if the hash selector is equal to the tab selector 660 if(this.tabs[i].selector === selector) { 661 return i; 662 } 663 } 664 // If none is found return a negative index 665 return -1; 666 }; 667 668 /** 669 * This function returns the current tab element 670 * @returns {Object} Current tab element 671 */ 672 ResponsiveContentTabs.prototype._getCurrentTab = function() { 673 return this._getTab(this._getCurrentTabRef()); 674 }; 675 676 /** 677 * This function returns the next tab's numeric reference 678 * @param {Integer} currentTabRef - Current numeric tab reference 679 * @returns {Integer} Numeric tab reference 680 */ 681 ResponsiveContentTabs.prototype._getNextTabRef = function(currentTabRef) { 682 var tabRef = (currentTabRef || this._getCurrentTabRef()); 683 var nextTabRef = (tabRef === this.tabs.length - 1) ? 0 : tabRef + 1; 684 return (this._getTab(nextTabRef).disabled) ? this._getNextTabRef(nextTabRef) : nextTabRef; 685 }; 686 687 /** 688 * This function returns the previous tab's numeric reference 689 * @returns {Integer} Numeric tab reference 690 */ 691 ResponsiveContentTabs.prototype._getPreviousTabRef = function() { 692 return (this._getCurrentTabRef() === 0) ? this.tabs.length - 1 : this._getCurrentTabRef() - 1; 693 }; 694 695 /** 696 * This function returns the current tab's numeric reference 697 * @returns {Integer} Numeric tab reference 698 */ 699 ResponsiveContentTabs.prototype._getCurrentTabRef = function() { 700 // Loop all tabs 701 for (var i=0; i<this.tabs.length; i++) { 702 // If this tab is active, return it 703 if(this.tabs[i].active) { 704 return i; 705 } 706 } 707 // No tabs have been found, return negative index 708 return -1; 709 }; 710 711 /** 712 * This function gets the tallest tab and applied the height to all tabs 713 */ 714 ResponsiveContentTabs.prototype._equaliseHeights = function() { 715 var maxHeight = 0; 716 717 $.each($.map(this.tabs, function(tab) { 718 maxHeight = Math.max(maxHeight, tab.panel.css('minHeight', '').height()); 719 return tab.panel; 720 }), function() { 721 this.css('minHeight', maxHeight); 722 }); 723 }; 724 725 // 726 // HELPER FUNCTIONS 727 // 728 729 ResponsiveContentTabs.prototype._isInView = function($element) { 730 var docViewTop = $(window).scrollTop(), 731 docViewBottom = docViewTop + $(window).height(), 732 elemTop = $element.offset().top, 733 elemBottom = elemTop + $element.height(); 734 return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)); 735 }; 736 737 // 738 // PUBLIC FUNCTIONS 739 // 740 741 /** 742 * This function activates a tab 743 * @param {Integer} tabRef - Numeric tab reference 744 * @param {Boolean} stopRotation - Defines if the tab rotation should stop after activation 745 */ 746 ResponsiveContentTabs.prototype.activate = function(tabRef, stopRotation) { 747 var e = jQuery.Event('tabs-activate'); 748 var oTab = this._getTab(tabRef); 749 750 if(!oTab.disabled) { 751 this._openTab(e, oTab, true, stopRotation || true); 752 } 753 }; 754 755 /** 756 * This function deactivates a tab 757 * @param {Integer} tabRef - Numeric tab reference 758 */ 759 ResponsiveContentTabs.prototype.deactivate = function(tabRef) { 760 var e = jQuery.Event('tabs-dectivate'); 761 var oTab = this._getTab(tabRef); 762 if(!oTab.disabled) { 763 this._closeTab(e, oTab); 764 } 765 }; 766 767 /** 768 * This function enables a tab 769 * @param {Integer} tabRef - Numeric tab reference 770 */ 771 ResponsiveContentTabs.prototype.enable = function(tabRef) { 772 var oTab = this._getTab(tabRef); 773 if(oTab){ 774 oTab.disabled = false;
775 oTab.tab.addClass(this.options.classes.stateDefault).removeClass(this.options.classes.stateDisabled); 776 oTab.accordionTab.addClass(this.options.classes.stateDefault).removeClass(this.options.classes.stateDisabled); 777 } 778 }; 779 780 /** 781 * This function disable a tab 782 * @param {Integer} tabRef - Numeric tab reference 783 */ 784 ResponsiveContentTabs.prototype.disable = function(tabRef) { 785 var oTab = this._getTab(tabRef); 786 if(oTab){ 787 oTab.disabled = true; 788 oTab.tab.removeClass(this.options.classes.stateDefault).addClass(this.options.classes.stateDisabled); 789 oTab.accordionTab.removeClass(this.options.classes.stateDefault).addClass(this.options.classes.stateDisabled); 790 } 791 }; 792 793 /** 794 * This function gets the current state of the plugin 795 * @returns {String} State of the plugin 796 */ 797 ResponsiveContentTabs.prototype.getState = function() { 798 return this.state; 799 }; 800 801 /** 802 * This function starts the rotation of the tabs 803 * @param {Integer} speed - The speed of the rotation 804 */ 805 ResponsiveContentTabs.prototype.startRotation = function(speed) { 806 var _this = this; 807 // Make sure not all tabs are disabled 808 if(this.tabs.length > this.options.disabled.length) { 809 this.rotateInterval = setInterval(function(){ 810 var e = jQuery.Event('rotate'); 811 _this._openTab(e, _this._getTab(_this._getNextTabRef()), true); 812 }, speed || (($.isNumeric(_this.options.rotate)) ? _this.options.rotate : 4000) ); 813 } else { 814 throw new Error("Rotation is not possible if all tabs are disabled"); 815 } 816 }; 817 818 /** 819 * This function stops the rotation of the tabs 820 */ 821 ResponsiveContentTabs.prototype.stopRotation = function() { 822 window.clearInterval(this.rotateInterval); 823 this.rotateInterval = 0; 824 }; 825 826 /** 827 * This function can be used to get/set options 828 * @return {any} Option value 829 */ 830 ResponsiveContentTabs.prototype.option = function(key, value) { 831 if(value) { 832 this.options[key] = value; 833 } 834 return this.options[key]; 835 }; 836 837 /** jQuery wrapper */ 838 $.fn.responsiveContentTabs = function ( event, options ) { 839 var args = arguments; 840 var instance; 841 842 if(event == 'init'){ 843 844 if (options === undefined || typeof options === 'object') { 845 return this.each(function () { 846 if (!$.data(this, 'responsivecontenttabs')) { 847 $.data(this, 'responsivecontenttabs', new ResponsiveContentTabs( this, options )); 848 } 849 }); 850 } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') { 851 instance = $.data(this[0], 'responsivecontenttabs'); 852 853 // Allow instances to be destroyed via the 'destroy' method 854 if (options === 'destroy') { 855 // TODO: destroy instance classes, etc 856 $.data(this, 'responsivecontenttabs', null); 857 } 858 859 if (instance instanceof ResponsiveContentTabs && typeof instance[options] === 'function') { 860 return instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) ); 861 } else { 862 return this; 863 } 864 } 865 866 } 867 868 if(event == 'reinit'){ 869 870 if (options === undefined || typeof options === 'object') { 871 872 if (!$.data(this, 'responsivecontenttabs')) { 873 $.data(this, 'responsivecontenttabs', new ResponsiveContentTabs( this, options )); 874 } 875 876 } 877 878 } 879 880 881 }; 882 883}(jQuery, window));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.