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