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