1( function( $ ) { 2 'use strict'; 3 4 class AdvancedTabsHandler extends elementorModules.frontend.handlers.Base { 5 getWidgetNumber() { 6 const $widget = this.$element.find( '> .elementor-widget-container > .kd-widget-container > .kd-advanced-tabs, > .kd-widget-container > .kd-advanced-tabs, > .kd-advanced-tabs' ); 7 const widgetNumber = $widget.attr( 'data-widget-number' ); 8 return widgetNumber; 9 } 10 11 getDefaultSettings() { 12 const widgetNumber = this.getWidgetNumber(); 13 return { 14 selectors: { 15 widgetContainer: `[data-widget-number="${widgetNumber}"]`, 16 tabTitle: `[aria-controls*="kd-advanced-tabs-pane-${widgetNumber}"]`, 17 tabTitleIcon: `[id*="kd-advanced-tabs-tab-${widgetNumber}"] > .kd-advanced-tabs__tab-icon`, 18 tabTitleText: `[id*="kd-advanced-tabs-tab-${widgetNumber}"] .kd-advanced-tabs__tab-title`, 19 tabTitleDescription: `[id*="kd-advanced-tabs-tab-${widgetNumber}"] .kd-advanced-tabs__tab-description`, 20 tabContent: `[data-widget-number="${widgetNumber}"] .kd-advanced-tabs__panes > .kd-advanced-tabs__pane`, 21 headingContainer: `[data-widget-number="${widgetNumber}"] > .kd-advanced-tabs__tabs`, 22 activeTabContentContainers: `[id*="kd-advanced-tabs-pane-${widgetNumber}"].e-active` 23 }, 24 classes: { 25 active: 'e-active' 26 }, 27 dataAttributes: { 28 tabIndex: 'data-tab-index' 29 }, 30 ariaAttributes: { 31 titleStateAttribute: 'aria-selected', 32 activeTitleSelector: '[aria-selected="true"]' 33 }, 34 toggleSelf: false, 35 hidePrevious: true, 36 autoExpand: true 37 }; 38 } 39 40 getDefaultElements() { 41 const selectors = this.getSettings( 'selectors' ); 42 return { 43 $widgetContainer: this.findElement( selectors.widgetContainer ), 44 $tabTitles: this.findElement( selectors.tabTitle ), 45 $tabContents: this.findElement( selectors.tabContent ), 46 $headingContainer: this.findElement( selectors.headingContainer ) 47 }; 48 } 49 50 getTabTitleFilterSelector( tabIndex ) {
51 return `[${this.getSettings( 'dataAttributes' ).tabIndex}="${tabIndex}"]`; 52 } 53 54 getTabContentFilterSelector( tabIndex ) { 55 return `*:nth-child(${tabIndex})`; 56 } 57 58 getTabIndex( tabTitleElement ) { 59 return tabTitleElement.getAttribute( this.getSettings( 'dataAttributes' ).tabIndex ); 60 } 61 62 getActiveTabIndex() { 63 const settings = this.getSettings(), 64 activeTitleFilter = settings.ariaAttributes.activeTitleSelector, 65 tabIndexSelector = settings.dataAttributes.tabIndex, 66 $activeTitle = this.elements.$tabTitles.filter( activeTitleFilter ); 67 68 return $activeTitle.attr( tabIndexSelector ) || null; 69 } 70 71 activateDefaultTab() { 72 const settings = this.getSettings(); 73 const defaultActiveTab = this.getEditSettings( 'activeItemIndex' ) || 1; 74 const originalToggleMethods = { 75 showTabFn: settings.showTabFn, 76 hideTabFn: settings.hideTabFn 77 }; 78 79 this.setSettings( { 80 showTabFn: 'show', 81 hideTabFn: 'hide' 82 } ); 83 84 this.changeActiveTab( defaultActiveTab ); 85 this.setSettings( originalToggleMethods ); 86 this.elements.$widgetContainer.addClass( 'e-activated' ); 87 } 88 89 deactivateActiveTab( newTabIndex ) { 90 const settings = this.getSettings(), 91 activeClass = settings.classes.active, 92 activeTitleFilter = settings.ariaAttributes.activeTitleSelector, 93 activeContentFilter = '.' + activeClass, 94 $activeTitle = this.elements.$tabTitles.filter( activeTitleFilter ), 95 $activeContent = this.elements.$tabContents.filter( activeContentFilter ); 96 97 this.setTabDeactivationAttributes( $activeTitle, newTabIndex ); 98 $activeContent.removeClass( activeClass ); 99 100 return $activeContent; 101 } 102 103 getTitleActivationAttributes() { 104 const titleStateAttribute = this.getSettings( 'ariaAttributes' ).titleStateAttribute; 105 return { 106 tabindex: '0', 107 [ titleStateAttribute ]: 'true' 108 }; 109 } 110 111 setTabDeactivationAttributes( $activeTitle ) { 112 const titleStateAttribute = this.getSettings( 'ariaAttributes' ).titleStateAttribute; 113 $activeTitle.attr( { 114 tabindex: '-1', 115 [ titleStateAttribute ]: 'false' 116 } ); 117 } 118 119 activateTab( tabIndex ) { 120 const settings = this.getSettings(), 121 activeClass = settings.classes.active; 122 123 let $requestedTitle = this.elements.$tabTitles.filter( this.getTabTitleFilterSelector( tabIndex ) ); 124 let $requestedContent = this.elements.$tabContents.filter( this.getTabContentFilterSelector( tabIndex ) ); 125 126 if ( ! $requestedTitle.length ) { 127 const previousTabIndex = Math.max( tabIndex - 1, 1 ); 128 $requestedTitle = this.elements.$tabTitles.filter( this.getTabTitleFilterSelector( previousTabIndex ) ); 129 $requestedContent = this.elements.$tabContents.filter( this.getTabContentFilterSelector( previousTabIndex ) ); 130 } 131 132 $requestedTitle.attr( this.getTitleActivationAttributes() ); 133 $requestedContent.addClass( activeClass ); 134 this.onShowTabContent( $requestedContent ); 135 } 136 137 onShowTabContent( $requestedContent ) { 138 elementorFrontend.elements.$window.trigger( 'elementor-pro/motion-fx/recalc' ); 139 elementorFrontend.elements.$window.trigger( 'elementor/keydesign-advanced-tabs/activate', $requestedContent ); 140 elementorFrontend.elements.$window.trigger( 'elementor/bg-video/recalc' ); 141 } 142 143 isActiveTab( tabIndex ) { 144 const settings = this.getSettings(); 145 const isActiveTabTitle = 'true' === this.elements.$tabTitles.filter( `[${settings.dataAttributes.tabIndex}="${tabIndex}"]` ).attr( settings.ariaAttributes.titleStateAttribute );
146 const isActiveTabContent = this.elements.$tabContents.filter( this.getTabContentFilterSelector( tabIndex ) ).hasClass( this.getActiveClass() ); 147 148 return isActiveTabTitle && isActiveTabContent; 149 } 150 151 onTabClick( event ) { 152 event.preventDefault(); 153 const tabIndex = event.currentTarget?.getAttribute( this.getSettings( 'dataAttributes' ).tabIndex ); 154 this.changeActiveTab( tabIndex, true ); 155 } 156 157 getTabEvents() { 158 return { 159 click: this.onTabClick.bind( this ) 160 }; 161 } 162 163 bindEvents() { 164 this.elements.$tabTitles.on( this.getTabEvents() ); 165 elementorFrontend.elements.$window.on( 'elementor/keydesign-advanced-tabs/activate', this.reInitSwipers ); 166 elementorFrontend.elements.$window.on( 'elementor/nested-container/atomic-repeater', this.linkContainer.bind( this ) ); 167 } 168 169 unbindEvents() { 170 this.elements.$tabTitles.off(); 171 this.elements.$headingContainer.off(); 172 this.elements.$tabContents.children().off(); 173 elementorFrontend.elements.$window.off( 'elementor/keydesign-advanced-tabs/activate', this.reInitSwipers ); 174 elementorFrontend.elements.$window.off( 'elementor/nested-container/atomic-repeater', this.linkContainer.bind( this ) ); 175 } 176 177 reInitSwipers( event, content ) { 178 if ( ! content ) { 179 return; 180 } 181 182 const contentElement = content instanceof jQuery ? content[ 0 ] : content; 183 184 if ( ! contentElement || ! contentElement.querySelectorAll ) { 185 return; 186 } 187 188 const swiperElements = contentElement.querySelectorAll( '.swiper' ); 189 for ( const element of swiperElements ) { 190 if ( ! element.swiper ) { 191 return; 192 } 193 element.swiper.initialized = false; 194 element.swiper.init(); 195 } 196 } 197 198 onInit() { 199 super.onInit( ...arguments ); 200 201 if ( this.getSettings( 'autoExpand' ) ) { 202 this.activateDefaultTab(); 203 } 204 } 205 206 onEditSettingsChange( propertyName, value ) { 207 if ( 'activeItemIndex' === propertyName ) { 208 this.changeActiveTab( value, false ); 209 } 210 } 211 212 changeActiveTab( tabIndex, fromUser = false ) { 213 if ( fromUser && this.isEdit && this.isElementInTheCurrentDocument() ) { 214 return window.top.$e.run( 'document/repeater/select', { 215 container: elementor.getContainer( this.$element.attr( 'data-id' ) ), 216 index: parseInt( tabIndex ) 217 } ); 218 } 219 220 const isActiveTab = this.isActiveTab( tabIndex ); 221 const settings = this.getSettings(); 222 223 if ( ( settings.toggleSelf || ! isActiveTab ) && settings.hidePrevious ) { 224 this.deactivateActiveTab( tabIndex ); 225 } 226 227 if ( ! settings.hidePrevious && isActiveTab ) { 228 this.deactivateActiveTab( tabIndex ); 229 } 230 231 if ( ! isActiveTab ) { 232 this.activateTab( tabIndex ); 233 } 234 } 235 236 getActiveClass() { 237 return this.getSettings( 'classes' ).active; 238 } 239 240 linkContainer( event ) { 241 const { container } = event.detail; 242 const id = container.model.get( 'id' );
243 const currentId = this.$element.data( 'id' ); 244 const view = container.view.$el; 245 246 if ( id === currentId ) { 247 this.updateIndexValues(); 248 this.updateListeners( view ); 249 elementor.$preview[ 0 ].contentWindow.dispatchEvent( new CustomEvent( 'elementor/elements/link-data-bindings' ) ); 250 } 251 252 if ( ! this.getActiveTabIndex() ) { 253 const targetIndex = event.detail.index + 1 || 1; 254 this.changeActiveTab( targetIndex ); 255 } 256 } 257 258 updateListeners( view ) { 259 this.elements.$tabContents = view.find( this.getSettings( 'selectors.tabContent' ) ); 260 this.elements.$tabTitles = view.find( this.getSettings( 'selectors.tabTitle' ) ); 261 this.elements.$tabTitles.on( this.getTabEvents() ); 262 } 263 264 updateIndexValues() { 265 const { $widgetContainer, $tabContents, $tabTitles } = this.getDefaultElements(); 266 const settings = this.getSettings(); 267 const dataTabIndex = settings.dataAttributes.tabIndex; 268 const widgetNumber = $widgetContainer.data( 'widgetNumber' ); 269 270 $tabTitles.each( ( index, element ) => { 271 const newIndex = index + 1; 272 const updatedTabID = `kd-advanced-tabs-tab-${widgetNumber}${newIndex}`; 273 const updatedContainerID = `kd-advanced-tabs-pane-${widgetNumber}${newIndex}`; 274 275 element.setAttribute( 'id', updatedTabID ); 276 element.setAttribute( dataTabIndex, newIndex ); 277 element.setAttribute( 'aria-controls', updatedContainerID ); 278 279 element.querySelector( settings.selectors.tabTitleIcon )?.setAttribute( 'data-binding-index', newIndex ); 280 element.querySelector( settings.selectors.tabTitleText )?.setAttribute( 'data-binding-index', newIndex ); 281 element.querySelector( settings.selectors.tabTitleDescription )?.setAttribute( 'data-binding-index', newIndex ); 282 283 if ( $tabContents[ index ] ) { 284 $tabContents[ index ].setAttribute( 'aria-labelledby', updatedTabID ); 285 $tabContents[ index ].setAttribute( dataTabIndex, newIndex ); 286 $tabContents[ index ].setAttribute( 'id', updatedContainerID ); 287 $tabContents[ index ].setAttribute( 'role', 'tabpanel' ); 288 } 289 } ); 290 } 291 } 292 293 $( window ).on( 'elementor/frontend/init', function() { 294 elementorFrontend.hooks.addAction( 'frontend/element_ready/keydesign-advanced-tabs.default', function( $scope ) { 295 elementorFrontend.elementsHandler.addHandler( AdvancedTabsHandler, { 296 $element: $scope 297 } ); 298 } ); 299 } ); 300 301} )( jQuery );
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.