1( function( $ ) { 2 'use strict'; 3 4 /** 5 * JetMegaMenuClass 6 */ 7 class JetMegaMenuClass { 8 9 /** 10 * [constructor description] 11 * @return {[type]} [description] 12 */ 13 constructor( instance, options ) { 14 this.defaultSettings = { 15 menuId: '0', 16 menuUniqId: window.jetMenu.getUniqId(), 17 layout: 'horizontal', 18 subTrigger: 'item', // item, submarker 19 subEvent: 'click', // hover, click 20 subCloseBehavior: 'mouseleave', // mouseleave, outside 21 bottomGap: 12, 22 rollUp: true, 23 breakpoint: 768, // Minimal menu width, when this plugin activates 24 mouseLeaveDelay: 500, 25 megaWidthType: 'container', 26 megaWidthSelector: '', 27 megaAjaxLoad: false, 28 classes: { 29 instance: 'menu', 30 menuContainer: 'menu-container', 31 menuList: 'menu-list', 32 menuItem: 'menu-item', 33 menuItemLink: 'menu-item__link', 34 subMenuContainer: 'sub-menu', 35 subMenuList: 'sub-menu__list', 36 megaContainer: 'mega-container', 37 } 38 } 39 40 this.$instance = $( instance ); 41 this.settings = $.extend( this.defaultSettings, options ); 42 this.$window = $( window ); 43 this.$document = $( document ); 44 this.$body = $( 'body' ); 45 this.isRTL = this.$body.hasClass( 'rtl' ); 46 this.isDropdownState = false; 47 48 this._prevViewportWidth = window.innerWidth || document.documentElement.clientWidth; 49 50 this.isContentLoading = false; 51 this._pendingMouseleave = false; 52 53 this.createInstance(); 54 } 55 56 createInstance() { 57 this.$menuList = $( `.${ this.settings.classes.menuList }`, this.$instance ); 58 this.$menuItems = $( `>.${ this.settings.classes.menuItem }:not(.${ this.settings.classes.menuItem }--roll-up)`, this.$menuList ); 59 this.$rollUpItem = $( `>.${ this.settings.classes.menuItem }--roll-up`, this.$menuList ); 60 61 this.menuItemsData = this.$menuItems.toArray().map( function( item ) { 62 return { 63 element: item, 64 outerWidth: $( item ).outerWidth( true ), 65 offsetLeft: $( item )[0].offsetLeft, 66 } 67 } ); 68 69 this.initWatcher( 50 ); 70 this.initEvents(); 71 this.maybeRollUpItems(); 72 this.rebuildSubContainers(); 73 74 document.addEventListener( 'DOMContentLoaded', ( event ) => { 75 setTimeout( () => { 76 this.watchTick(); 77 }, 250 ); 78 } ); 79 80 this.$instance.addClass( `${ this.settings.classes.instance }--inited` ); 81 this.$document.trigger( 'JetMegaMenuInited' ); 82 } 83 84 initEvents() { 85 let debounceTimer, 86 eventHandler = 'JetMegaMenu', 87 $itemTargetSelector = 'item' === this.settings.subTrigger ? `.${ this.settings.classes.menuItem } > .${ this.settings.classes.menuItem }__inner` : `.${ this.settings.classes.menuItem } > .${ this.settings.classes.menuItem }__inner .${ this.settings.classes.menuItem }__dropdown`; 88 89 const subCloseBehavior = this.settings.subCloseBehavior || 'mouseleave'; 90 const isHoverMode = this.settings.subEvent === 'hover'; 91 const isClickMode = this.settings.subEvent === 'click'; 92 const shouldCloseOnLeave = isHoverMode || ( isClickMode && subCloseBehavior === 'mouseleave' ); 93 const shouldCloseOnOutside = isClickMode && subCloseBehavior === 'outside'; 94 95 const clearInlineScroll = ( $root ) => { 96 $root 97 .find( `.${ this.settings.classes.subMenuContainer }, .${ this.settings.classes.megaContainer }` ) 98 .each( (_, wrap) => { 99 const $wrap = $( wrap ); 100 const $list = $wrap.children( `.${ this.settings.classes.subMenuList }:first` ); 101 const $inner = $wrap.children( `.${ this.settings.classes.megaContainer }__inner:first` ); 102 $wrap.add( $list ).add( $inner ).css( { 'max-height':'', 'overflow-y':'', 'overflow-x':'' } ); 103 }); 104 }; 105 106 switch ( this.settings.subEvent ) { 107 case 'hover': 108 this.$instance.on( `mouseenter.${ eventHandler }`, `.${ this.settings.classes.menuItem } > .${ this.settings.classes.menuItem }__inner`, { instance: this }, ( event ) => { 109 let $target = $( event.target ), 110 $menuItem = $target.parents( `.${ this.settings.classes.menuItem }` ), 111 $subContainer = $( `.${ this.settings.classes.subMenuContainer }:first, .${ this.settings.classes.megaContainer }:first`, $menuItem ), 112 templateContent = $subContainer.data( 'template-content' ) || false, 113 templateId = $subContainer.data( 'template-id' ) || false; 114 115 $( `.${ this.settings.classes.menuItem }--hover`, this.$instance ).removeClass( `${ this.settings.classes.menuItem }--hover` ); 116 117 if ( $menuItem.hasClass( `${ this.settings.classes.menuItem }-has-children` ) ) { 118 $menuItem.addClass( `${ this.settings.classes.menuItem }--hover` ); 119 120 if ( $menuItem.hasClass( `${ this.settings.classes.menuItem }--top-level` ) ) { 121 this.applySmartScroll( $menuItem ); 122 } 123 124 $menuItem 125 .find( '[role="button"][aria-haspopup="true"]' ) 126 .attr( 'aria-expanded', 'true' ); 127 128 if ( templateId ) { 129 this.maybeTemplateLoad( templateId, templateContent, $subContainer ); 130 } 131 } 132 } ); 133 134 this.$instance.on( `mouseleave.${ eventHandler }`, `.${ this.settings.classes.menuItem } > .${ this.settings.classes.menuItem }__inner`, ( event ) => { /* Item Mouse Leave Event */ } ); 135 break; 136
137 case 'click': 138 139 this.$instance.on( `click.${ eventHandler }`, $itemTargetSelector, ( event ) => { 140 event.preventDefault(); 141 event.stopPropagation(); 142 143 let $currentTarget = $( event.currentTarget ), 144 $menuItem = $currentTarget.closest( `.${this.settings.classes.menuItem}` ), 145 $menuItemLink = $( '.jet-mega-menu-item__link', $menuItem ).first(), 146 $siblingsItems = $menuItem.siblings( `.${this.settings.classes.menuItem}-has-children` ), 147 $subContainer = $( `.${this.settings.classes.subMenuContainer}:first, .${this.settings.classes.megaContainer}`, $menuItem ), 148 templateContent = $subContainer.data( 'template-content' ) || false, 149 templateId = $subContainer.data( 'template-id' ) || false; 150 151 if ( $siblingsItems.length ) { 152 $siblingsItems.removeClass( `${ this.settings.classes.menuItem }--hover` ); 153 $( `.${ this.settings.classes.menuItem }-has-children`, $siblingsItems ).removeClass( `${ this.settings.classes.menuItem }--hover` ); 154 } 155 156 if ( $menuItem.hasClass( `${ this.settings.classes.menuItem }-has-children` ) ) { 157 if ( ! $menuItem.hasClass( `${ this.settings.classes.menuItem }--hover` ) ) { 158 $menuItem.addClass( `${ this.settings.classes.menuItem }--hover` ); 159 160 $menuItem 161 .find( '[role="button"][aria-haspopup="true"]' ) 162 .attr( 'aria-expanded', 'true' ); 163 164 } else { 165 $menuItem.removeClass( `${ this.settings.classes.menuItem }--hover` ); 166 167 $menuItem 168 .find( '[role="button"][aria-haspopup="true"]' ) 169 .attr( 'aria-expanded', 'false' ); 170 } 171 172 if ( templateId ) { 173 this.maybeTemplateLoad( templateId, templateContent, $subContainer ); 174 } 175 176 if ( $menuItem.hasClass( `${ this.settings.classes.menuItem }--top-level` ) 177 && $menuItem.hasClass( `${ this.settings.classes.menuItem }--hover`) ) { 178 this.applySmartScroll( $menuItem ); 179 } 180 181 } else { 182 let itemLink = $menuItemLink.attr( 'href' ) || '#', 183 target = $menuItemLink.attr( 'target' ) || '_self'; 184 185 window.open( itemLink, target ); 186 187 return false; 188 } 189 } ); 190 break; 191 } 192 193 this.$instance.on( `mouseenter.${ eventHandler }`, `.${ this.settings.classes.subMenuContainer }, .${ this.settings.classes.megaContainer }`, ( event ) => { 194 clearTimeout( debounceTimer ); 195 } ); 196 197 this.$instance.on( `mouseenter.${ eventHandler }`, ( event ) => { 198 clearTimeout( debounceTimer ); 199 } ); 200 201 this.$instance.on( `mouseleave.${ eventHandler }`, ( event ) => { 202 203 if ( ! shouldCloseOnLeave ) { 204 return; 205 } 206 207 if ( this.isContentLoading ) { 208 clearTimeout( debounceTimer ); 209 this._pendingMouseleave = true; 210 211 return; 212 } 213 214 debounceTimer = setTimeout( () => { 215 $( `.${ this.settings.classes.menuItem }--hover`, this.$instance ).removeClass( `${ this.settings.classes.menuItem }--hover` ); 216 217 this.$instance 218 .find( '[role="button"][aria-haspopup="true"]' ) 219 .attr( 'aria-expanded', 'false' ); 220 221 clearInlineScroll( this.$instance ); 222 }, this.settings.mouseLeaveDelay ); 223 } ); 224 225 this.$document.on( `click.${ eventHandler }`, ( event ) => { 226 227 if ( ! shouldCloseOnOutside ) { 228 return; 229 } 230 231 this.closeOnOutside( event ); 232 clearInlineScroll( this.$instance ); 233 } ); 234 235 this.$window.on( `orientationchange.${ eventHandler } resize.${ eventHandler }`, ( event ) => { 236 const viewportWidth = window.innerWidth || document.documentElement.clientWidth; 237 238 if ( viewportWidth === this._prevViewportWidth ) { 239 return; 240 } 241 242 this._prevViewportWidth = viewportWidth; 243 244 $( `.${ this.settings.classes.menuItem }`, this.$instance ).removeClass( `${ this.settings.classes.menuItem }--hover` ); 245 this.$instance.removeClass( `${ this.settings.classes.instance }--dropdown-open` ); 246 247 clearInlineScroll( this.$instance ); 248 } ); 249 250 this.$document.on( `touchend.${ eventHandler }`, ( event ) => { 251 this.closeOnOutside( event ); 252 clearInlineScroll(this.$instance); 253 } ); 254 255 this.$instance.on( 'watchTickEventResetRegularState', ( event ) => { 256 this.resetRegularState(); 257 258 if ( this.$rollUpItem[0] ) { 259 $( `.${ this.settings.classes.subMenuList }:first`, this.$rollUpItem ).empty(); 260 this.$rollUpItem[0].hidden = true; 261 } 262 263 for ( let index = 0; index < this.menuItemsData.length; index++ ) { 264 this.menuItemsData[ index ].element.hidden = false;
265 } 266 } ); 267 268 this.$instance.on( 'watchTickEventResetDropdownState', ( event ) => { 269 this.resetDropdownState(); 270 this.$instance.removeClass( `${ this.settings.classes.instance }--dropdown-open` ); 271 } ); 272 273 this.$instance.on('watchTickEventDropdown watchTickEventResetDropdownState', () => { 274 clearInlineScroll(this.$instance); 275 }); 276 277 this.$instance.on( `click.${ eventHandler }`, `.${ this.settings.classes.instance }-toggle`, ( event ) => { 278 279 if ( ! this.$instance.hasClass( `${ this.settings.classes.instance }--dropdown-open` ) ) { 280 this.$instance.addClass( `${ this.settings.classes.instance }--dropdown-open` ); 281 } else { 282 this.$instance.removeClass( `${ this.settings.classes.instance }--dropdown-open` ); 283 } 284 } ); 285 286 this.$instance.on( `keydown.${ eventHandler }`, `.${ this.settings.classes.menuItem }__inner[role="button"], .${ this.settings.classes.menuItem }__dropdown[role="button"]`, ( event ) => { 287 288 if ( event.key === 'Enter' || event.key === ' ' ) { 289 event.preventDefault(); 290 291 if ( this.settings.subEvent === 'click' ) { 292 $( event.currentTarget ).trigger( 'click' ); 293 } 294 295 if ( this.settings.subEvent === 'hover' ) { 296 $( event.currentTarget ).trigger( 'mouseenter' ); 297 } 298 } 299 300 }); 301 302 } 303 304 /** 305 * Init watcher function. 306 * 307 * @param {number} Watcher debounce delay. 308 * @return {void} 309 */ 310 initWatcher( delay = 10 ) { 311 $( window ).off( `resize.JetMegaMenu${ this.settings['menuUniqId'] }` ).on( `resize.JetMegaMenu${ this.settings['menuUniqId'] } orientationchange.JetMegaMenu${ this.settings['menuUniqId'] }`, this.debounce( delay, this.watchTick.bind( this ) ) ); 312 this.$instance.trigger( 'containerResize' ); 313 } 314 315 /** 316 * Close submenu when a pointer event happens outside of the menu. 317 * 318 * @param {Event} event ( click/touchend ) 319 * @return {void} 320 */ 321 closeOnOutside( event ) { 322 323 if ( $( event.target ).closest( `.${ this.settings.classes.menuItem }, .${ this.settings.classes.subMenuContainer }, .${ this.settings.classes.megaContainer }` ).length ) { 324 return; 325 } 326 327 $( `.${ this.settings.classes.menuItem }`, this.$instance ).removeClass( `${ this.settings.classes.menuItem }--hover` ); 328 this.$instance.find( '[role="button"][aria-haspopup="true"]' ).attr( 'aria-expanded', 'false' ); 329 } 330 331 /** 332 * Responsive menu watcher callback. 333 * 334 * @param {Object} Resize or Orientationchange event. 335 * @return {void} 336 */ 337 watchTick( event ) { 338 339 if ( this.isDropdown() ) { 340 341 if ( ! this.isDropdownState ) { 342 this.$instance.trigger( 'watchTickEventResetRegularState' ); 343 } 344 345 this.isDropdownState = true; 346 this.$instance.removeClass( `${ this.settings.classes.instance }--layout-horizontal ${ this.settings.classes.instance }--layout-vertical` ); 347 this.$instance.addClass( `${ this.settings.classes.instance }--layout-dropdown` ); 348 this.$instance.trigger( 'watchTickEventDropdown' ); 349 } else { 350 351 if ( this.isDropdownState ) { 352 this.$instance.trigger( 'watchTickEventResetDropdownState' ); 353 } 354 355 this.isDropdownState = false; 356 this.$instance.removeClass( `${ this.settings.classes.instance }--layout-dropdown` ); 357 this.$instance.addClass( `${ this.settings.classes.instance }--layout-${ this.settings.layout }` ); 358 this.$instance.trigger( `watchTickEventRegular` ); 359 this.$instance.trigger( `watchTickEventRegular--${ this.settings.layout }` ); 360 } 361 362 this.$instance.trigger( 'watchTickEvent' ); 363 } 364 365 /** 366 * Rollup rebuilding function. 367 * 368 * @return {void} 369 */ 370 maybeRollUpItems() { 371 this.$instance.on( 'watchTickEventRegular--horizontal', ( event ) => { 372 373 if ( ! this.settings.rollUp ) { 374 return false; 375 } 376 377 let mainMenuWidth = this.$instance.width(), 378 rollUpWidth = this.$rollUpItem.outerWidth( true ), 379 visibleItemsArray = [], 380 hiddenItemsArray = []; 381 382 const minOffset = Math.min(...this.menuItemsData.map( d => d.offsetLeft ) ); 383 384 for ( let index = 0; index < this.menuItemsData.length; index++ ) { 385 let itemData = this.menuItemsData[ index ], 386 nextItemData = this.menuItemsData[ index + 1 ] || false, 387 rightEdge = ( nextItemData ? nextItemData.offsetLeft : itemData.offsetLeft + itemData.outerWidth ) - minOffset, 388 item = itemData.element; 389 390 if ( rightEdge + rollUpWidth > mainMenuWidth ) { 391 item.hidden = true; 392 hiddenItemsArray.push( item ); 393 } else { 394 item.hidden = false;
395 visibleItemsArray.push( item ); 396 } 397 } 398 399 $( `.${ this.settings.classes.subMenuList }:first`, this.$rollUpItem ).empty(); 400 401 for ( let hiddenMenuItem of hiddenItemsArray ) { 402 let $hiddenClone = $( hiddenMenuItem ).clone(); 403 404 $hiddenClone[0].hidden = false; 405 406 $( `>.${ this.settings.classes.menuItem }__inner >.${ this.settings.classes.menuItemLink }`, $hiddenClone ).toggleClass( `${ this.settings.classes.menuItemLink }--top-level ${ this.settings.classes.menuItemLink }--sub-level` ); 407 $( `.${ this.settings.classes.subMenuList }:first`, this.$rollUpItem ).append( $hiddenClone ); 408 } 409 410 if ( this.$rollUpItem[0] ) { 411 this.$rollUpItem[0].hidden = hiddenItemsArray.length ? false : true; 412 } 413 414 this.$instance.trigger( 'rollUpItemsEvent' ); 415 } ) 416 } 417 418 /** 419 * Rebuild SubContainers function. 420 * 421 * @return {void} 422 */ 423 rebuildSubContainers() { 424 this.$instance.on( 'watchTickEventRegular--horizontal', ( event ) => { 425 let $megaMenuList = $( `.${ this.settings.classes.megaContainer }`, this.$instance ), 426 $subMenuList = $( `.${ this.settings.classes.subMenuContainer }`, this.$instance ), 427 subInverseClass = `${ this.settings.classes.subMenuContainer }--inverse`, 428 instanceWidth = this.$instance.width(), 429 instanceOffset = this.$instance.offset(); 430 431 $subMenuList.each( ( index, element ) => { 432 let $element = $( element ); 433 434 if ( this.isOffscreenX( element ) ) { 435 $element.addClass( subInverseClass ); 436 } else { 437 $element.removeClass( subInverseClass ); 438 } 439 } ); 440 441 switch( this.settings.megaWidthType ) { 442 case 'container': 443 $megaMenuList.each( ( index, element ) => { 444 let $element = $( element ), 445 $elementPosition = $element.data( 'position' ), 446 elementOffset = $element.offset(), 447 elementDeltaOffset = 'default' === $elementPosition ? Math.ceil( instanceOffset.left - elementOffset.left ) : 0; 448 449 $element.css( { 450 '--jmm-submenu-width': `${ instanceWidth }px`, 451 '--jmm-submenu-delta-x-offset': `${ elementDeltaOffset }px` 452 } ); 453 } ); 454 455 break; 456 case 'selector': 457 let $customSelector = $( this.settings.megaWidthSelector ); 458 459 if ( $customSelector[0] ) { 460 let selectorWidth = $customSelector.width(), 461 selectorOffset = Math.round( $customSelector.offset().left ); 462 463 document.fonts.ready.then( () => { 464 $megaMenuList.each( ( index, element ) => { 465 let $element = $( element ), 466 $elementPosition = $element.data( 'position' ), 467 elementOffset = Math.round( $element.offset().left ), 468 elementDeltaOffset = 'default' === $elementPosition ? Math.round( selectorOffset - elementOffset ) : 0; 469 470 $element.css( { 471 '--jmm-submenu-width': `${ selectorWidth }px`, 472 '--jmm-submenu-delta-x-offset': `${ elementDeltaOffset }px` 473 } ); 474 } ); 475 } ); 476 477 } 478 479 break; 480 case 'items': 481 let $lastItem = $( `.${ this.settings.classes.menuItem }--top-level:not([hidden]):last`, this.$instance ), 482 $firstItem = $( `.${ this.settings.classes.menuItem }--top-level:not([hidden]):first`, this.$instance ), 483 lastItemBounding = $lastItem[0].getBoundingClientRect(), 484 firstItemBounding = $firstItem[0].getBoundingClientRect(), 485 itemsWidth = lastItemBounding.x + lastItemBounding.width - firstItemBounding.x; 486 487 $megaMenuList.each( ( index, element ) => { 488 let $element = $( element ), 489 $elementPosition = $element.data( 'position' ), 490 elementOffset = $element.offset(), 491 elementDeltaOffset = 'default' === $elementPosition ? Math.ceil( instanceOffset.left - elementOffset.left ) : 0; 492 493 $element.css( { 494 '--jmm-submenu-width': `${ itemsWidth }px`, 495 '--jmm-submenu-delta-x-offset': `${ elementDeltaOffset }px` 496 } ); 497 } ); 498 break; 499 } 500 } ); 501 502 this.$instance.on( 'watchTickEventRegular--vertical', ( event ) => { 503 let $megaMenuList = $( `.${ this.settings.classes.megaContainer }`, this.$instance ), 504 $subMenuList = $( `.${ this.settings.classes.subMenuContainer }`, this.$instance ), 505 instanceWidth = this.$instance.width(), 506 instanceHeight = this.$instance.height(), 507 instanceOffset = this.$instance.offset(), 508 windowWidth = this.$window.outerWidth( true ), 509 subInverseClass = `${ this.settings.classes.subMenuContainer }--inverse`, 510 megaInverseClass = `${ this.settings.classes.megaContainer }--inverse`; 511 512 $subMenuList.each( ( index, element ) => { 513 let $element = $( element ); 514 515 if ( this.isOffscreenX( element ) ) { 516 $element.addClass( subInverseClass ); 517 } else { 518 $element.removeClass( subInverseClass ); 519 } 520 } ); 521 522 $megaMenuList.each( ( index, element ) => { 523 let $element = $( element ), 524 $elementPosition = $element.data( 'position' ), 525 $parentElement = $element.parent(), 526 elementOffset = $element.offset(), 527 elementDeltaOffsetX = ( instanceOffset.left - elementOffset.left ) + instanceWidth, 528 elementDeltaOffsetY = 'default' === $elementPosition ? ( instanceOffset.top - elementOffset.top ) : 0, 529 elementDeltaWidth = ( elementDeltaOffsetX + $element.width() ); 530 531 if ( $parentElement.hasClass(`${ this.settings.classes.menuItem }--top-level` ) ) { 532 $element.css( { 533 //'--jmm-submenu-width': `${ instanceWidth }px`, 534 '--jmm-submenu-min-height': `${ instanceHeight }px`, 535 //'--jmm-submenu-delta-x-offset': `${ elementDeltaOffsetX }px`, 536 '--jmm-submenu-delta-y-offset': `${ elementDeltaOffsetY }px` 537 } ); 538 } 539 540 if ( this.isOffscreenX( element ) ) { 541 $element.addClass( megaInverseClass ); 542 } else { 543 $element.removeClass( megaInverseClass ); 544 } 545 } ); 546 } ); 547 } 548 549 /** 550 * Reset Regular State 551 * 552 * @return {void} 553 */ 554 resetRegularState() {} 555 556 /** 557 * Reset Dropdown State 558 * 559 * @return {void} 560 */ 561 resetDropdownState() {} 562 563 /** 564 * Get mobile status. 565 * 566 * @return {boolean} Mobile Status 567 */ 568 isDropdown() { 569 return ( this.$window.width() < this.settings.breakpoint || 'dropdown' === this.settings.layout ) ? true : false;
570 } 571 572 /** 573 * 574 * @param element 575 * @returns {boolean} 576 */ 577 isOffscreenX( element ) { 578 let rect = element.getBoundingClientRect(); 579 580 return ( 581 rect.x < 0 || ( rect.x + rect.width ) > window.innerWidth 582 ); 583 } 584 585 /** 586 * Mobile and tablet check funcion. 587 * 588 * @return {boolean} Mobile Status 589 */ 590 mobileAndTabletcheck() { 591 let check = false; 592 593 (function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera); 594 595 return check; 596 } 597 598 /** 599 * Debounce the function call 600 * 601 * @param {number} threshold The delay. 602 * @param {Function} callback The function. 603 */ 604 debounce( threshold, callback ) { 605 let timeout; 606 607 return function debounced( $event ) { 608 function delayed() { 609 callback.call( this, $event ); 610 timeout = null; 611 } 612 613 if ( timeout ) { 614 clearTimeout( timeout ); 615 } 616 617 timeout = setTimeout( delayed, threshold ); 618 }; 619 } 620 621 maybeTemplateLoad( templateId, templateContent, $templateContainer ) { 622 623 if ( ! this.settings.megaAjaxLoad ) { 624 return; 625 } 626 627 if ( $templateContainer.hasClass( 'template-loaded' ) ) { 628 return; 629 } 630 631 let getMegaContentUrl = 'default' === templateContent ? window.jetMenuPublicSettings.getBlocksTemplateApiUrl : window.jetMenuPublicSettings.getElementorTemplateApiUrl; 632 633 let signatures = this.settings['signatures']; 634 let signature = ''; 635 636 if ( signatures.hasOwnProperty(`template_${templateId}`) ) { 637 signature = signatures[`template_${templateId}`].signature; 638 } 639 640 this.isContentLoading = true; 641 642 const self = this; 643 644 $.ajax( { 645 type: 'GET', 646 url: getMegaContentUrl, 647 dataType: 'json', 648 data: { 649 'id': templateId, 650 'dev': window.jetMenuPublicSettings.devMode, 651 'signature': signature 652 }, 653 beforeSend: function( jqXHR, ajaxSettings ) { 654 jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce ); 655 }, 656 success: function( responce, textStatus, jqXHR ) { 657 const {content, contentElements} = responce; 658 const templateData = { 659 content, 660 contentElements, 661 contentType: templateContent, 662 } 663 664 $templateContainer.addClass( 'template-loaded' ); 665 666 jetMenu.megaContentRender( $( '.jet-mega-menu-mega-container__inner', $templateContainer ), templateData ); 667 }, 668 complete: function() { 669 self.isContentLoading = false;
670 671 if ( self._pendingMouseleave ) { 672 self._pendingMouseleave = false; 673 self.$instance.triggerHandler( 'mouseleave' ); 674 } 675 676 } 677 } ); 678 } 679 680 getNum( val ) { 681 val = parseFloat( val ); 682 return isNaN( val ) ? 0 : val; 683 } 684 685 applySmartScroll( $menuItem ) { 686 if ( this.settings.layout !== 'horizontal' || this.isDropdown() ) return; 687 688 const $subContainer = $menuItem.children( 689 `.${ this.settings.classes.subMenuContainer }, .${ this.settings.classes.megaContainer }` 690 ); 691 692 if ( ! $subContainer[0] ) return; 693 694 let $targetContainer = $subContainer.children( `.${ this.settings.classes.subMenuList }:first` ); 695 696 if ( ! $targetContainer[0] ) { 697 $targetContainer = $subContainer.children( `.${ this.settings.classes.megaContainer }__inner:first` ); 698 } 699 700 const element = $targetContainer[0] || $subContainer[0]; 701 702 $subContainer.add( $targetContainer ).css( { 703 'max-height' : '', 704 'overflow-y' : '', 705 'overflow-x' : '' 706 } ); 707 708 const elementRect = element.getBoundingClientRect(); 709 710 const elementMarginTop = this.getNum( getComputedStyle( element ).marginTop ); 711 712 const adminBarHeight = document.body.classList.contains( 'admin-bar' ) 713 ? ( window.innerWidth < 783 ? 46 : 32 ) 714 : 0; 715 716 const htmlMarginTop = parseFloat( getComputedStyle( document.documentElement ).marginTop ) || 0; 717 const bodyMarginTop = parseFloat( getComputedStyle( document.body ).marginTop ) || 0; 718 719 const adminBarCompensation = ( htmlMarginTop >= adminBarHeight - 1 || bodyMarginTop >= adminBarHeight - 1 ) 720 ? 0 721 : adminBarHeight; 722 723 const bottomGap = this.settings.bottomGap ?? 12; 724 725 const availableHeight = Math.max( 726 0, 727 window.innerHeight - elementRect.top - ( elementMarginTop + adminBarCompensation + bottomGap ) 728 ); 729 730 if ( element.scrollHeight > availableHeight ) { 731 $targetContainer.css( { 732 'max-height' : availableHeight + 'px', 733 'overflow-y' : 'auto', 734 'overflow-x' : 'hidden', 735 '-webkit-overflow-scrolling' : 'touch', 736 'overscroll-behavior' : 'contain', 737 } ); 738 } 739 } 740 741 } 742 743 // jQuery plugin 744 $.fn.JetMegaMenu = function( options ) { 745 return this.each( function() { 746 let $this = $( this ), 747 pluginOptions = ( 'object' === typeof options ) ? options : {}; 748 749 if ( ! $this.data( 'JetMegaMenu' ) ) { 750 // create plugin instance (only if not exists) and expose the entire instance API 751 $this.data( 'JetMegaMenu', new JetMegaMenuClass( this, pluginOptions ) ); 752 } 753 } ); 754 }; 755} ( jQuery )); 756 757// JetMenu Public Scripts 758( function( $ ) { 759 'use strict'; 760 761 window.jetMenu = { 762 763 addedScripts: {}, 764 765 addedStyles: {}, 766 767 addedAssetsPromises: [], 768 769 initedMobileRenderInstance: [], 770 771 eventBus: new Vue(), 772 773 $body: $( 'body' ), 774 775 init: function() { 776 this.initLocationMenuRender(); 777 this.mobileVueComponents(); 778 this.initMobileRender(); 779 780 window.addEventListener( 'jetMenu/editor/templateRenderer/renderSuccess', ( event ) => { 781 this.initLocationMenuRender(); 782 this.mobileVueComponents(); 783 this.initMobileRender(); 784 }, false ); 785 786 $( window ).on( 'jet-menu/ajax/frontend-init', ( event, payload ) => { 787 788 switch ( payload.contentType ) { 789 case 'elementor': 790 jetMenu.maybeElementorFrontendInit( payload.$container ); 791 break; 792 case 'default': 793 jetMenu.maybeDefaultFrontendInit( payload ); 794 break 795 } 796 } ); 797 798 $( window ).on( 'jet-menu/ajax/frontend-init/after', ( event, payload ) => { 799 this.initLocationMenuRender(); 800 this.mobileVueComponents(); 801 this.initMobileRender(); 802 this.megaContentHandler(event, payload); 803 804 if ( window.elementorFrontend ) { 805 const elementorLazyLoad = new CustomEvent( "elementor/lazyload/observe" ); 806 document.dispatchEvent( elementorLazyLoad ); 807 } 808 } ); 809 810 wp.hooks.addAction( 'jet-plugins.frontend.element-ready.jet-menu.mega-menu', 'jet-popup', ( $popupContainer, contentType ) => { 811 this.initLocationMenuRender(); 812 this.mobileVueComponents(); 813 this.initMobileRender(); 814 } ); 815 816 // Init Vue for hamburger menu block in Gutenberg ( also on DOM change ) 817 if ( document.body.classList.contains( 'block-editor-page' ) ) { 818 const tryObserve = () => { 819 const target = document.querySelector( '.block-editor-block-list__layout' ); 820 821 if ( target ) { 822 const initedMenus = new Set(); 823 824 const observer = new MutationObserver( () => { 825 const menus = document.querySelectorAll( '.jet-mobile-menu--location-wp-nav' ); 826
827 menus.forEach( (menu) => { 828 const menuId = menu.getAttribute( 'id' ); 829 830 if ( menuId && ! initedMenus.has( menuId ) ) { 831 jetMenu.initMobileRender(); 832 initedMenus.add( menuId ); 833 } 834 835 }); 836 }); 837 838 observer.observe( target, { childList: true, subtree: true } ); 839 } else { 840 requestAnimationFrame( tryObserve ); 841 } 842 }; 843 844 requestAnimationFrame( tryObserve ); 845 } 846 847 }, 848 849 initLocationMenuRender: function() { 850 851 let $megaMenuList = $( '.jet-mega-menu--location-wp-nav' ); 852 853 if ( ! $megaMenuList[0] ) { 854 return false; 855 } 856 857 $megaMenuList.each( function() { 858 let $this = $( this ), 859 settings = $this.data( 'settings' ); 860 861 $this.JetMegaMenu( { 862 rollUp: settings.rollUp, 863 layout: settings.layout, 864 subTrigger: settings.subTrigger, 865 subEvent: settings.subEvent, 866 subCloseBehavior: settings.subCloseBehavior, 867 mouseLeaveDelay: settings.mouseLeaveDelay, 868 breakpoint: settings.breakpoint, 869 megaWidthType: settings.megaWidthType, 870 megaWidthSelector: settings.megaWidthSelector, 871 megaAjaxLoad: settings.megaAjaxLoad, 872 classes: { 873 instance: 'jet-mega-menu', 874 menuContainer: 'jet-mega-menu-container', 875 menuList: 'jet-mega-menu-list', 876 menuItem: 'jet-mega-menu-item', 877 menuItemLink: 'jet-mega-menu-item__link', 878 subMenuContainer: 'jet-mega-menu-sub-menu', 879 subMenuList: 'jet-mega-menu-sub-menu__list', 880 megaContainer: 'jet-mega-menu-mega-container', 881 } 882 } ); 883 } ); 884 }, 885 886 megaContentHandler: function(event, payload) { 887 const container = payload.$container[0]; 888 const mobileMenu = container.closest('.jet-mobile-menu'); 889 890 if ( ! mobileMenu ) { 891 return; 892 } 893 894 const { menuOptions } = mobileMenu.dataset; 895 const { menuUniqId } = JSON.parse( menuOptions ); 896 897 container.addEventListener('click', function (event) { 898 const link = event.target.closest('a'); 899 900 if (!link) { 901 return; 902 } 903 904 if (link.getAttribute('href')[0] !== '#') { 905 return; 906 } 907 908 window.jetMenu.eventBus.$emit('closeMenu', { 909 menuUniqId: menuUniqId, 910 }); 911 }); 912 }, 913 914 initMobileRender: function() { 915 916 let mobileMenuList = $( '.jet-mobile-menu--location-wp-nav' ); 917 918 if ( ! mobileMenuList[0] ) { 919 return false; 920 } 921 922 if ( 'true' === window.jetMenuPublicSettings.devMode ) { 923 Vue.config.devtools = true; 924 } 925 926 mobileMenuList.each( function() { 927 let $this = $( this ), 928 menuInstanceId = $this.attr( 'id' ), 929 menuId = $this.data( 'menu-id' ) || false, 930 menuOptions = $this.data( 'menu-options' ) || {}; 931 932 jetMenu.createMobileRenderInstance( menuInstanceId, menuId, menuOptions ); 933 } ); 934 }, 935 936 createMobileRenderInstance: function( menuInstanceId, menuId, menuOptions ) { 937 938 if ( jetMenu.initedMobileRenderInstance.includes( menuInstanceId ) ) { 939 return; 940 } 941 942 jetMenu.initedMobileRenderInstance.push( menuInstanceId ); 943 944 let mobileRenderInstance = new Vue( { 945 el: '#' + menuInstanceId, 946 data: { 947 uniqId: menuInstanceId, 948 menuOptions: menuOptions, 949 refsHtml: {}, 950 }, 951 mounted: function() { 952 let refsHtml = {}; 953 954 for ( var ref in this.$refs ) { 955 Object.assign( refsHtml, { [ ref ]: this.$refs[ ref ].innerHTML } ); 956 } 957 958 this.refsHtml = refsHtml; 959 } 960 } ); 961 }, 962 963 mobileVueComponents: function() { 964 965 Vue.component( 'mobile-menu-item', { 966 template: '#mobile-menu-item-template', 967 968 props: { 969 itemDataObject: Object, 970 depth: Number 971 }, 972 973 data: function() { 974 return ( { 975 ajaxRequest: null, 976 templateLoadStatus: false, 977 subDropdownVisible: false 978 } ) 979 }, 980 981 computed: { 982 983 itemClasses: function() { 984 let itemClasses = [ 985 'jet-mobile-menu__item', 986 'jet-menu-item-' + this.itemDataObject.itemId, 987 'jet-mobile-menu__item--sub-trigger-' + ( this.$root.menuOptions.subTrigger || 'item' ), 988 ]; 989 990 let customClasses = this.itemDataObject.classes; 991 992 if ( 0 !== customClasses.length ) { 993 itemClasses = itemClasses.concat( customClasses ); 994 } 995 996 const { href } = window.location; 997 let pageURL = null; 998 999 if ( href.includes('?') ) { 1000 pageURL = href.substring(0, href.indexOf('?')); 1001 } else { 1002 pageURL = href; 1003 } 1004 1005 if ( pageURL === this.itemDataObject.url ) { 1006 itemClasses.push( 'jet-mobile-menu__item--active' ); 1007 } 1008 1009 return itemClasses; 1010 }, 1011 1012 itemLinkClasses: function() {
1013 let classes = [ 1014 'mobile-link', 1015 0 === this.depth ? 'mobile-top-level-link' : 'mobile-sub-level-link', 1016 ]; 1017 1018 return classes; 1019 }, 1020 1021 isСhildrenDefine: function() { 1022 return this.itemDataObject.children ? true : false; 1023 }, 1024 1025 isTemplateDefine: function() { 1026 return false !== this.itemDataObject.megaTemplateId ? true : false; 1027 }, 1028 1029 megaContentType: function() { 1030 return this.itemDataObject.megaContentType; 1031 }, 1032 1033 isAjaxLoadingEnabled: function() { 1034 return this.$root.menuOptions.megaAjaxLoad === true; 1035 }, 1036 1037 getTemplateUrl: function() { 1038 return 'default' === this.megaContentType ? window.jetMenuPublicSettings.getBlocksTemplateApiUrl : window.jetMenuPublicSettings.getElementorTemplateApiUrl; 1039 }, 1040 1041 isSub: function() { 1042 return this.isСhildrenDefine || this.isTemplateDefine ? true : false; 1043 }, 1044 1045 isTopLevel: function() { 1046 return 0 === this.depth ? true : false; 1047 }, 1048 1049 isDropdownLayout: function() { 1050 return this.isSub && ! this.isTemplateDefine && 'dropdown' === this.$root.menuOptions.subOpenLayout; 1051 }, 1052 1053 depthClass: function() { 1054 return 0 === this.depth ? 'mobile-top-level-link' : 'mobile-sub-level-link'; 1055 }, 1056 1057 dropdownIconHtml: function() { 1058 let dropdownIcon = this.$root.refsHtml.dropdownIcon ? this.$root.refsHtml.dropdownIcon : '<span class="dashicons dashicons-arrow-right"></span>', 1059 dropdownOpenedIcon = this.$root.refsHtml.dropdownOpenedIcon ? this.$root.refsHtml.dropdownOpenedIcon : '<span class="dashicons dashicons-arrow-down"></span>'; 1060 1061 if ( this.subDropdownVisible ) { 1062 dropdownIcon = dropdownOpenedIcon; 1063 } 1064 1065 return dropdownIcon; 1066 }, 1067 1068 itemIconHtml: function() { 1069 return this.itemDataObject.itemIcon; 1070 }, 1071 1072 isIconVisible: function() { 1073 let iconVisible = this.$root.menuOptions.itemIconVisible; 1074 1075 return ! iconVisible || '' === this.itemDataObject.itemIcon || ! this.itemDataObject.itemIcon ? false : true; 1076 }, 1077 1078 isBadgeVisible: function() { 1079 let badgeVisible = this.$root.menuOptions.itemBadgeVisible; 1080 1081 return false === badgeVisible || '' === this.itemDataObject.badgeContent || ! this.itemDataObject.badgeContent ? false : true; 1082 }, 1083 1084 isLabelVisible: function() { 1085 let labelVisible = ! this.itemDataObject.hideItemText; 1086 1087 return false === labelVisible || '' === this.itemDataObject.name || ! this.itemDataObject.name ? false : true; 1088 }, 1089 1090 isDescVisible: function() { 1091 let descVisible = this.$root.menuOptions.itemDescVisible; 1092 1093 return false === descVisible || '' === this.itemDataObject.description || ! this.itemDataObject.description ? false : true; 1094 }, 1095 1096 loaderColor: function() { 1097 return this.$root.menuOptions.loaderColor || '#3a3a3a'; 1098 }, 1099 }, 1100 1101 methods: { 1102 itemSubHandler: function( event ) { 1103 let target = event.target, 1104 mobileLink = $( target ).closest( '.mobile-link' ); 1105 1106 if ( 'item' !== this.$root.menuOptions.subTrigger ) { 1107 return; 1108 } 1109 1110 if ( this.isSub && mobileLink ) { 1111 event.preventDefault(); 1112 } 1113 1114 if ( ! this.isSub && mobileLink && this.$root.menuOptions.closeAfterNavigate ) { 1115 jetMenu.eventBus.$emit( 'closeMenu', { 1116 menuUniqId: this.$root.menuOptions.menuUniqId, 1117 } ); 1118 } 1119 1120 this.switchToSub( event ); 1121 }, 1122 1123 markerSubHandler: function( event ) { 1124 1125 if ( 'submarker' !== this.$root.menuOptions.subTrigger ) { 1126 return; 1127 } 1128 1129 this.switchToSub( event ); 1130 }, 1131 1132 switchToSub: function( event ) { 1133 1134 if ( ! this.isSub ) { 1135 return; 1136 } 1137 1138 if ( ! this.isTemplateDefine ) { 1139 1140 if ( this.isDropdownLayout ) { 1141 this.subDropdownVisible = !this.subDropdownVisible; 1142 1143 return; 1144 } 1145 1146 jetMenu.eventBus.$emit( 'itemsSubSwitch', { 1147 menuUniqId: this.$root.menuOptions.menuUniqId, 1148 id: this.itemDataObject.id, 1149 name: this.itemDataObject.name, 1150 children: this.itemDataObject.children || false 1151 } ); 1152 } else { 1153 if ( this.isAjaxLoadingEnabled && ! this.itemDataObject.megaContentLoaded ) { 1154 this.getMegaTemplate(); 1155 } else { 1156 jetMenu.eventBus.$emit( 'showTemplateContent', {
1157 menuUniqId: this.$root.menuOptions.menuUniqId, 1158 id: this.itemDataObject.id, 1159 name: this.itemDataObject.name, 1160 megaContent: this.itemDataObject.megaContent, 1161 megaContentType: this.itemDataObject.megaContentType, 1162 } ); 1163 } 1164 } 1165 }, 1166 1167 getMegaTemplate: function() { 1168 var vueInstance = this; 1169 1170 if ( ! this.isAjaxLoadingEnabled ) { 1171 return; 1172 } 1173 1174 var signature = vueInstance.itemDataObject.signature || ''; 1175 1176 vueInstance.ajaxRequest = $.ajax( { 1177 type: 'GET', 1178 url: vueInstance.getTemplateUrl, 1179 dataType: 'json', 1180 data: { 1181 'id': vueInstance.itemDataObject.megaTemplateId, 1182 'dev': window.jetMenuPublicSettings.devMode, 1183 'signature': signature 1184 }, 1185 beforeSend: function( jqXHR, ajaxSettings ) { 1186 1187 if ( null !== vueInstance.ajaxRequest ) { 1188 vueInstance.ajaxRequest.abort(); 1189 } 1190 1191 vueInstance.templateLoadStatus = true; 1192 1193 jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce ); 1194 }, 1195 success: function( responce, textStatus, jqXHR ) { 1196 let templateContent = responce['content'], 1197 contentElements = responce['contentElements']; 1198 1199 vueInstance.templateLoadStatus = false; 1200 vueInstance.itemDataObject.megaContent = templateContent; 1201 vueInstance.itemDataObject.megaContentLoaded = true; 1202 1203 jetMenu.eventBus.$emit( 'showTemplateContent', { 1204 menuUniqId: vueInstance.$root.menuOptions.menuUniqId, 1205 id: vueInstance.itemDataObject.id, 1206 name: vueInstance.itemDataObject.name, 1207 megaContent: vueInstance.itemDataObject.megaContent, 1208 megaContentType: vueInstance.itemDataObject.megaContentType, 1209 } ); 1210 } 1211 } ); 1212 } 1213 } 1214 1215 }); 1216 1217 Vue.component( 'mobile-menu-list', { 1218 template: '#mobile-menu-list-template', 1219 props: { 1220 depth: Number, 1221 childrenObject: Object 1222 } 1223 } ); 1224 1225 Vue.component( 'mobile-menu', { 1226 template: '#mobile-menu-template', 1227 1228 data: function() { 1229 return ( { 1230 menuOpen: false, 1231 children: false, 1232 itemsRawData: {}, 1233 trail:[], 1234 breadcrumbsData: [], 1235 animation: 'items-next-animation', 1236 ajaxRequest: null, 1237 templateVisible: false, 1238 instanceLoadStatus: false, 1239 itemTemplateContent: false, 1240 headerTemplate: this.$root.menuOptions['headerTemplate'] || 0, 1241 headerContent: false, 1242 beforeTemplate: this.$root.menuOptions['beforeTemplate'] || 0, 1243 beforeContent: false, 1244 afterTemplate: this.$root.menuOptions['afterTemplate'] || 0, 1245 afterContent: false, 1246 ajaxPromises: [], 1247 } ) 1248 }, 1249 1250 mounted: function() { 1251 const vueInstance = this; 1252 1253 if ( this.menuOpen ) { 1254 jetMenu.$body.addClass( 'jet-mobile-menu-visible' ); 1255 1256 if ( 'slide-out' === this.$root.menuOptions.menuLayout ) { 1257 jetMenu.$body.addClass( 'jet-menu-body-blocker' ); 1258 } 1259 } 1260 1261 let menuInstanceRenderData = false, 1262 renderDataElement = document.getElementById( 'jetMenuMobileWidgetRenderData' + this.$root.menuOptions.menuUniqId ); 1263 1264 try { 1265 menuInstanceRenderData = JSON.parse( renderDataElement.textContent ); 1266 } catch ( error ) { 1267 menuInstanceRenderData = false; 1268 } 1269 1270 if ( menuInstanceRenderData ) { 1271 this.itemsRawData = menuInstanceRenderData['items']; 1272 1273 const headerTemplateData = menuInstanceRenderData.headerTemplateData || false, 1274 beforeTemplateData = menuInstanceRenderData.beforeTemplateData || false, 1275 afterTemplateData = menuInstanceRenderData.afterTemplateData || false; 1276 1277 if ( headerTemplateData ) { 1278 this.headerContent = headerTemplateData.content; 1279 } 1280 1281 if ( beforeTemplateData ) { 1282 this.beforeContent = beforeTemplateData.content; 1283 } 1284 1285 if ( afterTemplateData ) { 1286 this.afterContent = afterTemplateData.content; 1287 } 1288 } else { 1289 this.ajaxPromises.push( 1290 new Promise( function( resolve, reject ) { 1291 1292 $.ajax( { 1293 type: 'GET', 1294 url: window.jetMenuPublicSettings.menuItemsApiUrl, 1295 dataType: 'json', 1296 data: { 1297 'menu_id': vueInstance.menuId, 1298 'dev': window.jetMenuPublicSettings.devMode, 1299 'lang': window.jetMenuPublicSettings.wpmlLanguageCode || false 1300 }, 1301 beforeSend: function( jqXHR, ajaxSettings ) { 1302 jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce ); 1303 }, 1304 success: function( responce, textStatus, jqXHR ) { 1305 let responceData = responce.data.items; 1306 1307 vueInstance.itemsRawData = responceData; 1308 1309 resolve(); 1310 } 1311 } ); 1312 } ) 1313 ); 1314 1315 if ( 0 !== +this.headerTemplate ) { 1316 this.ajaxPromises.push( 1317 new Promise( function( resolve, reject ) { 1318 $.ajax( { 1319 type: 'GET', 1320 url: window.jetMenuPublicSettings.getElementorTemplateApiUrl, 1321 dataType: 'json', 1322 data: { 1323 'id': vueInstance.headerTemplate, 1324 'dev': window.jetMenuPublicSettings.devMode, 1325 'nocache': new Date().getTime(), 1326 }, 1327 beforeSend: function( jqXHR, ajaxSettings ) { 1328 jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce ); 1329 }, 1330 success: function( responce, textStatus, jqXHR ) { 1331 let templateContent = responce['content'], 1332 templateScripts = responce['scripts'], 1333 templateStyles = responce['styles']; 1334 1335 for ( let scriptHandler in templateScripts ) { 1336 jetMenu.addedAssetsPromises.push( jetMenu.loadScriptAsync( scriptHandler, templateScripts[ scriptHandler ] ) ); 1337 } 1338 1339 for ( let styleHandler in templateStyles ) { 1340 jetMenu.addedAssetsPromises.push( jetMenu.loadStyle( styleHandler, templateStyles[ styleHandler ] ) ); 1341 } 1342 1343 vueInstance.headerContent = templateContent; 1344 1345 resolve(); 1346 } 1347 } ); 1348 } ) 1349 ); 1350 } 1351 1352 if ( 0 !== +this.beforeTemplate ) { 1353 this.ajaxPromises.push( 1354 new Promise( function( resolve, reject ) { 1355 $.ajax( { 1356 type: 'GET', 1357 url: window.jetMenuPublicSettings.getElementorTemplateApiUrl, 1358 dataType: 'json', 1359 data: { 1360 'id': vueInstance.beforeTemplate, 1361 'dev': window.jetMenuPublicSettings.devMode, 1362 'nocache': new Date().getTime(), 1363 }, 1364 beforeSend: function( jqXHR, ajaxSettings ) { 1365 jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce ); 1366 }, 1367 success: function( responce, textStatus, jqXHR ) { 1368 let templateContent = responce['content'], 1369 templateScripts = responce['scripts'], 1370 templateStyles = responce['styles']; 1371 1372 for ( let scriptHandler in templateScripts ) { 1373 jetMenu.addedAssetsPromises.push( jetMenu.loadScriptAsync( scriptHandler, templateScripts[ scriptHandler ] ) ); 1374 } 1375 1376 for ( let styleHandler in templateStyles ) { 1377 jetMenu.addedAssetsPromises.push( jetMenu.loadStyle( styleHandler, templateStyles[ styleHandler ] ) ); 1378 } 1379 1380 vueInstance.beforeContent = templateContent; 1381 1382 resolve(); 1383 } 1384 } ); 1385 } ) 1386 ); 1387 } 1388 1389 if ( 0 !== +this.afterTemplate ) { 1390 this.ajaxPromises.push( 1391 new Promise( function( resolve, reject ) { 1392 $.ajax( { 1393 type: 'GET', 1394 url: window.jetMenuPublicSettings.getElementorTemplateApiUrl, 1395 dataType: 'json', 1396 data: { 1397 'id': vueInstance.afterTemplate, 1398 'dev': window.jetMenuPublicSettings.devMode, 1399 'nocache': new Date().getTime(), 1400 }, 1401 beforeSend: function( jqXHR, ajaxSettings ) { 1402 jqXHR.setRequestHeader( 'X-WP-Nonce', window.jetMenuPublicSettings.restNonce ); 1403 }, 1404 success: function( responce, textStatus, jqXHR ) { 1405 let templateContent = responce['content'], 1406 templateScripts = responce['scripts'], 1407 templateStyles = responce['styles']; 1408 1409 for ( let scriptHandler in templateScripts ) { 1410 jetMenu.addedAssetsPromises.push( jetMenu.loadScriptAsync( scriptHandler, templateScripts[ scriptHandler ] ) ); 1411 } 1412 1413 for ( let styleHandler in templateStyles ) { 1414 jetMenu.addedAssetsPromises.push( jetMenu.loadStyle( styleHandler, templateStyles[ styleHandler ] ) ); 1415 } 1416 1417 vueInstance.afterContent = templateContent; 1418 resolve(); 1419 } 1420 } ); 1421 } ) 1422 ); 1423 } 1424 } 1425 1426 1427 1428 this.instanceLoadStatus = true; 1429 1430 Promise.all( this.ajaxPromises ).then( function() { 1431 vueInstance.instanceLoadStatus = false;
1432 //vueInstance.initTemplatesContent(); 1433 }, function( reason ) { 1434 console.log( 'Script Loaded Error' ); 1435 } ); 1436 1437 jetMenu.eventBus.$on( 'itemsSubSwitch', function ( payLoad ) { 1438 1439 if ( vueInstance.$root.menuOptions.menuUniqId !== payLoad.menuUniqId ) { 1440 return; 1441 } 1442 1443 vueInstance.trail.push( payLoad.children ); 1444 vueInstance.children = payLoad.children; 1445 vueInstance.animation = 'items-next-animation'; 1446 vueInstance.breadcrumbsData.push( payLoad.name ); 1447 } ); 1448 1449 jetMenu.eventBus.$on( 'showTemplateContent', function ( payLoad ) { 1450 1451 if ( vueInstance.$root.menuOptions.menuUniqId !== payLoad.menuUniqId ) { 1452 return; 1453 } 1454 1455 vueInstance.itemTemplateContent = payLoad.megaContent.content; 1456 vueInstance.templateVisible = true; 1457 vueInstance.breadcrumbsData.push( payLoad.name ); 1458 vueInstance.animation = 'items-next-animation'; 1459 1460 const templateData = { 1461 content: payLoad.megaContent.content !== undefined 1462 ? payLoad.megaContent.content 1463 : payLoad.megaContent, 1464 contentElements: payLoad.megaContent.contentElements, 1465 contentType: payLoad.megaContentType, 1466 } 1467 1468 vueInstance.showTemplateContent( templateData ); 1469 } ); 1470 1471 jetMenu.eventBus.$on( 'closeMenu', function( payLoad ) { 1472 1473 if ( vueInstance.$root.menuOptions.menuUniqId !== payLoad.menuUniqId ) { 1474 return; 1475 } 1476 1477 vueInstance.closeMenu(); 1478 } ); 1479 1480 }, 1481 1482 watch: { 1483 menuOpen: function( curr, prev ) { 1484 1485 if ( curr ) { 1486 jetMenu.$body.addClass( 'jet-mobile-menu-visible' ); 1487 1488 if ( 'slide-out' === this.$root.menuOptions.menuLayout ) { 1489 jetMenu.$body.addClass( 'jet-menu-body-blocker' ); 1490 } 1491 1492 this.initTemplatesContent(); 1493 } 1494 1495 if ( ! curr ) { 1496 jetMenu.$body.removeClass( 'jet-mobile-menu-visible' ); 1497 1498 if ( 'slide-out' === this.$root.menuOptions.menuLayout ) { 1499 jetMenu.$body.removeClass( 'jet-menu-body-blocker' ); 1500 } 1501 1502 this.clearStates(); 1503 } 1504 } 1505 }, 1506 1507 computed: { 1508 instanceClass: function() { 1509 1510 let classes = [ 1511 'jet-mobile-menu__instance', 1512 'jet-mobile-menu__instance--' + this.$root.menuOptions.menuLayout + '-layout', 1513 this.$root.menuOptions.menuPosition + '-container-position', 1514 ( this.$root.menuOptions.togglePosition || 'default' ) + '-toggle-position', 1515 this.$root.menuOptions.fillSvgIcon ? 'fill-svg-icon' : '', 1516 ]; 1517 1518 return classes; 1519 }, 1520 1521 menuContainerVisible: function() { 1522 return this.menuOpen && !this.instanceLoadStatus; 1523 }, 1524 1525 menuId: function() { 1526 1527 if ( this.$root.menuOptions.mobileMenuId && window.jetMenuPublicSettings.isMobile === 'true' ) { 1528 return this.$root.menuOptions.mobileMenuId; 1529 } 1530 1531 return this.$root.menuOptions.menuId; 1532 }, 1533 1534 coverVisible: function() { 1535 1536 let avaliableForLayout = [ 1537 'slide-out' 1538 ]; 1539 1540 return avaliableForLayout.includes( this.$root.menuOptions.menuLayout ); 1541 }, 1542 1543 itemsList: function() { 1544 1545 if ( ! this.children ) { 1546 return this.itemsRawData; 1547 } 1548 1549 return this.children; 1550 }, 1551 1552 isClose: function() { 1553 let avaliableForLayout = [ 1554 'slide-out' 1555 ]; 1556 1557 return avaliableForLayout.includes( this.$root.menuOptions.menuLayout ); 1558 }, 1559 1560 isBack: function() { 1561 return this.children || this.templateVisible ? true : false; 1562 }, 1563 1564 isBreadcrumbs: function() { 1565 return this.$root.menuOptions.useBreadcrumb && 0 !== this.breadcrumbsData.length ? true : false; 1566 }, 1567 1568 breadcrumbsPathData: function() { 1569 1570 if ( 'minimal' === this.$root.$root.menuOptions.breadcrumbPath && 1 < this.breadcrumbsData.length ) { 1571 return this.breadcrumbsData.filter( ( item, index, breadcrumbsData ) => { 1572 return index === breadcrumbsData.length - 1; 1573 } ); 1574 } 1575 1576 return this.breadcrumbsData; 1577 }, 1578 1579 depth: function() { 1580 return this.trail.length; 1581 }, 1582 1583 containerPosition: function() { 1584 return this.$root.menuOptions.menuPosition; 1585 }, 1586 1587 showAnimation: function() { 1588 1589 let animation = false;
1590 1591 switch( this.$root.menuOptions.menuLayout ) { 1592 1593 case 'slide-out': 1594 animation = 'right' === this.containerPosition ? 'menu-container-left-animation' : 'menu-container-right-animation'; 1595 break; 1596 1597 case 'dropdown': 1598 animation = 'menu-container-dropdown-animation'; 1599 break; 1600 1601 case 'push': 1602 animation = 'menu-container-expand-animation'; 1603 break; 1604 } 1605 1606 return animation; 1607 }, 1608 1609 toggleClosedIcon: function() { 1610 return this.$root.refsHtml.toggleClosedIcon || ''; 1611 }, 1612 1613 toggleOpenedIcon: function() { 1614 return this.$root.refsHtml.toggleOpenedIcon || ''; 1615 }, 1616 1617 toggleText: function() { 1618 return '' !== this.$root.menuOptions.toggleText ? this.$root.menuOptions.toggleText : false; 1619 }, 1620 1621 closeIcon: function() { 1622 return this.$root.refsHtml.closeIcon || ''; 1623 }, 1624 1625 backIcon: function() { 1626 let backIcon = this.$root.refsHtml.backIcon || '', 1627 backText = '' !== this.$root.menuOptions.backText ? '<span>' + this.$root.menuOptions.backText + '</span>' : '', 1628 backHtml = backIcon + backText; 1629 1630 return backHtml; 1631 }, 1632 1633 backText: function() { 1634 return '' !== this.$root.menuOptions.backText ? this.$root.menuOptions.backText : false; 1635 }, 1636 1637 breadcrumbIcon: function() { 1638 return this.$root.refsHtml.breadcrumbIcon || ''; 1639 }, 1640 1641 loaderColor: function() { 1642 return this.$root.menuOptions.loaderColor || '#3a3a3a'; 1643 }, 1644 1645 toggleLoaderVisible: function() { 1646 return this.$root.menuOptions.toggleLoader && this.instanceLoadStatus && this.menuOpen ? true : false; 1647 }, 1648 1649 headerTemplateVisible: function() { 1650 return this.headerContent ? true : false; 1651 }, 1652 1653 beforeTemplateVisible: function() { 1654 return this.beforeContent ? true : false; 1655 }, 1656 1657 afterTemplateVisible: function() { 1658 return this.afterContent ? true : false; 1659 } 1660 1661 }, 1662 1663 methods: { 1664 menuToggle: function() { 1665 this.menuOpen = ! this.menuOpen; 1666 }, 1667 1668 closeMenu: function() { 1669 this.menuOpen = false; 1670 }, 1671 1672 clearStates: function() { 1673 this.trail = []; 1674 this.children = false; 1675 this.breadcrumbsData = []; 1676 this.templateVisible = false; 1677 }, 1678 1679 goBack: function() { 1680 1681 this.animation = 'items-prev-animation'; 1682 1683 if ( ! this.templateVisible ) { 1684 this.$delete( this.trail, this.trail.length - 1 ); 1685 this.children = this.trail.slice(-1)[0] || false; 1686 } else { 1687 this.templateVisible = false; 1688 } 1689 1690 this.$delete(this.breadcrumbsData, this.breadcrumbsData.length - 1); 1691 }, 1692 1693 escapeKeyHandler: function() { 1694 1695 if ( this.isBack ) { 1696 this.goBack(); 1697 } else { 1698 this.closeMenu(); 1699 } 1700 }, 1701 1702 showTemplateContent: function( templateData = {} ) { 1703 let vueInstance = this; 1704 1705 this.$nextTick( function() { 1706 let $templateContainer = $( vueInstance.$refs['template-content'] ).find( '.jet-mobile-menu__template-content' ); 1707 1708 jetMenu.megaContentRender( $templateContainer, templateData ); 1709 } ); 1710 }, 1711 1712 initTemplatesContent: function() { 1713 let vueInstance = this; 1714 1715 this.$nextTick( function() { 1716 1717 if ( vueInstance.headerContent ) { 1718 let $headerContainer = $( vueInstance.$refs['header-template-content'] ); 1719 1720 jetMenu.megaContentRender( $headerContainer, { contentType: 'elementor' } ); 1721 } 1722 1723 if ( vueInstance.beforeContent ) { 1724 let $beforeContainer = $( vueInstance.$refs['before-template-content'] ); 1725 1726 jetMenu.megaContentRender( $beforeContainer, { contentType: 'elementor' } ); 1727 } 1728 1729 if ( vueInstance.afterContent ) { 1730 let $afterContainer = $( vueInstance.$refs['after-template-content'] ); 1731 1732 jetMenu.megaContentRender( $afterContainer, { contentType: 'elementor' } ); 1733 } 1734 } ); 1735 }, 1736 1737 breadcrumbHandle: function( index ) { 1738 1739 if ( index === this.breadcrumbsData.length ) { 1740 return; 1741 } 1742 1743 if ( 'minimal' === this.$root.menuOptions.breadcrumbPath ) { 1744 this.goBack(); 1745 1746 return; 1747 } 1748 1749 this.animation = 'items-prev-animation'; 1750 this.trail = this.trail.slice( 0, index ); 1751 this.children = this.trail.slice( -1 )[0] || false; 1752 this.templateVisible = false;
1753 this.breadcrumbsData = this.breadcrumbsData.slice( 0, index ); 1754 } 1755 1756 } 1757 }); 1758 }, 1759 1760 loadScriptAsync: function( script, uri ) { 1761 1762 if ( jetMenu.addedScripts.hasOwnProperty( script ) ) { 1763 return script; 1764 } 1765 1766 jetMenu.addedScripts[ script ] = uri; 1767 1768 return new Promise( function( resolve, reject ) { 1769 var tag = document.createElement( 'script' ); 1770 1771 tag.src = uri; 1772 tag.async = true; 1773 tag.onload = function() { 1774 resolve( script ); 1775 }; 1776 1777 document.head.appendChild( tag ); 1778 } ); 1779 }, 1780 1781 loadStyle: function( style, uri ) { 1782 1783 if ( jetMenu.addedStyles.hasOwnProperty( style ) && jetMenu.addedStyles[ style ] === uri) { 1784 return style; 1785 } 1786 1787 jetMenu.addedStyles[ style ] = uri; 1788 1789 return new Promise( function( resolve, reject ) { 1790 var tag = document.createElement( 'link' ); 1791 1792 tag.id = style; 1793 tag.rel = 'stylesheet'; 1794 tag.href = uri; 1795 tag.type = 'text/css'; 1796 tag.media = 'all'; 1797 tag.onload = function() { 1798 resolve( style ); 1799 }; 1800 1801 document.head.appendChild( tag ); 1802 }); 1803 }, 1804 1805 megaContentRender: function( $templateContainer, templateData = {} ) { 1806 1807 if ( templateData.content ) { 1808 $templateContainer.html( templateData.content ); 1809 } 1810 1811 const data = { 1812 $container: $templateContainer, 1813 ...templateData 1814 } 1815 1816 Promise.all( jetMenu.addedAssetsPromises ).then( function( value ) { 1817 // Before ajax frontend init 1818 $( window ).trigger( 'jet-menu/ajax/frontend-init/before', data ); 1819 1820 // Frontend init 1821 $( window ).trigger( 'jet-menu/ajax/frontend-init', data ); 1822 1823 // after ajax frontend init 1824 $( window ).trigger( 'jet-menu/ajax/frontend-init/after', data ); 1825 }, function( reason ) { 1826 console.log( 'Script Loaded Error' ); 1827 }); 1828 }, 1829 1830 maybeElementorFrontendInit: function( $templateContainer ) { 1831 1832 $templateContainer.find( 'div[data-element_type]' ).each( function() { 1833 var $this = $( this ), 1834 elementType = $this.data( 'element_type' ); 1835 1836 if ( ! elementType ) { 1837 return; 1838 } 1839 1840 try { 1841 if ( 'widget' === elementType ) { 1842 elementType = $this.data( 'widget_type' ); 1843 1844 if ( window.elementorFrontend && window.elementorFrontend.hooks ) { 1845 window.elementorFrontend.hooks.doAction( 'frontend/element_ready/widget', $this, $ ); 1846 } 1847 } 1848 1849 if ( window.elementorFrontend && window.elementorFrontend.hooks ) { 1850 window.elementorFrontend.hooks.doAction( 'frontend/element_ready/global', $this, $ ); 1851 window.elementorFrontend.hooks.doAction( 'frontend/element_ready/' + elementType, $this, $ ); 1852 } 1853 1854 } catch ( err ) { 1855 console.log(err); 1856 $this.remove(); 1857 1858 return false; 1859 } 1860 } ); 1861 }, 1862 1863 maybeDefaultFrontendInit: function ( payload ) { 1864 const contentElements = payload.contentElements || [], 1865 $container = payload.$container; 1866 1867 $container.find( '[data-is-block*="/"]' ).each( ( index, el ) => { 1868 window.JetPlugins.hooks.doAction( window.JetPlugins.hookNameFromBlock( el.dataset.isBlock ), jQuery( el ) ); 1869 } ); 1870 }, 1871 1872 getUniqId: function() { 1873 return Math.random().toString( 36 ).substr( 2, 9 ); 1874 }, 1875 1876 }; 1877 1878 jetMenu.init(); 1879 1880} ( jQuery ) ); 1881
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.