1 2;/* eslint-disable no-undef */ 3(function($) { 4 5 /** 6 * Class for Menu Module 7 * 8 * @since 1.6.1 9 */ 10 FLBuilderMenu = function( settings ){ 11 12 // set params 13 this.nodeId = settings.id; 14 this.nodeClass = '.fl-node-' + settings.id; 15 this.wrapperClass = this.nodeClass + ' .fl-menu'; 16 this.type = settings.type; 17 this.mobileToggle = settings.mobile; 18 this.mobileBelowRow = settings.mobileBelowRow; 19 this.mobileFlyout = settings.mobileFlyout; 20 this.breakPoints = settings.breakPoints; 21 this.mobileBreakpoint = settings.mobileBreakpoint; 22 this.currentBrowserWidth = $( window ).width(); 23 this.postId = settings.postId; 24 this.mobileStacked = settings.mobileStacked; 25 this.submenuIcon = settings.submenuIcon; 26 this.flyoutWidth = settings.flyoutWidth; 27 28 // initialize the menu 29 this._initMenu(); 30 31 // check if viewport is resizing 32 $( window ).on( 'resize', $.proxy( function() { 33 34 var width = $( window ).width(); 35 36 // if screen width is resized, reload the menu 37 if( width != this.currentBrowserWidth ){ 38 39 this.currentBrowserWidth = width; 40 this._initMenu( true ); 41 this._clickOrHover( true ); 42 } 43 44 this._resizeFlyoutMenuPanel(); 45 }, this ) ); 46 47 $( window ).on( 'scroll', $.proxy( function() { 48 this._resizeFlyoutMenuPanel(); 49 }, this ) ); 50 51 // Move focus to the first menu item if the layout is set to BelowRow 52 $( this.wrapperClass ).on( 'keydown', '.fl-menu-mobile-toggle, .menu-item:first a:first', $.proxy( function ( event ) { 53 // Make sure it is a tab key with both the menu toggle enabled & below row layout set 54 if ( event.key !== 'Tab' || ! this._isMenuToggle() || ! this._isMobileBelowRowEnabled() ) { 55 return; 56 } 57 // Trigger focus on the mobile toggle button if the user is shift tabbing from the first menu item 58 if ( event.shiftKey && $( event.currentTarget ).is( 'a' ) ) { 59 event.preventDefault(); 60 $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).trigger( 'focus' ); 61 } 62 // Trigger focus on the first menu item if the user is tabbing from the mobile toggle button 63 else if ( ! event.shiftKey && $( event.currentTarget ).hasClass( 'fl-menu-mobile-toggle' ) && $( event.currentTarget ).hasClass( 'fl-active' ) ) { 64 event.preventDefault(); 65 $( this.wrapperClass ).find( '.menu-item:first a:first' ).trigger( 'focus' ); 66 } 67 }, this ) ); 68 69 // Close mobile menu or accordion when tabbing out from the first or last menu item 70 $( this.wrapperClass ).on( 'focusout', $.proxy( function ( event ) { 71 if ( $( this.wrapperClass + ' nav' ).has( $( event.relatedTarget ) ).length === 0 ) { 72 if ( this.type === 'accordion' ) { 73 this._toggleSubmenu( $( event.target ).parents( '.fl-has-submenu:last' ), false ); 74 } 75 else { 76 this._clickOrHover( true ); 77 } 78 const mobileToggle = $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ); 79 if ( this._isMenuToggle() && mobileToggle.hasClass( 'fl-active' ) && ! $( event.relatedTarget ).is( mobileToggle ) && 'expanded' !== this.mobileToggle ) { 80 mobileToggle.trigger( 'click' ); 81 } 82 } 83 }, this ) ); 84 85 }; 86 87 FLBuilderMenu.prototype = { 88 nodeClass : '', 89 wrapperClass: '', 90 type : '', 91 breakPoints : {}, 92 $submenus : null, 93 94 /** 95 * Check if the screen size fits a mobile viewport. 96 * 97 * @since 1.6.1 98 * @return bool 99 */ 100 _isMobile: function(){ 101 return this.currentBrowserWidth <= this.breakPoints.small ? true : false; 102 }, 103 104 /** 105 * Check if the device is connected to a mouse. 106 * 107 * @since 2.9.0 108 * @return bool 109 */ 110 _isMouseAvailable: function(){ 111 return window.matchMedia("(pointer: fine) and (hover: hover)").matches; 112 }, 113 114 /** 115 * Check if the screen size fits a medium viewport. 116 * 117 * @since 1.10.5 118 * @return bool 119 */ 120 _isMedium: function(){ 121 return this.currentBrowserWidth <= this.breakPoints.medium ? true : false; 122 }, 123 124 /** 125 * Check if the screen size fits a large viewport. 126 * 127 * @since 1.10.5 128 * @return bool 129 */ 130 _isLarge: function(){ 131 return this.currentBrowserWidth <= this.breakPoints.large ? true : false;
132 }, 133 134 /** 135 * Check if the menu should toggle for the current viewport base on the selected breakpoint. 136 * 137 * @see this._isMobile() 138 * @see this._isMedium() 139 * @since 1.10.5 140 * @return bool 141 */ 142 _isMenuToggle: function(){ 143 if ( ( 'always' == this.mobileBreakpoint 144 || ( this._isMobile() && 'mobile' == this.mobileBreakpoint ) 145 || ( this._isMedium() && 'medium-mobile' == this.mobileBreakpoint ) 146 || ( this._isLarge() && 'large-mobile' == this.mobileBreakpoint ) 147 ) && ( $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).is(':visible') || 'expanded' == this.mobileToggle ) ) { 148 return true; 149 } 150 151 return false; 152 }, 153 154 /** 155 * Initialize the toggle logic for the menu. 156 * 157 * @see this._isMenuToggle() 158 * @see this._menuOnCLick() 159 * @see this._clickOrHover() 160 * @see this._submenuOnRight() 161 * @see this._submenuRowZindexFix() 162 * @see this._toggleForMobile() 163 * @since 1.6.1 164 * @return void 165 */ 166 _initMenu: function( resized = false ){ 167 this._setupSubmenu(); 168 if ( ! resized ) { 169 this._menuOnFocus(); 170 this._menuOnClick(); 171 this._menuOnEscape(); 172 } 173 if ( $( this.nodeClass ).length && this.type == 'horizontal' ) { 174 this._initMegaMenus(); 175 } 176 177 if( this._isMenuToggle() || this.type == 'accordion' ){ 178 179 $( this.wrapperClass ).off( 'mouseenter mouseleave' ); 180 this._clickOrHover(); 181 182 } else { 183 this._submenuOnRight(); 184 this._submenuRowZindexFix(); 185 } 186 187 if( this.mobileToggle != 'expanded' ){ 188 this._toggleForMobile(); 189 } 190 191 if( $( this.wrapperClass ).find( '.fl-menu-search-item' ).length ){ 192 this._toggleMenuSearch(); 193 } 194 195 if( $( this.wrapperClass ).find( '.fl-menu-cart-item').length ){ 196 this._wooUpdateParams(); 197 } 198 }, 199 200 /** 201 * Whether the toggle behavior for submenus is through hovering or not. 202 * 203 * @since 2.5 204 * @return void 205 */ 206 _setupSubmenu: function() { 207 if ( ! this._isMouseAvailable() || this._isMenuToggle() || this.type === 'accordion' ) { 208 $( this.wrapperClass ).addClass( 'no-hover' ); 209 } 210 else { 211 $( this.wrapperClass ).removeClass( 'no-hover' ); 212 } 213 }, 214 215 /** 216 * Logic for menu items when focused. 217 * 218 * @since 1.9.0 219 * @return void 220 */ 221 _menuOnFocus: function(){ 222 $( this.wrapperClass ).on( 'focus', 'a, .fl-menu-toggle', $.proxy( function( event ) { 223 const focusedMenuItem = $( event.currentTarget ).closest( '.menu-item' ); 224 const blurredMenuItem = $( event.relatedTarget ).closest( '.menu-item' ); 225 // In case the blurred & focused items are siblings 226 if ( focusedMenuItem.closest( 'ul' ).is( blurredMenuItem.closest( 'ul' ) ) ) { 227 // Check if the focus event is not between the link & submenu icon of the same menu item 228 if ( ! focusedMenuItem.is( blurredMenuItem ) ) { 229 this._toggleSubmenu( blurredMenuItem, false ); 230 } 231 } 232 // In case neither items are child & parent nor vice versa 233 else if ( focusedMenuItem.has( blurredMenuItem ).length === blurredMenuItem.has( focusedMenuItem ).length ) { 234 // Get the blurred item parent & is the sibling of the focused item 235 blurredMenuItem.parents( '.fl-has-submenu' ).each( ( _, parent ) => { 236 if ( focusedMenuItem.closest( 'ul' ).is( $( parent ).closest( 'ul' ) ) ) { 237 this._toggleSubmenu( $( parent ), false ); 238 return false; 239 } 240 } ); 241 } 242 // In case the blurred item is a child of the focused item 243 else if ( focusedMenuItem.has( blurredMenuItem ).length ) { 244 if ( this.type !== 'accordion' && this.submenuIcon === 'none' ) { 245 this._toggleSubmenu( blurredMenuItem, false ); 246 } 247 } 248 }, this ) ); 249 }, 250 251 /** 252 * Logic for menu items when Escape key is pressed. 253 * 254 * @since 2.7.1 255 * @return void 256 */ 257 _menuOnEscape: function(){ 258 $( this.wrapperClass ).on( 'keydown', $.proxy( function( event ){ 259 if ( event.key !== 'Escape' ) return; 260 const menuItem = $( event.target ).closest( '.menu-item' ); 261 const mobileToggle = $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ); 262 // In case there is a focused menu item 263 if ( menuItem.length || $( event.target ).hasClass( 'fl-menu-mobile-close' ) ) { 264 // Close all the submenus of the focused menu item 265 if ( menuItem.hasClass( 'fl-has-submenu' ) && menuItem.find( '.sub-menu:first' ).is( ':visible' ) ) { 266 this._toggleSubmenu( menuItem, false ); 267 } 268 else { 269 // Shift focus to the parent while closing all its submenus 270 const parentMenuItem = menuItem.parents( '.fl-has-submenu' ).not( '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading' ).first(); 271 // Close the mobile menu if there is no parent menu item and the mobile toggle is active 272 if ( parentMenuItem.length === 0 && this._isMenuToggle() && mobileToggle.hasClass( 'fl-active' ) ) { 273 // Blur to trigger the focus-out event for closing the menu 274 mobileToggle.trigger( 'blur' ).trigger( 'focus' ); 275 } 276 // Close the parent submenu and shift focus to its link 277 else if ( parentMenuItem.length !== 0 ) { 278 this._toggleSubmenu( parentMenuItem, false ); 279 parentMenuItem.find( 'a:first' ).trigger( 'focus' ); 280 } 281 } 282 } 283 // Close the mobile menu if the mobile toggle is active 284 else if ( $( event.target ).hasClass( 'fl-menu-mobile-toggle' ) && mobileToggle.hasClass( 'fl-active' ) ) { 285 // Blur to trigger the focus-out event for closing the menu 286 mobileToggle.trigger( 'blur' ).trigger( 'focus' ); 287 } 288 }, this ) ); 289 }, 290 291 /** 292 * Logic for menu items when clicked. 293 * 294 * @since 1.6.1 295 * @return void 296 */ 297 _menuOnClick: function(){ 298 // Fallback for span elements with role="button" to be clickable 299 $( this.wrapperClass ).on( 'keydown', 'span.fl-menu-toggle', $.proxy( function( event ) { 300 if ( event.key === 'Enter' || event.key === ' ' ) { 301 event.preventDefault(); 302 $( event.currentTarget ).trigger( 'click' ); 303 } 304 }, this ) ); 305 $( this.wrapperClass ).on( 'click', 'a, .fl-menu-toggle', $.proxy( function( event ) { 306 event.stopPropagation(); 307 // Only allow mouse clicks with accordion & mobile menus 308 if ( this._isMouseAvailable() && ! this._isMenuToggle() && event.detail && this.type !== 'accordion' ) return; 309 // Links only open & do not toggle submenus if there is either a submenu icon or an accordion layout 310 if ( $( event.currentTarget ).is( 'a' ) && ( this.submenuIcon !== 'none' || this.type === 'accordion' ) ) return; 311 const menuItem = $( event.currentTarget ).closest( '.menu-item, .fl-menu-logo' ); 312 const menuLink = menuItem.find( 'a:first' ).attr( 'href' ); 313 const submenuHidden = menuItem.find( '.sub-menu:first' ).is( ':hidden' ); 314 if ( typeof menuLink === 'undefined' || menuLink === '#' || submenuHidden ) { 315 event.preventDefault(); 316 } 317 if ( $( event.currentTarget ).hasClass( 'fl-menu-toggle' ) || submenuHidden ) { 318 this._toggleSubmenu( menuItem, submenuHidden ); 319 } 320 }, this ) ); 321 }, 322 323 /** 324 * Controls toggling the visibility of all submenu items for desktop & mobile. 325 * 326 * @since 2.10 327 * @return void 328 */ 329 _toggleSubmenu: function ( menuItem, opened ) { 330 const togglingClass = this._isMenuToggle() || this.type === 'accordion' ? 'fl-active' : 'focus'; 331 const toggleElement = this.submenuIcon === 'none' ? 'a' : '.fl-menu-toggle'; 332 const hiddenMenu = '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading'; 333 if ( opened && menuItem.hasClass( 'fl-has-submenu' ) && ! menuItem.is( hiddenMenu ) ) { 334 menuItem.addClass( togglingClass ); 335 menuItem.find( toggleElement ).first().attr( 'aria-expanded', true ); 336 if ( this._isMenuToggle() || this.type === 'accordion' ) { 337 menuItem.find( '.sub-menu:first:hidden' ).slideDown(); 338 } 339 } 340 else { 341 menuItem.parent().find( '.menu-item' ).removeClass( togglingClass ); 342 menuItem.parent().find( '.fl-has-submenu' ).not( hiddenMenu ).find( toggleElement ).attr( 'aria-expanded', false ); 343 if ( this._isMenuToggle() || this.type === 'accordion' ) {
344 menuItem.find( '.sub-menu:visible' ).slideUp(); 345 } 346 } 347 }, 348 349 /** 350 * Changes general styling and behavior of menus based on mobile / desktop viewport. 351 * 352 * @see this._isMenuToggle() 353 * @since 1.6.1 354 * @return void 355 */ 356 _clickOrHover: function( clear = false ){ 357 const selector = this._isMobileBelowRowEnabled() ? this.nodeClass + '-clone' : this.nodeClass; 358 this.$submenus = this.$submenus || $( selector ).find( '.sub-menu' ); 359 360 const className = this._isMenuToggle() || this.type === 'accordion' ? 'fl-active' : 'focus'; 361 const toggleElement = this.submenuIcon === 'none' ? 'a' : '.fl-menu-toggle'; 362 const hiddenMenu = '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading'; 363 $( selector ).find( '.fl-has-submenu' ).not( hiddenMenu ).each( function() { 364 if( clear || ! $ ( this ).hasClass( className ) ){ 365 if ( clear ) $( this ).removeClass( className ); 366 $( this ).find( toggleElement + ':first' ).attr( 'aria-expanded', false ); 367 if ( className === 'fl-active' ) { 368 $( this ).find( '.sub-menu' ).fadeOut(); 369 } else if ( className === 'focus' ) { 370 $( this ).find( '.sub-menu' ).css( { 371 'display' : '', 372 'opacity' : '' 373 } ); 374 } 375 } 376 } ); 377 }, 378 379 /** 380 * Logic to prevent submenus to go outside viewport boundaries. 381 * 382 * @since 1.6.1 383 * @return void 384 */ 385 _submenuOnRight: function(){ 386 387 $( this.wrapperClass ) 388 .on( 'mouseenter focus', '.fl-has-submenu', $.proxy( function( e ){ 389 390 if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) { 391 return; 392 } 393 394 var $link = $( e.currentTarget ), 395 $parent = $link.parent(), 396 $subMenu = $link.find( '.sub-menu' ), 397 subMenuWidth = $subMenu.width(), 398 subMenuPos = 0, 399 bodyWidth = $( 'body' ).width(); 400 401 if( $link.closest( '.fl-menu-submenu-right' ).length !== 0) { 402 403 $link.addClass( 'fl-menu-submenu-right' ); 404 405 } else if( $( 'body' ).hasClass( 'rtl' ) ) { 406 407 subMenuPos = $parent.is( '.sub-menu' ) ? 408 $parent.offset().left - subMenuWidth: 409 $link.offset().left - $link.width() - subMenuWidth; 410 411 if( subMenuPos <= 0 ) { 412 $link.addClass( 'fl-menu-submenu-right' ); 413 } 414 415 } else { 416 417 subMenuPos = $parent.is( '.sub-menu' ) ? 418 $parent.offset().left + $parent.width() + subMenuWidth : 419 $link.offset().left + $link.width() + subMenuWidth; 420 421 if( subMenuPos > bodyWidth ) { 422 $link.addClass('fl-menu-submenu-right'); 423 } 424 } 425 }, this ) ) 426 .on( 'mouseleave', '.fl-has-submenu', $.proxy( function( e ){ 427 $( e.currentTarget ).removeClass( 'fl-menu-submenu-right' ); 428 }, this ) ); 429 430 }, 431 432 /** 433 * Logic to prevent submenus to go behind the next overlay row. 434 * 435 * @since 1.10.9 436 * @return void 437 */ 438 _submenuRowZindexFix: function(){ 439 440 $( this.wrapperClass ) 441 .on( 'mouseenter', 'ul.menu > .fl-has-submenu', $.proxy( function( e ){ 442 443 if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) { 444 return; 445 } 446 447 $( this.nodeClass ) 448 .closest( '.fl-row' ) 449 .find( '.fl-row-content' ) 450 .css( 'z-index', '10' ); 451 452 }, this ) ) 453 .on( 'mouseleave', 'ul.menu > .fl-has-submenu', $.proxy( function(){ 454 455 $( this.nodeClass ) 456 .closest( '.fl-row' ) 457 .find( '.fl-row-content' ) 458 .css( 'z-index', '' ); 459 460 }, this ) ); 461 }, 462 463 /** 464 * Logic for the mobile menu button. 465 * 466 * @since 1.6.1 467 * @return void 468 */ 469 _toggleForMobile: function(){ 470 471 var $wrapper = null, 472 $menu = null, 473 self = this; 474 475 $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).attr('aria-controls', $( this.wrapperClass ).find( 'ul.menu' ).attr('id')); 476 477 if( this._isMenuToggle() ){ 478 479 if ( this._isMobileBelowRowEnabled() ) { 480 this._placeMobileMenuBelowRow(); 481 $wrapper = $( this.wrapperClass ); 482 $menu = $( this.nodeClass + '-clone' ); 483 $menu.find( 'ul.menu' ).show(); 484 } 485 else { 486 $wrapper = $( this.wrapperClass ); 487 $menu = $wrapper.find( '.menu' ); 488 } 489 490 if( !$wrapper.find( '.fl-menu-mobile-toggle' ).hasClass( 'fl-active' ) && ! self.mobileFlyout ){ 491 $menu.css({ display: 'none' }); 492 } 493 494 // Flayout Menu 495 if ( self.mobileFlyout ) { 496 this._initFlyoutMenu(); 497 } 498 499 $wrapper.on( 'click', '.fl-menu-mobile-toggle', function( e ){ 500 e.stopImmediatePropagation(); 501 502 $( this ).toggleClass( 'fl-active' ); 503 504 if ( self.mobileFlyout ) { 505 self._toggleFlyoutMenu(); 506 const flyoutWrapper = $( '.fl-menu-mobile-flyout' ); 507 if ( $( this ).hasClass( 'fl-active' ) ) { 508 flyoutWrapper.attr( 'aria-hidden', false ); 509 flyoutWrapper.find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex="-1"]' ).attr( 'tabindex', 0 ); 510 } 511 else { 512 flyoutWrapper.attr( 'aria-hidden', true ); 513 flyoutWrapper.find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex]:not
513([tabindex="-1"])' ).attr( 'tabindex', -1 ); 514 } 515 } 516 else { 517 var targetMenu = null; 518 519 if ( self.mobileBelowRow ) { 520 var $closestCol = $( this ).parents( '.fl-col, .fl-module-box' ), 521 $closestColGroup = $closestCol.length ? $closestCol.parent( '.fl-col-group' ) : null; 522 targetMenu = $closestCol.length ? $closestCol.last().next( '.fl-menu-mobile-clone' ) : null; 523 524 if ( $closestColGroup.length ) { 525 if ( $closestColGroup.hasClass( 'fl-col-group-responsive-reversed' ) ) { 526 $closestColGroup.find( '.fl-menu-mobile-clone' ).css( 'order', -1 ); 527 } else if ( $closestColGroup ) { 528 $closestColGroup.find( '.fl-menu-mobile-clone' ).css( 'order', 2 ); 529 } 530 } 531 } else { 532 targetMenu = $( this ).closest( '.fl-menu' ).find( 'ul.menu' ); 533 } 534 535 if ( targetMenu.length ) { 536 $menu = $( targetMenu ); 537 } 538 539 $menu.slideToggle(); 540 } 541 542 e.stopPropagation(); 543 } ); 544 545 // Hide active menu when click on anchor link ID that exists on a page 546 $menu.off().on( 'click', '.menu-item > a[href*="#"]:not([href="#"])', function(){ 547 var $href = $(this).attr('href'), 548 $targetID = $href.split('#')[1], 549 element = $('#' + $targetID); 550 if ( $('body').find(element).length > 0 ) { 551 $( this ).toggleClass( 'fl-active' ); 552 FLBuilderLayout._scrollToElement( element ); 553 if ( ! self._isMenuToggle() ) { 554 $menu.slideToggle(); 555 } 556 } 557 }); 558 } 559 else { 560 561 if ( this._isMobileBelowRowEnabled() ) { 562 this._removeMenuFromBelowRow(); 563 } 564 565 $wrapper = $( this.wrapperClass ), 566 $menu = $wrapper.find( 'ul.menu' ); 567 $wrapper.find( '.fl-menu-mobile-toggle' ).removeClass( 'fl-active' ); 568 $menu.css({ display: '' }); 569 570 if ( ! this._isMobileBelowRowEnabled() ) { 571 $menu.off( 'click', '.menu-item > a[href*="#"]:not([href="#"])' ); 572 } 573 574 if ( this.mobileFlyout && $wrapper.find( '.fl-menu-mobile-flyout' ).length > 0 ) { 575 $( 'body' ).css( 'margin', '' ); 576 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' ); 577 $menu.unwrap(); 578 $wrapper.find( '.fl-menu-mobile-close' ).remove(); 579 $wrapper.find( '.fl-menu-mobile-opacity' ).remove(); 580 } 581 } 582 }, 583 584 /** 585 * Init any mega menus that exist. 586 * 587 * @see this._isMenuToggle() 588 * @since 1.10.4 589 * @return void 590 */ 591 _initMegaMenus: function(){ 592 593 var module = $( this.nodeClass ), 594 rowContent = module.closest( '.fl-row-content' ), 595 rowWidth = rowContent.width(), 596 megas = module.find( '.mega-menu' ), 597 disabled = module.find( '.mega-menu-disabled' ), 598 isToggle = this._isMenuToggle(); 599 600 if ( isToggle ) { 601 megas.removeClass( 'mega-menu' ).addClass( 'mega-menu-disabled' ); 602 module.find( 'li.mega-menu-disabled > ul.sub-menu' ).css( 'width', '' ); 603 rowContent.css( 'position', '' ); 604 } else { 605 disabled.removeClass( 'mega-menu-disabled' ).addClass( 'mega-menu' ); 606 module.find( 'li.mega-menu > ul.sub-menu' ).css( 'width', rowWidth + 'px' ); 607 rowContent.css( 'position', 'relative' ); 608 } 609 }, 610 611 /** 612 * Check to see if Below Row should be enabled. 613 * 614 * @since 1.11 615 * @return boolean 616 */ 617 _isMobileBelowRowEnabled: function() { 618 return this.mobileBelowRow && ( $( this.nodeClass ).parents( '.fl-col, .fl-module-box' ).length ); 619 }, 620 621 /** 622 * Logic for putting the mobile menu below the menu's 623 * column so it spans the full width of the page. 624 * 625 * @since 1.10 626 * @return void 627 */ 628 _placeMobileMenuBelowRow: function(){ 629 630 if ( $( this.nodeClass + '-clone' ).length ) { 631 return; 632 } 633 634 var module = $( this.nodeClass ), 635 clone = null, 636 col = module.parents( '.fl-col, .fl-module-box' ).last(); 637 638 if ( module.length < 1 ) { 639 return; 640 } 641 642 clone = ( module.length > 1 ) ? $( module[0] ).clone() : module.clone(); 643 module.find( 'ul.menu' ).remove(); 644 clone.addClass( ( this.nodeClass + '-clone' ).replace( '.', '' ) ); 645 clone.addClass( 'fl-menu-mobile-clone' ); 646 clone.find( '.fl-menu-mobile-toggle' ).remove(); 647 col.after( clone ); 648 649 // Removes animation when enabled 650 if ( module.hasClass( 'fl-animation' ) ) { 651 clone.removeClass( 'fl-animation' ); 652 } 653 654 this._menuOnFocus(); 655 this._menuOnClick(); 656 this._menuOnEscape(); 657 }, 658 659 /** 660 * Logic for removing the mobile menu from below the menu's 661 * column and putting it back in the main wrapper. 662 * 663 * @since 1.10 664 * @return void 665 */ 666 _removeMenuFromBelowRow: function(){ 667 668 if ( ! $( this.nodeClass + '-clone' ).length ) { 669 return; 670 } 671 672 var module = $( this.nodeClass ), 673 clone = $( this.nodeClass + '-clone' ), 674 menu = clone.find( 'ul.menu' ), 675 nav = module.find( 'nav' ); 676
677 if ( nav.length ) { 678 nav.append( menu ); 679 } else { 680 module.find( '.fl-menu-mobile-toggle' ).after( menu ); 681 } 682 clone.remove(); 683 menu.find( 'a' ).each( FLBuilderLayout._initAnchorLink ); 684 }, 685 686 /** 687 * Logic for Flyout responsive menu. 688 * 689 * @since 2.2 690 * @return void 691 */ 692 _initFlyoutMenu: function(){ 693 var wrapper = $( this.wrapperClass ), 694 menu = wrapper.find( 'ul.menu' ), 695 button = wrapper.find( '.fl-menu-mobile-toggle' ); 696 697 if ( 0 === wrapper.find( '.fl-menu-mobile-flyout' ).length ) { 698 menu.wrap( '<div class="fl-menu-mobile-flyout" aria-hidden="true"></div>' ); 699 } 700 701 if ( 0 === wrapper.find( '.fl-menu-mobile-close' ).length ) { 702 var close = window.fl_responsive_close || 'Close' 703 wrapper.find( '.fl-menu-mobile-flyout' ).prepend( '<button class="fl-menu-mobile-close fl-content-ui-button" aria-label="' + close + '"><i class="fas fa-times"></i></button>' ); 704 } 705 706 // Push with opacity 707 if ( wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ) && 0 === wrapper.find( '.fl-menu-mobile-opacity' ).length ) { 708 wrapper.append( '<div class="fl-menu-mobile-opacity"></div>' ); 709 } 710 711 wrapper.off( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close' ).on( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close', function(e){ 712 button.trigger('focus').trigger( 'click' ); 713 e.stopPropagation(); 714 }); 715 716 if ( 'undefined' !== typeof FLBuilder ) { 717 FLBuilder.addHook('restartEditingSession', function(){ 718 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' ); 719 720 // Toggle active menu 721 if ( button.hasClass( 'fl-active' ) ) { 722 button.trigger( 'click' ); 723 } 724 }); 725 } 726 $( '.fl-menu-mobile-flyout' ).find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex]:not([tabindex="-1"])' ).attr( 'tabindex', -1 ); 727 }, 728 729 /** 730 * Logic to enable/disable the Flyout menu on button click. 731 * 732 * @since 2.2 733 * @return void 734 */ 735 _toggleFlyoutMenu: function(){ 736 var wrapper = $( this.wrapperClass ), 737 button = wrapper.find( '.fl-menu-mobile-toggle' ), 738 position = wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 739 pushMenu = wrapper.hasClass( 'fl-menu-responsive-flyout-push' ) || wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ), 740 opacity = wrapper.find( '.fl-menu-mobile-opacity' ), 741 marginPos = {}, 742 fixedPos = {}, 743 fixedHeader = $('header, header > div'); 744 745 this._resizeFlyoutMenuPanel(); 746 747 // Fix the push menu when builder ui panel is pinned 748 if ( $( '.fl-builder-ui-pinned-content-transform' ).length > 0 && ! $( 'body' ).hasClass( 'fl-builder-edit' ) ) { 749 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', 'none' ); 750 } 751 752 if ( pushMenu ) { 753 marginPos[ 'margin-' + position ] = button.hasClass( 'fl-active' ) ? this.flyoutWidth + 'px' : '0px'; 754 $( 'body' ).animate( marginPos, 200); 755 756 // Fixed header 757 if ( fixedHeader.length > 0 ) { 758 fixedPos[ position] = button.hasClass( 'fl-active' ) ? this.flyoutWidth + 'px' : '0px'; 759 fixedHeader.each(function(){ 760 if ( 'fixed' == $( this ).css( 'position' ) ) { 761 $( this ).css({ 'transition' : 'none' }); 762 $( this ).animate( fixedPos, 200 ); 763 } 764 }); 765 } 766 } 767 768 if ( opacity.length > 0 && button.hasClass( 'fl-active' ) ) { 769 opacity.show(); 770 } 771 else { 772 opacity.hide(); 773 } 774 }, 775 776 /** 777 * Resize or reposition the Flyout Menu Panel. 778 * 779 * @since 2.8.1 780 * @return void 781 */ 782 _resizeFlyoutMenuPanel: function(){ 783 const wrapper = $( this.wrapperClass ); 784 const wrapFlyout = wrapper.find( '.fl-menu-mobile-flyout' ); 785 786 if ( wrapFlyout.length > 0 ) { 787 wrapFlyout.css( this._getFlyoutMenuPanelPosition() ); 788 } 789 }, 790 791 /** 792 * Compute the Flyout Menu Panel's position on the screen. 793 * 794 * @since 2.8.1 795 * @return object 796 */ 797 _getFlyoutMenuPanelPosition: function() { 798 var wrapper = $( this.wrapperClass ), 799 button = wrapper.find( '.fl-menu-mobile-toggle' ), 800 side = wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 801 winHeight = $(window).outerHeight(), 802 winTop = $(window).scrollTop(), 803 adminBarHeight = $( '#wpadminbar' ).length ? $( '#wpadminbar' ).height() : 0, 804 flyoutPosition = {}; 805 806 flyoutPosition[ side ] = '-' + ( parseInt( this.flyoutWidth ) + 15 ) + 'px'; 807 if ( ! button.hasClass( 'fl-active' ) ) { 808 return flyoutPosition; 809 } 810 811 flyoutPosition[ side ] = '0px'; 812 flyoutPosition[ 'height' ] = winHeight + 'px'; 813 flyoutPosition[ 'top' ] = '0px'; 814 815 if ( adminBarHeight > 0 ) { 816 const diff = adminBarHeight - winTop; 817 flyoutPosition[ 'top' ] = diff <= 0 ? '0px' : (diff) + 'px'; 818 } 819 820 return flyoutPosition; 821 }, 822 823 /** 824 * Shows or hides the nav search form. 825 * 826 * @since 2.5 827 * @method _toggleMenuSearch 828 */ 829 _toggleMenuSearch: function(){ 830 var wrapper = $( this.wrapperClass ).find('.fl-menu-search-item'), 831 button = wrapper.find('.fl-button:is(a, button)'), 832 form = wrapper.find('.fl-search-form-input-wrap'), 833 self = this; 834 835 button.attr( 'tabindex', 0 ); 836 button.attr( 'aria-label', 'Search' ); 837 button.on('click', function(e){ 838 e.preventDefault(); 839 840 if(form.is(':visible')) { 841 form.stop().fadeOut(200); 842 } 843 else { 844 form.stop().fadeIn(200); 845 $('body').on('click.fl-menu-search', $.proxy(self._hideMenuSearch, self)); 846 form.find('.fl-search-text').focus(); 847 } 848 }); 849 }, 850 851 /** 852 * Hides the nav search form. 853 * 854 * @since 2.5 855 * @method _hideMenuSearch 856 */ 857 _hideMenuSearch: function(e){ 858 var form = $( this.wrapperClass ).find('.fl-search-form-input-wrap'); 859 860 if(e !== undefined) { 861 if($(e.target).closest('.fl-menu-search-item').length > 0) { 862 return; 863 } 864 } 865 866 form.stop().fadeOut(200); 867 $('body').off('click.fl-menu-search'); 868 }, 869 870 /** 871 * Adds menu node and post ID to WooCommerce ajax URL requests. 872 * 873 * @since 2.5 874 * @return void 875 */ 876 _wooUpdateParams: function() { 877 if ( 'undefined' !== typeof wc_cart_fragments_params ) { 878 wc_cart_fragments_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId; 879 } 880 if ( 'undefined' !== typeof wc_add_to_cart_params ) { 881 wc_add_to_cart_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId; 882 } 883 }, 884 }; 885 886})(jQuery); 887 888(function($) { 889 890 $(function() { 891 892 new FLBuilderMenu({ 893 id: '5a73ccfc4808e', 894 type: 'accordion', 895 mobile: 'expanded', 896 mobileBelowRow: false, 897 mobileFlyout: false, 898 breakPoints: { 899 large: 1200, 900 medium: 992, 901 small: 768 }, 902 mobileBreakpoint: 'mobile', 903 postId : '1080', 904 mobileStacked: true, 905 submenuIcon: 'arrows', 906 flyoutWidth: '250', 907 }); 908 909 }); 910 911})(jQuery); 912 913/* Start Layout Custom JS */ 914 915/* End Layout Custom JS */ 916 917 918 919/* Start Layout Custom JS */ 920 921/* End Layout Custom JS */ 922 923 924 925/* Start Layout Custom JS */ 926 927/* End Layout Custom JS */ 928 929
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.