1var wpAjaxUrl = 'https://wolfoffranchises.com/wp-admin/admin-ajax.php';var flBuilderUrl = 'https://wolfoffranchises.com/wp-content/plugins/bb-plugin/';var FLBuilderLayoutConfig = { 2 anchorLinkAnimations : { 3 duration : 1000, 4 easing : 'swing', 5 offset : 100 6 }, 7 paths : { 8 pluginUrl : 'https://wolfoffranchises.com/wp-content/plugins/bb-plugin/', 9 wpAjaxUrl : 'https://wolfoffranchises.com/wp-admin/admin-ajax.php' 10 }, 11 breakpoints : { 12 small : 768, 13 medium : 992, 14 large : 1200 }, 15 waypoint: { 16 offset: 80 17 } 18}; 19(function($){ 20 21 if(typeof FLBuilderLayout != 'undefined') { 22 return; 23 } 24 25 /** 26 * Helper class with generic logic for a builder layout. 27 * 28 * @class FLBuilderLayout 29 * @since 1.0 30 */ 31 FLBuilderLayout = { 32 33 /** 34 * Initializes a builder layout. 35 * 36 * @since 1.0 37 * @method init 38 */ 39 init: function() 40 { 41 // Destroy existing layout events. 42 FLBuilderLayout._destroy(); 43 44 // Init CSS classes. 45 FLBuilderLayout._initClasses(); 46 47 // Init backgrounds. 48 FLBuilderLayout._initBackgrounds(); 49 50 // Init row shape layer height. 51 FLBuilderLayout._initRowShapeLayerHeight(); 52 53 // Only init if the builder isn't active. 54 if ( 0 === $('.fl-builder-edit').length ) { 55 56 // Init module animations. 57 FLBuilderLayout._initModuleAnimations(); 58 59 // Init anchor links. 60 FLBuilderLayout._initAnchorLinks(); 61 62 // Init the browser hash. 63 FLBuilderLayout._initHash(); 64 65 // Init forms. 66 FLBuilderLayout._initForms(); 67 68 FLBuilderLayout._reorderMenu(); 69 } 70 }, 71 72 /** 73 * Public method for refreshing Wookmark or MosaicFlow galleries 74 * within an element. 75 * 76 * @since 1.7.4 77 * @method refreshGalleries 78 */ 79 refreshGalleries: function( element ) 80 { 81 var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), 82 mfContent = $element.find( '.fl-mosaicflow-content' ), 83 wmContent = $element.find( '.fl-gallery' ), 84 mfObject = null; 85 86 if ( mfContent ) { 87 88 mfObject = mfContent.data( 'mosaicflow' ); 89 90 if ( mfObject ) { 91 mfObject.columns = $( [] ); 92 mfObject.columnsHeights = []; 93 mfContent.data( 'mosaicflow', mfObject ); 94 mfContent.mosaicflow( 'refill' ); 95 } 96 } 97 if ( wmContent ) { 98 wmContent.trigger( 'refreshWookmark' ); 99 } 100 }, 101 102 /** 103 * Public method for refreshing Masonry within an element 104 * 105 * @since 1.8.1 106 * @method refreshGridLayout 107 */ 108 refreshGridLayout: function( element ) 109 { 110 var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), 111 msnryContent = $element.find('.masonry'); 112 113 if ( msnryContent.length ) { 114 msnryContent.masonry('layout'); 115 } 116 }, 117 118 /** 119 * Public method for reloading BxSlider within an element 120 * 121 * @since 1.8.1 122 * @method reloadSlider 123 */ 124 reloadSlider: function( element ) 125 { 126 var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), 127 bxContent = $element.find('.bx-viewport > div').eq(0), 128 bxObject = null; 129 130 if ( bxContent.length ) { 131 bxObject = bxContent.data( 'bxSlider'); 132 if ( bxObject ) { 133 bxObject.reloadSlider(); 134 } 135 } 136 }, 137 138 /** 139 * Public method for resizing WP audio player 140 * 141 * @since 1.8.2 142 * @method resizeAudio 143 */ 144 resizeAudio: function( element ) 145 { 146 var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), 147 audioPlayers = $element.find('.wp-audio-shortcode.mejs-audio'), 148 player = null, 149 mejsPlayer = null, 150 rail = null, 151 railWidth = 400; 152 153 if ( audioPlayers.length && typeof mejs !== 'undefined' ) { 154 audioPlayers.each(function(){ 155 player = $(this); 156 mejsPlayer = mejs.players[player.attr('id')]; 157 rail = player.find('.mejs-controls .mejs-time-rail'); 158 var innerMejs = player.find('.mejs-inner'), 159 total = player.find('.mejs-controls .mejs-time-total'); 160 161 if ( typeof mejsPlayer !== 'undefined' ) { 162 railWidth = Math.ceil(player.width() * 0.8); 163 164 if ( innerMejs.length ) { 165
166 rail.css('width', railWidth +'px!important'); 167 //total.width(rail.width() - 10); 168 169 mejsPlayer.options.autosizeProgress = true; 170 171 // webkit has trouble doing this without a delay 172 setTimeout(function () { 173 mejsPlayer.setControlsSize(); 174 }, 50); 175 176 player.find('.mejs-inner').css({ 177 visibility: 'visible', 178 height: 'inherit' 179 }); 180 } 181 } 182 }); 183 } 184 }, 185 186 /** 187 * Public method for preloading WP audio player when it's inside the hidden element 188 * 189 * @since 1.8.2 190 * @method preloadAudio 191 */ 192 preloadAudio: function(element) 193 { 194 var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), 195 contentWrap = $element.closest('.fl-accordion-item'), 196 audioPlayers = $element.find('.wp-audio-shortcode.mejs-audio'); 197 198 if ( ! contentWrap.hasClass('fl-accordion-item-active') && audioPlayers.find('.mejs-inner').length ) { 199 audioPlayers.find('.mejs-inner').css({ 200 visibility : 'hidden', 201 height: 0 202 }); 203 } 204 }, 205 206 /** 207 * Public method for resizing slideshow momdule within the tab 208 * 209 * @since 1.10.5 210 * @method resizeSlideshow 211 */ 212 resizeSlideshow: function(){ 213 if(typeof YUI !== 'undefined') { 214 YUI().use('node-event-simulate', function(Y) { 215 Y.one(window).simulate("resize"); 216 }); 217 } 218 }, 219 220 /** 221 * Public method for reloading an embedded Google Map within the tabs or hidden element. 222 * 223 * @since 2.2 224 * @method reloadGoogleMap 225 */ 226 reloadGoogleMap: function(element){ 227 var $element = 'undefined' == typeof element ? $( 'body' ) : $( element ), 228 googleMap = $element.find( 'iframe[src*="google.com/maps"]' ); 229 230 if ( googleMap.length ) { 231 googleMap.attr( 'src', function(i, val) { 232 return val; 233 }); 234 } 235 }, 236 237 /** 238 * Unbinds builder layout events. 239 * 240 * @since 1.0 241 * @access private 242 * @method _destroy 243 */ 244 _destroy: function() 245 { 246 var win = $(window); 247 248 win.off('scroll.fl-bg-parallax'); 249 win.off('resize.fl-bg-video'); 250 }, 251 252 /** 253 * Checks to see if the current device has touch enabled. 254 * 255 * @since 1.0 256 * @access private 257 * @method _isTouch 258 * @return {Boolean} 259 */ 260 _isTouch: function() 261 { 262 if(('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)) { 263 return true; 264 } 265 266 return false; 267 }, 268 269 /** 270 * Checks to see if the current device is mobile. 271 * 272 * @since 1.7 273 * @access private 274 * @method _isMobile 275 * @return {Boolean} 276 */ 277 _isMobile: function() 278 { 279 return /Mobile|Android|Silk\/|Kindle|BlackBerry|Opera Mini|Opera Mobi|webOS/i.test( navigator.userAgent ); 280 }, 281 282 /** 283 * Initializes builder body classes. 284 * 285 * @since 1.0 286 * @access private 287 * @method _initClasses 288 */ 289 _initClasses: function() 290 { 291 var body = $( 'body' ), 292 ua = navigator.userAgent; 293 294 // Add the builder body class. 295 if ( ! body.hasClass( 'archive' ) && $( '.fl-builder-content-primary' ).length > 0 ) { 296 body.addClass('fl-builder'); 297 } 298 299 // Add the builder touch body class. 300 if(FLBuilderLayout._isTouch()) { 301 body.addClass('fl-builder-touch'); 302 } 303 304 // Add the builder mobile body class. 305 if(FLBuilderLayout._isMobile()) { 306 body.addClass('fl-builder-mobile'); 307 } 308 309 if ( $(window).width() < FLBuilderLayoutConfig.breakpoints.small ) { 310 body.addClass( 'fl-builder-breakpoint-small' ); 311 } 312 313 if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.small && $(window).width() < FLBuilderLayoutConfig.breakpoints.medium ) { 314 body.addClass( 'fl-builder-breakpoint-medium' ); 315 } 316 317 if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.medium && $(window).width() < FLBuilderLayoutConfig.breakpoints.large ) { 318 body.addClass( 'fl-builder-breakpoint-large' ); 319 } 320 321 if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.large ) { 322 body.addClass( 'fl-builder-breakpoint-default' ); 323 } 324 325 // IE11 body class. 326 if ( ua.indexOf( 'Trident/7.0' ) > -1 && ua.indexOf( 'rv:11.0' ) > -1 ) {
327 body.addClass( 'fl-builder-ie-11' ); 328 } 329 }, 330 331 /** 332 * Initializes builder node backgrounds that require 333 * additional JavaScript logic such as parallax. 334 * 335 * @since 1.1.4 336 * @access private 337 * @method _initBackgrounds 338 */ 339 _initBackgrounds: function() 340 { 341 var win = $(window); 342 343 // Init parallax backgrounds. 344 if($('.fl-row-bg-parallax').length > 0 && !FLBuilderLayout._isMobile()) { 345 FLBuilderLayout._scrollParallaxBackgrounds(); 346 FLBuilderLayout._initParallaxBackgrounds(); 347 win.on('resize.fl-bg-parallax', FLBuilderLayout._initParallaxBackgrounds); 348 win.on('scroll.fl-bg-parallax', FLBuilderLayout._scrollParallaxBackgrounds); 349 } 350 351 // Init video backgrounds. 352 if($('.fl-bg-video').length > 0) { 353 FLBuilderLayout._initBgVideos(); 354 FLBuilderLayout._resizeBgVideos(); 355 win.on('resize.fl-bg-video', FLBuilderLayout._resizeBgVideos); 356 } 357 }, 358 359 /** 360 * Initializes all parallax backgrounds in a layout. 361 * 362 * @since 1.1.4 363 * @access private 364 * @method _initParallaxBackgrounds 365 */ 366 _initParallaxBackgrounds: function() 367 { 368 $('.fl-row-bg-parallax').each(FLBuilderLayout._initParallaxBackground); 369 }, 370 371 /** 372 * Initializes a single parallax background. 373 * 374 * @since 1.1.4 375 * @access private 376 * @method _initParallaxBackgrounds 377 */ 378 _initParallaxBackground: function() 379 { 380 var row = $(this), 381 content = row.find('> .fl-row-content-wrap'), 382 winWidth = $(window).width(), 383 screenSize = '', 384 imageSrc = { 385 default: '', 386 medium: '', 387 responsive: '', 388 }; 389 390 imageSrc.default = row.data('parallax-image') || ''; 391 imageSrc.medium = row.data('parallax-image-medium') || imageSrc.default; 392 imageSrc.responsive = row.data('parallax-image-responsive') || imageSrc.medium; 393 394 if (winWidth > FLBuilderLayoutConfig.breakpoints.medium) { 395 screenSize = 'default'; 396 } else if (winWidth > FLBuilderLayoutConfig.breakpoints.small && winWidth <= FLBuilderLayoutConfig.breakpoints.medium ) { 397 screenSize = 'medium'; 398 } else if (winWidth <= FLBuilderLayoutConfig.breakpoints.small) { 399 screenSize = 'responsive'; 400 } 401 402 content.css('background-image', 'url(' + imageSrc[screenSize] + ')'); 403 row.data('current-image-loaded', screenSize ); 404 405 }, 406 407 /** 408 * Fires when the window is scrolled to adjust 409 * parallax backgrounds. 410 * 411 * @since 1.1.4 412 * @access private 413 * @method _scrollParallaxBackgrounds 414 */ 415 _scrollParallaxBackgrounds: function() 416 { 417 $('.fl-row-bg-parallax').each(FLBuilderLayout._scrollParallaxBackground); 418 }, 419 420 /** 421 * Fires when the window is scrolled to adjust 422 * a single parallax background. 423 * 424 * @since 1.1.4 425 * @access private 426 * @method _scrollParallaxBackground 427 */ 428 _scrollParallaxBackground: function() 429 { 430 var win = $(window), 431 row = $(this), 432 content = row.find('> .fl-row-content-wrap'), 433 speed = row.data('parallax-speed'), 434 offset = content.offset(), 435 yPos = -((win.scrollTop() - offset.top) / speed), 436 initialOffset = ( row.data('parallax-offset') != null ) ? row.data('parallax-offset') : 0, 437 totalOffset = yPos - initialOffset; 438 439 content.css('background-position', 'center ' + totalOffset + 'px'); 440 }, 441 442 /** 443 * Initializes all video backgrounds. 444 * 445 * @since 1.6.3.3 446 * @access private 447 * @method _initBgVideos 448 */ 449 _initBgVideos: function() 450 { 451 $('.fl-bg-video').each(FLBuilderLayout._initBgVideo); 452 }, 453 454 /** 455 * Initializes a video background. 456 * 457 * @since 1.6.3.3 458 * @access private 459 * @method _initBgVideo 460 */ 461 _initBgVideo: function() 462 { 463 var wrap = $( this ), 464 width = wrap.data( 'width' ), 465 height = wrap.data( 'height' ), 466 mp4 = wrap.data( 'mp4' ), 467 youtube = wrap.data( 'youtube'), 468 vimeo = wrap.data( 'vimeo'), 469 mp4Type = wrap.data( 'mp4-type' ), 470 webm = wrap.data( 'webm' ), 471 webmType = wrap.data( 'webm-type' ), 472 fallback = wrap.data( 'fallback' ), 473 loaded = wrap.data( 'loaded' ), 474 videoMobile = wrap.data( 'video-mobile' ), 475 fallbackTag = '', 476 videoTag = null, 477 mp4Tag = null, 478 webmTag = null; 479 480 // Return if the video has been loaded for this row. 481 if ( loaded ) { 482 return; 483 } 484
485 videoTag = $( '<video autoplay loop muted playsinline></video>' ); 486 487 /** 488 * Add poster image (fallback image) 489 */ 490 if( 'undefined' != typeof fallback && '' != fallback ) { 491 videoTag.attr( 'poster', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' ) 492 videoTag.css( 'background', 'transparent url("' + fallback + '") no-repeat center center' ) 493 videoTag.css( 'background-size', 'cover' ) 494 videoTag.css( 'height', '100%' ) 495 } 496 497 // MP4 Source Tag 498 if ( 'undefined' != typeof mp4 && '' != mp4 ) { 499 500 mp4Tag = $( '<source />' ); 501 mp4Tag.attr( 'src', mp4 ); 502 mp4Tag.attr( 'type', mp4Type ); 503 504 videoTag.append( mp4Tag ); 505 } 506 // WebM Source Tag 507 if ( 'undefined' != typeof webm && '' != webm ) { 508 509 webmTag = $( '<source />' ); 510 webmTag.attr( 'src', webm ); 511 webmTag.attr( 'type', webmType ); 512 513 videoTag.append( webmTag ); 514 } 515 516 // This is either desktop, or mobile is enabled. 517 if ( ! FLBuilderLayout._isMobile() || ( FLBuilderLayout._isMobile() && "yes" == videoMobile ) ) { 518 if ( 'undefined' != typeof youtube ) { 519 FLBuilderLayout._initYoutubeBgVideo.apply( this ); 520 } 521 else if ( 'undefined' != typeof vimeo ) { 522 FLBuilderLayout._initVimeoBgVideo.apply( this ); 523 } 524 else { 525 wrap.append( videoTag ); 526 } 527 } 528 else { 529 // if we are here, it means we are on mobile and NO is set so remove video src and use fallback 530 videoTag.attr('src', '') 531 wrap.append( videoTag ); 532 } 533 534 // Mark this video as loaded. 535 wrap.data('loaded', true); 536 }, 537 538 /** 539 * Initializes Youtube video background 540 * 541 * @since 1.9 542 * @access private 543 * @method _initYoutubeBgVideo 544 */ 545 _initYoutubeBgVideo: function() 546 { 547 var playerWrap = $(this), 548 videoId = playerWrap.data('video-id'), 549 videoPlayer = playerWrap.find('.fl-bg-video-player'), 550 enableAudio = playerWrap.data('enable-audio'), 551 audioButton = playerWrap.find('.fl-bg-video-audio'), 552 startTime = 'undefined' !== typeof playerWrap.data('start') ? playerWrap.data('start') : 0, 553 startTime = 'undefined' !== typeof playerWrap.data('t') && startTime === 0 ? playerWrap.data('t') : startTime, 554 endTime = 'undefined' !== typeof playerWrap.data('end') ? playerWrap.data('end') : 0, 555 loop = 'undefined' !== typeof playerWrap.data('loop') ? playerWrap.data('loop') : 1, 556 stateCount = 0, 557 player,fallback_showing; 558 559 if ( videoId ) { 560 fallback = playerWrap.data('fallback') || false 561 if( fallback ) { 562 playerWrap.find('iframe').remove() 563 fallbackTag = $( '<div></div>' ); 564 fallbackTag.addClass( 'fl-bg-video-fallback' ); 565 fallbackTag.css( 'background-image', 'url(' + playerWrap.data('fallback') + ')' ); 566 fallbackTag.css( 'background-size', 'cover' ); 567 fallbackTag.css( 'transition', 'background-image 1s') 568 playerWrap.append( fallbackTag ); 569 fallback_showing = true; 570 } 571 FLBuilderLayout._onYoutubeApiReady( function( YT ) { 572 setTimeout( function() { 573 574 player = new YT.Player( videoPlayer[0], { 575 videoId: videoId, 576 events: { 577 onReady: function(event) { 578 if ( "no" === enableAudio || FLBuilderLayout._isMobile() ) { 579 event.target.mute(); 580 } 581 else if ( "yes" === enableAudio && event.target.isMuted ) { 582 event.target.unMute(); 583 } 584 585 // Store an instance to a parent 586 playerWrap.data('YTPlayer', player); 587 FLBuilderLayout._resizeYoutubeBgVideo.apply(playerWrap); 588 589 // Queue the video. 590 event.target.playVideo(); 591 592 if ( audioButton.length > 0 && ! FLBuilderLayout._isMobile() ) { 593 audioButton.on( 'click', {button: audioButton, player: player}, FLBuilderLayout._toggleBgVideoAudio ); 594 } 595 }, 596 onStateChange: function( event ) { 597 598 if ( event.data === 1 ) { 599 if ( fallback_showing ) { 600 $( '.fl-bg-video-fallback' ).css( 'background-image', 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)' ) 601 } 602 } 603 // Manual check if video is not playable in some browsers. 604 // StateChange order: [-1, 3, -1] 605 if ( stateCount < 4 ) { 606 stateCount++; 607 } 608 609 // Comply with the audio policy in some browsers like Chrome and Safari. 610 if ( stateCount > 1 && (-1 === event.data || 2 === event.data) && "yes" === enableAudio ) { 611 player.mute(); 612 player.playVideo(); 613 audioButton.show(); 614 } 615 616 if ( event.data === YT.PlayerState.ENDED && 1 === loop ) { 617 if ( startTime > 0 ) { 618 player.seekTo( startTime ); 619 } 620 else { 621 player.playVideo(); 622 } 623 } 624 }, 625 onError: function(event) { 626 console.info('YT Error: ' + event.data) 627 FLBuilderLayout._onErrorYoutubeVimeo(playerWrap) 628 } 629 }, 630 playerVars: { 631 playsinline: FLBuilderLayout._isMobile() ? 1 : 0, 632 controls: 0, 633 showinfo: 0, 634 rel : 0, 635 start: startTime, 636 end: endTime, 637 } 638 } ); 639 }, 1 ); 640 } ); 641 } 642 }, 643 644 /** 645 * On youtube or vimeo error show the fallback image if available. 646 * @since 2.0.7 647 */ 648 _onErrorYoutubeVimeo: function(playerWrap) { 649 650 fallback = playerWrap.data('fallback') || false 651 if( ! fallback ) { 652 return false;
653 } 654 playerWrap.find('iframe').remove() 655 fallbackTag = $( '<div></div>' ); 656 fallbackTag.addClass( 'fl-bg-video-fallback' ); 657 fallbackTag.css( 'background-image', 'url(' + playerWrap.data('fallback') + ')' ); 658 playerWrap.append( fallbackTag ); 659 }, 660 661 /** 662 * Check if Youtube API has been downloaded 663 * 664 * @since 1.9 665 * @access private 666 * @method _onYoutubeApiReady 667 * @param {Function} callback Method to call when YT API has been loaded 668 */ 669 _onYoutubeApiReady: function( callback ) { 670 if ( window.YT && YT.loaded ) { 671 callback( YT ); 672 } else { 673 // If not ready check again by timeout.. 674 setTimeout( function() { 675 FLBuilderLayout._onYoutubeApiReady( callback ); 676 }, 350 ); 677 } 678 }, 679 680 /** 681 * Initializes Vimeo video background 682 * 683 * @since 1.9 684 * @access private 685 * @method _initVimeoBgVideo 686 */ 687 _initVimeoBgVideo: function() 688 { 689 var playerWrap = $(this), 690 videoId = playerWrap.data('video-id'), 691 videoPlayer = playerWrap.find('.fl-bg-video-player'), 692 enableAudio = playerWrap.data('enable-audio'), 693 audioButton = playerWrap.find('.fl-bg-video-audio'), 694 player, 695 width = playerWrap.outerWidth(), 696 ua = navigator.userAgent; 697 698 if ( typeof Vimeo !== 'undefined' && videoId ) { 699 player = new Vimeo.Player(videoPlayer[0], { 700 id : videoId, 701 loop : true, 702 title : false, 703 portrait : false, 704 background : true, 705 autopause : false, 706 muted : true 707 }); 708 709 playerWrap.data('VMPlayer', player); 710 if ( "no" === enableAudio ) { 711 player.setVolume(0); 712 } 713 else if ("yes" === enableAudio ) { 714 // Chrome, Safari, Firefox have audio policy restrictions for autoplay videos. 715 if ( ua.indexOf("Safari") > -1 || ua.indexOf("Chrome") > -1 || ua.indexOf("Firefox") > -1 ) { 716 player.setVolume(0); 717 audioButton.show(); 718 } 719 else { 720 player.setVolume(1); 721 } 722 } 723 724 player.play().catch(function(error) { 725 FLBuilderLayout._onErrorYoutubeVimeo(playerWrap) 726 }); 727 728 if ( audioButton.length > 0 ) { 729 audioButton.on( 'click', {button: audioButton, player: player}, FLBuilderLayout._toggleBgVideoAudio ); 730 } 731 } 732 }, 733 734 /** 735 * Mute / unmute audio on row's video background. 736 * It works for both Youtube and Vimeo. 737 * 738 * @since 2.1.3 739 * @access private 740 * @method _toggleBgVideoAudio 741 * @param {Object} e Method arguments 742 */ 743 _toggleBgVideoAudio: function( e ) { 744 var player = e.data.player, 745 control = e.data.button.find('.fl-audio-control'); 746 747 if ( control.hasClass( 'fa-volume-off' ) ) { 748 // Unmute 749 control 750 .removeClass( 'fa-volume-off' ) 751 .addClass( 'fa-volume-up' ); 752 e.data.button.find( '.fa-times' ).hide(); 753 754 if ( 'function' === typeof player.unMute ) { 755 player.unMute(); 756 } 757 else { 758 player.setVolume( 1 ); 759 } 760 } 761 else { 762 // Mute 763 control 764 .removeClass( 'fa-volume-up' ) 765 .addClass( 'fa-volume-off' ); 766 e.data.button.find( '.fa-times' ).show(); 767 768 if ( 'function' === typeof player.unMute ) { 769 player.mute(); 770 } 771 else { 772 player.setVolume( 0 ); 773 } 774 } 775 }, 776 777 /** 778 * Fires when there is an error loading a video 779 * background source and shows the fallback. 780 * 781 * @since 1.6.3.3 782 * @access private 783 * @method _videoBgSourceError 784 * @param {Object} e An event object 785 * @deprecated 2.0.3 786 */ 787 _videoBgSourceError: function( e ) 788 { 789 var source = $( e.target ), 790 wrap = source.closest( '.fl-bg-video' ), 791 vid = wrap.find( 'video' ), 792 fallback = wrap.data( 'fallback' ), 793 fallbackTag = ''; 794 source.remove(); 795 796 if ( vid.find( 'source' ).length ) { 797 // Don't show the fallback if we still have other sources to check. 798 return; 799 } else if ( '' !== fallback ) { 800 fallbackTag = $( '<div></div>' ); 801 fallbackTag.addClass( 'fl-bg-video-fallback' ); 802 fallbackTag.css( 'background-image', 'url(' + fallback + ')' ); 803 wrap.append( fallbackTag ); 804 vid.remove(); 805 } 806 }, 807 808 /** 809 * Fires when the window is resized to resize 810 * all video backgrounds. 811 * 812 * @since 1.1.4 813 * @access private 814 * @method _resizeBgVideos 815 */ 816 _resizeBgVideos: function() 817 { 818 $('.fl-bg-video').each( function() { 819 820 FLBuilderLayout._resizeBgVideo.apply( this ); 821 822 if ( $( this ).parent().find( 'img' ).length > 0 ) { 823 $( this ).parent().imagesLoaded( $.proxy( FLBuilderLayout._resizeBgVideo, this ) ); 824 } 825 } ); 826 }, 827 828 /** 829 * Fires when the window is resized to resize 830 * a single video background. 831 * 832 * @since 1.1.4 833 * @access private 834 * @method _resizeBgVideo 835 */ 836 _resizeBgVideo: function() 837 { 838 if ( 0 === $( this ).find( 'video' ).length && 0 === $( this ).find( 'iframe' ).length ) { 839 return; 840 } 841 842 var wrap = $(this), 843 wrapHeight = wrap.outerHeight(), 844 wrapWidth = wrap.outerWidth(), 845 vid = wrap.find('video'), 846 vidHeight = wrap.data('height'), 847 vidWidth = wrap.data('width'), 848 newWidth = wrapWidth, 849 newHeight = Math.round(vidHeight * wrapWidth/vidWidth), 850 newLeft = 0, 851 newTop = 0, 852 iframe = wrap.find('iframe'); 853 854 if ( vid.length ) { 855 if(vidHeight === '' || typeof vidHeight === 'undefined' || vidWidth === '' || typeof vidWidth === 'undefined') { 856 vid.css({ 857 'left' : '0px', 858 'top' : '0px', 859 'width' : newWidth + 'px' 860 }); 861 862 // Try to set the actual video dimension on 'loadedmetadata' when using URL as video source 863 vid.on('loadedmetadata', FLBuilderLayout._resizeOnLoadedMeta); 864 865 } 866 else { 867 if(newHeight < wrapHeight) { 868 newHeight = wrapHeight; 869 newLeft = -((newWidth - wrapWidth) / 2); 870 871 if ( 0 != vidHeight ) { 872 newWidth = Math.round(vidWidth * wrapHeight/vidHeight); 873 } 874 } 875 else { 876 newTop = -((newHeight - wrapHeight)/2); 877 } 878 879 vid.css({ 880 'left' : newLeft + 'px', 881 'top' : newTop + 'px', 882 'height' : newHeight + 'px', 883 'width' : newWidth + 'px' 884 }); 885 886 vid.on('loadedmetadata', FLBuilderLayout._resizeOnLoadedMeta); 887 888 } 889 } 890 else if ( iframe.length ) { 891 892 // Resize Youtube video player within iframe tag 893 if ( typeof wrap.data('youtube') !== 'undefined' ) { 894 FLBuilderLayout._resizeYoutubeBgVideo.apply(this); 895 } 896 } 897 }, 898 899 /** 900 * Fires when video meta has been loaded. 901 * This will be Triggered when width/height attributes were not specified during video background resizing. 902 * 903 * @since 1.8.5 904 * @access private 905 * @method _resizeOnLoadedMeta 906 */ 907 _resizeOnLoadedMeta: function(){ 908 var video = $(this), 909 wrapHeight = video.parent().outerHeight(), 910 wrapWidth = video.parent().outerWidth(), 911 vidWidth = video[0].videoWidth, 912 vidHeight = video[0].videoHeight, 913 newHeight = Math.round(vidHeight * wrapWidth/vidWidth), 914 newWidth = wrapWidth, 915 newLeft = 0, 916 newTop = 0; 917 918 if(newHeight < wrapHeight) { 919 newHeight = wrapHeight; 920 newWidth = Math.round(vidWidth * wrapHeight/vidHeight); 921 newLeft = -((newWidth - wrapWidth)/2); 922 } 923 else { 924 newTop = -((newHeight - wrapHeight)/2); 925 } 926 927 video.parent().data('width', vidWidth); 928 video.parent().data('height', vidHeight); 929 930 video.css({ 931 'left' : newLeft + 'px', 932 'top' : newTop + 'px', 933 'width' : newWidth + 'px', 934 'height' : newHeight + 'px' 935 }); 936 }, 937 938 /** 939 * Fires when the window is resized to resize 940 * a single Youtube video background. 941 * 942 * @since 1.9 943 * @access private 944 * @method _resizeYoutubeBgVideo 945 */ 946 _resizeYoutubeBgVideo: function() 947 { 948 var wrap = $(this), 949 wrapWidth = wrap.outerWidth(), 950 wrapHeight = wrap.outerHeight(), 951 player = wrap.data('YTPlayer'), 952 video = player ? player.getIframe() : null, 953 aspectRatioSetting = '16:9', // Medium 954 aspectRatioArray = aspectRatioSetting.split( ':' ),
955 aspectRatio = aspectRatioArray[0] / aspectRatioArray[1], 956 ratioWidth = wrapWidth / aspectRatio, 957 ratioHeight = wrapHeight * aspectRatio, 958 isWidthFixed = wrapWidth / wrapHeight > aspectRatio, 959 width = isWidthFixed ? wrapWidth : ratioHeight, 960 height = isWidthFixed ? ratioWidth : wrapHeight; 961 962 if ( video ) { 963 $(video).width( width ).height( height ); 964 } 965 }, 966 967 /** 968 * Initializes module animations. 969 * 970 * @since 1.1.9 971 * @access private 972 * @method _initModuleAnimations 973 */ 974 _initModuleAnimations: function() 975 { 976 if(typeof jQuery.fn.waypoint !== 'undefined') { 977 $('.fl-animation').each( function() { 978 var node = $( this ), 979 nodeTop = node.offset().top, 980 winHeight = $( window ).height(), 981 bodyHeight = $( 'body' ).height(), 982 waypoint = FLBuilderLayoutConfig.waypoint, 983 offset = '80%'; 984 985 if ( typeof waypoint.offset !== undefined ) { 986 offset = FLBuilderLayoutConfig.waypoint.offset + '%'; 987 } 988 989 if ( bodyHeight - nodeTop < winHeight * 0.2 ) { 990 offset = '100%'; 991 } 992 993 node.waypoint({ 994 offset: offset, 995 handler: FLBuilderLayout._doModuleAnimation 996 }); 997 } ); 998 } 999 }, 1000 1001 /** 1002 * Runs a module animation. 1003 * 1004 * @since 1.1.9 1005 * @access private 1006 * @method _doModuleAnimation 1007 */ 1008 _doModuleAnimation: function() 1009 { 1010 var module = 'undefined' == typeof this.element ? $(this) : $(this.element), 1011 delay = parseFloat(module.data('animation-delay')), 1012 duration = parseFloat(module.data('animation-duration')); 1013 1014 if ( ! isNaN( duration ) ) { 1015 module.css( 'animation-duration', duration + 's' ); 1016 } 1017 1018 if(!isNaN(delay) && delay > 0) { 1019 setTimeout(function(){ 1020 module.addClass('fl-animated'); 1021 }, delay * 1000); 1022 } else { 1023 setTimeout(function(){ 1024 module.addClass('fl-animated'); 1025 }, 1); 1026 } 1027 }, 1028 1029 /** 1030 * Opens a tab or accordion item if the browser hash is set 1031 * to the ID of one on the page. 1032 * 1033 * @since 1.6.0 1034 * @access private 1035 * @method _initHash 1036 */ 1037 _initHash: function() 1038 { 1039 var hash = window.location.hash.replace( '#', '' ).split( '/' ).shift(), 1040 element = null, 1041 tabs = null, 1042 responsiveLabel = null, 1043 tabIndex = null, 1044 label = null; 1045 1046 if ( '' !== hash ) { 1047 1048 try { 1049 1050 element = $( '#' + hash ); 1051 1052 if ( element.length > 0 ) { 1053 1054 if ( element.hasClass( 'fl-accordion-item' ) ) { 1055 setTimeout( function() { 1056 element.find( '.fl-accordion-button' ).trigger( 'click' ); 1057 }, 100 ); 1058 } 1059 if ( element.hasClass( 'fl-tabs-panel' ) ) { 1060 1061 setTimeout( function() { 1062 1063 tabs = element.closest( '.fl-tabs' ); 1064 responsiveLabel = element.find( '.fl-tabs-panel-label' ); 1065 tabIndex = responsiveLabel.data( 'index' ); 1066 label = tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' ); 1067 1068 if ( responsiveLabel.is( ':visible' ) ) { 1069 responsiveLabel.trigger( 'click' ); 1070 } 1071 else { 1072 label[0].click(); 1073 FLBuilderLayout._scrollToElement( element ); 1074 } 1075 1076 }, 100 ); 1077 } 1078 } 1079 } 1080 catch( e ) {} 1081 } 1082 }, 1083 1084 /** 1085 * Initializes all anchor links on the page for smooth scrolling. 1086 * 1087 * @since 1.4.9 1088 * @access private 1089 * @method _initAnchorLinks 1090 */ 1091 _initAnchorLinks: function() 1092 { 1093 $( 'a' ).each( FLBuilderLayout._initAnchorLink ); 1094 }, 1095 1096 /** 1097 * Initializes a single anchor link for smooth scrolling. 1098 * 1099 * @since 1.4.9 1100 * @access private 1101 * @method _initAnchorLink 1102 */ 1103 _initAnchorLink: function() 1104 { 1105 var link = $( this ), 1106 href = link.attr( 'href' ), 1107 loc = window.location, 1108 id = null, 1109 element = null, 1110 flNode = false; 1111 1112 if ( 'undefined' != typeof href && href.indexOf( '#' ) > -1 && link.closest('svg').length < 1 ) { 1113 1114 if ( loc.pathname.replace( /^\//, '' ) == this.pathname.replace( /^\//, '' ) && loc.hostname == this.hostname ) { 1115 1116 try { 1117 1118 id = href.split( '#' ).pop(); 1119 // If there is no ID then we have nowhere to look 1120 // Fixes a quirk in jQuery and FireFox 1121 if( ! id ) { 1122 return; 1123 } 1124 element = $( '#' + id ); 1125 1126 if ( element.length > 0 ) { 1127 flNode = element.hasClass( 'fl-row' ) || element.hasClass( 'fl-col' ) || element.hasClass( 'fl-module' ); 1128 if ( !element.hasClass( 'fl-no-scroll' ) && ( link.hasClass( 'fl-scroll-link' ) || flNode ) ) { 1129 $( link ).on( 'click', FLBuilderLayout._scrollToElementOnLinkClick ); 1130 } 1131 if ( element.hasClass( 'fl-accordion-item' ) ) { 1132 $( link ).on( 'click', FLBuilderLayout._scrollToAccordionOnLinkClick ); 1133 } 1134 if ( element.hasClass( 'fl-tabs-panel' ) ) { 1135 $( link ).on( 'click', FLBuilderLayout._scrollToTabOnLinkClick ); 1136 } 1137 } 1138 } 1139 catch( e ) {} 1140 } 1141 } 1142 }, 1143 1144 /** 1145 * Scrolls to an element when an anchor link is clicked. 1146 * 1147 * @since 1.4.9 1148 * @access private 1149 * @method _scrollToElementOnLinkClick 1150 * @param {Object} e An event object. 1151 * @param {Function} callback A function to call when the scroll is complete. 1152 */ 1153 _scrollToElementOnLinkClick: function( e, callback ) 1154 { 1155 var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() ); 1156 1157 FLBuilderLayout._scrollToElement( element, callback ); 1158 1159 e.preventDefault(); 1160 }, 1161 1162 /** 1163 * Scrolls to an element. 1164 * 1165 * @since 1.6.4.5 1166 * @access private 1167 * @method _scrollToElement 1168 * @param {Object} element The element to scroll to. 1169 * @param {Function} callback A function to call when the scroll is complete. 1170 */ 1171 _scrollToElement: function( element, callback ) 1172 { 1173 var config = FLBuilderLayoutConfig.anchorLinkAnimations, 1174 dest = 0, 1175 win = $( window ), 1176 doc = $( document ); 1177 1178 if ( element.length > 0 ) { 1179 1180 if ( 'fixed' === element.css('position') || 'fixed' === element.parent().css('position') ) { 1181 dest = element.position().top; 1182 } 1183 else if ( element.offset().top > doc.height() - win.height() ) { 1184 dest = doc.height() - win.height(); 1185 } 1186 else { 1187 dest = element.offset().top - config.offset; 1188 } 1189 1190 $( 'html, body' ).animate( { scrollTop: dest }, config.duration, config.easing, function() { 1191 1192 if ( 'undefined' != typeof callback ) { 1193 callback(); 1194 } 1195 1196 if ( undefined != element.attr( 'id' ) ) { 1197 1198 if ( history.pushState ) { 1199 history.pushState( null, null, '#' + element.attr( 'id' ) ); 1200 } 1201 else { 1202 window.location.hash = element.attr( 'id' ); 1203 } 1204 } 1205 } ); 1206 } 1207 }, 1208 1209 /** 1210 * Scrolls to an accordion item when a link is clicked. 1211 * 1212 * @since 1.5.9 1213 * @access private 1214 * @method _scrollToAccordionOnLinkClick 1215 * @param {Object} e An event object. 1216 */ 1217 _scrollToAccordionOnLinkClick: function( e ) 1218 { 1219 var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() ); 1220 1221 if ( element.length > 0 ) { 1222 1223 var callback = function() { 1224 if ( element ) { 1225 element.find( '.fl-accordion-button' ).trigger( 'click' ); 1226 element = false;
1227 } 1228 }; 1229 1230 FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback ); 1231 } 1232 }, 1233 1234 /** 1235 * Scrolls to a tab panel when a link is clicked. 1236 * 1237 * @since 1.5.9 1238 * @access private 1239 * @method _scrollToTabOnLinkClick 1240 * @param {Object} e An event object. 1241 */ 1242 _scrollToTabOnLinkClick: function( e ) 1243 { 1244 var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() ), 1245 tabs = null, 1246 label = null, 1247 responsiveLabel = null; 1248 1249 if ( element.length > 0 ) { 1250 1251 tabs = element.closest( '.fl-tabs' ); 1252 responsiveLabel = element.find( '.fl-tabs-panel-label' ); 1253 tabIndex = responsiveLabel.data( 'index' ); 1254 label = tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' ); 1255 1256 if ( responsiveLabel.is( ':visible' ) ) { 1257 1258 var callback = function() { 1259 if ( element ) { 1260 responsiveLabel.trigger( 'click' ); 1261 element = false; 1262 } 1263 }; 1264 1265 FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback ); 1266 } 1267 else { 1268 label[0].click(); 1269 FLBuilderLayout._scrollToElement( element ); 1270 } 1271 1272 e.preventDefault(); 1273 } 1274 }, 1275 1276 /** 1277 * Initializes all builder forms on a page. 1278 * 1279 * @since 1.5.4 1280 * @access private 1281 * @method _initForms 1282 */ 1283 _initForms: function() 1284 { 1285 if ( ! FLBuilderLayout._hasPlaceholderSupport ) { 1286 $( '.fl-form-field input' ).each( FLBuilderLayout._initFormFieldPlaceholderFallback ); 1287 } 1288 1289 $( '.fl-form-field input' ).on( 'focus', FLBuilderLayout._clearFormFieldError ); 1290 }, 1291 1292 /** 1293 * Checks to see if the current device has HTML5 1294 * placeholder support. 1295 * 1296 * @since 1.5.4 1297 * @access private 1298 * @method _hasPlaceholderSupport 1299 * @return {Boolean} 1300 */ 1301 _hasPlaceholderSupport: function() 1302 { 1303 var input = document.createElement( 'input' ); 1304 1305 return 'undefined' != input.placeholder; 1306 }, 1307 1308 /** 1309 * Initializes the fallback for when placeholders aren't supported. 1310 * 1311 * @since 1.5.4 1312 * @access private 1313 * @method _initFormFieldPlaceholderFallback 1314 */ 1315 _initFormFieldPlaceholderFallback: function() 1316 { 1317 var field = $( this ), 1318 val = field.val(), 1319 placeholder = field.attr( 'placeholder' ); 1320 1321 if ( 'undefined' != placeholder && '' === val ) { 1322 field.val( placeholder ); 1323 field.on( 'focus', FLBuilderLayout._hideFormFieldPlaceholderFallback ); 1324 field.on( 'blur', FLBuilderLayout._showFormFieldPlaceholderFallback ); 1325 } 1326 }, 1327 1328 /** 1329 * Hides a fallback placeholder on focus. 1330 * 1331 * @since 1.5.4 1332 * @access private 1333 * @method _hideFormFieldPlaceholderFallback 1334 */ 1335 _hideFormFieldPlaceholderFallback: function() 1336 { 1337 var field = $( this ), 1338 val = field.val(), 1339 placeholder = field.attr( 'placeholder' ); 1340 1341 if ( val == placeholder ) { 1342 field.val( '' ); 1343 } 1344 }, 1345 1346 /** 1347 * Shows a fallback placeholder on blur. 1348 * 1349 * @since 1.5.4 1350 * @access private 1351 * @method _showFormFieldPlaceholderFallback 1352 */ 1353 _showFormFieldPlaceholderFallback: function() 1354 { 1355 var field = $( this ), 1356 val = field.val(), 1357 placeholder = field.attr( 'placeholder' ); 1358 1359 if ( '' === val ) { 1360 field.val( placeholder ); 1361 } 1362 }, 1363 1364 /** 1365 * Clears a form field error message. 1366 * 1367 * @since 1.5.4 1368 * @access private 1369 * @method _clearFormFieldError 1370 */ 1371 _clearFormFieldError: function() 1372 { 1373 var field = $( this ); 1374 1375 field.removeClass( 'fl-form-error' ); 1376 field.siblings( '.fl-form-error-message' ).hide(); 1377 }, 1378 1379 /** 1380 * Init Row Shape Layer's height. 1381 * 1382 * @since 2.5.3 1383 * @access private 1384 * @method _initRowShapeLayerHeight 1385 */ 1386 _initRowShapeLayerHeight: function () { 1387 FLBuilderLayout._adjustRowShapeLayerHeight(); 1388 $( window ).on( 'resize', FLBuilderLayout._adjustRowShapeLayerHeight ); 1389 }, 1390 1391 /** 1392 * Adjust Row Shape Layer's height to fix to remove the fine line that appears on certain screen sizes. 1393 * 1394 * @since 2.5.3 1395 * @access private 1396 * @method _adjustRowShapeLayerHeight 1397 */ 1398 _adjustRowShapeLayerHeight: function() { 1399 var rowShapeLayers = $('.fl-builder-shape-layer'); 1400 1401 $( rowShapeLayers ).each(function (index) { 1402 var rowShapeLayer = $(this), 1403 shape = $(rowShapeLayer).find('svg'), 1404 height = shape.height(),
1405 excludeShapes = '.fl-builder-shape-circle, .fl-builder-shape-dot-cluster, .fl-builder-shape-topography, .fl-builder-shape-rect'; 1406 1407 if ( ! rowShapeLayer.is( excludeShapes ) ) { 1408 $(shape).css('height', Math.ceil( height ) ); 1409 } 1410 }); 1411 }, 1412 _string_to_slug: function( str ) { 1413 str = str.replace(/^\s+|\s+$/g, ''); // trim 1414 // remove accents, swap ñ for n, etc 1415 var from = "à áäâèéëêìÃïîòóöôùúüûñçÄÅ¡ÄÅžýúůÄťŷ"; 1416 var to = "aaaaeeeeiiiioooouuuuncescrzyuudtn-"; 1417 for (var i=0, l=from.length ; i < l ; i++) { 1418 str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i)); 1419 } 1420 if ( 'undefined' == typeof window._fl_string_to_slug_regex ) { 1421 regex = new RegExp('[^a-zA-Z0-9\'":() !.,-_|]', 'g'); 1422 } else { 1423 regex = new RegExp('[^' + window._fl_string_to_slug_regex + '\'":\(\) !.,-_|]', 'g'); 1424 } 1425 str = str.replace(regex, '') // remove invalid chars 1426 .replace(/\s+/g, ' '); // collapse whitespace and replace by a space 1427 return str; 1428 }, 1429 _reorderMenu: function() { 1430 if ( $('#wp-admin-bar-fl-builder-frontend-edit-link-default li').length > 1 ) { 1431 $( '#wp-admin-bar-fl-builder-frontend-duplicate-link' ) 1432 .appendTo('#wp-admin-bar-fl-builder-frontend-edit-link-default') 1433 .css( 'padding-top', '5px' ) 1434 .css( 'border-top', '2px solid #1D2125' ) 1435 .css( 'margin-top', '5px' ) 1436 } 1437 } 1438 }; 1439 1440 /* Initializes the builder layout. */ 1441 $(function(){ 1442 FLBuilderLayout.init(); 1443 }); 1444 1445})(jQuery); 1446 1447/* Start Global JS */ 1448 1449/* End Global JS */ 1450 1451 1452/* Start Global Node Custom JS */ 1453 1454/* End Global Node Custom JS */ 1455 1456 1457/* Start Layout Custom JS */ 1458 1459/* End Layout Custom JS */ 1460 1461(function($){ 1462 1463 /** 1464 * Helper class for header layout logic. 1465 * 1466 * @since 1.0 1467 * @class FLThemeBuilderHeaderLayout 1468 */ 1469 FLThemeBuilderHeaderLayout = { 1470 1471 /** 1472 * A reference to the window object for this page. 1473 * 1474 * @since 1.0 1475 * @property {Object} win 1476 */ 1477 win : null, 1478 1479 /** 1480 * A reference to the body object for this page. 1481 * 1482 * @since 1.0 1483 * @property {Object} body 1484 */ 1485 body : null, 1486 1487 /** 1488 * A reference to the header object for this page. 1489 * 1490 * @since 1.0 1491 * @property {Object} header 1492 */ 1493 header : null, 1494 1495 /** 1496 * Whether this header overlays the content or not. 1497 * 1498 * @since 1.0 1499 * @property {Boolean} overlay 1500 */ 1501 overlay : false, 1502 1503 /** 1504 * Whether the page has the WP admin bar or not. 1505 * 1506 * @since 1.0 1507 * @property {Boolean} hasAdminBar 1508 */ 1509 hasAdminBar : false, 1510 1511 /** 1512 * Breakpoint for when the sticky header should apply. 1513 * 1514 * @since 1.4 1515 * @property {String} stickyOn 1516 */ 1517 stickyOn: '', 1518 1519 /** 1520 * A reference of the sticky and shrink header breakpoint. 1521 * 1522 * @since 1.2.5 1523 * @property {Number} breakpointWidth 1524 */ 1525 breakpointWidth: 0, 1526 1527 /** 1528 * Initializes header layout logic. 1529 * 1530 * @since 1.0 1531 * @method init 1532 */ 1533 init: function() 1534 { 1535 var editing = $( 'html.fl-builder-edit' ).length, 1536 header = $( '.fl-builder-content[data-type=header]' ), 1537 menuModule = header.find( '.fl-module-menu' ), 1538 breakpoint = null; 1539 1540 if ( ! editing && header.length ) { 1541 1542 header.imagesLoaded( $.proxy( function() { 1543 1544 this.win = $( window ); 1545 this.body = $( 'body' ); 1546 this.header = header.eq( 0 ); 1547 this.overlay = !! Number( header.attr( 'data-overlay' ) ); 1548 this.hasAdminBar = !! $( 'body.admin-bar' ).length; 1549 this.stickyOn = this.header.data( 'sticky-on' ); 1550 breakpoint = this.header.data( 'sticky-breakpoint' ); 1551 1552 if ( '' == this.stickyOn ) { 1553 if ( typeof FLBuilderLayoutConfig.breakpoints[ breakpoint ] !== undefined ) { 1554 this.breakpointWidth = FLBuilderLayoutConfig.breakpoints[ breakpoint ]; 1555 } 1556 else { 1557 this.breakpointWidth = FLBuilderLayoutConfig.breakpoints.medium; 1558 } 1559 } 1560 1561 if ( Number( header.attr( 'data-sticky' ) ) ) { 1562 1563 this.header.data( 'original-top', this.header.offset().top ); 1564 this.win.on( 'resize', $.throttle( 500, $.proxy( this._initSticky, this ) ) ); 1565 this._initSticky(); 1566 1567 } 1568 1569 }, this ) ); 1570 } 1571 }, 1572 1573 /** 1574 * Initializes sticky logic for a header. 1575 * 1576 * @since 1.0 1577 * @access private 1578 * @method _initSticky 1579 */ 1580 _initSticky: function( e ) 1581 {
1582 var header = $('.fl-builder-content[data-type=header]'), 1583 windowSize = this.win.width(), 1584 makeSticky = false; 1585 1586 makeSticky = this._makeWindowSticky( windowSize ); 1587 if ( makeSticky || ( this.breakpointWidth > 0 && windowSize >= this.breakpointWidth ) ) { 1588 this.win.on( 'scroll.fl-theme-builder-header-sticky', $.proxy( this._doSticky, this ) ); 1589 // 1590 // Check if Event Type is 'resize' then invoke this._doSticky() 1591 // only if the 'fl-theme-builder-header-sticky' class is already present. 1592 // 1593 if ( e && 'resize' === e.type ) { 1594 if ( this.header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 1595 this._doSticky( e ); 1596 } 1597 this._adjustStickyHeaderWidth(); 1598 } 1599 1600 if ( Number( header.attr( 'data-shrink' ) ) ) { 1601 this.header.data( 'original-height', this.header.outerHeight() ); 1602 this.win.on( 'resize', $.throttle( 500, $.proxy( this._initShrink, this ) ) ); 1603 this._initShrink(); 1604 } 1605 1606 this._initFlyoutMenuFix( e ); 1607 } else { 1608 this.win.off( 'scroll.fl-theme-builder-header-sticky' ); 1609 this.win.off( 'resize.fl-theme-builder-header-sticky' ); 1610 1611 this.header.removeClass( 'fl-theme-builder-header-sticky' ); 1612 this.header.removeAttr( 'style' ); 1613 this.header.parent().css( 'padding-top', '0' ); 1614 } 1615 }, 1616 1617 /** 1618 * Check if Header should be sticky at a particular Window size. 1619 * 1620 * @since 1.4 1621 * @access private 1622 * @param widowSize 1623 * @method _makeWindowSticky 1624 */ 1625 _makeWindowSticky: function ( windowSize ) 1626 { 1627 var makeSticky = false; 1628 1629 switch (this.stickyOn) { 1630 case 'xl': 1631 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['large']; 1632 break; 1633 case '': // Default 1634 case 'desktop': 1635 makeSticky = windowSize >= FLBuilderLayoutConfig.breakpoints['medium']; 1636 break; 1637 case 'desktop-medium': 1638 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small']; 1639 break; 1640 case 'large': 1641 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['medium'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large']; 1642 break; 1643 case 'large-medium': 1644 makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large']; 1645 break; 1646 case 'medium': 1647 makeSticky = ( windowSize <= FLBuilderLayoutConfig.breakpoints['medium'] && windowSize > FLBuilderLayoutConfig.breakpoints['small'] ); 1648 break; 1649 case 'medium-mobile': 1650 makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['medium']); 1651 break; 1652 case 'mobile': 1653 makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['small']); 1654 break; 1655 case 'all': 1656 makeSticky = true; 1657 break; 1658 } 1659 1660 return makeSticky; 1661 }, 1662 1663 /** 1664 * Sticks the header when the page is scrolled. 1665 * 1666 * @since 1.0 1667 * @access private 1668 * @method _doSticky 1669 */ 1670 _doSticky: function( e ) 1671 { 1672 var winTop = Math.floor( this.win.scrollTop() ), 1673 headerTop = Math.floor( this.header.data( 'original-top' ) ), 1674 hasStickyClass = this.header.hasClass( 'fl-theme-builder-header-sticky' ), 1675 hasScrolledClass = this.header.hasClass( 'fl-theme-builder-header-scrolled' ), 1676 beforeHeader = this.header.prevAll( '.fl-builder-content' ), 1677 bodyTopPadding = parseInt( jQuery('body').css('padding-top') ), 1678 winBarHeight = $('#wpadminbar').length ? $('#wpadminbar').outerHeight() : 0, 1679 headerHeight = 0; 1680 1681 if ( isNaN( bodyTopPadding ) ) { 1682 bodyTopPadding = 0; 1683 } 1684 1685 if ( this.hasAdminBar && this.win.width() > 600 ) { 1686 winTop += Math.floor( winBarHeight ); 1687 } 1688 1689 if ( winTop > headerTop ) { 1690 if ( ! hasStickyClass ) { 1691 if ( e && ( 'scroll' === e.type || 'smartscroll' === e.type ) ) { 1692 this.header.addClass( 'fl-theme-builder-header-sticky' ); 1693 if ( this.overlay && beforeHeader.length ) { 1694 this.header.css( 'top', winBarHeight); 1695 } 1696 } 1697 1698 if ( ! this.overlay ) { 1699 this._adjustHeaderHeight(); 1700 } 1701 } 1702 } 1703 else if ( hasStickyClass ) { 1704 this.header.removeClass( 'fl-theme-builder-header-sticky' ); 1705 this.header.removeAttr( 'style' ); 1706 this.header.parent().css( 'padding-top', '0' ); 1707 } 1708 1709 this._adjustStickyHeaderWidth(); 1710 1711 if ( winTop > headerTop ) { 1712 if ( ! hasScrolledClass ) {
1713 this.header.addClass( 'fl-theme-builder-header-scrolled' ); 1714 } 1715 } else if ( hasScrolledClass ) { 1716 this.header.removeClass( 'fl-theme-builder-header-scrolled' ); 1717 } 1718 1719 this._flyoutMenuFix( e ); 1720 }, 1721 1722 /** 1723 * Initializes flyout menu fixes on sticky header. 1724 * 1725 * @since 1.4.1 1726 * @method _initFlyoutMenuFix 1727 */ 1728 _initFlyoutMenuFix: function( e ) { 1729 var header = this.header, 1730 menuModule = header.find( '.fl-menu' ), 1731 flyoutMenu = menuModule.find( '.fl-menu-mobile-flyout' ), 1732 isPushMenu = menuModule.hasClass( 'fl-menu-responsive-flyout-push' ) || menuModule.hasClass( 'fl-menu-responsive-flyout-push-opacity' ), 1733 isSticky = header.hasClass( 'fl-theme-builder-header-sticky' ), 1734 isOverlay = menuModule.hasClass( 'fl-menu-responsive-flyout-overlay' ), 1735 flyoutPos = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 1736 flyoutParent = header.parent().is( 'header' ) ? header.parent().parent() : header.parent(); 1737 isFullWidth = this.win.width() === header.width(), 1738 flyoutLayout = '', 1739 activePos = 250, 1740 headerPos = 0; 1741 1742 if ( ! flyoutMenu.length ) { 1743 return; 1744 } 1745 1746 if ( this.win.width() > header.parent().width() ) { 1747 headerPos = ( this.win.width() - header.width() ) / 2; 1748 } 1749 1750 if ( isOverlay ) { 1751 activePos = headerPos; 1752 } 1753 else if ( isPushMenu ) { 1754 activePos = activePos + headerPos; 1755 } 1756 flyoutMenu.data( 'activePos', activePos ); 1757 1758 if ( isPushMenu ) { 1759 flyoutLayout = 'push-' + flyoutPos; 1760 } 1761 else if ( isOverlay ) { 1762 flyoutLayout = 'overlay-' + flyoutPos; 1763 } 1764 1765 if ( isPushMenu && ! $( 'html' ).hasClass( 'fl-theme-builder-has-flyout-menu' ) ) { 1766 $( 'html' ).addClass( 'fl-theme-builder-has-flyout-menu' ); 1767 } 1768 1769 if ( ! flyoutParent.hasClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout ) ) { 1770 flyoutParent.addClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout ); 1771 } 1772 1773 if ( ! header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && isOverlay ) { 1774 header.addClass( 'fl-theme-builder-flyout-menu-overlay' ); 1775 } 1776 1777 if ( ! header.hasClass( 'fl-theme-builder-header-full-width' ) && isFullWidth ) { 1778 header.addClass( 'fl-theme-builder-header-full-width' ); 1779 } 1780 else if ( ! isFullWidth ) { 1781 header.removeClass( 'fl-theme-builder-header-full-width' ); 1782 } 1783 1784 menuModule.on( 'click', '.fl-menu-mobile-toggle', $.proxy( function( event ){ 1785 if ( menuModule.find( '.fl-menu-mobile-toggle.fl-active' ).length ) { 1786 $( 'html' ).addClass( 'fl-theme-builder-flyout-menu-active' ); 1787 event.stopImmediatePropagation(); 1788 } 1789 else { 1790 $( 'html' ).removeClass( 'fl-theme-builder-flyout-menu-active' ); 1791 } 1792 1793 this._flyoutMenuFix( event ); 1794 }, this ) ); 1795 }, 1796 1797 /** 1798 * Fix flyout menu inside the sticky header. 1799 * 1800 * @since 1.4.1 1801 * @method _flyoutMenuFix 1802 */ 1803 _flyoutMenuFix: function( e ){ 1804 var header = this.header, 1805 menuModule = header.find( '.fl-menu' ), 1806 flyoutMenu = menuModule.find( '.fl-menu-mobile-flyout' ), 1807 isPushMenu = menuModule.hasClass( 'fl-menu-responsive-flyout-push' ) || menuModule.hasClass( 'fl-menu-responsive-flyout-push-opacity' ), 1808 flyoutPos = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 1809 menuOpacity = menuModule.find( '.fl-menu-mobile-opacity' ), 1810 isScroll = 'undefined' !== typeof e && 'scroll' === e.handleObj.type, 1811 activePos = 'undefined' !== typeof flyoutMenu.data( 'activePos' ) ? flyoutMenu.data( 'activePos' ) : 0, 1812 headerPos = ( this.win.width() - header.width() ) / 2, 1813 inactivePos = headerPos > 0 ? activePos + 4 : 254; 1814 1815 if ( ! flyoutMenu.length ) { 1816 return; 1817 } 1818 1819 if ( this.overlay ) { 1820 return; 1821 } 1822 1823 if( $( '.fl-theme-builder-flyout-menu-active' ).length ) { 1824 1825 if ( isScroll && ! flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) { 1826 flyoutMenu.addClass( 'fl-menu-disable-transition' ); 1827 } 1828 1829 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 1830 if ( ! isScroll ) { 1831 setTimeout( $.proxy( function(){ 1832 flyoutMenu.css( flyoutPos, '-' + activePos + 'px' ); 1833 }, this ), 1 ); 1834 } 1835 else { 1836 flyoutMenu.css( flyoutPos, '-' + activePos + 'px' ); 1837 } 1838 } 1839 else { 1840 flyoutMenu.css( flyoutPos, '0px' ); 1841 } 1842 } 1843 else { 1844 if ( flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) { 1845 flyoutMenu.removeClass( 'fl-menu-disable-transition' ); 1846 } 1847
1848 if ( header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && headerPos > 0 && headerPos < 250 ) { 1849 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 1850 inactivePos = headerPos + 254; 1851 } 1852 else { 1853 inactivePos = 254; 1854 } 1855 } 1856 1857 if ( e && e.type === 'resize' ) { 1858 inactivePos = headerPos + 254; 1859 } 1860 1861 flyoutMenu.css( flyoutPos, '-' + inactivePos + 'px' ); 1862 } 1863 1864 if ( e && menuModule.is('.fl-menu-responsive-flyout-overlay') && $.infinitescroll ) { 1865 e.stopImmediatePropagation(); 1866 } 1867 1868 if( menuOpacity.length ) { 1869 if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) { 1870 if ( '0px' === menuOpacity.css( 'left' ) ) { 1871 menuOpacity.css( 'left', '-' + headerPos + 'px' ); 1872 } 1873 } 1874 else { 1875 menuOpacity.css( 'left', '' ); 1876 } 1877 } 1878 }, 1879 1880 /** 1881 * Adjust sticky header width if BB Theme Boxed Layout is used. 1882 * 1883 * @since 1.4 1884 * @access private 1885 * @method _adjustStickyHeaderWidth 1886 */ 1887 _adjustStickyHeaderWidth: function () { 1888 if ( $('body').hasClass( 'fl-fixed-width' ) ) { 1889 var parentWidth = this.header.parent().width(); 1890 1891 // Better if this is set in the stylesheet file. 1892 if ( this.win.width() >= 992 ) { 1893 this.header.css({ 1894 'margin': '0 auto', 1895 'max-width': parentWidth, 1896 }); 1897 } 1898 else { 1899 this.header.css({ 1900 'margin': '', 1901 'max-width': '', 1902 }); 1903 } 1904 } 1905 }, 1906 1907 /** 1908 * Adjust Sticky Header Height 1909 * 1910 * @since 1.4 1911 * @access private 1912 * @method _adjustHeaderHeight 1913 */ 1914 _adjustHeaderHeight: function () { 1915 var beforeHeader = this.header.prevAll('.fl-builder-content'), 1916 beforeHeaderHeight = 0, 1917 beforeHeaderFix = 0, 1918 headerHeight = Math.floor( this.header.outerHeight() ), 1919 bodyTopPadding = parseInt( $( 'body' ).css( 'padding-top' ) ), 1920 wpAdminBarHeight = 0, 1921 totalHeaderHeight = 0; 1922 1923 if ( isNaN( bodyTopPadding ) ) { 1924 bodyTopPadding = 0; 1925 } 1926 1927 if ( beforeHeader.length ) { 1928 $.each( beforeHeader, function() { 1929 beforeHeaderHeight += Math.floor( $(this).outerHeight() ); 1930 }); 1931 // Subtract this value from the header parent's top padding. 1932 beforeHeaderFix = 2; 1933 } 1934 1935 if ( this.hasAdminBar && this.win.width() <= 600 ) { 1936 wpAdminBarHeight = Math.floor( $('#wpadminbar').outerHeight() ); 1937 } 1938 1939 totalHeaderHeight = Math.floor( beforeHeaderHeight + headerHeight); 1940 1941 if ( headerHeight > 0 ) { 1942 var headerParent = this.header.parent(), 1943 headerParentTopPadding = 0; 1944 1945 // If the header's parent container is the BODY tag ignore its top padding. 1946 if ( $( headerParent ).is('body') ) { 1947 headerParentTopPadding = Math.floor( headerHeight - wpAdminBarHeight ); 1948 } else { 1949 headerParentTopPadding = Math.floor( headerHeight - bodyTopPadding - wpAdminBarHeight ); 1950 } 1951 1952 $( headerParent ).css( 'padding-top', ( headerParentTopPadding - beforeHeaderFix ) + 'px' ); 1953 1954 this.header.css({ 1955 '-webkit-transform': 'translate(0px, -' + totalHeaderHeight + 'px)', 1956 '-ms-transform': 'translate(0px, -' + totalHeaderHeight + 'px)', 1957 'transform': 'translate(0px, -' + totalHeaderHeight + 'px)' 1958 }); 1959 1960 } 1961 1962 }, 1963 1964 /** 1965 * Initializes shrink logic for a header. 1966 * 1967 * @since 1.0 1968 * @access private 1969 * @method _initShrink 1970 */ 1971 _initShrink: function( e ) 1972 { 1973 if ( this.win.width() >= this.breakpointWidth ) { 1974 this.win.on( 'scroll.fl-theme-builder-header-shrink', $.proxy( this._doShrink, this ) ); 1975 this._setImageMaxHeight(); 1976 1977 if ( this.win.scrollTop() > 0 ){ 1978 this._doShrink(); 1979 } 1980 1981 } else { 1982 this.header.parent().css( 'padding-top', '0' ); 1983 this.win.off( 'scroll.fl-theme-builder-header-shrink' ); 1984 this._removeShrink(); 1985 this._removeImageMaxHeight(); 1986 } 1987 }, 1988 1989 /** 1990 * Shrinks the header when the page is scrolled. 1991 * 1992 * @since 1.0 1993 * @access private 1994 * @method _doShrink 1995 */ 1996 _doShrink: function( e ) 1997 { 1998 var winTop = this.win.scrollTop(), 1999 headerTop = this.header.data('original-top'), 2000 headerHeight = this.header.data('original-height'), 2001 shrinkImageHeight = this.header.data('shrink-image-height'), 2002 windowSize = this.win.width(), 2003 makeSticky = this._makeWindowSticky( windowSize ),
2004 hasClass = this.header.hasClass( 'fl-theme-builder-header-shrink' ); 2005 2006 2007 if ( this.hasAdminBar ) { 2008 winTop += 32; 2009 } 2010 2011 if ( makeSticky && ( winTop > headerTop + headerHeight ) ) { 2012 if ( ! hasClass ) { 2013 2014 this.header.addClass( 'fl-theme-builder-header-shrink' ); 2015 2016 // Shrink images but don't include lightbox and menu images. 2017 this.header.find('img').each( function( i ) { 2018 var image = $( this ), 2019 maxMegaMenu = image.closest( '.max-mega-menu' ).length, 2020 imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length, 2021 imageInNavMenu = image.closest( 'li.menu-item' ).length; 2022 2023 if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu ) ) { 2024 image.css( 'max-height', shrinkImageHeight ); 2025 } 2026 2027 }); 2028 2029 this.header.find( '.fl-row-content-wrap' ).each( function() { 2030 2031 var row = $( this ); 2032 2033 if ( parseInt( row.css( 'padding-bottom' ) ) > 5 ) { 2034 row.addClass( 'fl-theme-builder-header-shrink-row-bottom' ); 2035 } 2036 2037 if ( parseInt( row.css( 'padding-top' ) ) > 5 ) { 2038 row.addClass( 'fl-theme-builder-header-shrink-row-top' ); 2039 } 2040 } ); 2041 2042 this.header.find( '.fl-module-content' ).each( function() { 2043 2044 var module = $( this ); 2045 2046 if ( parseInt( module.css( 'margin-bottom' ) ) > 5 ) { 2047 module.addClass( 'fl-theme-builder-header-shrink-module-bottom' ); 2048 } 2049 2050 if ( parseInt( module.css( 'margin-top' ) ) > 5 ) { 2051 module.addClass( 'fl-theme-builder-header-shrink-module-top' ); 2052 } 2053 } ); 2054 } 2055 } else if (hasClass) { 2056 this.header.find( 'img' ).css( 'max-height', '' ); 2057 this._removeShrink(); 2058 } 2059 2060 // Fixes Shrink header issue with BB Theme when window is scrolled then resized and back. 2061 if ( 'undefined' === typeof( e ) && $('body').hasClass( 'fl-fixed-width' ) ) { 2062 if ( ! this.overlay ) { 2063 this._adjustHeaderHeight(); 2064 } 2065 } 2066 2067 }, 2068 2069 /** 2070 * Removes the header shrink effect. 2071 * 2072 * @since 1.0 2073 * @access private 2074 * @method _removeShrink 2075 */ 2076 _removeShrink: function() 2077 { 2078 var rows = this.header.find( '.fl-row-content-wrap' ), 2079 modules = this.header.find( '.fl-module-content' ); 2080 2081 rows.removeClass( 'fl-theme-builder-header-shrink-row-bottom' ); 2082 rows.removeClass( 'fl-theme-builder-header-shrink-row-top' ); 2083 modules.removeClass( 'fl-theme-builder-header-shrink-module-bottom' ); 2084 modules.removeClass( 'fl-theme-builder-header-shrink-module-top' ); 2085 this.header.removeClass( 'fl-theme-builder-header-shrink' ); 2086 }, 2087 2088 /** 2089 * Adds max height to images in modules for smooth scrolling. 2090 * 2091 * @since 1.1.1 2092 * @access private 2093 * @method _setImageMaxHeight 2094 */ 2095 _setImageMaxHeight: function() 2096 { 2097 var head = $( 'head' ), 2098 stylesId = 'fl-header-styles-' + this.header.data( 'post-id' ), 2099 styles = '', 2100 images = this.header.find( '.fl-module-content img' ); 2101 2102 if ( $( '#' + stylesId ).length ) { 2103 return; 2104 } 2105 2106 images.each( function( i ) { 2107 var image = $( this ), 2108 height = image.height(), 2109 node = image.closest( '.fl-module' ).data( 'node' ), 2110 className = 'fl-node-' + node + '-img-' + i, 2111 maxMegaMenu = image.closest( '.max-mega-menu' ).length, 2112 imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length, 2113 imageInNavMenu = image.closest( 'li.menu-item' ).length; 2114 2115 if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu ) ) { 2116 image.addClass( className ); 2117 styles += '.' + className + ' { max-height: ' + ( height ? height : image[0].height ) + 'px }'; 2118 } 2119 2120 } ); 2121 2122 if ( '' !== styles ) { 2123 head.append( '<style id="' + stylesId + '">' + styles + '</style>' ); 2124 } 2125 }, 2126 2127 /** 2128 * Removes max height on images in modules for smooth scrolling. 2129 * 2130 * @since 1.1.1 2131 * @access private 2132 * @method _removeImageMaxHeight 2133 */ 2134 _removeImageMaxHeight: function() 2135 { 2136 $( '#fl-header-styles-' + this.header.data( 'post-id' ) ).remove(); 2137 }, 2138 }; 2139 2140 $( function() { FLThemeBuilderHeaderLayout.init(); } ); 2141 2142})(jQuery); 2143 2144(function($) { 2145 2146 /** 2147 * Class for Menu Module 2148 * 2149 * @since 1.6.1 2150 */ 2151 FLBuilderMenu = function( settings ){ 2152 2153 // set params 2154 this.nodeId = settings.id; 2155 this.nodeClass = '.fl-node-' + settings.id; 2156 this.wrapperClass = this.nodeClass + ' .fl-menu'; 2157 this.type = settings.type; 2158 this.mobileToggle = settings.mobile; 2159 this.mobileBelowRow = settings.mobileBelowRow; 2160 this.mobileFlyout = settings.mobileFlyout; 2161 this.breakPoints = settings.breakPoints; 2162 this.mobileBreakpoint = settings.mobileBreakpoint; 2163 this.currentBrowserWidth = $( window ).width(); 2164 this.postId = settings.postId; 2165 this.mobileStacked = settings.mobileStacked; 2166 2167 // initialize the menu 2168 this._initMenu(); 2169 2170 // check if viewport is resizing 2171 $( window ).on( 'resize', $.proxy( function( e ) { 2172 2173 var width = $( window ).width(); 2174 2175 // if screen width is resized, reload the menu 2176 if( width != this.currentBrowserWidth ){ 2177 2178 this.currentBrowserWidth = width; 2179 this._initMenu(); 2180 this._clickOrHover(); 2181 } 2182 2183 }, this ) ); 2184 2185 $( 'body' ).on( 'click', $.proxy( function( e ) { 2186 if ( 'undefined' !== typeof FLBuilderConfig ){ 2187 return; 2188 } 2189 2190 var activeMobileMenu = $(this.wrapperClass + ' .fl-menu-mobile-toggle.fl-active' ); 2191 if ( activeMobileMenu.length && ( 'expanded' !== this.mobileToggle ) ){ 2192 $( activeMobileMenu ).trigger('click'); 2193 } 2194 2195 $( this.wrapperClass ).find( '.fl-has-submenu' ).removeClass( 'focus' ); 2196 $( this.wrapperClass ).find( '.fl-has-submenu .sub-menu' ).removeClass( 'focus' ); 2197 2198 }, this ) ); 2199 2200 // Close Mobile menu when tabbing out from the last menu item. 2201 $( this.wrapperClass + ' ul.menu > li:last-child' ).on( 'focusout', $.proxy(function (e) { 2202 if ( $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).hasClass( 'fl-active' ) && ( 'expanded' !== this.mobileToggle ) ) { 2203 if ( ! $( e.relatedTarget ).parent().hasClass( 'menu-item' ) ) { 2204 $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).trigger( 'click' ); 2205 } 2206 } 2207 }, this ) ); 2208 2209 }; 2210 2211 FLBuilderMenu.prototype = { 2212 nodeClass : '', 2213 wrapperClass : '', 2214 type : '', 2215 breakPoints : {}, 2216 $submenus : null, 2217 2218 /** 2219 * Check if the screen size fits a mobile viewport. 2220 * 2221 * @since 1.6.1 2222 * @return bool 2223 */ 2224 _isMobile: function(){ 2225 return this.currentBrowserWidth <= this.breakPoints.small ? true : false;
2226 }, 2227 2228 /** 2229 * Check if the screen size fits a medium viewport. 2230 * 2231 * @since 1.10.5 2232 * @return bool 2233 */ 2234 _isMedium: function(){ 2235 return this.currentBrowserWidth <= this.breakPoints.medium ? true : false; 2236 }, 2237 2238 /** 2239 * Check if the screen size fits a large viewport. 2240 * 2241 * @since 1.10.5 2242 * @return bool 2243 */ 2244 _isLarge: function(){ 2245 return this.currentBrowserWidth <= this.breakPoints.large ? true : false; 2246 }, 2247 2248 /** 2249 * Check if the menu should toggle for the current viewport base on the selected breakpoint 2250 * 2251 * @see this._isMobile() 2252 * @see this._isMedium() 2253 * @since 1.10.5 2254 * @return bool 2255 */ 2256 _isMenuToggle: function(){ 2257 if ( ( 'always' == this.mobileBreakpoint 2258 || ( this._isMobile() && 'mobile' == this.mobileBreakpoint ) 2259 || ( this._isMedium() && 'medium-mobile' == this.mobileBreakpoint ) 2260 || ( this._isLarge() && 'large-mobile' == this.mobileBreakpoint ) 2261 ) && ( $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).is(':visible') || 'expanded' == this.mobileToggle ) ) { 2262 return true; 2263 } 2264 2265 return false; 2266 }, 2267 2268 /** 2269 * Initialize the toggle logic for the menu. 2270 * 2271 * @see this._isMenuToggle() 2272 * @see this._menuOnCLick() 2273 * @see this._clickOrHover() 2274 * @see this._submenuOnRight() 2275 * @see this._submenuRowZindexFix() 2276 * @see this._toggleForMobile() 2277 * @since 1.6.1 2278 * @return void 2279 */ 2280 _initMenu: function(){ 2281 this._setupSubmenu(); 2282 this._menuOnFocus(); 2283 this._submenuOnClick(); 2284 if ( $( this.nodeClass ).length && this.type == 'horizontal' ) { 2285 this._initMegaMenus(); 2286 } 2287 2288 if( this._isMenuToggle() || this.type == 'accordion' ){ 2289 2290 $( this.wrapperClass ).off( 'mouseenter mouseleave' ); 2291 this._menuOnClick(); 2292 this._clickOrHover(); 2293 2294 } else { 2295 $( this.wrapperClass ).off( 'click' ); 2296 this._submenuOnRight(); 2297 this._submenuRowZindexFix(); 2298 } 2299 2300 if( this.mobileToggle != 'expanded' ){ 2301 this._toggleForMobile(); 2302 } 2303 2304 if( $( this.wrapperClass ).find( '.fl-menu-search-item' ).length ){ 2305 this._toggleMenuSearch(); 2306 } 2307 2308 if( $( this.wrapperClass ).find( '.fl-menu-cart-item').length ){ 2309 this._wooUpdateParams(); 2310 } 2311 }, 2312 2313 /** 2314 * Initializes submenu dropdowns. 2315 * 2316 * @since 3.0 2317 * @return void 2318 */ 2319 _setupSubmenu: function() { 2320 $( this.wrapperClass + ' ul.sub-menu' ).each( function(){ 2321 $( this ).closest( 'li' ).attr( 'aria-haspopup', 'true' ); 2322 }); 2323 }, 2324 2325 /** 2326 * Adds a focus class to menu elements similar to be used similar to CSS :hover psuedo event 2327 * 2328 * @since 1.9.0 2329 * @return void 2330 */ 2331 _menuOnFocus: function(){ 2332 var cKey = 0, 2333 isShifted = false; 2334 2335 $( this.nodeClass ).off('keydown').on( 'keydown', 'a', function( e ){ 2336 cKey = e.which; 2337 isShifted = e.shiftKey; 2338 }); 2339 2340 $( this.nodeClass ).off('focus').on( 'focus', 'a', $.proxy( function( e ){ 2341 var $menuItem = $( e.target ).parents( '.menu-item' ).first(), 2342 $parents = $( e.target ).parentsUntil( this.wrapperClass ); 2343 2344 $('.fl-menu .focus').removeClass('focus'); 2345 2346 $menuItem.addClass('focus') 2347 $parents.addClass('focus') 2348 2349 }, this ) ).on( 'focusout', 'a', $.proxy( function( e ){ 2350 var el = $(e.target).parent(), 2351 $megaMenu = el.closest( '.mega-menu' ), 2352 $megaLastItem = $megaMenu.find('> .sub-menu > .menu-item:last-child'), 2353 isLastChild = ! $megaMenu.length && el.is(':last-child' ); 2354 2355 if( $megaMenu.length ) { 2356 isLastChild = el.is( $megaLastItem ) || el.is( $megaLastItem.find( '.menu-item:last-child' ) ); 2357 } 2358 2359 if ( isLastChild && cKey === 9 && isShifted ) { 2360 isLastChild = false; 2361 cKey = 0; 2362 isShifted = false; 2363 } 2364 2365 if ( isLastChild ) { 2366 $( e.target ).parentsUntil( this.wrapperClass ).removeClass( 'focus' ); 2367 } 2368 2369 }, this ) ); 2370 }, 2371 2372 /** 2373 * Logic for submenu toggling on accordions or mobile menus (vertical, horizontal) 2374 * 2375 * @since 1.6.1 2376 * @return void 2377 */ 2378 _menuOnClick: function(){ 2379 $( this.wrapperClass ).off().on( 'click', '.fl-has-submenu-container', $.proxy( function( e ){ 2380 2381 var $link = $( e.target ).parents( '.fl-has-submenu' ).first(), 2382 $subMenu = $link.children( '.sub-menu' ).first(), 2383 $href = $link.children('.fl-has-submenu-container').first().find('> a').attr('href'), 2384 $subMenuParents = $( e.target ).parents( '.sub-menu' ), 2385 $activeParents = $( e.target ).parents( '.fl-has-submenu.fl-active' ); 2386 2387 if( !$subMenu.is(':visible') || $(e.target).hasClass('fl-menu-toggle') 2388 || ($subMenu.is(':visible') && (typeof $href === 'undefined' || $href == '#')) ){ 2389 e.preventDefault(); 2390 } 2391 else { 2392 e.stopPropagation(); 2393 window.location.href = $href; 2394 return; 2395 } 2396 2397 if ($(this.wrapperClass).hasClass('fl-menu-accordion-collapse')) { 2398 2399 if ( !$link.parents('.menu-item').hasClass('fl-active') ) { 2400 $('.menu .fl-active', this.wrapperClass).not($link).removeClass('fl-active'); 2401 } 2402 else if ($link.parents('.menu-item').hasClass('fl-active') && $link.parent('.sub-menu').length) { 2403 $('.menu .fl-active', this.wrapperClass).not($link).not($activeParents).removeClass('fl-active'); 2404 } 2405 2406 $('.sub-menu', this.wrapperClass).not($subMenu).not($subMenuParents).slideUp('normal'); 2407 } 2408 2409 if ( ! this.mobileStacked && 'horizontal' == this.type && 'expanded' == this.mobileToggle ) { 2410 $( this.wrapperClass ).find( '.fl-active' ).not($link).not($activeParents).removeClass( 'fl-active' ); 2411 } 2412 else { 2413 $subMenu.slideToggle(); 2414 } 2415 2416 $link.toggleClass( 'fl-active' ); 2417 e.stopPropagation(); 2418 2419 }, this ) ); 2420 2421 }, 2422 2423 /** 2424 * Logic for submenu items click event 2425 * 2426 * @since 1.10.6 2427 * @return void 2428 */ 2429 _submenuOnClick: function(){ 2430 $( this.wrapperClass + ' .sub-menu' ).off().on( 'click', 'a', $.proxy( function( e ){ 2431 if ( $( e.target ).parent().hasClass('focus') ) { 2432 $( e.target ).parentsUntil( this.wrapperClass ).removeClass('focus'); 2433 } 2434 }, this ) ); 2435 }, 2436 2437 /** 2438 * Changes general styling and behavior of menus based on mobile / desktop viewport. 2439 * 2440 * @see this._isMenuToggle() 2441 * @since 1.6.1 2442 * @return void 2443 */ 2444 _clickOrHover: function(){ 2445 this.$submenus = this.$submenus || $( this.wrapperClass ).find( '.sub-menu' ); 2446 var $wrapper = $( this.wrapperClass ), 2447 $menu = $wrapper.find( '.menu' ); 2448 $li = $wrapper.find( '.fl-has-submenu' ); 2449 2450 if( this._isMenuToggle() ){ 2451 $li.each( function( el ){ 2452 if( !$(this).hasClass('fl-active') ){ 2453 $(this).find( '.sub-menu' ).fadeOut(); 2454 } 2455 } ); 2456 } else { 2457 $li.each( function( el ){ 2458 if( !$(this).hasClass('fl-active') ){ 2459 $(this).find( '.sub-menu' ).css( { 2460 'display' : '', 2461 'opacity' : '' 2462 } ); 2463 } 2464 } ); 2465 } 2466 }, 2467 2468 /** 2469 * Logic to prevent submenus to go outside viewport boundaries. 2470 * 2471 * @since 1.6.1 2472 * @return void 2473 */ 2474 _submenuOnRight: function(){ 2475 2476 $( this.wrapperClass ) 2477 .on( 'mouseenter focus', '.fl-has-submenu', $.proxy( function( e ){ 2478 2479 if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) { 2480 return; 2481 } 2482 2483 var $link = $( e.currentTarget ), 2484 $parent = $link.parent(), 2485 $subMenu = $link.find( '.sub-menu' ), 2486 subMenuWidth = $subMenu.width(), 2487 subMenuPos = 0, 2488 bodyWidth = $( 'body' ).width(); 2489 2490 if( $link.closest( '.fl-menu-submenu-right' ).length !== 0) { 2491 2492 $link.addClass( 'fl-menu-submenu-right' ); 2493 2494 } else if( $( 'body' ).hasClass( 'rtl' ) ) { 2495 2496 subMenuPos = $parent.is( '.sub-menu' ) ? 2497 $parent.offset().left - subMenuWidth: 2498 $link.offset().left - $link.width() - subMenuWidth; 2499 2500 if( subMenuPos <= 0 ) { 2501 $link.addClass( 'fl-menu-submenu-right' ); 2502 } 2503 2504 } else { 2505 2506 subMenuPos = $parent.is( '.sub-menu' ) ? 2507 $parent.offset().left + $parent.width() + subMenuWidth : 2508 $link.offset().left + $link.width() + subMenuWidth; 2509 2510 if( subMenuPos > bodyWidth ) { 2511 $link.addClass('fl-menu-submenu-right'); 2512 } 2513 } 2514 }, this ) ) 2515 .on( 'mouseleave', '.fl-has-submenu', $.proxy( function( e ){ 2516 $( e.currentTarget ).removeClass( 'fl-menu-submenu-right' ); 2517 }, this ) ); 2518 2519 }, 2520 2521 /** 2522 * Logic to prevent submenus to go behind the next overlay row. 2523 * 2524 * @since 1.10.9 2525 * @return void 2526 */ 2527 _submenuRowZindexFix: function( e ){ 2528 2529 $( this.wrapperClass ) 2530 .on( 'mouseenter', 'ul.menu > .fl-has-submenu', $.proxy( function( e ){ 2531 2532 if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) { 2533 return; 2534 } 2535 2536 $( this.nodeClass ) 2537 .closest( '.fl-row' ) 2538 .find( '.fl-row-content' ) 2539 .css( 'z-index', '10' ); 2540 2541 }, this ) ) 2542 .on( 'mouseleave', 'ul.menu > .fl-has-submenu', $.proxy( function( e ){ 2543 2544 $( this.nodeClass ) 2545 .closest( '.fl-row' ) 2546 .find( '.fl-row-content' ) 2547 .css( 'z-index', '' ); 2548 2549 }, this ) ); 2550 }, 2551 2552 /** 2553 * Logic for the mobile menu button. 2554 * 2555 * @since 1.6.1 2556 * @return void 2557 */ 2558 _toggleForMobile: function(){ 2559 2560 var $wrapper = null, 2561 $menu = null, 2562 self = this; 2563 2564 if( this._isMenuToggle() ){ 2565 2566 if ( this._isMobileBelowRowEnabled() ) { 2567 this._placeMobileMenuBelowRow(); 2568 $wrapper = $( this.wrapperClass ); 2569 $menu = $( this.nodeClass + '-clone' ); 2570 $menu.find( 'ul.menu' ).show(); 2571 } 2572 else { 2573 $wrapper = $( this.wrapperClass ); 2574 $menu = $wrapper.find( '.menu' ); 2575 } 2576 2577 if( !$wrapper.find( '.fl-menu-mobile-toggle' ).hasClass( 'fl-active' ) && ! self.mobileFlyout ){ 2578 $menu.css({ display: 'none' }); 2579 } 2580 2581 // Flayout Menu 2582 if ( self.mobileFlyout ) { 2583 this._initFlyoutMenu(); 2584 } 2585 2586 $wrapper.on( 'click', '.fl-menu-mobile-toggle', function( e ){ 2587 2588 $( this ).toggleClass( 'fl-active' ); 2589 2590 if ( self.mobileFlyout ) { 2591 self._toggleFlyoutMenu(); 2592 } 2593 else { 2594 var targetMenu = null; 2595 2596 if ( self.mobileBelowRow ) { 2597 targetMenu = $( this ).closest( '.fl-col' ).next( '.fl-menu-mobile-clone' ); 2598 } else { 2599 targetMenu = $( this ).closest( '.fl-menu' ).find( 'ul.menu' ); 2600 } 2601 2602 if ( targetMenu.length ) { 2603 $menu = $( targetMenu ); 2604 } 2605 2606 $menu.slideToggle(); 2607 } 2608 2609 e.stopPropagation(); 2610 } ); 2611 2612 // Hide active menu when click on anchor link ID that exists on a page. 2613 $menu.on( 'click', '.menu-item > a[href*="#"]:not([href="#"])', function(e){ 2614 var $href = $(this).attr('href'), 2615 $targetID = $href.split('#')[1], 2616 element = $('#' + $targetID); 2617 if ( $('body').find(element).length > 0 ) { 2618 $( this ).toggleClass( 'fl-active' ); 2619 FLBuilderLayout._scrollToElement( element ); 2620 if ( ! self._isMenuToggle() ) { 2621 $menu.slideToggle(); 2622 } 2623 } 2624 }); 2625 } 2626 else { 2627 2628 if ( this._isMobileBelowRowEnabled() ) { 2629 this._removeMenuFromBelowRow(); 2630 } 2631 2632 $wrapper = $( this.wrapperClass ), 2633 $menu = $wrapper.find( 'ul.menu' ); 2634 $wrapper.find( '.fl-menu-mobile-toggle' ).removeClass( 'fl-active' ); 2635 $menu.css({ display: '' }); 2636 2637 if ( this.mobileFlyout && $wrapper.find( '.fl-menu-mobile-flyout' ).length > 0 ) { 2638 $( 'body' ).css( 'margin', '' );
2639 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' ); 2640 $menu.unwrap(); 2641 $wrapper.find( '.fl-menu-mobile-close' ).remove(); 2642 $wrapper.find( '.fl-menu-mobile-opacity' ).remove(); 2643 } 2644 } 2645 }, 2646 2647 /** 2648 * Init any mega menus that exist. 2649 * 2650 * @see this._isMenuToggle() 2651 * @since 1.10.4 2652 * @return void 2653 */ 2654 _initMegaMenus: function(){ 2655 2656 var module = $( this.nodeClass ), 2657 rowContent = module.closest( '.fl-row-content' ), 2658 rowWidth = rowContent.width(), 2659 megas = module.find( '.mega-menu' ), 2660 disabled = module.find( '.mega-menu-disabled' ), 2661 isToggle = this._isMenuToggle(); 2662 2663 if ( isToggle ) { 2664 megas.removeClass( 'mega-menu' ).addClass( 'mega-menu-disabled' ); 2665 module.find( 'li.mega-menu-disabled > ul.sub-menu' ).css( 'width', '' ); 2666 rowContent.css( 'position', '' ); 2667 } else { 2668 disabled.removeClass( 'mega-menu-disabled' ).addClass( 'mega-menu' ); 2669 module.find( 'li.mega-menu > ul.sub-menu' ).css( 'width', rowWidth + 'px' ); 2670 rowContent.css( 'position', 'relative' ); 2671 } 2672 }, 2673 2674 /** 2675 * Check to see if Below Row should be enabled. 2676 * 2677 * @since 1.11 2678 * @return boolean 2679 */ 2680 _isMobileBelowRowEnabled: function() { 2681 return this.mobileBelowRow && $( this.nodeClass ).closest( '.fl-col' ).length; 2682 }, 2683 2684 /** 2685 * Logic for putting the mobile menu below the menu's 2686 * column so it spans the full width of the page. 2687 * 2688 * @since 1.10 2689 * @return void 2690 */ 2691 _placeMobileMenuBelowRow: function(){ 2692 2693 if ( $( this.nodeClass + '-clone' ).length ) { 2694 return; 2695 } 2696 2697 var module = $( this.nodeClass ), 2698 clone = null, 2699 col = module.closest( '.fl-col' ); 2700 2701 if ( module.length < 1 ) { 2702 return; 2703 } 2704 2705 clone = ( module.length > 1 ) ? $( module[0] ).clone() : module.clone(); 2706 module.find( 'ul.menu' ).remove(); 2707 clone.addClass( ( this.nodeClass + '-clone' ).replace( '.', '' ) ); 2708 clone.addClass( 'fl-menu-mobile-clone' ); 2709 clone.find( '.fl-menu-mobile-toggle' ).remove(); 2710 col.after( clone ); 2711 2712 // Removes animation when enabled. 2713 if ( module.hasClass( 'fl-animation' ) ) { 2714 clone.removeClass( 'fl-animation' ); 2715 } 2716 2717 this._menuOnClick(); 2718 }, 2719 2720 /** 2721 * Logic for removing the mobile menu from below the menu's 2722 * column and putting it back in the main wrapper. 2723 * 2724 * @since 1.10 2725 * @return void 2726 */ 2727 _removeMenuFromBelowRow: function(){ 2728 2729 if ( ! $( this.nodeClass + '-clone' ).length ) { 2730 return; 2731 } 2732 2733 var module = $( this.nodeClass ), 2734 clone = $( this.nodeClass + '-clone' ), 2735 menu = clone.find( 'ul.menu' ); 2736 2737 module.find( '.fl-menu-mobile-toggle' ).after( menu ); 2738 clone.remove(); 2739 }, 2740 2741 /** 2742 * Logic for Flyout responsive menu. 2743 * 2744 * @since 2.2 2745 * @return void 2746 */ 2747 _initFlyoutMenu: function(){ 2748 var win = $( window ), 2749 wrapper = $( this.wrapperClass ), 2750 menu = wrapper.find( 'ul.menu' ), 2751 button = wrapper.find( '.fl-menu-mobile-toggle' ); 2752 2753 if ( 0 === wrapper.find( '.fl-menu-mobile-flyout' ).length ) { 2754 menu.wrap( '<div class="fl-menu-mobile-flyout"></div>' ); 2755 } 2756 2757 if ( 0 === wrapper.find( '.fl-menu-mobile-close' ).length ) { 2758 close = window.fl_responsive_close || 'Close' 2759 wrapper.find( '.fl-menu-mobile-flyout' ) 2760 .prepend( '<button class="fl-menu-mobile-close" aria-label="' + close + '"><i class="fas fa-times" aria-hidden="true"></i></button>' ); 2761 } 2762 2763 // Push with opacity 2764 if ( wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ) && 0 === wrapper.find( '.fl-menu-mobile-opacity' ).length ) { 2765 wrapper.append( '<div class="fl-menu-mobile-opacity"></div>' ); 2766 } 2767 2768 wrapper.on( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close', function(e){ 2769 button.trigger( 'click' ); 2770 e.stopPropagation(); 2771 }); 2772 2773 if ( 'undefined' !== typeof FLBuilder ) { 2774 FLBuilder.addHook('restartEditingSession', function(){ 2775 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' ); 2776 2777 // Toggle active menu. 2778 if ( button.hasClass( 'fl-active' ) ) { 2779 button.trigger( 'click' ); 2780 } 2781 }); 2782 } 2783 }, 2784 2785 /** 2786 * Logic to enable/disable the Flyout menu on button click. 2787 * 2788 * @since 2.2 2789 * @return void 2790 */ 2791 _toggleFlyoutMenu: function(){ 2792 var wrapper = $( this.wrapperClass ), 2793 button = wrapper.find( '.fl-menu-mobile-toggle' ), 2794 wrapFlyout = wrapper.find( '.fl-menu-mobile-flyout' ), 2795 position = wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left', 2796 pushMenu = wrapper.hasClass( 'fl-menu-responsive-flyout-push' ) || wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ), 2797 opacity = wrapper.find( '.fl-menu-mobile-opacity' ),
2798 marginPos = {}, 2799 posAttr = {}, 2800 fixedPos = {}, 2801 winHeight = $(window).height(), 2802 fixedHeader = $('header, header > div'); 2803 2804 if ( button.hasClass( 'fl-active' ) ) { 2805 posAttr[ position ] = '0px'; 2806 posAttr[ 'height' ] = winHeight + 'px'; 2807 } else { 2808 posAttr[ position ] = '-267px'; 2809 } 2810 2811 wrapFlyout.css( posAttr ); 2812 2813 // Fix the push menu when builder ui panel is pinned. 2814 if ( $( '.fl-builder-ui-pinned-content-transform' ).length > 0 && ! $( 'body' ).hasClass( 'fl-builder-edit' ) ) { 2815 $( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', 'none' ); 2816 } 2817 2818 if ( pushMenu ) { 2819 marginPos[ 'margin-' + position ] = button.hasClass( 'fl-active' ) ? '250px' : '0px'; 2820 $( 'body' ).animate( marginPos, 200); 2821 2822 // Fixed header 2823 if ( fixedHeader.length > 0 ) { 2824 fixedPos[ position] = button.hasClass( 'fl-active' ) ? '250px' : '0px'; 2825 fixedHeader.each(function(){ 2826 if ( 'fixed' == $( this ).css( 'position' ) ) { 2827 $( this ).css({ 2828 '-webkit-transition': 'none', 2829 '-o-transition' : 'none', 2830 'transition' : 'none' 2831 }); 2832 $( this ).animate( fixedPos, 200 ); 2833 } 2834 }); 2835 } 2836 } 2837 2838 if ( opacity.length > 0 && button.hasClass( 'fl-active' ) ) { 2839 opacity.show(); 2840 } 2841 else { 2842 opacity.hide(); 2843 } 2844 }, 2845 2846 /** 2847 * Shows or hides the nav search form. 2848 * 2849 * @since 2.5 2850 * @method _toggleMenuSearch 2851 */ 2852 _toggleMenuSearch: function(){ 2853 var wrapper = $( this.wrapperClass ).find('.fl-menu-search-item'), 2854 button = wrapper.find('a.fl-button'), 2855 form = wrapper.find('.fl-search-form-input-wrap'), 2856 self = this; 2857 2858 button.on('click', function(e){ 2859 e.preventDefault(); 2860 2861 if(form.is(':visible')) { 2862 form.stop().fadeOut(200); 2863 } 2864 else { 2865 form.stop().fadeIn(200); 2866 $('body').on('click.fl-menu-search', $.proxy(self._hideMenuSearch, self)); 2867 form.find('.fl-search-text').focus(); 2868 } 2869 }); 2870 }, 2871 2872 /** 2873 * Hides the nav search form. 2874 * 2875 * @since 2.5 2876 * @method _hideMenuSearch 2877 */ 2878 _hideMenuSearch: function(e){ 2879 var form = $( this.wrapperClass ).find('.fl-search-form-input-wrap'); 2880 2881 if(e !== undefined) { 2882 if($(e.target).closest('.fl-menu-search-item').length > 0) { 2883 return; 2884 } 2885 } 2886 2887 form.stop().fadeOut(200); 2888 $('body').off('click.fl-menu-search'); 2889 }, 2890 2891 /** 2892 * Adds menu node and post ID to WooCommerce ajax URL requests. 2893 * 2894 * @since 3.0 2895 * @return void 2896 */ 2897 _wooUpdateParams: function() { 2898 if ( 'undefined' !== typeof wc_cart_fragments_params ) { 2899 wc_cart_fragments_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId; 2900 } 2901 if ( 'undefined' !== typeof wc_add_to_cart_params ) { 2902 wc_add_to_cart_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId; 2903 } 2904 }, 2905 }; 2906 2907})(jQuery); 2908 2909(function($) { 2910 2911 $(function() { 2912 2913 new FLBuilderMenu({ 2914 id: '62425ad7d8de1', 2915 type: 'vertical', 2916 mobile: 'expanded', 2917 mobileBelowRow: false, 2918 mobileFlyout: false, 2919 breakPoints: { 2920 large: 1200, 2921 medium: 992, 2922 small: 768 }, 2923 mobileBreakpoint: 'mobile', 2924 postId : '28', 2925 mobileStacked: true, 2926 }); 2927 2928 }); 2929 2930})(jQuery); 2931 2932(function($) { 2933 2934 $(function() { 2935 2936 new FLBuilderMenu({ 2937 id: '62425b00a665b', 2938 type: 'vertical', 2939 mobile: 'expanded', 2940 mobileBelowRow: false, 2941 mobileFlyout: false, 2942 breakPoints: { 2943 large: 1200, 2944 medium: 992, 2945 small: 768 }, 2946 mobileBreakpoint: 'mobile', 2947 postId : '28', 2948 mobileStacked: true, 2949 }); 2950 2951 }); 2952 2953})(jQuery); 2954jQuery(function($) { 2955 2956 $(function() { 2957 $( '.fl-node-62467c369740f .fl-photo-img' ) 2958 .on( 'mouseenter', function( e ) { 2959 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 2960 } ) 2961 .on( 'mouseleave', function( e ){ 2962 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 2963 } ); 2964 }); 2965 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 2966}); 2967jQuery(function($) { 2968 2969 $(function() { 2970 $( '.fl-node-62467c152519c .fl-photo-img' ) 2971 .on( 'mouseenter', function( e ) { 2972 $( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' ); 2973 } ) 2974 .on( 'mouseleave', function( e ){ 2975 $( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null ); 2976 } ); 2977 }); 2978 window._fl_string_to_slug_regex = 'a-zA-Z0-9'; 2979}); 2980 2981/* Start Global Node Custom JS */ 2982 2983/* End Global Node Custom JS */ 2984 2985 2986/* Start Layout Custom JS */ 2987 2988/* End Layout Custom JS */ 2989
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.