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().find( '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:not(.fl-button), .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 the search form if it is open 265 if ( menuItem.hasClass( 'fl-menu-search-item' ) && $( this.wrapperClass ).find('.fl-search-form-input-wrap').is( ':visible' ) ) { 266 $( this.wrapperClass ).find('.fl-menu-search-item .fl-button:is(a, button:not([type="submit"]))').trigger( 'focus' ); 267 } 268 // Close all the submenus of the focused menu item 269 else if ( menuItem.hasClass( 'fl-has-submenu' ) && menuItem.find( '.sub-menu' ).first().is( ':visible' ) ) { 270 this._toggleSubmenu( menuItem, false ); 271 } 272 else { 273 // Shift focus to the parent while closing all its submenus 274 const parentMenuItem = menuItem.parents( '.fl-has-submenu' ).not( '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading' ).first(); 275 // Close the mobile menu if there is no parent menu item and the mobile toggle is active 276 if ( parentMenuItem.length === 0 && this._isMenuToggle() && mobileToggle.hasClass( 'fl-active' ) ) { 277 // Blur to trigger the focus-out event for closing the menu 278 mobileToggle.trigger( 'blur' ).trigger( 'focus' ); 279 } 280 // Close the parent submenu and shift focus to its link 281 else if ( parentMenuItem.length !== 0 ) { 282 this._toggleSubmenu( parentMenuItem, false ); 283 parentMenuItem.find( 'a' ).first().trigger( 'focus' ); 284 } 285 } 286 } 287 // Close the mobile menu if the mobile toggle is active 288 else if ( $( event.target ).hasClass( 'fl-menu-mobile-toggle' ) && mobileToggle.hasClass( 'fl-active' ) ) { 289 // Blur to trigger the focus-out event for closing the menu 290 mobileToggle.trigger( 'blur' ).trigger( 'focus' ); 291 } 292 }, this ) ); 293 }, 294 295 /** 296 * Logic for menu items when clicked. 297 * 298 * @since 1.6.1 299 * @return void 300 */ 301 _menuOnClick: function(){ 302 // Fallback for span elements and fake links to interact with the keyboard 303 $( this.wrapperClass ).on( 'keydown', 'a:not(.fl-button, [href]), span.fl-menu-toggle', $.proxy( function( event ) { 304 if ( event.key === 'Enter' || event.key === ' ' ) { 305 event.preventDefault(); 306 $( event.currentTarget ).trigger( 'click' ); 307 } 308 }, this ) ); 309 $( this.wrapperClass ).on( 'click', 'a, .fl-menu-toggle', $.proxy( function( event ) { 310 // Only allow mouse clicks with accordion & mobile menus 311 if ( this._isMouseAvailable() && ! this._isMenuToggle() && event.detail && this.type !== 'accordion' ) return; 312 // Links only open & do not toggle submenus if there is either a submenu icon or an accordion layout 313 if ( $( event.currentTarget ).is( 'a' ) && ( this.submenuIcon !== 'none' || this.type === 'accordion' ) ) return; 314 const menuItem = $( event.currentTarget ).closest( '.menu-item, .fl-menu-logo' ); 315 const menuLink = menuItem.find( 'a' ).first().attr( 'href' ); 316 const submenuHidden = menuItem.find( '.sub-menu' ).first().is( ':hidden' ); 317 if ( typeof menuLink === 'undefined' || menuLink === '#' || submenuHidden ) { 318 event.preventDefault(); 319 } 320 if ( $( event.currentTarget ).hasClass( 'fl-menu-toggle' ) || submenuHidden ) { 321 this._toggleSubmenu( menuItem, submenuHidden ); 322 } 323 }, this ) ); 324 }, 325 326 /** 327 * Controls toggling the visibility of all submenu items for desktop & mobile. 328 * 329 * @since 2.10 330 * @return void 331 */ 332 _toggleSubmenu: function ( menuItem, opened ) { 333 const togglingClass = this._isMenuToggle() || this.type === 'accordion' ? 'fl-active' : 'focus'; 334 const toggleElement = this.submenuIcon === 'none' ? 'a' : '.fl-menu-toggle'; 335 const hiddenMenu = '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading'; 336 if ( opened && menuItem.hasClass( 'fl-has-submenu' ) && ! menuItem.is( hiddenMenu ) ) { 337 menuItem.addClass( togglingClass ); 338 menuItem.find( toggleElement ).first().attr( 'aria-expanded', true ); 339 if ( this._isMenuToggle() || this.type === 'accordion' ) { 340 menuItem.find( '.sub-menu' ).first().filter( ':hidden' ).slideDown(); 341 } 342 } 343 else { 344 menuItem.parent().find( '.menu-item' ).removeClass( togglingClass ); 345 menuItem.parent().find( '.fl-has-submenu' ).not( hiddenMenu ).find( toggleElement ).attr( 'aria-expanded', false ); 346 if ( this._isMenuToggle() || this.type === 'accordion' ) {
347 menuItem.find( '.sub-menu' ).filter( ':visible' ).slideUp(); 348 } 349 } 350 }, 351 352 /** 353 * Changes general styling and behavior of menus based on mobile / desktop viewport. 354 * 355 * @see this._isMenuToggle() 356 * @since 1.6.1 357 * @return void 358 */ 359 _clickOrHover: function( clear = false ){ 360 const selector = this._isMobileBelowRowEnabled() ? this.nodeClass + '-clone' : this.nodeClass; 361 this.$submenus = this.$submenus || $( selector ).find( '.sub-menu' ); 362 363 const className = this._isMenuToggle() || this.type === 'accordion' ? 'fl-active' : 'focus'; 364 const toggleElement = this.submenuIcon === 'none' ? 'a' : '.fl-menu-toggle'; 365 const hiddenMenu = '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading'; 366 $( selector ).find( '.fl-has-submenu' ).not( hiddenMenu ).each( function() { 367 if( clear || ! $ ( this ).hasClass( className ) ){ 368 if ( clear ) $( this ).removeClass( className ); 369 $( this ).find( toggleElement ).first().attr( 'aria-expanded', false ); 370 if ( className === 'fl-active' ) { 371 $( this ).find( '.sub-menu' ).fadeOut(); 372 } else if ( className === 'focus' ) { 373 $( this ).find( '.sub-menu' ).css( { 374 'display' : '', 375 'opacity' : '' 376 } ); 377 } 378 } 379 } ); 380 }, 381 382 /** 383 * Logic to prevent submenus to go outside viewport boundaries. 384 * 385 * @since 1.6.1 386 * @return void 387 */ 388 _submenuOnRight: function(){ 389 390 $( this.wrapperClass ) 391 .on( 'mouseenter focus', '.fl-has-submenu', $.proxy( function( e ){ 392 393 if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) { 394 return; 395 } 396 397 var $link = $( e.currentTarget ), 398 $parent = $link.parent(), 399 $subMenu = $link.find( '.sub-menu' ), 400 subMenuWidth = $subMenu.width(), 401 subMenuPos = 0, 402 bodyWidth = $( 'body' ).width(); 403 404 if( $link.closest( '.fl-menu-submenu-right' ).length !== 0) { 405 406 $link.addClass( 'fl-menu-submenu-right' ); 407 408 } else if( $( 'body' ).hasClass( 'rtl' ) ) { 409 410 subMenuPos = $parent.is( '.sub-menu' ) ? 411 $parent.offset().left - subMenuWidth: 412 $link.offset().left - $link.width() - subMenuWidth; 413 414 if( subMenuPos <= 0 ) { 415 $link.addClass( 'fl-menu-submenu-right' ); 416 } 417 418 } else { 419 420 subMenuPos = $parent.is( '.sub-menu' ) ? 421 $parent.offset().left + $parent.width() + subMenuWidth : 422 $link.offset().left + $link.width() + subMenuWidth; 423 424 if( subMenuPos > bodyWidth ) { 425 $link.addClass('fl-menu-submenu-right'); 426 } 427 } 428 }, this ) ) 429 .on( 'mouseleave', '.fl-has-submenu', $.proxy( function( e ){ 430 $( e.currentTarget ).removeClass( 'fl-menu-submenu-right' ); 431 }, this ) ); 432 433 }, 434 435 /** 436 * Logic to prevent submenus to go behind the next overlay row. 437 * 438 * @since 1.10.9 439 * @return void 440 */ 441 _submenuRowZindexFix: function(){ 442 443 $( this.wrapperClass ) 444 .on( 'mouseenter', 'ul.menu > .fl-has-submenu', $.proxy( function( e ){ 445 446 if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) { 447 return; 448 } 449 450 $( this.nodeClass ) 451 .closest( '.fl-row' ) 452 .find( '.fl-row-content' ) 453 .css( 'z-index', '10' ); 454 455 }, this ) ) 456 .on( 'mouseleave', 'ul.menu > .fl-has-submenu', $.proxy( function(){ 457 458 $( this.nodeClass ) 459 .closest( '.fl-row' ) 460 .find( '.fl-row-content' ) 461 .css( 'z-index', '' ); 462 463 }, this ) ); 464 }, 465 466 /** 467 * Logic for the mobile menu button. 468 * 469 * @since 1.6.1 470 * @return void 471 */ 472 _toggleForMobile: function(){ 473 474 var $wrapper = null, 475 $menu = null, 476 self = this; 477 478 $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).attr('aria-controls', $( this.wrapperClass ).find( 'ul.menu' ).attr('id')); 479 480 if( this._isMenuToggle() ){ 481 482 if ( this._isMobileBelowRowEnabled() ) { 483 this._placeMobileMenuBelowRow(); 484 $wrapper = $( this.wrapperClass ); 485 $menu = $( this.nodeClass + '-clone' ); 486 $menu.find( 'ul.menu' ).show(); 487 } 488 else { 489 $wrapper = $( this.wrapperClass ); 490 $menu = $wrapper.find( '.menu' ); 491 } 492 493 if( !$wrapper.find( '.fl-menu-mobile-toggle' ).hasClass( 'fl-active' ) && ! self.mobileFlyout ){ 494 $menu.css({ display: 'none' }); 495 } 496 497 // Flayout Menu 498 if ( self.mobileFlyout ) { 499 this._initFlyoutMenu(); 500 } 501 502 $wrapper.on( 'click', '.fl-menu-mobile-toggle', function( e ){ 503 e.stopImmediatePropagation(); 504 505 $( this ).toggleClass( 'fl-active' ); 506 507 if ( self.mobileFlyout ) { 508 self._toggleFlyoutMenu(); 509 const flyoutWrapper = $( '.fl-menu-mobile-flyout' ); 510 if ( $( this ).hasClass( 'fl-active' ) ) { 511 flyoutWrapper.attr( 'aria-hidden', false ); 512 flyoutWrapper.find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex="-1"]' ).attr( 'tabindex', 0 ); 513 } 514 else { 515 flyoutWrapper.attr( 'aria-hidden', true ); 516 flyoutWrapper.find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex]:not
516([tabindex="-1"])' ).attr( 'tabindex', -1 ); 517 } 518 } 519 else { 520 var targetMenu = null; 521 522 if ( self.mobileBelowRow ) { 523 var $closestCol = $( this ).parents( '.fl-col, .fl-module-box' ), 524 $closestColGroup = $closestCol.length ? $closestCol.parent( '.fl-col-group' ) : null; 525 targetMenu = $closestCol.length ? $closestCol.last().next( '.fl-menu-mobile-clone' ) : null; 526 527 if ( $closestColGroup.length ) { 528 if ( $closestColGroup.hasClass( 'fl-col-group-responsive-reversed' ) ) { 529 $closestColGroup.find( '.fl-menu-mobile-clone' ).css( 'order', -1 ); 530 } else if ( $closestColGroup ) { 531 $closestColGroup.find( '.fl-menu-mobile-clone' ).css( 'order', 2 ); 532 } 533 } 534 } else { 535 targetMenu = $( this ).closest( '.fl-menu' ).find( 'ul.menu' ); 536 } 537 538 if ( targetMenu.length ) { 539 $menu = $( targetMenu ); 540 } 541 542 $menu.slideToggle(); 543 } 544 545 e.stopPropagation(); 546 } ); 547 548 // Hide active menu when click on anchor link ID that exists on a page 549 $menu.off().on( 'click', '.menu-item > a[href*="#"]:not([href="#"])', function(){ 550 var $href = $(this).attr('href'), 551 $targetID = $href.split('#')[1], 552 element = $('#' + $targetID); 553 if ( $('body').find(element).length > 0 ) { 554 $( this ).toggleClass( 'fl-active' ); 555 FLBuilderLayout._scrollToElement( element ); 556 if ( ! self._isMenuToggle() ) { 557 $menu.slideToggle(); 558 } 559 } 560 }); 561 } 562 else { 563 564 if ( this._isMobileBelowRowEnabled() ) { 565 this._removeMenuFromBelowRow(); 566 } 567 568 $wrapper = $( this.wrapperClass ), 569 $menu = $wrapper.find( 'ul.menu' ); 570 $wrapper.find( '.fl-menu-mobile-toggle' ).removeClass( 'fl-active' ); 571 $menu.css({ display: '' }); 572 573 if ( ! this._isMobileBelowRowEnabled() ) { 574 $menu.off( 'click', '.menu-item > a[href*="#"]:not([href="#"])' ); 575 } 576 577 if ( this.mobileFlyout && $wrapper.find( '.fl-menu-mobile-flyout' ).length > 0 ) { 578 $( 'body' ).css( 'margin', '' ); 579 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' ); 580 $menu.unwrap(); 581 $wrapper.find( '.fl-menu-mobile-close' ).remove(); 582 $wrapper.find( '.fl-menu-mobile-opacity' ).remove(); 583 } 584 } 585 }, 586 587 /** 588 * Init any mega menus that exist. 589 * 590 * @see this._isMenuToggle() 591 * @since 1.10.4 592 * @return void 593 */ 594 _initMegaMenus: function(){ 595 596 var module = $( this.nodeClass ), 597 rowContent = module.closest( '.fl-row-content' ), 598 rowWidth = rowContent.width(), 599 megas = module.find( '.mega-menu' ), 600 disabled = module.find( '.mega-menu-disabled' ), 601 isToggle = this._isMenuToggle(); 602 603 if ( isToggle ) { 604 megas.removeClass( 'mega-menu' ).addClass( 'mega-menu-disabled' ); 605 module.find( 'li.mega-menu-disabled > ul.sub-menu' ).css( 'width', '' ); 606 rowContent.css( 'position', '' ); 607 } else { 608 disabled.removeClass( 'mega-menu-disabled' ).addClass( 'mega-menu' ); 609 module.find( 'li.mega-menu > ul.sub-menu' ).css( 'width', rowWidth + 'px' ); 610 rowContent.css( 'position', 'relative' ); 611 } 612 }, 613 614 /** 615 * Check to see if Below Row should be enabled. 616 * 617 * @since 1.11 618 * @return boolean 619 */ 620 _isMobileBelowRowEnabled: function() { 621 return this.mobileBelowRow && ( $( this.nodeClass ).parents( '.fl-col, .fl-module-box' ).length ); 622 }, 623 624 /** 625 * Logic for putting the mobile menu below the menu's 626 * column so it spans the full width of the page. 627 * 628 * @since 1.10 629 * @return void 630 */ 631 _placeMobileMenuBelowRow: function(){ 632 633 if ( $( this.nodeClass + '-clone' ).length ) { 634 return; 635 } 636 637 var module = $( this.nodeClass ), 638 clone = null, 639 col = module.parents( '.fl-col, .fl-module-box' ).last(); 640 641 if ( module.length < 1 ) { 642 return; 643 } 644 645 clone = ( module.length > 1 ) ? $( module[0] ).clone() : module.clone(); 646 module.find( 'ul.menu' ).remove(); 647 clone.addClass( ( this.nodeClass + '-clone' ).replace( '.', '' ) ); 648 clone.addClass( 'fl-menu-mobile-clone' ); 649 clone.find( '.fl-menu-mobile-toggle' ).remove(); 650 col.after( clone ); 651 652 // Removes animation when enabled 653 if ( module.hasClass( 'fl-animation' ) ) { 654 clone.removeClass( 'fl-animation' ); 655 } 656 657 this._menuOnFocus(); 658 this._menuOnClick(); 659 this._menuOnEscape(); 660 }, 661 662 /** 663 * Logic for removing the mobile menu from below the menu's 664 * column and putting it back in the main wrapper. 665 * 666 * @since 1.10 667 * @return void 668 */ 669 _removeMenuFromBelowRow: function(){ 670 671 if ( ! $( this.nodeClass + '-clone' ).length ) { 672 return; 673 } 674 675 var module = $( this.nodeClass ), 676 clone = $( this.nodeClass + '-clone' ), 677 menu = clone.find( 'ul.menu' ), 678 nav = module.find( 'nav' ); 679
680 if ( nav.length ) { 681 nav.append( menu ); 682 } else { 683 module.find( '.fl-menu-mobile-toggle' ).after( menu ); 684 } 685 clone.remove(); 686 menu.find( 'a' ).each( FLBuilderLayout._initAnchorLink ); 687 }, 688 689 /** 690 * Logic for Flyout responsive menu. 691 * 692 * @since 2.2 693 * @return void 694 */ 695 _initFlyoutMenu: function(){ 696 var wrapper = $( this.wrapperClass ), 697 menu = wrapper.find( 'ul.menu' ), 698 button = wrapper.find( '.fl-menu-mobile-toggle' ); 699 700 if ( 0 === wrapper.find( '.fl-menu-mobile-flyout' ).length ) { 701 menu.wrap( '<div class="fl-menu-mobile-flyout" aria-hidden="true"></div>' ); 702 } 703 704 if ( 0 === wrapper.find( '.fl-menu-mobile-close' ).length ) { 705 var close = window.fl_responsive_close || 'Close' 706 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>' ); 707 } 708 709 // Push with opacity 710 if ( wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ) && 0 === wrapper.find( '.fl-menu-mobile-opacity' ).length ) { 711 wrapper.append( '<div class="fl-menu-mobile-opacity"></div>' ); 712 } 713 714 wrapper.off( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close' ).on( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close', function(e){ 715 button.trigger('focus').trigger( 'click' ); 716 e.stopPropagation(); 717 }); 718 719 if ( 'undefined' !== typeof FLBuilder ) { 720 FLBuilder.addHook('restartEditingSession', function(){ 721 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' ); 722 723 // Toggle active menu 724 if ( button.hasClass( 'fl-active' ) ) { 725 button.trigger( 'click' ); 726 } 727 }); 728 } 729 $( '.fl-menu-mobile-flyout' ).find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex]:not([tabindex="-1"])' ).attr( 'tabindex', -1 ); 730 }, 731 732 /** 733 * Logic to enable/disable the Flyout menu on button click. 734 * 735 * @since 2.2 736 * @return void 737 */ 738 _toggleFlyoutMenu: function(){ 739 var wrapper = $( this.wrapperClass ), 740 button = wrapper.find( '.fl-menu-mobile-toggle' ), 741 position = wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 742 pushMenu = wrapper.hasClass( 'fl-menu-responsive-flyout-push' ) || wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ), 743 opacity = wrapper.find( '.fl-menu-mobile-opacity' ), 744 marginPos = {}, 745 fixedPos = {}, 746 fixedHeader = $('header, header > div'); 747 748 this._resizeFlyoutMenuPanel(); 749 750 // Fix the push menu when builder ui panel is pinned 751 if ( $( '.fl-builder-ui-pinned-content-transform' ).length > 0 && ! $( 'body' ).hasClass( 'fl-builder-edit' ) ) { 752 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', 'none' ); 753 } 754 755 if ( pushMenu ) { 756 marginPos[ 'margin-' + position ] = button.hasClass( 'fl-active' ) ? this.flyoutWidth + 'px' : '0px'; 757 $( 'body' ).animate( marginPos, 200); 758 759 // Fixed header 760 if ( fixedHeader.length > 0 ) { 761 fixedPos[ position] = button.hasClass( 'fl-active' ) ? this.flyoutWidth + 'px' : '0px'; 762 fixedHeader.each(function(){ 763 if ( 'fixed' == $( this ).css( 'position' ) ) { 764 $( this ).css({ 'transition' : 'none' }); 765 $( this ).animate( fixedPos, 200 ); 766 } 767 }); 768 } 769 } 770 771 if ( opacity.length > 0 && button.hasClass( 'fl-active' ) ) { 772 opacity.show(); 773 } 774 else { 775 opacity.hide(); 776 } 777 }, 778 779 /** 780 * Resize or reposition the Flyout Menu Panel. 781 * 782 * @since 2.8.1 783 * @return void 784 */ 785 _resizeFlyoutMenuPanel: function(){ 786 const wrapper = $( this.wrapperClass ); 787 const wrapFlyout = wrapper.find( '.fl-menu-mobile-flyout' ); 788 789 if ( wrapFlyout.length > 0 ) { 790 wrapFlyout.css( this._getFlyoutMenuPanelPosition() ); 791 } 792 }, 793 794 /** 795 * Compute the Flyout Menu Panel's position on the screen. 796 * 797 * @since 2.8.1 798 * @return object 799 */ 800 _getFlyoutMenuPanelPosition: function() { 801 var wrapper = $( this.wrapperClass ), 802 button = wrapper.find( '.fl-menu-mobile-toggle' ), 803 side = wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 804 winHeight = $(window).outerHeight(), 805 winTop = $(window).scrollTop(), 806 adminBarHeight = $( '#wpadminbar' ).length ? $( '#wpadminbar' ).height() : 0, 807 flyoutPosition = {}; 808 809 flyoutPosition[ side ] = '-' + ( parseInt( this.flyoutWidth ) + 15 ) + 'px'; 810 if ( ! button.hasClass( 'fl-active' ) ) { 811 return flyoutPosition; 812 } 813 814 flyoutPosition[ side ] = '0px'; 815 flyoutPosition[ 'height' ] = winHeight + 'px'; 816 flyoutPosition[ 'top' ] = '0px'; 817 818 if ( adminBarHeight > 0 ) { 819 const diff = adminBarHeight - winTop; 820 flyoutPosition[ 'top' ] = diff <= 0 ? '0px' : (diff) + 'px'; 821 } 822 823 return flyoutPosition; 824 }, 825 826 /** 827 * Shows or hides the nav search form. 828 * 829 * @since 2.5 830 * @method _toggleMenuSearch 831 */ 832 _toggleMenuSearch: function(){ 833 const form = $( this.wrapperClass ).find('.fl-menu-search-item .fl-search-form-input-wrap');
834 const button = $( this.wrapperClass ).find('.fl-menu-search-item .fl-button:is(a, button:not([type="submit"]))'); 835 form.on('submit', () => form.stop().fadeToggle('fast')); 836 // Close the search form when focus is lost 837 form.on('focusout', (event) => { 838 if (form.is(':visible') && form.has($(event.relatedTarget)).length === 0) { 839 button.trigger('click'); 840 } 841 }); 842 button.attr('aria-expanded', false); 843 // Close other open submenus when focusing on the search button 844 button.on('focus', (event) => { 845 const parentMenus = $(event.relatedTarget).parents('.menu-item.fl-has-submenu'); 846 if (event.relatedTarget && parentMenus.length) { 847 this._toggleSubmenu(parentMenus, false); 848 } 849 }); 850 button.on('click', (event) => { 851 // Prevent toggling when clicking with mouse while the form is already open 852 if (event.detail && event.type === 'click' && form.is(':visible')) return; 853 form.stop().fadeToggle('fast', () => { 854 button.attr('aria-expanded', form.is(':visible')); 855 if(form.is(':visible')) { 856 form.find('.fl-search-text').focus(); 857 } 858 }); 859 }); 860 }, 861 862 /** 863 * Adds menu node and post ID to WooCommerce ajax URL requests. 864 * 865 * @since 2.5 866 * @return void 867 */ 868 _wooUpdateParams: function() { 869 if ( 'undefined' !== typeof wc_cart_fragments_params ) { 870 wc_cart_fragments_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId; 871 } 872 if ( 'undefined' !== typeof wc_add_to_cart_params ) { 873 wc_add_to_cart_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId; 874 } 875 }, 876 }; 877 878})(jQuery); 879 880(function($) { 881 882 $(function() { 883 884 new FLBuilderMenu({ 885 id: '6149bc9f8217c', 886 type: 'horizontal', 887 mobile: 'hamburger', 888 mobileBelowRow: true, 889 mobileFlyout: false, 890 breakPoints: { 891 large: 1200, 892 medium: 992, 893 small: 768 }, 894 mobileBreakpoint: 'medium-mobile', 895 postId : '8', 896 mobileStacked: true, 897 submenuIcon: 'arrows', 898 flyoutWidth: '250', 899 }); 900 901 }); 902 903})(jQuery); 904jQuery(function($) { 905 906 $(function() { 907 $( '.fl-node-6149bd7fd9f1e .fl-photo-img' ) 908 .on( 'mouseenter', function( e ) { 909 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 910 } ) 911 .on( 'mouseleave', function( e ){ 912 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 913 } ); 914 }); 915 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 916}); 917(function($){ 918 })(jQuery); 919jQuery(function($) { 920 921 $(function() { 922 $( '.fl-node-61659e1ecf2b5 .fl-photo-img' ) 923 .on( 'mouseenter', function( e ) { 924 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 925 } ) 926 .on( 'mouseleave', function( e ){ 927 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 928 } ); 929 }); 930 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 931}); 932jQuery(function($) { 933 934 $(function() { 935 $( '.fl-node-61659ebeca178 .fl-photo-img' ) 936 .on( 'mouseenter', function( e ) { 937 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 938 } ) 939 .on( 'mouseleave', function( e ){ 940 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 941 } ); 942 }); 943 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 944}); 945 946(function($) { 947 948 $(function() { 949 950 new FLBuilderMenu({ 951 id: '61659ebeca17a', 952 type: 'horizontal', 953 mobile: 'hamburger', 954 mobileBelowRow: false, 955 mobileFlyout: true, 956 breakPoints: { 957 large: 1200, 958 medium: 992, 959 small: 768 }, 960 mobileBreakpoint: 'medium-mobile', 961 postId : '8', 962 mobileStacked: true, 963 submenuIcon: 'arrows', 964 flyoutWidth: '250', 965 }); 966 967 }); 968 969})(jQuery); 970(function($){ 971 })(jQuery); 972 973(function($) { 974 975 $(function() { 976 977 new FLBuilderMenu({ 978 id: '61659ede4860b', 979 type: 'horizontal', 980 mobile: 'hamburger', 981 mobileBelowRow: false, 982 mobileFlyout: true, 983 breakPoints: { 984 large: 1200, 985 medium: 992, 986 small: 768 }, 987 mobileBreakpoint: 'medium-mobile', 988 postId : '8', 989 mobileStacked: true, 990 submenuIcon: 'arrows', 991 flyoutWidth: '250', 992 }); 993 994 }); 995 996})(jQuery); 997 998/* Start Layout Custom JS */ 999 1000/* End Layout Custom JS */ 1001 1002(function($){ 1003 1004 /** 1005 * Helper class for header layout logic. 1006 * 1007 * @since 1.0 1008 * @class FLThemeBuilderHeaderLayout 1009 */ 1010 FLThemeBuilderHeaderLayout = { 1011 1012 /** 1013 * A reference to the window object for this page. 1014 * 1015 * @since 1.0 1016 * @property {Object} win 1017 */ 1018 win : null, 1019 1020 /** 1021 * A reference to the body object for this page. 1022 * 1023 * @since 1.0 1024 * @property {Object} body 1025 */ 1026 body : null, 1027 1028 /** 1029 * A reference to the header object for this page. 1030 * 1031 * @since 1.0 1032 * @property {Object} header 1033 */ 1034 header : null, 1035 1036 /** 1037 * Whether this header overlays the content or not. 1038 * 1039 * @since 1.0 1040 * @property {Boolean} overlay 1041 */ 1042 overlay : false, 1043 1044 /** 1045 * Whether the page has the WP admin bar or not. 1046 * 1047 * @since 1.0 1048 * @property {Boolean} hasAdminBar 1049 */ 1050 hasAdminBar : false, 1051 1052 /** 1053 * Breakpoint for when the sticky header should apply. 1054 * 1055 * @since 1.4 1056 * @property {String} stickyOn 1057 */ 1058 stickyOn: '', 1059 1060 /** 1061 * A reference of the sticky and shrink header breakpoint. 1062 * 1063 * @since 1.2.5 1064 * @property {Number} breakpointWidth 1065 */ 1066 breakpointWidth: 0, 1067 1068 /** 1069 * Whether this header can be pinned from page load. 1070 * 1071 * @since 1.6.1 1072 * @property {Boolean} pinnable 1073 */ 1074 pinnable : false, 1075 1076 /** 1077 * Initializes header layout logic. 1078 * 1079 * @since 1.0 1080 * @method init 1081 */ 1082 init: function() 1083 {
1084 var editing = $( 'html.fl-builder-edit' ).length, 1085 header = $( '.fl-builder-content[data-type=header]' ), 1086 menuModule = header.find( '.fl-module-menu' ), 1087 breakpoint = null, 1088 adminBarHeight = 0; 1089 1090 if ( ! editing && header.length ) { 1091 1092 header.imagesLoaded( $.proxy( function() { 1093 1094 this.win = $( window ); 1095 this.body = $( 'body' ); 1096 this.header = header.eq( 0 ); 1097 this.overlay = !! Number( header.attr( 'data-overlay' ) ); 1098 this.hasAdminBar = !! $( 'body.admin-bar' ).length; 1099 this.stickyOn = this.header.data( 'sticky-on' ); 1100 breakpoint = this.header.data( 'sticky-breakpoint' ); 1101 1102 if ( '' == this.stickyOn ) { 1103 if ( typeof FLBuilderLayoutConfig.breakpoints[ breakpoint ] !== undefined ) { 1104 this.breakpointWidth = FLBuilderLayoutConfig.breakpoints[ breakpoint ]; 1105 } 1106 else { 1107 this.breakpointWidth = FLBuilderLayoutConfig.breakpoints.medium; 1108 } 1109 } 1110 1111 if ( Number( header.attr( 'data-sticky' ) ) ) { 1112 1113 this.header.data( 'original-top', this.header.offset().top ); 1114 1115 // The pin decision is made once here, while the header offset and the admin bar height are read from the same layout. 1116 adminBarHeight = $( '#wpadminbar' ).length ? $( '#wpadminbar' ).outerHeight() : 0; 1117 this.pinnable = this.overlay && this.header.data( 'original-top' ) <= adminBarHeight; 1118 1119 this.win.on( 'resize', $.throttle( 500, $.proxy( this._initSticky, this ) ) ); 1120 this._initSticky(); 1121 1122 } 1123 1124 }, this ) ); 1125 } 1126 }, 1127 1128 /** 1129 * Initializes sticky logic for a header. 1130 * 1131 * @since 1.0 1132 * @access private 1133 * @method _initSticky 1134 */ 1135 _initSticky: function( e ) 1136 { 1137 var header = $('.fl-builder-content[data-type=header]'), 1138 windowSize = this.win.width(), 1139 makeSticky = false; 1140 1141 makeSticky = this._makeWindowSticky( windowSize ); 1142 if ( makeSticky || ( this.breakpointWidth > 0 && windowSize >= this.breakpointWidth ) ) { 1143 this.win.on( 'scroll.fl-theme-builder-header-sticky', $.proxy( this._doSticky, this ) ); 1144 this._initPin(); 1145
1146 // Apply the sticky state on initial load when the page is 1147 // already scrolled past the header â e.g. when the browser 1148 // restores the scroll position on refresh. Overlay headers are 1149 // out of scope here; this mirrors the shrink-on-load behavior 1150 // in _initShrink(). 1151 if ( ! e && ! this.overlay && ! this.header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 1152 var loadWinTop = this.win.scrollTop(), 1153 loadHeaderTop = Math.floor( this.header.data( 'original-top' ) ); 1154 1155 if ( this.hasAdminBar && windowSize > 600 ) { 1156 loadWinTop += Math.floor( $( '#wpadminbar' ).outerHeight() ); 1157 } 1158 1159 if ( loadWinTop > loadHeaderTop ) { 1160 this.header.addClass( 'fl-theme-builder-header-sticky' ); 1161 this.header.addClass( 'fl-theme-builder-header-scrolled' ); 1162 this._adjustHeaderHeight(); 1163 this._adjustStickyHeaderWidth(); 1164 } 1165 } 1166 1167 // 1168 // Check if Event Type is 'resize' then invoke this._doSticky() 1169 // only if the 'fl-theme-builder-header-sticky' class is already present. 1170 // 1171 if ( e && 'resize' === e.type ) { 1172 if ( this.header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 1173 this._doSticky( e ); 1174 } 1175 this._adjustStickyHeaderWidth(); 1176 } 1177 1178 if ( Number( header.attr( 'data-shrink' ) ) ) { 1179 this.header.data( 'original-height', this.header.outerHeight() ); 1180 this.win.on( 'resize', $.throttle( 500, $.proxy( this._initShrink, this ) ) ); 1181 this._initShrink(); 1182 } 1183 1184 this._initFlyoutMenuFix( e ); 1185 } else { 1186 this.win.off( 'scroll.fl-theme-builder-header-sticky' ); 1187 this.win.off( 'resize.fl-theme-builder-header-sticky' ); 1188 1189 this.header.removeClass( 'fl-theme-builder-header-sticky' ); 1190 this.header.removeClass( 'fl-theme-builder-header-pinned' ); 1191 this.header.removeAttr( 'style' ); 1192 this.header.parent().css( 'padding-top', '0' ); 1193 } 1194 }, 1195 1196 /** 1197 * Pins an overlay header with fixed positioning from page load, avoiding a position change that a scroll handler cannot apply before the compositor paints. 1198 * 1199 * @since 1.6.1 1200 * @access private 1201 * @method _initPin 1202 */ 1203 _initPin: function() 1204 { 1205 this.header.toggleClass( 'fl-theme-builder-header-pinned', this.pinnable ); 1206 1207 if ( ! this.pinnable ) { 1208 return; 1209 } 1210 1211 // Fixed positioning resolves the width against the viewport, so boxed layouts require their maximum width immediately. 1212 this._adjustStickyHeaderWidth(); 1213 1214 // The header is visible from the first paint, so the scrolled state must reflect any restored scroll position. 1215 if ( this.win.scrollTop() > Math.floor( this.header.data( 'original-top' ) ) ) { 1216 this.header.addClass( 'fl-theme-builder-header-scrolled' ); 1217 } 1218 }, 1219 1220 /** 1221 * Check if Header should be sticky at a particular Window size. 1222 * 1223 * @since 1.4 1224 * @access private 1225 * @param widowSize 1226 * @method _makeWindowSticky 1227 */ 1228 _makeWindowSticky: function ( windowSize ) 1229 { 1230 var makeSticky = false; 1231 1232 switch (this.stickyOn) { 1233 case 'xl': 1234 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['large']; 1235 break; 1236 case '': // Default 1237 case 'desktop': 1238 makeSticky = windowSize >= FLBuilderLayoutConfig.breakpoints['medium']; 1239 break; 1240 case 'desktop-medium': 1241 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small']; 1242 break; 1243 case 'large': 1244 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['medium'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large']; 1245 break; 1246 case 'large-medium': 1247 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large']; 1248 break; 1249 case 'medium': 1250 makeSticky = ( windowSize <= FLBuilderLayoutConfig.breakpoints['medium'] && windowSize > FLBuilderLayoutConfig.breakpoints['small'] ); 1251 break; 1252 case 'medium-mobile': 1253 makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['medium']); 1254 break; 1255 case 'mobile': 1256 makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['small']); 1257 break; 1258 case 'all':
1259 makeSticky = true; 1260 break; 1261 } 1262 1263 return makeSticky; 1264 }, 1265 1266 /** 1267 * Sticks the header when the page is scrolled. 1268 * 1269 * @since 1.0 1270 * @access private 1271 * @method _doSticky 1272 */ 1273 _doSticky: function( e ) 1274 { 1275 var winTop = Math.floor( this.win.scrollTop() ), 1276 headerTop = Math.floor( this.header.data( 'original-top' ) ), 1277 hasStickyClass = this.header.hasClass( 'fl-theme-builder-header-sticky' ), 1278 hasScrolledClass = this.header.hasClass( 'fl-theme-builder-header-scrolled' ), 1279 beforeHeader = this.header.prevAll( '.fl-builder-content' ), 1280 bodyTopPadding = parseInt( jQuery('body').css('padding-top') ), 1281 winBarHeight = $('#wpadminbar').length ? $('#wpadminbar').outerHeight() : 0, 1282 headerHeight = 0; 1283 1284 if ( isNaN( bodyTopPadding ) ) { 1285 bodyTopPadding = 0; 1286 } 1287 1288 if ( this.hasAdminBar && this.win.width() > 600 ) { 1289 winTop += Math.floor( winBarHeight ); 1290 } 1291 1292 if ( winTop > headerTop ) { 1293 if ( ! hasStickyClass ) { 1294 if ( e && ( 'scroll' === e.type || 'smartscroll' === e.type ) ) { 1295 this.header.addClass( 'fl-theme-builder-header-sticky' ); 1296 if ( this.overlay && beforeHeader.length ) { 1297 this.header.css( 'top', winBarHeight); 1298 } 1299 } 1300 1301 if ( ! this.overlay ) { 1302 this._adjustHeaderHeight(); 1303 } 1304 } 1305 } 1306 else if ( hasStickyClass ) { 1307 this.header.removeClass( 'fl-theme-builder-header-sticky' ); 1308 this.header.removeAttr( 'style' ); 1309 this.header.parent().css( 'padding-top', '0' ); 1310 } 1311 1312 this._adjustStickyHeaderWidth(); 1313 1314 if ( winTop > headerTop ) { 1315 if ( ! hasScrolledClass ) { 1316 this.header.addClass( 'fl-theme-builder-header-scrolled' ); 1317 } 1318 } else if ( hasScrolledClass ) { 1319 this.header.removeClass( 'fl-theme-builder-header-scrolled' ); 1320 } 1321 1322 this._flyoutMenuFix( e ); 1323 }, 1324 1325 /** 1326 * Initializes flyout menu fixes on sticky header. 1327 * 1328 * @since 1.4.1 1329 * @method _initFlyoutMenuFix 1330 */ 1331 _initFlyoutMenuFix: function( e ) { 1332 var header = this.header, 1333 menuModule = header.closest( '.fl-menu' ), 1334 flyoutMenu = menuModule.find( '.fl-menu-mobile-flyout' ), 1335 isPushMenu = menuModule.hasClass( 'fl-menu-responsive-flyout-push' ) || menuModule.hasClass( 'fl-menu-responsive-flyout-push-opacity' ), 1336 isOverlay = menuModule.hasClass( 'fl-menu-responsive-flyout-overlay' ), 1337 flyoutPos = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 1338 flyoutParent = header.parent().is( 'header' ) ? header.parent().parent() : header.parent(); 1339 isFullWidth = this.win.width() === header.width(), 1340 flyoutLayout = '', 1341 activePos = 250, 1342 headerPos = 0; 1343 1344 if ( ! flyoutMenu.length ) { 1345 return; 1346 } 1347 1348 if ( this.win.width() > header.parent().width() ) { 1349 headerPos = ( this.win.width() - header.width() ) / 2; 1350 } 1351 1352 if ( isOverlay ) { 1353 activePos = headerPos; 1354 } 1355 else if ( isPushMenu ) { 1356 activePos = activePos + headerPos; 1357 } 1358 flyoutMenu.data( 'activePos', activePos ); 1359 1360 if ( isPushMenu ) { 1361 flyoutLayout = 'push-' + flyoutPos; 1362 } 1363 else if ( isOverlay ) { 1364 flyoutLayout = 'overlay-' + flyoutPos; 1365 } 1366 1367 if ( isPushMenu && ! $( 'html' ).hasClass( 'fl-theme-builder-has-flyout-menu' ) ) { 1368 $( 'html' ).addClass( 'fl-theme-builder-has-flyout-menu' ); 1369 } 1370 1371 if ( ! flyoutParent.hasClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout ) ) { 1372 flyoutParent.addClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout ); 1373 } 1374 1375 if ( ! header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && isOverlay ) { 1376 header.addClass( 'fl-theme-builder-flyout-menu-overlay' ); 1377 } 1378 1379 if ( ! header.hasClass( 'fl-theme-builder-header-full-width' ) && isFullWidth ) { 1380 header.addClass( 'fl-theme-builder-header-full-width' ); 1381 } 1382 else if ( ! isFullWidth ) { 1383 header.removeClass( 'fl-theme-builder-header-full-width' ); 1384 } 1385 1386 menuModule.on( 'click', '.fl-menu-mobile-toggle', $.proxy( function( event ){ 1387 if ( menuModule.find( '.fl-menu-mobile-toggle.fl-active' ).length ) {
1388 $( 'html' ).addClass( 'fl-theme-builder-flyout-menu-active' ); 1389 event.stopImmediatePropagation(); 1390 } 1391 else { 1392 $( 'html' ).removeClass( 'fl-theme-builder-flyout-menu-active' ); 1393 } 1394 1395 this._flyoutMenuFix( event ); 1396 }, this ) ); 1397 }, 1398 1399 /** 1400 * Fix flyout menu inside the sticky header. 1401 * 1402 * @since 1.4.1 1403 * @method _flyoutMenuFix 1404 */ 1405 _flyoutMenuFix: function( e ){ 1406 var header = this.header, 1407 menuModule = $( e.target ).closest( '.fl-menu' ), 1408 flyoutMenu = menuModule.find( '.fl-menu-mobile-flyout' ), 1409 flyoutPos = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 1410 menuOpacity = menuModule.find( '.fl-menu-mobile-opacity' ), 1411 isScroll = 'undefined' !== typeof e && 'scroll' === e.handleObj.type, 1412 activePos = 'undefined' !== typeof flyoutMenu.data( 'activePos' ) ? flyoutMenu.data( 'activePos' ) : 0, 1413 headerPos = ( this.win.width() - header.width() ) / 2, 1414 inactivePos = headerPos > 0 ? activePos + 4 : 254; 1415 1416 if ( ! flyoutMenu.length ) { 1417 return; 1418 } 1419 1420 if ( this.overlay ) { 1421 return; 1422 } 1423 1424 if( $( '.fl-theme-builder-flyout-menu-active' ).length ) { 1425 1426 if ( isScroll && ! flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) { 1427 flyoutMenu.addClass( 'fl-menu-disable-transition' ); 1428 } 1429 1430 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 1431 if ( ! isScroll ) { 1432 setTimeout( $.proxy( function(){ 1433 flyoutMenu.css( flyoutPos, '-' + activePos + 'px' ); 1434 }, this ), 1 ); 1435 } 1436 else { 1437 flyoutMenu.css( flyoutPos, '-' + activePos + 'px' ); 1438 } 1439 } 1440 else { 1441 flyoutMenu.css( flyoutPos, '0px' ); 1442 } 1443 } 1444 else { 1445 if ( flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) { 1446 flyoutMenu.removeClass( 'fl-menu-disable-transition' ); 1447 } 1448 1449 if ( header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && headerPos > 0 && headerPos < 250 ) { 1450 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 1451 inactivePos = headerPos + 254; 1452 } 1453 else { 1454 inactivePos = 254; 1455 } 1456 } 1457 1458 if ( e && e.type === 'resize' ) { 1459 inactivePos = headerPos + 254; 1460 } 1461 1462 flyoutMenu.css( flyoutPos, '-' + inactivePos + 'px' ); 1463 } 1464 1465 if ( e && menuModule.is('.fl-menu-responsive-flyout-overlay') && $.infinitescroll ) { 1466 e.stopImmediatePropagation(); 1467 } 1468 1469 if( menuOpacity.length ) { 1470 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 1471 if ( '0px' === menuOpacity.css( 'left' ) ) { 1472 menuOpacity.css( 'left', '-' + headerPos + 'px' ); 1473 } 1474 } 1475 else { 1476 menuOpacity.css( 'left', '' ); 1477 } 1478 } 1479 }, 1480 1481 /** 1482 * Adjust sticky header width if BB Theme Boxed Layout is used. 1483 * 1484 * @since 1.4 1485 * @access private 1486 * @method _adjustStickyHeaderWidth 1487 */ 1488 _adjustStickyHeaderWidth: function () { 1489 if ( $('body').hasClass( 'fl-fixed-width' ) ) { 1490 var parentWidth = this.header.parent().width(); 1491 1492 // Better if this is set in the stylesheet file. 1493 if ( this.win.width() >= 992 ) { 1494 this.header.css({ 1495 'margin': '0 auto', 1496 'max-width': parentWidth, 1497 }); 1498 } 1499 else { 1500 this.header.css({ 1501 'margin': '', 1502 'max-width': '', 1503 }); 1504 } 1505 } 1506 }, 1507 1508 /** 1509 * Adjust Sticky Header Height 1510 * 1511 * @since 1.4 1512 * @access private 1513 * @method _adjustHeaderHeight 1514 */ 1515 _adjustHeaderHeight: function () { 1516 var beforeHeader = this.header.prevAll('.fl-builder-content'), 1517 beforeHeaderHeight = 0, 1518 beforeHeaderFix = 0, 1519 headerHeight = Math.floor( this.header.outerHeight() ), 1520 bodyTopPadding = parseInt( $( 'body' ).css( 'padding-top' ) ), 1521 wpAdminBarHeight = 0, 1522 totalHeaderHeight = 0; 1523 1524 if ( isNaN( bodyTopPadding ) ) { 1525 bodyTopPadding = 0; 1526 } 1527 1528 if ( beforeHeader.length ) { 1529 $.each( beforeHeader, function() { 1530 beforeHeaderHeight += Math.floor( $(this).outerHeight() ); 1531 }); 1532 // Subtract this value from the header parent's top padding. 1533 beforeHeaderFix = 2; 1534 } 1535 1536 if ( this.hasAdminBar && this.win.width() <= 600 ) { 1537 wpAdminBarHeight = Math.floor( $('#wpadminbar').outerHeight() ); 1538 } 1539 1540 totalHeaderHeight = Math.floor( beforeHeaderHeight + headerHeight); 1541 1542 if ( headerHeight > 0 ) { 1543 var headerParent = this.header.parent(), 1544 headerParentTopPadding = 0; 1545 1546 // If the header's parent container is the BODY tag ignore its top padding. 1547 if ( $( headerParent ).is('body') ) { 1548 headerParentTopPadding = Math.floor( headerHeight - wpAdminBarHeight ); 1549 } else { 1550 headerParentTopPadding = Math.floor( headerHeight - bodyTopPadding - wpAdminBarHeight ); 1551 } 1552 1553 $( headerParent ).css( 'padding-top', ( headerParentTopPadding - beforeHeaderFix ) + 'px' ); 1554 1555 this.header.css({ 1556 '-webkit-transform': 'translate(0px, -' + totalHeaderHeight + 'px)', 1557 '-ms-transform': 'translate(0px, -' + totalHeaderHeight + 'px)', 1558 'transform': 'translate(0px, -' + totalHeaderHeight + 'px)' 1559 }); 1560 1561 } 1562 1563 }, 1564 1565 /** 1566 * Initializes shrink logic for a header. 1567 * 1568 * @since 1.0 1569 * @access private 1570 * @method _initShrink 1571 */ 1572 _initShrink: function( e ) 1573 { 1574 if ( this.win.width() >= this.breakpointWidth ) {
1575 this.win.on( 'scroll.fl-theme-builder-header-shrink', $.proxy( this._doShrink, this ) ); 1576 this._setImageMaxHeight(); 1577 1578 if ( this.win.scrollTop() > 0 ){ 1579 this._doShrink(); 1580 } 1581 1582 } else { 1583 this.header.parent().css( 'padding-top', '0' ); 1584 this.win.off( 'scroll.fl-theme-builder-header-shrink' ); 1585 this._removeShrink(); 1586 this._removeImageMaxHeight(); 1587 } 1588 }, 1589 1590 /** 1591 * Shrinks the header when the page is scrolled. 1592 * 1593 * @since 1.0 1594 * @access private 1595 * @method _doShrink 1596 */ 1597 _doShrink: function( e ) 1598 { 1599 var winTop = this.win.scrollTop(), 1600 headerTop = this.header.data('original-top'), 1601 headerHeight = this.header.data('original-height'), 1602 shrinkImageHeight = this.header.data('shrink-image-height'), 1603 windowSize = this.win.width(), 1604 makeSticky = this._makeWindowSticky( windowSize ), 1605 hasClass = this.header.hasClass( 'fl-theme-builder-header-shrink' ); 1606 1607 1608 if ( this.hasAdminBar ) { 1609 winTop += 32; 1610 } 1611 1612 if ( makeSticky && ( winTop > headerTop + headerHeight ) ) { 1613 if ( ! hasClass ) { 1614 1615 this.header.addClass( 'fl-theme-builder-header-shrink' ); 1616 1617 // Shrink images but don't include lightbox and menu images. 1618 this.header.find('img').each( function( i ) { 1619 var image = $( this ), 1620 maxMegaMenu = image.closest( '.max-mega-menu' ).length, 1621 imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length, 1622 imageInNavMenu = image.closest( 'li.menu-item' ).length; 1623 1624 if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu ) ) { 1625 image.css( 'max-height', shrinkImageHeight ); 1626 } 1627 1628 }); 1629 1630 this.header.find( '.fl-row-content-wrap' ).each( function() { 1631 1632 var row = $( this ); 1633 1634 if ( parseInt( row.css( 'padding-bottom' ) ) > 5 ) { 1635 row.addClass( 'fl-theme-builder-header-shrink-row-bottom' ); 1636 } 1637 1638 if ( parseInt( row.css( 'padding-top' ) ) > 5 ) { 1639 row.addClass( 'fl-theme-builder-header-shrink-row-top' ); 1640 } 1641 } ); 1642 1643 this.header.find( '.fl-module' ).each( function() { 1644 1645 var module = $( this ).find( '.fl-module-content' ).length ? $( this ).find( '.fl-module-content' ) : $( this ); 1646 1647 if ( parseInt( module.css( 'margin-bottom' ) ) > 5 ) { 1648 module.addClass( 'fl-theme-builder-header-shrink-module-bottom' ); 1649 } 1650 1651 if ( parseInt( module.css( 'margin-top' ) ) > 5 ) { 1652 module.addClass( 'fl-theme-builder-header-shrink-module-top' ); 1653 } 1654 } ); 1655 } 1656 } else if (hasClass) { 1657 this.header.find( 'img' ).css( 'max-height', '' ); 1658 this._removeShrink(); 1659 } 1660 1661 // Fixes Shrink header issue with BB Theme when window is scrolled then resized and back. 1662 if ( 'undefined' === typeof( e ) && $('body').hasClass( 'fl-fixed-width' ) ) { 1663 if ( ! this.overlay ) { 1664 this._adjustHeaderHeight(); 1665 } 1666 } 1667 1668 }, 1669 1670 /** 1671 * Removes the header shrink effect. 1672 * 1673 * @since 1.0 1674 * @access private 1675 * @method _removeShrink 1676 */ 1677 _removeShrink: function() 1678 { 1679 var rows = this.header.find( '.fl-row-content-wrap' ), 1680 modules = this.header.find('.fl-module, .fl-module-content'); 1681 1682 rows.removeClass( 'fl-theme-builder-header-shrink-row-bottom' ); 1683 rows.removeClass( 'fl-theme-builder-header-shrink-row-top' ); 1684 modules.removeClass( 'fl-theme-builder-header-shrink-module-bottom' ); 1685 modules.removeClass( 'fl-theme-builder-header-shrink-module-top' ); 1686 this.header.removeClass( 'fl-theme-builder-header-shrink' ); 1687 }, 1688 1689 /** 1690 * Adds max height to images in modules for smooth scrolling. 1691 * 1692 * @since 1.1.1 1693 * @access private 1694 * @method _setImageMaxHeight 1695 */ 1696 _setImageMaxHeight: function() 1697 { 1698 var head = $( 'head' ), 1699 stylesId = 'fl-header-styles-' + this.header.data( 'post-id' ), 1700 styles = '', 1701 images = this.header.find( '.fl-module img' ); 1702 1703 if ( $( '#' + stylesId ).length ) { 1704 return; 1705 } 1706 1707 images.each( function( i ) { 1708 var image = $( this ), 1709 height = image.height(), 1710 node = image.closest( '.fl-module' ).data( 'node' ), 1711 className = 'fl-node-' + node + '-img-' + i, 1712 maxMegaMenu = image.closest( '.max-mega-menu' ).length, 1713 imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length, 1714 imageInNavMenu = image.closest( 'li.menu-item' ).length; 1715 1716 if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu ) ) { 1717 image.addClass( className ); 1718 styles += '.' + className + ' { max-height: ' + ( height ? height : image[0].height ) + 'px }'; 1719 } 1720 1721 } ); 1722
1723 if ( '' !== styles ) { 1724 head.append( '<style id="' + stylesId + '">' + styles + '</style>' ); 1725 } 1726 }, 1727 1728 /** 1729 * Removes max height on images in modules for smooth scrolling. 1730 * 1731 * @since 1.1.1 1732 * @access private 1733 * @method _removeImageMaxHeight 1734 */ 1735 _removeImageMaxHeight: function() 1736 { 1737 $( '#fl-header-styles-' + this.header.data( 'post-id' ) ).remove(); 1738 }, 1739 }; 1740 1741 $( function() { FLThemeBuilderHeaderLayout.init(); } ); 1742 1743})(jQuery); 1744 1745 1746(function($) { 1747 1748 $(function() { 1749 1750 new FLBuilderMenu({ 1751 id: '6180ff203c33f', 1752 type: 'horizontal', 1753 mobile: 'hamburger', 1754 mobileBelowRow: true, 1755 mobileFlyout: false, 1756 breakPoints: { 1757 large: 1200, 1758 medium: 992, 1759 small: 768 }, 1760 mobileBreakpoint: 'medium-mobile', 1761 postId : '19668', 1762 mobileStacked: true, 1763 submenuIcon: 'arrows', 1764 flyoutWidth: '250', 1765 }); 1766 1767 }); 1768 1769})(jQuery); 1770jQuery(function($) { 1771 1772 $(function() { 1773 $( '.fl-node-6180ff203c340 .fl-photo-img' ) 1774 .on( 'mouseenter', function( e ) { 1775 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 1776 } ) 1777 .on( 'mouseleave', function( e ){ 1778 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 1779 } ); 1780 }); 1781 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 1782}); 1783(function($){ 1784 })(jQuery); 1785jQuery(function($) { 1786 1787 $(function() { 1788 $( '.fl-node-6180ff203c346 .fl-photo-img' ) 1789 .on( 'mouseenter', function( e ) { 1790 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 1791 } ) 1792 .on( 'mouseleave', function( e ){ 1793 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 1794 } ); 1795 }); 1796 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 1797}); 1798jQuery(function($) { 1799 1800 $(function() { 1801 $( '.fl-node-6180ff203c34b .fl-photo-img' ) 1802 .on( 'mouseenter', function( e ) { 1803 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 1804 } ) 1805 .on( 'mouseleave', function( e ){ 1806 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 1807 } ); 1808 }); 1809 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 1810}); 1811(function($){ 1812 })(jQuery); 1813 1814;(function($) { 1815 1816 PPAdvancedMenu = function( settings ) { 1817 1818 // set params 1819 this.settingsId = settings.id; 1820 this.nodeClass = '.fl-node-' + settings.id; 1821 this.wrapperClass = this.nodeClass + ' .pp-advanced-menu'; 1822 this.type = settings.type; 1823 this.mobileToggle = settings.mobile; 1824 this.mobileBelowRow = 'below' === settings.menuPosition; 1825 this.breakpoints = settings.breakpoints; 1826 this.mobileBreakpoint = settings.mobileBreakpoint; 1827 this.mediaBreakpoint = settings.mediaBreakpoint; 1828 this.mobileMenuType = settings.mobileMenuType; 1829 this.offCanvasDirection = settings.offCanvasDirection; 1830 this.postId = bb_powerpack.post_id; 1831 this.isBuilderActive = settings.isBuilderActive; 1832 this.currentBrowserWidth = window.innerWidth; 1833 this.fullScreenMenu = null; 1834 this.offCanvasMenu = null; 1835 this.$submenus = null; 1836 1837 // initialize the menu 1838 $( this._initMenu.bind( this ) ); 1839 1840 // check if viewport is resizing 1841 $( window ).on( 'resize', function( e ) { 1842 1843 var width = window.innerWidth; 1844 1845 // if screen width is resized, reload the menu 1846 if( width != this.currentBrowserWidth ) { 1847 1848 this._initMenu(); 1849 this._clickOrHover(); 1850 this.currentBrowserWidth = width; 1851 } 1852 1853 }.bind( this ) ); 1854 1855 $( 'body' ).on( 'click', function( e ) { 1856 if ( 'undefined' !== typeof FLBuilderConfig ){ 1857 return; 1858 } 1859 1860 if ( $( this.wrapperClass ).find( '.pp-advanced-menu-mobile-toggle' ).hasClass( 'pp-active' ) && ( 'expanded' !== this.mobileToggle ) ) { 1861 if ( $( e.target ).parents('.fl-module-pp-advanced-menu').length > 0 ) { 1862 return; 1863 } 1864 if ( $( e.target ).is( 'input' ) && $( e.target ).parents('.pp-advanced-menu').length > 0 ) { 1865 return; 1866 } 1867 if ( $( e.target ).hasClass( 'pp-menu-close-btn' ) ) { 1868 return; 1869 } 1870 $( this.wrapperClass ).find( '.pp-advanced-menu-mobile-toggle' ).trigger( 'click' ); 1871 } 1872 1873 $( this.wrapperClass ).find( '.pp-has-submenu' ).each( function() { 1874 if ( ! $( this ).find( '> .sub-menu' ).is( ':visible' ) ) { 1875 $( this ).removeClass( 'pp-active' ); 1876 } 1877 } ); 1878 $( this.wrapperClass ).find( '.pp-has-submenu' ).removeClass( 'focus' ); 1879 $( this.wrapperClass ).find( '.pp-has-submenu .sub-menu' ).removeClass( 'focus' ); 1880 $( this.wrapperClass ).find( '.pp-has-submenu-container' ).removeClass( 'focus' ); 1881 $( this.wrapperClass ).find( '.pp-menu-toggle' ).attr( 'aria-expanded', false ); 1882 1883 }.bind( this ) ); 1884 1885 // Esc key to close the submenu. 1886 $( document ).on( 'keyup', function( e ) { 1887 if ( 27 == e.which ) { 1888 $( this.wrapperClass ).find( '.pp-has-submenu' ).each( function() { 1889 if ( ! $( this ).find( '> .sub-menu' ).is( ':visible' ) ) { 1890 $( this ).removeClass( 'pp-active' ); 1891 } 1892 } ); 1893 $( this.wrapperClass ).find( '.pp-has-submenu' ).removeClass( 'focus' ); 1894 $( this.wrapperClass ).find( '.pp-has-submenu .sub-menu' ).removeClass( 'focus' ); 1895 $( this.wrapperClass ).find( '.pp-has-submenu-container' ).removeClass( 'focus' ); 1896 $( this.wrapperClass ).find( '.pp-menu-toggle' ).attr( 'aria-expanded', false ); 1897 if ( $( this.wrapperClass ).find( '.pp-menu-toggle.focus' ).is( ':visible' ) ) { 1898 $( this.wrapperClass ).find( '.pp-menu-toggle.focus' ).delay(100).trigger( 'focus' ); 1899 } 1900 } 1901 }.bind( this ) ); 1902 1903 }; 1904 1905 PPAdvancedMenu.prototype = { 1906 nodeClass : '', 1907 wrapperClass : '', 1908 type : '', 1909 breakpoints : {}, 1910 $submenus : null, 1911 fullScreenMenu : null, 1912 offCanvasMenu : null, 1913 1914 /** 1915 * Check if the screen size fits a mobile viewport. 1916 * 1917 * @since 1.6.1 1918 * @return bool 1919 */ 1920 _isMobile: function() { 1921 return window.innerWidth <= this.breakpoints.small ? true : false;
1922 }, 1923 1924 /** 1925 * Check if the screen size fits a medium viewport. 1926 * 1927 * @since 1.10.5 1928 * @return bool 1929 */ 1930 _isMedium: function() { 1931 return window.innerWidth <= this.breakpoints.medium ? true : false; 1932 }, 1933 1934 /** 1935 * Check if the screen size fits a large viewport. 1936 * 1937 * @since 1.10.5 1938 * @return bool 1939 */ 1940 _isLarge: function() { 1941 return window.innerWidth <= this.breakpoints.large ? true : false; 1942 }, 1943 1944 /** 1945 * Check if the screen size fits a custom viewport. 1946 * 1947 * @since 1.10.5 1948 * @return bool 1949 */ 1950 _isCustom: function() { 1951 return window.innerWidth <= this.breakpoints.custom ? true : false; 1952 }, 1953 1954 _isTouch: function() { 1955 var prefixes = ' -webkit- -moz- -o- -ms- '.split(' '); 1956 var mq = function(query) { 1957 return window.matchMedia(query).matches; 1958 } 1959 1960 if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { 1961 return true; 1962 } 1963 1964 // include the 'heartz' as a way to have a non matching MQ to help terminate the join 1965 // https://git.io/vznFH 1966 var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(''); 1967 return mq(query); 1968 }, 1969 1970 _isIOS: function() { 1971 return [ 1972 'iPad Simulator', 1973 'iPhone Simulator', 1974 'iPod Simulator', 1975 'iPad', 1976 'iPhone', 1977 'iPod' 1978 ].includes(navigator.platform) 1979 // This explicitly catches modern iPads mimicking desktop Macs: 1980 || (navigator.userAgent.includes("Mac") && navigator.maxTouchPoints > 1); 1981 }, 1982 1983 /** 1984 * Check if the menu should toggle for the current viewport base on the selected breakpoint 1985 * 1986 * @see this._isMobile() 1987 * @see this._isMedium() 1988 * @since 1.10.5 1989 * @return bool 1990 */ 1991 _isMenuToggle: function() { 1992 if ( ( 'always' == this.mobileBreakpoint 1993 || ( this._isMobile() && 'mobile' == this.mobileBreakpoint ) 1994 || ( this._isMedium() && 'medium-mobile' == this.mobileBreakpoint ) 1995 || ( this._isCustom() && 'custom' == this.mobileBreakpoint ) 1996 ) && ( $( this.nodeClass ).find( '.pp-advanced-menu-mobile-toggle' ).is(':visible') || 'expanded' == this.mobileToggle ) ) { 1997 return true; 1998 } 1999 2000 return false; 2001 }, 2002 2003 _bindSettingsFormEvents: function() 2004 { 2005 // $('body').on( 'change', '.fl-builder-settings select[name="offcanvas_direction"]', function() { 2006 // $('html').removeClass('pp-off-canvas-menu-open'); 2007 // } ); 2008 }, 2009 2010 /** 2011 * Initialize the toggle logic for the menu. 2012 * 2013 * @see this._isMobile() 2014 * @see this._menuOnCLick() 2015 * @see this._clickOrHover() 2016 * @see this._submenuOnRight() 2017 * @see this._submenuRowZindexFix() 2018 * @see this._toggleForMobile() 2019 * @since 1.6.1 2020 * @return void 2021 */ 2022 _initMenu: function() { 2023 if ( this.mobileToggle != 'expanded' ) { 2024 this._initOffCanvas(); 2025 this._initFullScreen(); 2026 } 2027 2028 this._setupSubmenu(); 2029 this._menuOnHover(); 2030 this._menuOnFocus(); 2031 this._submenuOnClick(); 2032 2033 if ( $( this.nodeClass ).length && this.type == 'horizontal' ) { 2034 this._initMegaMenus(); 2035 } 2036 2037 if ( this.type == 'horizontal' || this.type == 'vertical' ) { 2038 var self = this; 2039 $( this.wrapperClass ).find('.pp-has-submenu-container').on( 'click', function( e ) { 2040 if ( self.mobileMenuType !== 'off-canvas' && self.mobileMenuType !== 'full-screen' ) { 2041 if ( self._isTouch() ) { 2042 if ( ! $(this).hasClass('first-click') ) { 2043 e.preventDefault(); 2044 $(this).addClass('first-click'); 2045 } 2046 } 2047 } 2048 } ); 2049 2050 // Keyboard nav support for submenu toggle. 2051 $( this.wrapperClass ).on( 'keydown.pp-menu', 'a, .pp-has-submenu-container > .pp-menu-toggle', function(e) { 2052 var $current = $(e.target); 2053 2054 var key = e.key || e.which; 2055 2056 // Normalize keys 2057 var KEYS = { 2058 LEFT: 'ArrowLeft', 2059 RIGHT: 'ArrowRight', 2060 UP: 'ArrowUp', 2061 DOWN: 'ArrowDown', 2062 ENTER: 'Enter', 2063 SPACE: ' ', 2064 }; 2065 2066 function isKey(match) { 2067 return key === match || key === { 2068 ArrowLeft: 37, 2069 ArrowUp: 38, 2070 ArrowRight: 39, 2071 ArrowDown: 40, 2072 Enter: 13, 2073 ' ': 32 2074 }[match]; 2075 } 2076 2077 var $item = $current.closest('li'); 2078 var $parentItem = $current.closest('li.pp-has-submenu'); 2079 var $submenu = $current.closest('ul.sub-menu'); 2080 var isTopLevel = $current.closest('.sub-menu').length === 0; 2081 2082 /* ========================= 2083 TOGGLE HANDLING 2084 ========================= */ 2085 2086 function toggleSubmenu($el) { 2087 var $li = $el.closest('li.pp-has-submenu'); 2088 var $btn = $li.find('> .pp-has-submenu-container > .pp-menu-toggle'); 2089 2090 $li.toggleClass('pp-active'); 2091 2092 var isOpen = $li.hasClass('pp-active'); 2093 2094 if ($btn.length) { 2095 $btn.attr('aria-expanded', isOpen); 2096 } 2097 } 2098 2099 // Button toggle 2100 if ($current.hasClass('pp-menu-toggle')) { 2101 if (isKey(KEYS.ENTER) || isKey(KEYS.SPACE)) { 2102 e.preventDefault(); 2103 e.stopPropagation(); 2104 toggleSubmenu($current); 2105 return; 2106 } 2107 } 2108 2109 /* ========================= 2110 TOP LEVEL NAV (â â) 2111 ========================= */ 2112 2113 if (isTopLevel && (isKey(KEYS.LEFT) || isKey(KEYS.RIGHT))) { 2114 e.preventDefault(); 2115 e.stopPropagation(); 2116 2117 if (isKey(KEYS.LEFT)) { 2118 if ( $current.is( '.pp-menu-toggle' ) ) { 2119 $current.prev('a').focus(); 2120 } else { 2121 var $prev = $item.prev(); 2122 if ($prev.length) { 2123 var $target = $prev.find('> .pp-has-submenu-container > .pp-menu-toggle:visible'); 2124 ($target.length ? $target : $prev.find('a')).first().focus(); 2125 } 2126 } 2127 } 2128 2129 if (isKey(KEYS.RIGHT)) { 2130 if ( $current.next().is( '.pp-menu-toggle:visible' ) ) { 2131 $current.next().focus(); 2132 } else { 2133 var $next = $item.next(); 2134 if ($next.length) { 2135 $next.find('a').first().focus(); 2136 } 2137 } 2138 } 2139 2140 return; 2141 } 2142 2143 // NESTED submenu navigation (LEFT / RIGHT) 2144 if (!isTopLevel && (isKey(KEYS.RIGHT) || isKey(KEYS.LEFT))) { 2145 2146 var $parentItem = $current.closest('li.pp-has-submenu'); 2147 2148 // RIGHT â go into child submenu 2149 if (isKey(KEYS.RIGHT)) { 2150 var $childSubmenu = $parentItem.children('.sub-menu'); 2151 2152 if ($childSubmenu.length) { 2153 e.preventDefault(); 2154 e.stopPropagation(); 2155 2156 // Ensure open state 2157 $parentItem.addClass('pp-active'); 2158 2159 var $toggle = $parentItem.find('> .pp-has-submenu-container > .pp-menu-toggle:visible'); 2160 if ($toggle.length) { 2161 $toggle.attr('aria-expanded', true); 2162 } else { 2163 $parentItem.find('> .pp-has-submenu-container > a').attr('aria-expanded', true); 2164 } 2165 2166 // Focus first item in child submenu 2167 $childSubmenu.find('a, .pp-menu-toggle:visible').first().focus(); 2168 } 2169 return; 2170 } 2171 2172 // LEFT â go back to parent menu item 2173 if (isKey(KEYS.LEFT)) { 2174 var $currentSubmenu = $current.closest('ul.sub-menu'); 2175 var $parentItem = $currentSubmenu.parent('li'); 2176 2177 if ($parentItem.length) { 2178 e.preventDefault(); 2179 e.stopPropagation(); 2180 2181 // CLOSE submenu 2182 $parentItem.removeClass('pp-active'); 2183 2184 var $toggle = $parentItem.find('> .pp-has-submenu-container > .pp-menu-toggle:visible'); 2185 2186 if ($toggle.length) { 2187 $toggle.attr('aria-expanded', false); 2188 $toggle.focus(); 2189 } else { 2190 $parentItem.find('> .pp-has-submenu-container > a').attr('aria-expanded', false).focus(); 2191 } 2192 } 2193 return; 2194 } 2195 } 2196 2197 /* ========================= 2198 SUBMENU NAV (â â) 2199 ========================= */ 2200 2201 // DOWN from toggle â first submenu item 2202 if (isKey(KEYS.DOWN) && isTopLevel && $parentItem.length) { 2203 e.preventDefault(); 2204 e.stopPropagation(); 2205 2206 var $submenu = $parentItem.children('.sub-menu'); 2207 2208 if ($submenu.length) { 2209 // ensure open state 2210 if (!$parentItem.hasClass('pp-active')) { 2211 $parentItem.addClass('pp-active'); 2212 2213 var $toggle = $parentItem.find('> .pp-has-submenu-container > .pp-menu-toggle:visible'); 2214 if ($toggle.length) { 2215 $toggle.attr('aria-expanded', true); 2216 } else { 2217 $parentItem.find('> .pp-has-submenu-container > a').attr('aria-expanded', true); 2218 } 2219 } 2220 2221 // move focus into submenu 2222 $submenu.find('a, .pp-menu-toggle:visible').first().focus(); 2223 } 2224 2225 return; 2226 } 2227 2228 if (!$submenu.length) { 2229 return; 2230 } 2231 2232 var $items = $submenu.find('a, .pp-menu-toggle').filter(':visible'); 2233 var index = $items.index($current); 2234 2235 if (index === -1) return; 2236 2237 // DOWN â 2238 if (isKey(KEYS.DOWN)) { 2239 e.preventDefault(); 2240 e.stopPropagation(); 2241 2242 var next = index + 1; 2243 if (next < $items.length) { 2244 $items.eq(next).focus(); 2245 } 2246 return; 2247 } 2248 2249 // UP â 2250 if (isKey(KEYS.UP)) { 2251 e.preventDefault(); 2252 e.stopPropagation(); 2253 2254 if (index === 0 && ! $current.closest('.sub-menu').parents('.sub-menu').length) { 2255 var $currentSubmenu = $current.closest('ul.sub-menu'); 2256 var $parentItem = $currentSubmenu.parent('li'); 2257 var $toggle = $parentItem.find('> .pp-has-submenu-container > .pp-menu-toggle:visible'); 2258 if ($toggle.length) { 2259 $toggle.focus(); 2260 } else { 2261 $parentItem.find('> .pp-has-submenu-container > a').focus(); 2262 } 2263 return; 2264 } 2265 2266 // Don't loop back to the last item if we're on the first item of a submenu 2267 if ( index === 0 ) { 2268 $items.eq(index).focus(); 2269 return; 2270 } 2271 2272 $items.eq(index - 1).focus(); 2273 return; 2274 } 2275 2276 }.bind( this ) ); 2277 } 2278 2279 if ( this._isMenuToggle() || this.type == 'accordion' ) { 2280 $( this.wrapperClass ).off( 'mouseenter mouseleave' ); 2281 this._menuOnClick(); 2282 this._clickOrHover(); 2283 } else { 2284 $( this.wrapperClass ).off( 'click' ); 2285 this._submenuOnRight(); 2286 this._submenuRowZindexFix(); 2287 } 2288 2289 if ( this.mobileToggle != 'expanded' ) { 2290 this._toggleForMobile(); 2291 } 2292 2293 $(this.wrapperClass).find('li:not(.menu-item-has-children)').on('click', 'a', function (e) { 2294 if ( $(e.target).closest( '.pp-menu-search-item' ).length > 0 ) { 2295 return; 2296 } 2297 2298 $(this.nodeClass).find('.pp-advanced-menu').removeClass('menu-open'); 2299 $(this.nodeClass).find('.pp-advanced-menu').addClass('menu-close'); 2300 $('html').removeClass('pp-off-canvas-menu-open'); 2301 $('html').removeClass('pp-full-screen-menu-open'); 2302 2303 }.bind( this ) ); 2304 2305 if ( $( this.wrapperClass ).find( '.pp-menu-search-item' ).length ) { 2306 this._toggleMenuSearch(); 2307 } 2308 2309 if ( $( this.wrapperClass ).find( '.pp-menu-cart-item').length ) { 2310 this._wooUpdateParams(); 2311 } 2312 }, 2313 2314 /** 2315 * Initializes submenu dropdowns. 2316 * 2317 * @since 2.33.x 2318 * @return void 2319 */ 2320 _setupSubmenu: function() { 2321 // $( this.wrapperClass + ' ul.sub-menu' ).each( function(){ 2322 // $( this ).closest( 'li' ).attr( 'aria-haspopup', 'true' ); 2323 // }); 2324 }, 2325 2326 _menuOnHover: function() { 2327 $( this.wrapperClass ).on( 'mouseenter', 'li.menu-item', function() { 2328 $(this).addClass( 'hover' ); 2329 } ).on( 'mouseleave', 'li.menu-item', function() { 2330 $(this).removeClass( 'hover' ); 2331 } ); 2332 }, 2333 2334 /** 2335 * Adds a focus class to menu elements similar to be used similar to CSS :hover psuedo event 2336 * 2337 * @since 1.9.0 2338 * @return void 2339 */ 2340 _menuOnFocus: function() { 2341 $( this.nodeClass ).off('focus', 'a').on( 'focus', 'a', function( e ) { 2342 var $menuItem = $( e.target ).parents( '.menu-item' ).first(), 2343 $parents = $( e.target ).parentsUntil( this.wrapperClass ); 2344 2345 $('.pp-advanced-menu .focus:not(.pp-menu-toggle)').removeClass('focus'); 2346 2347 $menuItem.addClass('focus'); 2348 $parents.addClass('focus'); 2349 2350 }.bind( this ) ).on( 'focusout', 'a', function( e ) { 2351 if ( $('.pp-advanced-menu .focus').hasClass('pp-has-submenu') ) { 2352 $( e.target ).parentsUntil( this.wrapperClass ).find('.pp-has-submenu-container').removeClass('first-click'); 2353 } 2354 }.bind( this ) ); 2355 2356 $( this.nodeClass ).off('focus', '.pp-menu-toggle').on( 'focus', '.pp-menu-toggle', function( e ) { 2357 $(e.target).addClass( 'focus' ); 2358 }.bind( this ) ).off('blur', '.pp-menu-toggle').on( 'blur', '.pp-menu-toggle', function( e ) { 2359 if ( $(e.target).parents( 'li.pp-has-submenu.pp-active' ).length === 0 || $(e.target).parents( 'li.pp-has-submenu.pp-active' ).parent( 'ul.menu' ).length === 0 ) { 2360 $(e.target).removeClass( 'focus' ); 2361 } 2362 }.bind( this ) ); 2363 }, 2364 2365 /** 2366 * Logic for submenu toggling on accordions or mobile menus (vertical, horizontal) 2367 * 2368 * @since 1.6.1 2369 * @return void 2370 */ 2371 _menuOnClick: function() { 2372 var self = this; 2373 var $mainItem = ''; 2374 2375 $( this.wrapperClass ) 2376 .off( 'click.pp-advanced-menu keyup', '.pp-has-submenu-container' ) 2377 .on( 'click.pp-advanced-menu keyup', '.pp-has-submenu-container', function( e ) { 2378 var isValidEvent = e.which == 1 || e.which == 13 || e.which == undefined; // click or enter key press. 2379 if ( ! isValidEvent ) { 2380 return; 2381 } 2382 if ( e.which == 13 && ! $(e.target).hasClass( 'pp-menu-toggle' ) ) { // prevent event bubbling. 2383 return; 2384 } 2385 if ( self._isTouch() ) { 2386 if ( ! $(this).hasClass('first-click') ) { 2387 e.preventDefault(); 2388 $(this).addClass('first-click'); 2389 } 2390 } 2391 2392 e.stopPropagation(); 2393 2394 var isMainEl = $(e.target).parents('.menu-item').parent().parent().hasClass('pp-advanced-menu'); 2395 2396 if (isMainEl && $mainItem === '') { 2397 $mainItem = $(e.target).parents('.menu-item'); 2398 } 2399 2400 var $link = $( e.target ).parents( '.pp-has-submenu' ).first(), 2401 $subMenu = $link.children( '.sub-menu' ).first(), 2402 $href = $link.children('.pp-has-submenu-container').first().find('> a').attr('href'), 2403 $subMenuParents = $( e.target ).parents( '.sub-menu' ), 2404 $activeParent = $( e.target ).closest( '.pp-has-submenu.pp-active' ); 2405 2406 if ( $activeParent.length > 0 ) { 2407 $activeParent.find( '.pp-menu-toggle' ).first().attr('aria-expanded', true); 2408 } else { 2409 $activeParent.find( '.pp-menu-toggle' ).first().attr('aria-expanded', false); 2410 } 2411 2412 if( !$subMenu.is(':visible') || $(e.target).hasClass('pp-menu-toggle') 2413 || ($subMenu.is(':visible') && (typeof $href === 'undefined' || $href == '#')) ) { 2414 if ( ! $(this.wrapperClass).hasClass('pp-advanced-menu-accordion-collapse') ) { 2415 e.preventDefault(); 2416 } 2417 if ( $(e.target).hasClass('pp-menu-toggle') ) { 2418 e.stopPropagation(); 2419 e.preventDefault(); 2420 } 2421 } 2422 else { 2423 e.stopPropagation(); 2424 window.location.href = $href; 2425 return; 2426 } 2427 2428 if ($(this.wrapperClass).hasClass('pp-advanced-menu-accordion-collapse')) { 2429 2430 if ( $link.parents('.menu-item').length && !$link.parents('.menu-item').hasClass('pp-active') ) { 2431 $('.menu .pp-active', this.wrapperClass).not($link).removeClass('pp-active'); 2432 } 2433 else if ($link.parents('.menu-item').hasClass('pp-active') && $link.parent('.sub-menu').length) { 2434 $('.menu .pp-active', this.wrapperClass).not($link).not($activeParent).removeClass('pp-active'); 2435 } 2436 2437 $('.sub-menu', this.wrapperClass).not($subMenu).not($subMenuParents).slideUp('normal'); 2438 } 2439 2440 // Parent menu toggle icon was being reversed on collapsing its submenu, 2441 // so here is the workaround to fix this behavior. 2442 if ($(self.wrapperClass).find('.sub-menu:visible').length > 0) { 2443 $(self.wrapperClass).find('.sub-menu:visible').parent().addClass('pp-active'); 2444 } 2445 $subMenu.slideToggle(400, function() { 2446 // Reset previously opened sub-menu toggle icon. 2447 $(e.target).parents('.pp-has-submenu-container').parent().parent().find('> .menu-item.pp-active').removeClass('pp-active'); 2448 2449 if ($mainItem !== '') { 2450 $mainItem.parent().find('.menu-item.pp-active').removeClass('pp-active'); 2451 $(self.wrapperClass).find('.sub-menu').parent().removeClass('pp-active'); 2452 2453 if ($(self.wrapperClass).find('.sub-menu:visible').length > 0) { 2454 $(self.wrapperClass).find('.sub-menu:visible').parent().addClass('pp-active'); 2455 } else { 2456 $link.toggleClass('pp-active'); 2457 $mainItem.removeClass('pp-active'); 2458 } 2459 } else { 2460 $link.toggleClass('pp-active'); 2461 } 2462 if (!$subMenu.is(':visible')) { 2463 $subMenu.parent().removeClass('pp-active'); 2464 $subMenu.parent().find('> .p
2464p-has-submenu-container .pp-menu-toggle').attr('aria-expanded', false); 2465 } else { 2466 $subMenu.parent().find('> .pp-has-submenu-container .pp-menu-toggle').attr('aria-expanded', true); 2467 } 2468 }); 2469 2470 }.bind( this ) ); 2471 2472 }, 2473 2474 /** 2475 * Logic for submenu items click event 2476 * 2477 * @since 1.3.1 2478 * @return void 2479 */ 2480 _submenuOnClick: function(){ 2481 $( 'body' ).off( 'click', this.wrapperClass + ' .sub-menu a' ).on( 'click', this.wrapperClass + ' .sub-menu a', function( e ){ 2482 if ( $( e.target ).parent().hasClass('focus') ) { 2483 $( e.target ).parentsUntil( this.wrapperClass ).removeClass( 'focus' ); 2484 } 2485 }.bind( this ) ); 2486 }, 2487 2488 /** 2489 * Changes general styling and behavior of menus based on mobile / desktop viewport. 2490 * 2491 * @see this._isMobile() 2492 * @since 1.6.1 2493 * @return void 2494 */ 2495 _clickOrHover: function() { 2496 this.$submenus = this.$submenus || $( this.wrapperClass ).find( '.sub-menu' ); 2497 var $wrapper = $( this.wrapperClass ), 2498 $menu = $wrapper.find( '.menu' ); 2499 $li = $wrapper.find( '.pp-has-submenu' ); 2500 2501 if( this._isMenuToggle() ) { 2502 $li.each( function() { 2503 if( !$(this).hasClass('pp-active') ) { 2504 $(this).find( '.sub-menu' ).fadeOut(); 2505 } 2506 } ); 2507 } else { 2508 $li.each( function() { 2509 if( !$(this).hasClass('pp-active') ) { 2510 $(this).find( '.sub-menu' ).css( { 2511 'display' : '', 2512 'opacity' : '' 2513 } ); 2514 } 2515 } ); 2516 } 2517 }, 2518 2519 /** 2520 * Logic to prevent submenus to go outside viewport boundaries. 2521 * 2522 * @since 1.6.1 2523 * @return void 2524 */ 2525 _submenuOnRight: function() { 2526 2527 $( this.wrapperClass ) 2528 .on( 'mouseenter focus', '.pp-has-submenu', function( e ) { 2529 2530 if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) { 2531 return; 2532 } 2533 2534 var $link = $( e.currentTarget ), 2535 $parent = $link.parent(), 2536 $subMenu = $link.find( '.sub-menu' ), 2537 subMenuWidth = $subMenu.width(), 2538 subMenuPos = 0, 2539 winWidth = window.innerWidth; 2540 2541 if( $link.closest( '.pp-menu-submenu-right' ).length !== 0) { 2542 2543 $link.addClass( 'pp-menu-submenu-right' ); 2544 2545 } else if( $( 'body' ).hasClass( 'rtl' ) ) { 2546 2547 subMenuPos = $parent.is( '.sub-menu' ) ? 2548 $parent.offset().left - subMenuWidth: 2549 $link.offset().left - subMenuWidth; 2550 2551 if( subMenuPos <= 0 ) { 2552 $link.addClass( 'pp-menu-submenu-right' ); 2553 } 2554 2555 } else { 2556 2557 subMenuPos = $parent.is( '.sub-menu' ) ? 2558 $parent.offset().left + $parent.width() + subMenuWidth : 2559 $link.offset().left + subMenuWidth; 2560 2561 if( subMenuPos > winWidth ) { 2562 $link.addClass('pp-menu-submenu-right'); 2563 } 2564 } 2565 }.bind( this ) ) 2566 .on( 'mouseleave', '.pp-has-submenu', function( e ) { 2567 $( e.currentTarget ).removeClass( 'pp-menu-submenu-right' ); 2568 }.bind( this ) ); 2569 2570 }, 2571 2572 /** 2573 * Logic to prevent submenus to go behind the next overlay row. 2574 * 2575 * @since 2.2 2576 * @return void 2577 */ 2578 _submenuRowZindexFix: function (e) { 2579 2580 $(this.wrapperClass) 2581 .on('mouseenter', 'ul.menu > .pp-has-submenu', function (e) { 2582 2583 if ($(e.currentTarget).find('.sub-menu').length === 0) { 2584 return; 2585 } 2586 2587 $(this.nodeClass) 2588 .closest('.fl-row') 2589 .find('.fl-row-content') 2590 .css('z-index', '10'); 2591 2592 }.bind( this ) ) 2593 .on('mouseleave', 'ul.menu > .pp-has-submenu', function (e) { 2594 2595 $(this.nodeClass) 2596 .closest('.fl-row') 2597 .find('.fl-row-content') 2598 .css('z-index', ''); 2599 2600 }.bind( this ) ); 2601 }, 2602 2603 /** 2604 * Logic for the mobile menu button. 2605 * 2606 * @since 1.6.1 2607 * @return void 2608 */ 2609 _toggleForMobile: function() { 2610 2611 var $wrapper = null, 2612 $menu = null, 2613 self = this; 2614 2615 if ( this._isMenuToggle() ) { 2616 $wrapper = $(this.wrapperClass); 2617 if ( this._isMobileBelowRowEnabled() ) { 2618 this._placeMobileMenuBelowRow(); 2619 $menu = $(this.nodeClass + '-clone'); 2620 $menu.find('ul.menu').show(); 2621 } else { 2622 $menu = $wrapper.find('.menu'); 2623 } 2624 2625 if( !$wrapper.find( '.pp-advanced-menu-mobile-toggle' ).hasClass( 'pp-active' ) && this.mobileMenuType === 'default' ) { 2626 $menu.css({ display: 'none' }); 2627 } 2628 2629 $wrapper 2630 .off( 'click.pp-mobile-menu-toggle', '.pp-advanced-menu-mobile-toggle' ) 2631 .on( 'click.pp-mobile-menu-toggle', '.pp-advanced-menu-mobile-toggle', function( e ) { 2632 e.stopPropagation(); 2633 $(this).toggleClass( 'pp-active' ); 2634 if ( $(this).hasClass('pp-active') ) { 2635 $(this).attr('aria-expanded', 'true'); 2636 $menu.addClass( 'pp-menu-visible' ); 2637 } else { 2638 $(this).attr('aria-expanded', 'false'); 2639 $menu.removeClass( 'pp-menu-visible' ); 2640 } 2641 $menu.slideToggle(); 2642 } ); 2643 2644 $menu.on( 'click', '.menu-item > a[href*="#"]', function(e) { 2645 var $href = $(this).attr('href'), 2646 $targetID = ''; 2647 2648 if ( $href !== '#' ) { 2649 $targetID = $href.split('#')[1]; 2650 2651 if ( $('body').find('#'+ $targetID).length > 0 ) { 2652 e.preventDefault(); 2653 $( this ).toggleClass( 'pp-active' ); 2654 setTimeout(function() { 2655 $('html, body').animate({ 2656 scrollTop: $('#'+ $targetID).offset().top 2657 }, 1000, function() { 2658 window.location.hash = $targetID; 2659 }); 2660 }, 500); 2661 2662 if ( ! self._isMenuToggle() ) { 2663 $menu.slideToggle(); 2664 } 2665 } 2666 } 2667 }); 2668 } 2669 else { 2670 2671 if ( this._isMobileBelowRowEnabled() ) { 2672 this._removeMenuFromBelowRow(); 2673 } 2674 2675 $wrapper = $( this.wrapperClass ), 2676 $menu = $wrapper.children( '.menu' ); 2677 $wrapper.find( '.pp-advanced-menu-mobile-toggle' ).removeClass( 'pp-active' ); 2678 $menu.css({ display: '' }); 2679 } 2680 }, 2681 2682 /** 2683 * Init any mega menus that exist. 2684 * 2685 * @see this._isMenuToggle() 2686 * @since 1.10.4 2687 * @return void 2688 */ 2689 _initMegaMenus: function() { 2690 2691 var module = $( this.nodeClass ), 2692 rowContent = module.closest( '.fl-row-content' ), 2693 rowWidth = rowContent.width(), 2694 megas = module.find( '.mega-menu' ), 2695 disabled = module.find( '.mega-menu-disabled' ), 2696 isToggle = this._isMenuToggle(); 2697 2698 if ( isToggle ) { 2699 megas.removeClass( 'mega-menu' ).addClass( 'mega-menu-disabled' ); 2700 module.find( 'li.mega-menu-disabled > ul.sub-menu' ).css( 'width', '' ); 2701 rowContent.css( 'position', '' ); 2702 } else { 2703 disabled.removeClass( 'mega-menu-disabled' ).addClass( 'mega-menu' ); 2704 module.find( 'li.mega-menu > ul.sub-menu' ).css( 'width', rowWidth + 'px' ); 2705 rowContent.css( 'position', 'relative' ); 2706 } 2707 }, 2708 2709 /** 2710 * Init off-canvas menu. 2711 * 2712 * @since 1.2.8 2713 * @return void 2714 */ 2715 _initOffCanvas: function() { 2716 if ( this.mobileMenuType !== 'off-canvas' ) { 2717 return; 2718 } 2719 $('html').addClass('pp-off-canvas-menu-module'); 2720 $('html').addClass('pp-off-canvas-menu-' + this.offCanvasDirection); 2721 2722 if ( $(this.nodeClass).find( '#pp-menu-' + this.settingsId ).length === 0 ) { 2723 return; 2724 } 2725 2726 var menuHTML = $(this.nodeClass).find( '#pp-menu-' + this.settingsId ).html(); 2727 2728 if ( null === this.offCanvasMenu ) {
2729 this.offCanvasMenu = $('<div id="pp-advanced-menu-off-canvas-'+this.settingsId+'" class="fl-node-'+this.settingsId+' pp-menu-off-canvas" />').html( menuHTML ); 2730 } 2731 if ( $('#pp-advanced-menu-off-canvas-'+this.settingsId).length === 0 && null !== this.offCanvasMenu && ! this.isBuilderActive ) { 2732 this.offCanvasMenu.appendTo( 'body' ); 2733 } 2734 2735 $(this.nodeClass).trigger('pp-advanced-menu-off-canvas-init', [this.offCanvasMenu]); 2736 2737 this._toggleMenu(); 2738 }, 2739 2740 /** 2741 * Init full-screen overlay menu. 2742 * 2743 * @since 1.2.8 2744 * @return void 2745 */ 2746 _initFullScreen: function() { 2747 if ( this.mobileMenuType !== 'full-screen' ) { 2748 return; 2749 } 2750 2751 $('html').addClass('pp-full-screen-menu-module'); 2752 2753 if ( $(this.nodeClass).find( '#pp-menu-' + this.settingsId ).length === 0 ) { 2754 return; 2755 } 2756 2757 var menuHTML = $(this.nodeClass).find( '#pp-menu-' + this.settingsId ).html(); 2758 2759 if ( null === this.fullScreenMenu ) { 2760 this.fullScreenMenu = $('<div id="pp-advanced-menu-full-screen-'+this.settingsId+'" class="fl-node-'+this.settingsId+' pp-menu-full-screen" />').html( menuHTML ); 2761 } 2762 if ( $('#pp-advanced-menu-full-screen-'+this.settingsId).length === 0 && null !== this.fullScreenMenu && ! this.isBuilderActive ) { 2763 this.fullScreenMenu.appendTo( 'body' ); 2764 } 2765 2766 $(this.nodeClass).trigger('pp-advanced-menu-full-screen-init', [this.fullScreenMenu]); 2767 2768 this._toggleMenu(); 2769 }, 2770 2771 /** 2772 * Trigger the toggle event for off-canvas 2773 * and full-screen overlay menus. 2774 * 2775 * @since 1.2.8 2776 * @return void 2777 */ 2778 _toggleMenu: function() { 2779 var self = this; 2780 var singleInstance = true; 2781 if( self.mobileMenuType === 'full-screen' ) { 2782 var winHeight = window.innerHeight; 2783 $(self.nodeClass).find('.pp-menu-overlay').css('height', winHeight + 'px'); 2784 $(window).on('resize', function() { 2785 winHeight = window.innerHeight; 2786 $(self.nodeClass).find('.pp-menu-overlay').css('height', winHeight + 'px'); 2787 }); 2788 } 2789 2790 // Toggle Click 2791 var toggleEvent = ('ontouchend' in window) && this._isIOS() ? 'touchend' : 'click'; 2792 $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle' ).off(toggleEvent).on( toggleEvent, function() { 2793 if ( singleInstance ) { 2794 if ( $('.pp-advanced-menu.menu-open').length > 0 ) { 2795 $('.pp-advanced-menu').removeClass('menu-open'); 2796 $('html').removeClass('pp-full-screen-menu-open'); 2797 } 2798 } 2799 if( $(self.nodeClass).find('.pp-advanced-menu').hasClass('menu-open') ) { 2800 $(self.nodeClass).find('.pp-advanced-menu').removeClass('menu-open'); 2801 $(self.nodeClass).find('.pp-advanced-menu').addClass('menu-close'); 2802 $('html').removeClass('pp-off-canvas-menu-open'); 2803 $('html').removeClass('pp-full-screen-menu-open'); 2804 } else { 2805 $(self.nodeClass).find('.pp-advanced-menu').addClass('menu-open'); 2806 if( self.mobileMenuType === 'off-canvas' ) { 2807 $('html').addClass('pp-off-canvas-menu-open'); 2808 self.offCanvasMenu.find('nav').attr('tabindex', '0').trigger( 'focus' ); 2809 $(this).attr( 'tabindex', '-1' ).trigger( 'blur' ); 2810 } 2811 if( self.mobileMenuType === 'full-screen' ) { 2812 $('html').addClass('pp-full-screen-menu-open'); 2813 self.fullScreenMenu.find('nav').attr('tabindex', '0').trigger( 'focus' ); 2814 $(this).attr( 'tabindex', '-1' ).trigger( 'blur' ); 2815 } 2816 } 2817 2818 if ( '0' == $(this).attr('tabindex') ) { 2819 $(this).attr('aria-expanded', 'false'); 2820 } else { 2821 $(this).attr('aria-expanded', 'true'); 2822 } 2823 } ); 2824 2825 // iOS Safari "hover" fix. 2826 // This is needed to ensure the click event works properly on iOS devices since they treat the first tap as a hover event, 2827 // which can interfere with the intended toggle behavior of the menu. 2828 // $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle' ).on( 'touchstart', function(e) { 2829 // e.preventDefault(); 2830 // e.stopPropagation(); 2831 // $(this).trigger('click'); 2832 // } ); 2833 2834 // Keyboard navigation. 2835 $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle').on('keyup', function(e) { 2836 if ( 13 === e.keyCode || 13 === e.which ) { 2837 $(this).trigger('click'); 2838 } 2839 }); 2840 2841 // Close button click 2842 $(self.nodeClass).find('.pp-advanced-menu .pp-menu-close-btn, .pp-clear').on( 'click', function() { 2843 $(self.nodeClass).find('.pp-advanced-menu').removeClass('menu-open'); 2844 $(self.nodeClass).find('.pp-advanced-menu').addClass('menu-close'); 2845 $('html').removeClass('pp-off-canvas-menu-open'); 2846 $('html').removeClass('pp-full-screen-menu-open'); 2847 2848 if ( $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle' ).is( ':visible' ) ) { 2849 setTimeout(function() { 2850 $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle' ) 2851 .attr( 'tabindex', 0 ) 2852 .attr( 'aria-expanded', 'false' ) 2853 .trigger( 'focus' ); 2854 }, 120); 2855 } 2856 2857 if ( self.offCanvasMenu && self.offCanvasMenu.length > 0 ) { 2858 self.offCanvasMenu.find('nav').attr('tabindex', '-1').trigger( 'blur' ); 2859 } 2860 if ( self.fullScreenMenu && self.fullScreenMenu.length > 0 ) { 2861 self.fullScreenMenu.find('nav').attr('tabindex', '-1').trigger( 'blur' ); 2862 } 2863 } ); 2864 2865 if ( this.isBuilderActive ) { 2866 setTimeout(function() {
2867 if ( $('.fl-builder-settings[data-node="'+self.settingsId+'"]').length > 0 ) { 2868 $('.pp-advanced-menu').removeClass('menu-open'); 2869 $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle').trigger('click'); 2870 } 2871 }, 600); 2872 2873 FLBuilder.addHook('settings-form-init', function() { 2874 if ( ! $('.fl-builder-settings[data-node="'+self.settingsId+'"]').length > 0 ) { 2875 return; 2876 } 2877 if ( ! $(self.nodeClass).find('.pp-advanced-menu').hasClass('menu-open') ) { 2878 $('.pp-advanced-menu').removeClass('menu-open'); 2879 $(self.nodeClass).find('.pp-advanced-menu-mobile-toggle').trigger('click'); 2880 } 2881 }); 2882 2883 if ( $('html').hasClass('pp-full-screen-menu-open') && ! $(self.nodeClass).find('.pp-advanced-menu').hasClass('menu-open') ) { 2884 $('html').removeClass('pp-full-screen-menu-open'); 2885 } 2886 if ( $('html').hasClass('pp-off-canvas-menu-open') && ! $(self.nodeClass).find('.pp-advanced-menu').hasClass('menu-open') ) { 2887 $('html').removeClass('pp-off-canvas-menu-open'); 2888 } 2889 } 2890 }, 2891 2892 /** 2893 * Check to see if Below Row should be enabled. 2894 * 2895 * @since 2.8.0 2896 * @return boolean 2897 */ 2898 _isMobileBelowRowEnabled: function() { 2899 if (this.mobileMenuType === 'default') { 2900 return this.mobileBelowRow && $( this.nodeClass ).closest( '.fl-col' ).length; 2901 } 2902 return false; 2903 }, 2904 2905 /** 2906 * Logic for putting the mobile menu below the menu's 2907 * column so it spans the full width of the page. 2908 * 2909 * @since 2.2 2910 * @return void 2911 */ 2912 _placeMobileMenuBelowRow: function () { 2913 2914 if ($(this.nodeClass + '-clone').length) { 2915 return; 2916 } 2917 // if ( $('html').hasClass( 'fl-builder-edit' ) ) { 2918 // return; 2919 // } 2920 2921 var module = $(this.nodeClass), 2922 clone = null, 2923 row = module.closest('.fl-row-content'); 2924 2925 if ( module.length < 1 ) { 2926 return; 2927 } 2928 2929 clone = ( module.length > 1 ) ? $( module[0] ).clone() : module.clone(); 2930 module.find('.pp-menu-nav').remove(); 2931 clone.addClass((this.nodeClass + '-clone').replace('.', '')); 2932 clone.addClass('pp-menu-mobile-clone'); 2933 clone.find('.pp-advanced-menu-mobile').remove(); 2934 row.append(clone); 2935 2936 // Removes animation when enabled. 2937 if ( module.hasClass( 'fl-animation' ) ) { 2938 clone.removeClass( 'fl-animation' ); 2939 } 2940 2941 this._menuOnClick(); 2942 }, 2943 2944 /** 2945 * Logic for removing the mobile menu from below the menu's 2946 * column and putting it back in the main wrapper. 2947 * 2948 * @since 2.2 2949 * @return void 2950 */ 2951 _removeMenuFromBelowRow: function () { 2952 2953 if (!$(this.nodeClass + '-clone').length) { 2954 return; 2955 } 2956 2957 var module = $(this.nodeClass), 2958 clone = $(this.nodeClass + '-clone'), 2959 menu = clone.find('.pp-menu-nav'); 2960 2961 module.find('.pp-advanced-menu-mobile').after(menu); 2962 module.find('.pp-advanced-menu-mobile-toggle').attr( 'aria-expanded', false ); 2963 clone.remove(); 2964 }, 2965 2966 _toggleMenuSearch: function() { 2967 var items = $( this.wrapperClass ).find( '.pp-menu-search-item' ), 2968 self = this; 2969 2970 items.each( function() { 2971 var item = $(this); 2972 var button = item.find( '> a' ), 2973 form = item.find( '.pp-search-form' ), 2974 input = item.find('.pp-search-form__input'); 2975 2976 button.on( 'click', function(e) { 2977 e.preventDefault(); 2978 item.toggleClass( 'pp-search-active' ); 2979 if ( item.hasClass( 'pp-search-active' ) ) { 2980 setTimeout( function() { 2981 input.focus(); 2982 self._focusMenuSearch( input ); 2983 }, 100 ); 2984 } 2985 2986 $('body').on( 'click.pp-menu-search', self._hideMenuSearch.bind( self ) ); 2987 } ); 2988 2989 input.on( 'focus', function() { 2990 form.addClass( 'pp-search-form--focus' ); 2991 } ).on( 'blur', function() { 2992 form.removeClass( 'pp-search-form--focus' ); 2993 } ); 2994 2995 // Close search form on ESC key press. 2996 input.on( 'keyup', function(e) { 2997 if ( e.key === 'Escape' || e.keyCode === 27 ) { 2998 item.removeClass( 'pp-search-active' ); 2999 $('body').off('click.pp-menu-search'); 3000 button.delay(100).focus(); 3001 } 3002 } ); 3003 } ); 3004 }, 3005 3006 _hideMenuSearch: function(e) { 3007 if (e !== undefined) { 3008 if ($(e.target).closest('.pp-menu-search-item').length > 0) { 3009 return; 3010 } 3011 } 3012 3013 $( this.wrapperClass ).find( '.pp-menu-search-item' ).removeClass( 'pp-search-active' ); 3014 $('body').off('click.pp-menu-search'); 3015 }, 3016 3017 _focusMenuSearch: function( $el ) { 3018 // If this function exists... (IE 9+) 3019 if ( $el[0].setSelectionRange ) { 3020 // Double the length because Opera is inconsistent about whether a carriage return is one character or tw
3020o. 3021 var len = $el.val().length * 2; 3022 3023 // Timeout seems to be required for Blink 3024 setTimeout(function() { 3025 $el[0].setSelectionRange( len, len ); 3026 }, 1); 3027 } else { 3028 // As a fallback, replace the contents with itself 3029 // Doesn't work in Chrome, but Chrome supports setSelectionRange 3030 $el.val( $el.val() ); 3031 } 3032 }, 3033 3034 /** 3035 * Adds menu node and post ID to WooCommerce ajax URL requests. 3036 * 3037 * @since 2.20 3038 * @return void 3039 */ 3040 _wooUpdateParams: function() { 3041 if ( 'undefined' !== typeof wc_cart_fragments_params ) { 3042 wc_cart_fragments_params.wc_ajax_url += '&pp-advanced-menu-node='+ this.settingsId +'&post-id='+ this.postId; 3043 } 3044 if ( 'undefined' !== typeof wc_add_to_cart_params ) { 3045 wc_add_to_cart_params.wc_ajax_url += '&pp-advanced-menu-node='+ this.settingsId +'&post-id='+ this.postId; 3046 } 3047 }, 3048 3049 _validClick: function(e) { 3050 return (e.which == 1 || e.which == 13 || e.which == 32 || e.which == undefined) ? true : false; 3051 } 3052 3053 }; 3054 3055})(jQuery); 3056 3057var pp_menu_6181036352c2a; 3058(function($) { 3059 3060 pp_menu_6181036352c2a = new PPAdvancedMenu({ 3061 id: '6181036352c2a', 3062 type: 'accordion', 3063 mobile: 'hamburger', 3064 menuPosition: 'below', 3065 breakpoints: { 3066 large: 1200, 3067 medium: 992, 3068 small: 768, 3069 custom: 768 }, 3070 mobileBreakpoint: 'medium-mobile', 3071 mediaBreakpoint: '992', 3072 mobileMenuType: 'off-canvas', 3073 offCanvasDirection: 'left', 3074 fullScreenAnimation: '', 3075 isBuilderActive: false }); 3076 3077})(jQuery); 3078 3079var pp_menu_61810c1eef1f3; 3080(function($) { 3081 3082 pp_menu_61810c1eef1f3 = new PPAdvancedMenu({ 3083 id: '61810c1eef1f3', 3084 type: 'accordion', 3085 mobile: 'hamburger', 3086 menuPosition: 'below', 3087 breakpoints: { 3088 large: 1200, 3089 medium: 992, 3090 small: 768, 3091 custom: 768 }, 3092 mobileBreakpoint: 'medium-mobile', 3093 mediaBreakpoint: '992', 3094 mobileMenuType: 'off-canvas', 3095 offCanvasDirection: 'left', 3096 fullScreenAnimation: '', 3097 isBuilderActive: false }); 3098 3099})(jQuery); 3100 3101/* Start Layout Custom JS */ 3102 3103/* End Layout Custom JS */ 3104 3105(function($){ 3106 3107 /** 3108 * Helper class for header layout logic. 3109 * 3110 * @since 1.0 3111 * @class FLThemeBuilderHeaderLayout 3112 */ 3113 FLThemeBuilderHeaderLayout = { 3114 3115 /** 3116 * A reference to the window object for this page. 3117 * 3118 * @since 1.0 3119 * @property {Object} win 3120 */ 3121 win : null, 3122 3123 /** 3124 * A reference to the body object for this page. 3125 * 3126 * @since 1.0 3127 * @property {Object} body 3128 */ 3129 body : null, 3130 3131 /** 3132 * A reference to the header object for this page. 3133 * 3134 * @since 1.0 3135 * @property {Object} header 3136 */ 3137 header : null, 3138 3139 /** 3140 * Whether this header overlays the content or not. 3141 * 3142 * @since 1.0 3143 * @property {Boolean} overlay 3144 */ 3145 overlay : false, 3146 3147 /** 3148 * Whether the page has the WP admin bar or not. 3149 * 3150 * @since 1.0 3151 * @property {Boolean} hasAdminBar 3152 */ 3153 hasAdminBar : false, 3154 3155 /** 3156 * Breakpoint for when the sticky header should apply. 3157 * 3158 * @since 1.4 3159 * @property {String} stickyOn 3160 */ 3161 stickyOn: '', 3162 3163 /** 3164 * A reference of the sticky and shrink header breakpoint. 3165 * 3166 * @since 1.2.5 3167 * @property {Number} breakpointWidth 3168 */ 3169 breakpointWidth: 0, 3170 3171 /** 3172 * Whether this header can be pinned from page load. 3173 * 3174 * @since 1.6.1 3175 * @property {Boolean} pinnable 3176 */ 3177 pinnable : false, 3178 3179 /** 3180 * Initializes header layout logic. 3181 * 3182 * @since 1.0 3183 * @method init 3184 */ 3185 init: function() 3186 { 3187 var editing = $( 'html.fl-builder-edit' ).length, 3188 header = $( '.fl-builder-content[data-type=header]' ), 3189 menuModule = header.find( '.fl-module-menu' ), 3190 breakpoint = null, 3191 adminBarHeight = 0; 3192 3193 if ( ! editing && header.length ) { 3194 3195 header.imagesLoaded( $.proxy( function() { 3196 3197 this.win = $( window ); 3198 this.body = $( 'body' ); 3199 this.header = header.eq( 0 ); 3200 this.overlay = !! Number( header.attr( 'data-overlay' ) ); 3201 this.hasAdminBar = !! $( 'body.admin-bar' ).length; 3202 this.stickyOn = this.header.data( 'sticky-on' ); 3203 breakpoint = this.header.data( 'sticky-breakpoint' ); 3204 3205 if ( '' == this.stickyOn ) { 3206 if ( typeof FLBuilderLayoutConfig.breakpoints[ breakpoint ] !== undefined ) { 3207 this.breakpointWidth = FLBuilderLayoutConfig.breakpoints[ breakpoint ]; 3208 } 3209 else { 3210 this.breakpointWidth = FLBuilderLayoutConfig.breakpoints.medium; 3211 } 3212 } 3213 3214 if ( Number( header.attr( 'data-sticky' ) ) ) { 3215 3216 this.header.data( 'original-top', this.header.offset().top ); 3217 3218 // The pin decision is made once here, while the header offset and the admin bar height are read from the same layout. 3219 adminBarHeight = $( '#wpadminbar' ).length ? $( '#wpadminbar' ).outerHeight() : 0; 3220 this.pinnable = this.overlay && this.header.data( 'original-top' ) <= adminBarHeight; 3221 3222 this.win.on( 'resize', $.throttle( 500, $.proxy( this._initSticky, this ) ) ); 3223 this._initSticky(); 3224 3225 } 3226 3227 }, this ) ); 3228 } 3229 }, 3230 3231 /** 3232 * Initializes sticky logic for a header. 3233 * 3234 * @since 1.0 3235 * @access private 3236 * @method _initSticky 3237 */ 3238 _initSticky: function( e ) 3239 {
3240 var header = $('.fl-builder-content[data-type=header]'), 3241 windowSize = this.win.width(), 3242 makeSticky = false; 3243 3244 makeSticky = this._makeWindowSticky( windowSize ); 3245 if ( makeSticky || ( this.breakpointWidth > 0 && windowSize >= this.breakpointWidth ) ) { 3246 this.win.on( 'scroll.fl-theme-builder-header-sticky', $.proxy( this._doSticky, this ) ); 3247 this._initPin(); 3248 3249 // Apply the sticky state on initial load when the page is 3250 // already scrolled past the header â e.g. when the browser 3251 // restores the scroll position on refresh. Overlay headers are 3252 // out of scope here; this mirrors the shrink-on-load behavior 3253 // in _initShrink(). 3254 if ( ! e && ! this.overlay && ! this.header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 3255 var loadWinTop = this.win.scrollTop(), 3256 loadHeaderTop = Math.floor( this.header.data( 'original-top' ) ); 3257 3258 if ( this.hasAdminBar && windowSize > 600 ) { 3259 loadWinTop += Math.floor( $( '#wpadminbar' ).outerHeight() ); 3260 } 3261 3262 if ( loadWinTop > loadHeaderTop ) { 3263 this.header.addClass( 'fl-theme-builder-header-sticky' ); 3264 this.header.addClass( 'fl-theme-builder-header-scrolled' ); 3265 this._adjustHeaderHeight(); 3266 this._adjustStickyHeaderWidth(); 3267 } 3268 } 3269 3270 // 3271 // Check if Event Type is 'resize' then invoke this._doSticky() 3272 // only if the 'fl-theme-builder-header-sticky' class is already present. 3273 // 3274 if ( e && 'resize' === e.type ) { 3275 if ( this.header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 3276 this._doSticky( e ); 3277 } 3278 this._adjustStickyHeaderWidth(); 3279 } 3280 3281 if ( Number( header.attr( 'data-shrink' ) ) ) { 3282 this.header.data( 'original-height', this.header.outerHeight() ); 3283 this.win.on( 'resize', $.throttle( 500, $.proxy( this._initShrink, this ) ) ); 3284 this._initShrink(); 3285 } 3286 3287 this._initFlyoutMenuFix( e ); 3288 } else { 3289 this.win.off( 'scroll.fl-theme-builder-header-sticky' ); 3290 this.win.off( 'resize.fl-theme-builder-header-sticky' ); 3291 3292 this.header.removeClass( 'fl-theme-builder-header-sticky' ); 3293 this.header.removeClass( 'fl-theme-builder-header-pinned' ); 3294 this.header.removeAttr( 'style' ); 3295 this.header.parent().css( 'padding-top', '0' ); 3296 } 3297 }, 3298 3299 /** 3300 * Pins an overlay header with fixed positioning from page load, avoiding a position change that a scroll handler cannot apply before the compositor paints. 3301 * 3302 * @since 1.6.1 3303 * @access private 3304 * @method _initPin 3305 */ 3306 _initPin: function() 3307 { 3308 this.header.toggleClass( 'fl-theme-builder-header-pinned', this.pinnable ); 3309 3310 if ( ! this.pinnable ) { 3311 return; 3312 } 3313 3314 // Fixed positioning resolves the width against the viewport, so boxed layouts require their maximum width immediately. 3315 this._adjustStickyHeaderWidth(); 3316 3317 // The header is visible from the first paint, so the scrolled state must reflect any restored scroll position. 3318 if ( this.win.scrollTop() > Math.floor( this.header.data( 'original-top' ) ) ) { 3319 this.header.addClass( 'fl-theme-builder-header-scrolled' ); 3320 } 3321 }, 3322 3323 /** 3324 * Check if Header should be sticky at a particular Window size. 3325 * 3326 * @since 1.4 3327 * @access private 3328 * @param widowSize 3329 * @method _makeWindowSticky 3330 */ 3331 _makeWindowSticky: function ( windowSize ) 3332 { 3333 var makeSticky = false; 3334 3335 switch (this.stickyOn) { 3336 case 'xl': 3337 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['large']; 3338 break; 3339 case '': // Default 3340 case 'desktop': 3341 makeSticky = windowSize >= FLBuilderLayoutConfig.breakpoints['medium']; 3342 break; 3343 case 'desktop-medium': 3344 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small']; 3345 break; 3346 case 'large': 3347 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['medium'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large']; 3348 break; 3349 case 'large-medium': 3350 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large']; 3351 break; 3352 case 'medium': 3353 makeSticky = ( windowSize <= FLBuilderLayoutConfig.breakpoints['medium'] && windowSize > FLBuilderLayoutConfig.breakpoints['small'] ); 3354 break; 3355 case 'medium-mobile':
3356 makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['medium']); 3357 break; 3358 case 'mobile': 3359 makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['small']); 3360 break; 3361 case 'all': 3362 makeSticky = true; 3363 break; 3364 } 3365 3366 return makeSticky; 3367 }, 3368 3369 /** 3370 * Sticks the header when the page is scrolled. 3371 * 3372 * @since 1.0 3373 * @access private 3374 * @method _doSticky 3375 */ 3376 _doSticky: function( e ) 3377 { 3378 var winTop = Math.floor( this.win.scrollTop() ), 3379 headerTop = Math.floor( this.header.data( 'original-top' ) ), 3380 hasStickyClass = this.header.hasClass( 'fl-theme-builder-header-sticky' ), 3381 hasScrolledClass = this.header.hasClass( 'fl-theme-builder-header-scrolled' ), 3382 beforeHeader = this.header.prevAll( '.fl-builder-content' ), 3383 bodyTopPadding = parseInt( jQuery('body').css('padding-top') ), 3384 winBarHeight = $('#wpadminbar').length ? $('#wpadminbar').outerHeight() : 0, 3385 headerHeight = 0; 3386 3387 if ( isNaN( bodyTopPadding ) ) { 3388 bodyTopPadding = 0; 3389 } 3390 3391 if ( this.hasAdminBar && this.win.width() > 600 ) { 3392 winTop += Math.floor( winBarHeight ); 3393 } 3394 3395 if ( winTop > headerTop ) { 3396 if ( ! hasStickyClass ) { 3397 if ( e && ( 'scroll' === e.type || 'smartscroll' === e.type ) ) { 3398 this.header.addClass( 'fl-theme-builder-header-sticky' ); 3399 if ( this.overlay && beforeHeader.length ) { 3400 this.header.css( 'top', winBarHeight); 3401 } 3402 } 3403 3404 if ( ! this.overlay ) { 3405 this._adjustHeaderHeight(); 3406 } 3407 } 3408 } 3409 else if ( hasStickyClass ) { 3410 this.header.removeClass( 'fl-theme-builder-header-sticky' ); 3411 this.header.removeAttr( 'style' ); 3412 this.header.parent().css( 'padding-top', '0' ); 3413 } 3414 3415 this._adjustStickyHeaderWidth(); 3416 3417 if ( winTop > headerTop ) { 3418 if ( ! hasScrolledClass ) { 3419 this.header.addClass( 'fl-theme-builder-header-scrolled' ); 3420 } 3421 } else if ( hasScrolledClass ) { 3422 this.header.removeClass( 'fl-theme-builder-header-scrolled' ); 3423 } 3424 3425 this._flyoutMenuFix( e ); 3426 }, 3427 3428 /** 3429 * Initializes flyout menu fixes on sticky header. 3430 * 3431 * @since 1.4.1 3432 * @method _initFlyoutMenuFix 3433 */ 3434 _initFlyoutMenuFix: function( e ) { 3435 var header = this.header, 3436 menuModule = header.closest( '.fl-menu' ), 3437 flyoutMenu = menuModule.find( '.fl-menu-mobile-flyout' ), 3438 isPushMenu = menuModule.hasClass( 'fl-menu-responsive-flyout-push' ) || menuModule.hasClass( 'fl-menu-responsive-flyout-push-opacity' ), 3439 isOverlay = menuModule.hasClass( 'fl-menu-responsive-flyout-overlay' ), 3440 flyoutPos = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 3441 flyoutParent = header.parent().is( 'header' ) ? header.parent().parent() : header.parent(); 3442 isFullWidth = this.win.width() === header.width(), 3443 flyoutLayout = '', 3444 activePos = 250, 3445 headerPos = 0; 3446 3447 if ( ! flyoutMenu.length ) { 3448 return; 3449 } 3450 3451 if ( this.win.width() > header.parent().width() ) { 3452 headerPos = ( this.win.width() - header.width() ) / 2; 3453 } 3454 3455 if ( isOverlay ) { 3456 activePos = headerPos; 3457 } 3458 else if ( isPushMenu ) { 3459 activePos = activePos + headerPos; 3460 } 3461 flyoutMenu.data( 'activePos', activePos ); 3462 3463 if ( isPushMenu ) { 3464 flyoutLayout = 'push-' + flyoutPos; 3465 } 3466 else if ( isOverlay ) { 3467 flyoutLayout = 'overlay-' + flyoutPos; 3468 } 3469 3470 if ( isPushMenu && ! $( 'html' ).hasClass( 'fl-theme-builder-has-flyout-menu' ) ) { 3471 $( 'html' ).addClass( 'fl-theme-builder-has-flyout-menu' ); 3472 } 3473 3474 if ( ! flyoutParent.hasClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout ) ) { 3475 flyoutParent.addClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout ); 3476 } 3477 3478 if ( ! header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && isOverlay ) { 3479 header.addClass( 'fl-theme-builder-flyout-menu-overlay' ); 3480 } 3481 3482 if ( ! header.hasClass( 'fl-theme-builder-header-full-width' ) && isFullWidth ) { 3483 header.addClass( 'fl-theme-builder-header-full-width' ); 3484 } 3485 else if ( ! isFullWidth ) { 3486 header.removeClass( 'fl-theme-builder-header-full-width' ); 3487 } 3488 3489 menuModule.on( 'click', '.fl-menu-mobile-toggle', $.proxy( function( event ){ 3490 if ( menuModule.find( '.fl-menu-mobile-toggle.fl-active' ).length ) {
3491 $( 'html' ).addClass( 'fl-theme-builder-flyout-menu-active' ); 3492 event.stopImmediatePropagation(); 3493 } 3494 else { 3495 $( 'html' ).removeClass( 'fl-theme-builder-flyout-menu-active' ); 3496 } 3497 3498 this._flyoutMenuFix( event ); 3499 }, this ) ); 3500 }, 3501 3502 /** 3503 * Fix flyout menu inside the sticky header. 3504 * 3505 * @since 1.4.1 3506 * @method _flyoutMenuFix 3507 */ 3508 _flyoutMenuFix: function( e ){ 3509 var header = this.header, 3510 menuModule = $( e.target ).closest( '.fl-menu' ), 3511 flyoutMenu = menuModule.find( '.fl-menu-mobile-flyout' ), 3512 flyoutPos = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 3513 menuOpacity = menuModule.find( '.fl-menu-mobile-opacity' ), 3514 isScroll = 'undefined' !== typeof e && 'scroll' === e.handleObj.type, 3515 activePos = 'undefined' !== typeof flyoutMenu.data( 'activePos' ) ? flyoutMenu.data( 'activePos' ) : 0, 3516 headerPos = ( this.win.width() - header.width() ) / 2, 3517 inactivePos = headerPos > 0 ? activePos + 4 : 254; 3518 3519 if ( ! flyoutMenu.length ) { 3520 return; 3521 } 3522 3523 if ( this.overlay ) { 3524 return; 3525 } 3526 3527 if( $( '.fl-theme-builder-flyout-menu-active' ).length ) { 3528 3529 if ( isScroll && ! flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) { 3530 flyoutMenu.addClass( 'fl-menu-disable-transition' ); 3531 } 3532 3533 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 3534 if ( ! isScroll ) { 3535 setTimeout( $.proxy( function(){ 3536 flyoutMenu.css( flyoutPos, '-' + activePos + 'px' ); 3537 }, this ), 1 ); 3538 } 3539 else { 3540 flyoutMenu.css( flyoutPos, '-' + activePos + 'px' ); 3541 } 3542 } 3543 else { 3544 flyoutMenu.css( flyoutPos, '0px' ); 3545 } 3546 } 3547 else { 3548 if ( flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) { 3549 flyoutMenu.removeClass( 'fl-menu-disable-transition' ); 3550 } 3551 3552 if ( header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && headerPos > 0 && headerPos < 250 ) { 3553 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 3554 inactivePos = headerPos + 254; 3555 } 3556 else { 3557 inactivePos = 254; 3558 } 3559 } 3560 3561 if ( e && e.type === 'resize' ) { 3562 inactivePos = headerPos + 254; 3563 } 3564 3565 flyoutMenu.css( flyoutPos, '-' + inactivePos + 'px' ); 3566 } 3567 3568 if ( e && menuModule.is('.fl-menu-responsive-flyout-overlay') && $.infinitescroll ) { 3569 e.stopImmediatePropagation(); 3570 } 3571 3572 if( menuOpacity.length ) { 3573 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 3574 if ( '0px' === menuOpacity.css( 'left' ) ) { 3575 menuOpacity.css( 'left', '-' + headerPos + 'px' ); 3576 } 3577 } 3578 else { 3579 menuOpacity.css( 'left', '' ); 3580 } 3581 } 3582 }, 3583 3584 /** 3585 * Adjust sticky header width if BB Theme Boxed Layout is used. 3586 * 3587 * @since 1.4 3588 * @access private 3589 * @method _adjustStickyHeaderWidth 3590 */ 3591 _adjustStickyHeaderWidth: function () { 3592 if ( $('body').hasClass( 'fl-fixed-width' ) ) { 3593 var parentWidth = this.header.parent().width(); 3594 3595 // Better if this is set in the stylesheet file. 3596 if ( this.win.width() >= 992 ) { 3597 this.header.css({ 3598 'margin': '0 auto', 3599 'max-width': parentWidth, 3600 }); 3601 } 3602 else { 3603 this.header.css({ 3604 'margin': '', 3605 'max-width': '', 3606 }); 3607 } 3608 } 3609 }, 3610 3611 /** 3612 * Adjust Sticky Header Height 3613 * 3614 * @since 1.4 3615 * @access private 3616 * @method _adjustHeaderHeight 3617 */ 3618 _adjustHeaderHeight: function () { 3619 var beforeHeader = this.header.prevAll('.fl-builder-content'), 3620 beforeHeaderHeight = 0, 3621 beforeHeaderFix = 0, 3622 headerHeight = Math.floor( this.header.outerHeight() ), 3623 bodyTopPadding = parseInt( $( 'body' ).css( 'padding-top' ) ), 3624 wpAdminBarHeight = 0, 3625 totalHeaderHeight = 0; 3626 3627 if ( isNaN( bodyTopPadding ) ) { 3628 bodyTopPadding = 0; 3629 } 3630 3631 if ( beforeHeader.length ) { 3632 $.each( beforeHeader, function() { 3633 beforeHeaderHeight += Math.floor( $(this).outerHeight() ); 3634 }); 3635 // Subtract this value from the header parent's top padding. 3636 beforeHeaderFix = 2; 3637 } 3638 3639 if ( this.hasAdminBar && this.win.width() <= 600 ) { 3640 wpAdminBarHeight = Math.floor( $('#wpadminbar').outerHeight() ); 3641 } 3642 3643 totalHeaderHeight = Math.floor( beforeHeaderHeight + headerHeight); 3644 3645 if ( headerHeight > 0 ) { 3646 var headerParent = this.header.parent(), 3647 headerParentTopPadding = 0; 3648 3649 // If the header's parent container is the BODY tag ignore its top padding. 3650 if ( $( headerParent ).is('body') ) { 3651 headerParentTopPadding = Math.floor( headerHeight - wpAdminBarHeight ); 3652 } else { 3653 headerParentTopPadding = Math.floor( headerHeight - bodyTopPadding - wpAdminBarHeight ); 3654 } 3655 3656 $( headerParent ).css( 'padding-top', ( headerParentTopPadding - beforeHeaderFix ) + 'px' ); 3657 3658 this.header.css({ 3659 '-webkit-transform': 'translate(0px, -' + totalHeaderHeight + 'px)', 3660 '-ms-transform': 'translate(0px, -' + totalHeaderHeight + 'px)', 3661 'transform': 'translate(0px, -' + totalHeaderHeight + 'px)' 3662 }); 3663 3664 } 3665 3666 }, 3667 3668 /** 3669 * Initializes shrink logic for a header. 3670 * 3671 * @since 1.0 3672 * @access private 3673 * @method _initShrink 3674 */ 3675 _initShrink: function( e ) 3676 { 3677 if ( this.win.width() >= this.breakpointWidth ) {
3678 this.win.on( 'scroll.fl-theme-builder-header-shrink', $.proxy( this._doShrink, this ) ); 3679 this._setImageMaxHeight(); 3680 3681 if ( this.win.scrollTop() > 0 ){ 3682 this._doShrink(); 3683 } 3684 3685 } else { 3686 this.header.parent().css( 'padding-top', '0' ); 3687 this.win.off( 'scroll.fl-theme-builder-header-shrink' ); 3688 this._removeShrink(); 3689 this._removeImageMaxHeight(); 3690 } 3691 }, 3692 3693 /** 3694 * Shrinks the header when the page is scrolled. 3695 * 3696 * @since 1.0 3697 * @access private 3698 * @method _doShrink 3699 */ 3700 _doShrink: function( e ) 3701 { 3702 var winTop = this.win.scrollTop(), 3703 headerTop = this.header.data('original-top'), 3704 headerHeight = this.header.data('original-height'), 3705 shrinkImageHeight = this.header.data('shrink-image-height'), 3706 windowSize = this.win.width(), 3707 makeSticky = this._makeWindowSticky( windowSize ), 3708 hasClass = this.header.hasClass( 'fl-theme-builder-header-shrink' ); 3709 3710 3711 if ( this.hasAdminBar ) { 3712 winTop += 32; 3713 } 3714 3715 if ( makeSticky && ( winTop > headerTop + headerHeight ) ) { 3716 if ( ! hasClass ) { 3717 3718 this.header.addClass( 'fl-theme-builder-header-shrink' ); 3719 3720 // Shrink images but don't include lightbox and menu images. 3721 this.header.find('img').each( function( i ) { 3722 var image = $( this ), 3723 maxMegaMenu = image.closest( '.max-mega-menu' ).length, 3724 imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length, 3725 imageInNavMenu = image.closest( 'li.menu-item' ).length; 3726 3727 if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu ) ) { 3728 image.css( 'max-height', shrinkImageHeight ); 3729 } 3730 3731 }); 3732 3733 this.header.find( '.fl-row-content-wrap' ).each( function() { 3734 3735 var row = $( this ); 3736 3737 if ( parseInt( row.css( 'padding-bottom' ) ) > 5 ) { 3738 row.addClass( 'fl-theme-builder-header-shrink-row-bottom' ); 3739 } 3740 3741 if ( parseInt( row.css( 'padding-top' ) ) > 5 ) { 3742 row.addClass( 'fl-theme-builder-header-shrink-row-top' ); 3743 } 3744 } ); 3745 3746 this.header.find( '.fl-module' ).each( function() { 3747 3748 var module = $( this ).find( '.fl-module-content' ).length ? $( this ).find( '.fl-module-content' ) : $( this ); 3749 3750 if ( parseInt( module.css( 'margin-bottom' ) ) > 5 ) { 3751 module.addClass( 'fl-theme-builder-header-shrink-module-bottom' ); 3752 } 3753 3754 if ( parseInt( module.css( 'margin-top' ) ) > 5 ) { 3755 module.addClass( 'fl-theme-builder-header-shrink-module-top' ); 3756 } 3757 } ); 3758 } 3759 } else if (hasClass) { 3760 this.header.find( 'img' ).css( 'max-height', '' ); 3761 this._removeShrink(); 3762 } 3763 3764 // Fixes Shrink header issue with BB Theme when window is scrolled then resized and back. 3765 if ( 'undefined' === typeof( e ) && $('body').hasClass( 'fl-fixed-width' ) ) { 3766 if ( ! this.overlay ) { 3767 this._adjustHeaderHeight(); 3768 } 3769 } 3770 3771 }, 3772 3773 /** 3774 * Removes the header shrink effect. 3775 * 3776 * @since 1.0 3777 * @access private 3778 * @method _removeShrink 3779 */ 3780 _removeShrink: function() 3781 { 3782 var rows = this.header.find( '.fl-row-content-wrap' ), 3783 modules = this.header.find('.fl-module, .fl-module-content'); 3784 3785 rows.removeClass( 'fl-theme-builder-header-shrink-row-bottom' ); 3786 rows.removeClass( 'fl-theme-builder-header-shrink-row-top' ); 3787 modules.removeClass( 'fl-theme-builder-header-shrink-module-bottom' ); 3788 modules.removeClass( 'fl-theme-builder-header-shrink-module-top' ); 3789 this.header.removeClass( 'fl-theme-builder-header-shrink' ); 3790 }, 3791 3792 /** 3793 * Adds max height to images in modules for smooth scrolling. 3794 * 3795 * @since 1.1.1 3796 * @access private 3797 * @method _setImageMaxHeight 3798 */ 3799 _setImageMaxHeight: function() 3800 { 3801 var head = $( 'head' ), 3802 stylesId = 'fl-header-styles-' + this.header.data( 'post-id' ), 3803 styles = '', 3804 images = this.header.find( '.fl-module img' ); 3805 3806 if ( $( '#' + stylesId ).length ) { 3807 return; 3808 } 3809 3810 images.each( function( i ) { 3811 var image = $( this ), 3812 height = image.height(), 3813 node = image.closest( '.fl-module' ).data( 'node' ), 3814 className = 'fl-node-' + node + '-img-' + i, 3815 maxMegaMenu = image.closest( '.max-mega-menu' ).length, 3816 imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length, 3817 imageInNavMenu = image.closest( 'li.menu-item' ).length; 3818 3819 if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu ) ) { 3820 image.addClass( className ); 3821 styles += '.' + className + ' { max-height: ' + ( height ? height : image[0].height ) + 'px }'; 3822 } 3823 3824 } ); 3825
3826 if ( '' !== styles ) { 3827 head.append( '<style id="' + stylesId + '">' + styles + '</style>' ); 3828 } 3829 }, 3830 3831 /** 3832 * Removes max height on images in modules for smooth scrolling. 3833 * 3834 * @since 1.1.1 3835 * @access private 3836 * @method _removeImageMaxHeight 3837 */ 3838 _removeImageMaxHeight: function() 3839 { 3840 $( '#fl-header-styles-' + this.header.data( 'post-id' ) ).remove(); 3841 }, 3842 }; 3843 3844 $( function() { FLThemeBuilderHeaderLayout.init(); } ); 3845 3846})(jQuery); 3847 3848jQuery(function($) { 3849 3850 $(function() { 3851 $( '.fl-node-6149cf3dce147 .fl-photo-img' ) 3852 .on( 'mouseenter', function( e ) { 3853 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 3854 } ) 3855 .on( 'mouseleave', function( e ){ 3856 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 3857 } ); 3858 }); 3859 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 3860}); 3861 3862/* Start Layout Custom JS */ 3863 3864/* End Layout Custom JS */ 3865 3866
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.