1jQuery( window ).on( 'elementor/frontend/init', () => { 2 elementorFrontend.hooks.addAction( 'frontend/element_ready/art-tabs.default', ( $element ) => { 3 elementorFrontend.elementsHandler.addHandler( ArtTabs, { 4 $element, 5 } ); 6 } ); 7} ); 8 9 10class ArtTabs extends elementorModules.frontend.handlers.Base { 11 getDefaultSettings() { 12 return { 13 selectors: { 14 tablist: '[role="tablist"]', 15 tabTitle: '.art-tab-title', 16 tabContent: '.art-tab-content', 17 }, 18 classes: { 19 active: 'art-active', 20 }, 21 showTabFn: 'show', 22 hideTabFn: 'hide', 23 toggleSelf: false, 24 hidePrevious: true, 25 autoExpand: true, 26 keyDirection: { 27 ArrowLeft: elementorFrontendConfig.is_rtl ? 1 : -1, 28 ArrowUp: -1, 29 ArrowRight: elementorFrontendConfig.is_rtl ? -1 : 1, 30 ArrowDown: 1, 31 }, 32 }; 33 } 34 35 getDefaultElements() { 36 const selectors = this.getSettings( 'selectors' ); 37 38 return { 39 $tabTitles: this.findElement( selectors.tabTitle ), 40 $tabContents: this.findElement( selectors.tabContent ), 41 }; 42 } 43 44 activateDefaultTab() { 45 const settings = this.getSettings(); 46 47 if ( ! settings.autoExpand || ( 'editor' === settings.autoExpand && ! this.isEdit ) ) { 48 return; 49 } 50 51 const defaultActiveTab = this.getEditSettings( 'activeItemIndex' ) || 1, 52 originalToggleMethods = { 53 showTabFn: settings.showTabFn, 54 hideTabFn: settings.hideTabFn, 55 }; 56 57 // Toggle tabs without animation to avoid jumping 58 this.setSettings( { 59 showTabFn: 'show', 60 hideTabFn: 'hide', 61 } ); 62 63 this.changeActiveTab( defaultActiveTab ); 64 65 // Return back original toggle effects 66 this.setSettings( originalToggleMethods ); 67 } 68 69 deactivateActiveTab( tabIndex ) { 70 const settings = this.getSettings(), 71 activeClass = settings.classes.active, 72 activeFilter = tabIndex ? '[data-tab="' + tabIndex + '"]' : '.' + activeClass, 73 $activeTitle = this.elements.$tabTitles.filter( activeFilter ), 74 $activeContent = this.elements.$tabContents.filter( activeFilter ); 75 76 $activeTitle.add( $activeContent ).removeClass( activeClass ); 77 $activeTitle.attr( { 78 tabindex: '-1', 79 'aria-selected': 'false', 80 'aria-expanded': 'false', 81 } ); 82 83 $activeContent[ settings.hideTabFn ](); 84 $activeContent.attr( 'hidden', 'hidden' ); 85 } 86 87 activateTab( tabIndex ) { 88 const settings = this.getSettings(), 89 activeClass = settings.classes.active, 90 $requestedTitle = this.elements.$tabTitles.filter( '[data-tab="' + tabIndex + '"]' ), 91 $requestedContent = this.elements.$tabContents.filter( '[data-tab="' + tabIndex + '"]' ), 92 animationDuration = 'show' === settings.showTabFn ? 0 : 400; 93 94 $requestedTitle.add( $requestedContent ).addClass( activeClass ); 95 $requestedTitle.attr( { 96 tabindex: '0', 97 'aria-selected': 'true', 98 'aria-expanded': 'true', 99 } ); 100 101 $requestedContent[ settings.showTabFn ]( 102 animationDuration, 103 () => elementorFrontend.elements.$window.trigger( 'elementor-pro/motion-fx/recalc' ), 104 ); 105 106 $requestedContent.removeAttr( 'hidden' ); 107 } 108 109 isActiveTab( tabIndex ) { 110 return this.elements.$tabTitles.filter( '[data-tab="' + tabIndex + '"]' ).hasClass( this.getSettings( 'classes.active' ) ); 111 } 112 113 bindEvents() { 114 this.elements.$tabTitles.on( 'click', ( event ) => { 115 event.preventDefault(); 116 this.changeActiveTab( event.currentTarget.getAttribute( 'data-tab' ) ); 117 } ); 118 } 119 120 onInit( ...args ) { 121 super.onInit( ...args ); 122 123 this.activateDefaultTab(); 124 125 this.initSlider(); 126 } 127 128 onEditSettingsChange( propertyName ) { 129 if ( 'activeItemIndex' === propertyName ) { 130 this.activateDefaultTab(); 131 } 132 } 133 134 changeActiveTab( tabIndex ) { 135 const isActiveTab = this.isActiveTab( tabIndex ), 136 settings = this.getSettings(); 137 138 if ( ( settings.toggleSelf || ! isActiveTab ) && settings.hidePrevious ) { 139 this.deactivateActiveTab(); 140 } 141 142 if ( ! settings.hidePrevious && isActiveTab ) { 143 this.deactivateActiveTab( tabIndex ); 144 } 145 146 if ( ! isActiveTab ) { 147 this.activateTab( tabIndex ); 148 } 149 } 150 151 async initSwiper( swiperElement, swiperConfig ) { 152 let mySwiper; 153 154 const asyncSwiper = elementorFrontend.utils.swiper; 155 156 mySwiper = await new asyncSwiper( swiperElement, swiperConfig ).then( ( newSwiperInstance ) => { 157 mySwiper = newSwiperInstance; 158 } ); 159 160 return mySwiper; 161 } 162 163 async initSlider() { 164 if ( 1 > this.findElement( '.swiper-container' ).length ) { 165 return; 166 } 167 168 elementorModules.frontend.handlers.Base.prototype.onInit.apply( this, arguments ); 169 170 const $mainSwiper = this.$element.find( '.swiper-container' ); 171 172 $mainSwiper.each( async ( index, item ) => { 173 await this.initSwiper( jQuery( item ), { 174 navigation: { 175 prevEl: '.art-swiper-arrow-prev', 176 nextEl: '.art-swiper-arrow-next', 177 }, 178 pagination: false, 179 autoHeight: true, 180 slidesPerView: 1, 181 slidesPerGroup: 1, 182 loop: false, 183 spaceBetween: 30, 184 observer: true, 185 observeParents: true, 186 } ); 187 } ).bind( this ); 188 } 189}
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.