PageSourceSearch

https://www.obdlink.com/wp-content/uploads/bb-plugin/cache/bbaf650…5166f6ace-layout-bundle.js?ver=2.11.0.3-1.6

js obdlink.com collected 2026-09-24 18:13:10 UTC 101,804 bytes, 3,485 lines download raw bytes

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;(function($) {
1647
1648	FLBuilderTabs = function( settings )
1649	{
1650		this.settings 	= settings;
1651		this.nodeClass  = '.fl-node-' + settings.id;
1652		this.tabsOnMobile = settings.tabsOnMobile;
1653		this.activeTab = settings.activeTab;
1654		this._init();
1655	};
1656
1657	FLBuilderTabs.prototype = {
1658
1659		settings	: {},
1660		nodeClass   : '',
1661
1662		_init: function()
1663		{
1664			var win = $(window);
1665
1666			$(this.nodeClass + ' .fl-tabs-labels .fl-tabs-label').click($.proxy(this._labelClick, this));
1667			$(this.nodeClass + ' .fl-tabs-labels .fl-tabs-label').on('keydown', $.proxy(this._labelClick, this));
1668			$(this.nodeClass + ' .fl-tabs-panels .fl-tabs-label').click($.proxy(this._responsiveLabelClick, this));
1669			$(this.nodeClass + ' .fl-tabs-panels .fl-tabs-label').on('keydown', $.proxy(this._responsiveLabelClick, this));
1670
1671			win.on('resize', $.proxy( this._setupTabs, this));
1672
1673			if($(this.nodeClass + ' .fl-tabs-vertical').length > 0) {
1674				this._resize();
1675				win.off('resize' + this.nodeClass);
1676				win.on('resize' + this.nodeClass, $.proxy(this._resize, this));
1677			}
1678
1679			FLBuilderLayout.preloadAudio( this.nodeClass + ' .fl-tabs-panel-content' );
1680			this._setupTabs();
1681		},
1682
1683		_labelClick: function(e)
1684		{
1685			var label       = $(e.target).closest('.fl-tabs-label'),
1686				index       = label.data('index'),
1687				wrap        = label.closest('.fl-tabs'),
1688				allIcons    = wrap.find('.fl-tabs-panels .fl-tabs-label .fas'),
1689				icon        = wrap.find('.fl-tabs-panels .fl-tabs-label[data-index="' + index + '"] .fas');
1690
1691			// Click or keyboard (enter or space) input?
1692			if(!this._validClick(e)) {
1693				return;
1694			}
1695
1696			// Toggle the responsive icons.
1697			allIcons.addClass('fa-plus');
1698			icon.removeClass('fa-plus');
1699
1700			// Toggle the tabs.
1701			wrap.find('.fl-tabs-labels:first .fl-tab-active').removeClass('fl-tab-active').attr('aria-selected', 'false');
1702			wrap.find('.fl-tabs-panels:first > .fl-tabs-panel > .fl-tab-active').removeClass('fl-tab-active').attr('aria-selected', 'false');
1703			wrap.find('.fl-tabs-panels:first > .fl-tabs-panel > .fl-tabs-panel-content').attr('aria-hidden', 'true').css('display', '');
1704
1705			wrap.find('.fl-tabs-labels:first .fl-tabs-label[data-index="' + index + '"]').addClass('fl-tab-active').attr('aria-selected', 'true');
1706			wrap.find('.fl-tabs-panels:first > .fl-tabs-panel > .fl-tabs-panel-label[data-index="' + index + '"]').addClass('fl-tab-active').attr('aria-selected', 'true');
1707			wrap.find('.fl-tabs-panels:first > .fl-tabs-panel > .fl-tabs-panel-content[data-index="' + index + '"]').addClass('fl-tab-active').attr('aria-hidden', 'false');
1708
1709			// Gallery module support.
1710			FLBuilderLayout.refreshGalleries( wrap.find('.fl-tabs-panel-content[data-index="' + index + '"]') );
1711
1712			// Grid layout support (uses Masonry)
1713			FLBuilderLayout.refreshGridLayout( wrap.find('.fl-tabs-panel-content[data-index="' + index + '"]') );
1714
1715			// Post Carousel support (uses BxSlider)
1716			FLBuilderLayout.reloadSlider( wrap.find('.fl-tabs-panel-content[data-index="' + index + '"]') );
1717
1718			// WP audio shortcode support
1719			FLBuilderLayout.resizeAudio( wrap.find('.fl-tabs-panel-content[data-index="' + index + '"]') );
1720
1721			// Slideshow module support.
1722			FLBuilderLayout.resizeSlideshow();
1723
1724			// Reload Google Map embed.
1725			FLBuilderLayout.reloadGoogleMap( wrap.find('.fl-tabs-panel-content[data-index="' + index + '"]') );
1726
1727			e.preventDefault();
1728		},
1729
1730		_responsiveLabelClick: function(e)
1731		{
1732			var label           = $(e.target).closest('.fl-tabs-label'),
1733				wrap            = label.closest('.fl-tabs'),
1734				index           = label.data('index'),
1735				content         = label.siblings('.fl-tabs-panel-content'),
1736				activeContent   = wrap.find('.fl-tabs-panel-content.fl-tab-active'),
1737				allIcons        = wrap.find('.fl-tabs-panels .fl-tabs-label > .fas'),
1738				icon            = label.find('.fas');
1739
1740			// Click or keyboard (enter or space) input?
1741			if(!this._validClick(e)) {
1742				return;
1743			}
1744
1745			if( label.hasClass( 'fl-tab-active' ) || wrap.hasClass( 'fl-tabs-animation' ) ) {
1746				return;
1747			}
1748
1749			// Toggle the icons.
1750			allIcons.addClass('fa-plus');
1751			icon.removeClass('fa-plus');
1752
1753			// Run the animations.
1754			wrap.addClass('fl-tabs-animation');
1755			activeContent.slideUp('normal');
1756
1757			content.slideDown('normal', function(){
1758
1759				wrap.find('.fl-tab-active').removeClass('fl-tab-active').attr('aria-selected', 'false');
1760				wrap.find('.fl-tabs-panels:first > .fl-tabs-panel > .fl-tabs-panel-content').attr('aria-hidden', 'true');
1761				wrap.find('.fl-tabs-label[data-index="' + index + '"]').addClass('fl-tab-active').attr('aria-selected', 'true');
1762				wrap.find('.fl-tabs-panels:first > .fl-tabs-panel > .fl-tabs-panel-content[data-index="' + index + '"]').attr('aria-hidden', 'false');
1763				content.addClass('fl-tab-active');
1764				wrap.removeClass('fl-tabs-animation');
1765
1766				// Gallery module support.
1767				FLBuilderLayout.refreshGalleries( content );
1768
1769				// Grid layout support (uses Masonry)
1770				FLBuilderLayout.refreshGridLayout( content );
1771
1772				// Post Carousel support (uses BxSlider)
1773				FLBuilderLayout.reloadSlider( content );
1774
1775				// WP audio shortcode support
1776				FLBuilderLayout.resizeAudio( content );
1777
1778				// Reload Google Map embed.
1779				FLBuilderLayout.reloadGoogleMap( wrap.find('.fl-tabs-panel-content[data-index="' + index + '"]') );
1780
1781				if(label.offset().top < $(window).scrollTop() + 100) {
1782					$('html, body').animate({ scrollTop: label.offset().top - 100 }, 500, 'swing');
1783				}
1784			});
1785		},
1786
1787		_resize: function()
1788		{
1789			$(this.nodeClass + ' .fl-tabs-vertical').each($.proxy(this._resizeVertical, this));
1790		},
1791
1792		_resizeVertical: function(e)
1793		{
1794			var wrap    = $(this.nodeClass + ' .fl-tabs-vertical'),
1795				labels  = wrap.find('.fl-tabs-labels'),
1796				panels  = wrap.find('.fl-tabs-panels');
1797
1798			panels.css('min-height', labels.height() + 'px');
1799		},
1800
1801		_validClick: function(e)
1802		{
1803			return (e.which == 1 || e.which == 13 || e.which == 32) ? true : false;
1804		},
1805
1806		_setupTabs: function() {
1807			index = this.activeTab - 1;
1808			if ( index < 0 ) {
1809				index = 0;
1810			}
1811			// $( this.nodeClass ).find('.fl-tabs-panel-content[data-index="' + index + '"]').addClass('fl-tab-active');
1812			var winWidth = $(window).width(),
1813				activeTabContent = $( this.nodeClass + ' .fl-tabs-panel-content.fl-tab-active' ),
1814				activeTabPanel = activeTabContent.parent(),
1815				activeTabLabelIcon = activeTabPanel.find('.fl-tabs-label > i'),
1816				smallBreakPoint = FLBuilderLayoutConfig.breakpoints.small;
1817
1818			if ( winWidth <= smallBreakPoint && 'close-all' == this.tabsOnMobile ) {
1819				activeTabContent.hide();
1820				activeTabLabelIcon.addClass('fa-plus');
1821				activeTabPanel.find('.fl-tab-active').removeClass('fl-tab-active').attr('aria-hidden', 'true');
1822			} else if ( winWidth >= smallBreakPoint ) {
1823				activeTabContent.show();
1824				activeTabLabelIcon.removeClass('fa-plus');
1825			}
1826		},
1827	};
1828
1829})(jQuery);
1830(function($) {
1831
1832	$(function() {
1833
1834		new FLBuilderTabs({
1835			id: '5f8de49eea527',
1836			tabsOnMobile: 'open-active',
1837			activeTab: '1',
1838		});
1839	});
1840
1841})(jQuery);
1842
1843/* Start Global Node Custom JS */
1844
1845/* End Global Node Custom JS */
1846
1847
1848/* Start Layout Custom JS */
1849
1850/* End Layout Custom JS */
1851
1852
1853
1854;/* eslint-disable no-undef */
1855(function($) {
1856
1857	/**
1858	 * Class for Menu Module
1859	 *
1860	 * @since 1.6.1
1861	 */
1862	FLBuilderMenu = function( settings ){
1863
1864		// set params
1865		this.nodeId              = settings.id;
1866		this.nodeClass           = '.fl-node-' + settings.id;
1867		this.wrapperClass        = this.nodeClass + ' .fl-menu';
1868		this.type				 				 = settings.type;
1869		this.mobileToggle		     = settings.mobile;
1870		this.mobileBelowRow		   = settings.mobileBelowRow;
1871		this.mobileFlyout		     = settings.mobileFlyout;
1872		this.breakPoints         = settings.breakPoints;
1873		this.mobileBreakpoint	 	 = settings.mobileBreakpoint;
1874		this.currentBrowserWidth = $( window ).width();
1875		this.postId              = settings.postId;
1876		this.mobileStacked       = settings.mobileStacked;
1877		this.submenuIcon         = settings.submenuIcon;
1878		this.flyoutWidth         = settings.flyoutWidth;
1879
1880		// initialize the menu
1881		this._initMenu();
1882
1883		// check if viewport is resizing
1884		$( window ).on( 'resize', $.proxy( function() {
1885
1886			var width = $( window ).width();
1887
1888			// if screen width is resized, reload the menu
1889		    if( width != this.currentBrowserWidth ){
1890
1891				this.currentBrowserWidth = width;
1892				this._initMenu( true );
1893 				this._clickOrHover( true );
1894			}
1895
1896			this._resizeFlyoutMenuPanel();
1897		}, this ) );
1898
1899		$( window ).on( 'scroll', $.proxy( function() {
1900			this._resizeFlyoutMenuPanel();
1901		}, this ) );
1902
1903		// Move focus to the first menu item if the layout is set to BelowRow
1904		$( this.wrapperClass ).on( 'keydown', '.fl-menu-mobile-toggle, .menu-item:first a:first', $.proxy( function ( event ) {
1905			// Make sure it is a tab key with both the menu toggle enabled & below row layout set
1906			if ( event.key !== 'Tab' || ! this._isMenuToggle() || ! this._isMobileBelowRowEnabled() ) {
1907				return;
1908			}
1909			// Trigger focus on the mobile toggle button if the user is shift tabbing from the first menu item
1910			if ( event.shiftKey && $( event.currentTarget ).is( 'a' ) ) {
1911				event.preventDefault();
1912				$( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).trigger( 'focus' );
1913			}
1914			// Trigger focus on the first menu item if the user is tabbing from the mobile toggle button
1915			else if ( ! event.shiftKey && $( event.currentTarget ).hasClass( 'fl-menu-mobile-toggle' ) && $( event.currentTarget ).hasClass( 'fl-active' )  ) {
1916				event.preventDefault();
1917				$( this.wrapperClass ).find( '.menu-item' ).first().find( 'a' ).first().trigger( 'focus' );
1918			}
1919		}, this ) );
1920
1921		// Close mobile menu or accordion when tabbing out from the first or last menu item
1922		$( this.wrapperClass ).on( 'focusout', $.proxy( function ( event ) {
1923			if ( $( this.wrapperClass + ' nav' ).has( $( event.relatedTarget ) ).length === 0 ) {
1924				if ( this.type === 'accordion' ) {
1925					this._toggleSubmenu( $( event.target ).parents( '.fl-has-submenu' ).last(), false );
1926				}
1927				else {
1928					this._clickOrHover( true );
1929				}
1930				const mobileToggle = $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' );
1931				if ( this._isMenuToggle() && mobileToggle.hasClass( 'fl-active' ) && ! $( event.relatedTarget ).is( mobileToggle ) && 'expanded' !== this.mobileToggle ) {
1932					mobileToggle.trigger( 'click' );
1933				}
1934			}
1935		}, this ) );
1936
1937	};
1938
1939	FLBuilderMenu.prototype = {
1940		nodeClass		: '',
1941		wrapperClass: '',
1942		type				: '',
1943		breakPoints	: {},
1944		$submenus		: null,
1945
1946		/**
1947		 * Check if the screen size fits a mobile viewport.
1948		 *
1949		 * @since  1.6.1
1950		 * @return bool
1951		 */
1952		_isMobile: function(){
1953			return this.currentBrowserWidth <= this.breakPoints.small ? true : false;
1954		},
1955
1956		/**
1957		 * Check if the device is connected to a mouse.
1958		 * 
1959		 * @since  2.9.0
1960		 * @return bool
1961		 */
1962		_isMouseAvailable: function(){
1963			return window.matchMedia("(pointer: fine) and (hover: hover)").matches;
1964		},
1965
1966		/**
1967		 * Check if the screen size fits a medium viewport.
1968		 *
1969		 * @since  1.10.5
1970		 * @return bool
1971		 */
1972		_isMedium: function(){
1973			return this.currentBrowserWidth <= this.breakPoints.medium ? true : false;
1974		},
1975
1976		/**
1977		 * Check if the screen size fits a large viewport.
1978		 *
1979		 * @since  1.10.5
1980		 * @return bool
1981		 */
1982		_isLarge: function(){
1983			return this.currentBrowserWidth <= this.breakPoints.large ? true : false;
1984		},
1985
1986		/**
1987		 * Check if the menu should toggle for the current viewport base on the selected breakpoint.
1988		 *
1989		 * @see 	 this._isMobile()
1990		 * @see 	 this._isMedium()
1991		 * @since  1.10.5
1992		 * @return bool
1993		 */
1994		_isMenuToggle: function(){
1995			if ( ( 'always' == this.mobileBreakpoint
1996				|| ( this._isMobile() && 'mobile' == this.mobileBreakpoint )
1997				|| ( this._isMedium() && 'medium-mobile' == this.mobileBreakpoint )
1998				|| ( this._isLarge() && 'large-mobile' == this.mobileBreakpoint )
1999			) && ( $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).is(':visible') || 'expanded' == this.mobileToggle ) ) {
2000				return true;
2001			}
2002
2003			return false;
2004		},
2005
2006		/**
2007		 * Initialize the toggle logic for the menu.
2008		 *
2009		 * @see    this._isMenuToggle()
2010		 * @see    this._menuOnCLick()
2011		 * @see    this._clickOrHover()
2012		 * @see    this._submenuOnRight()
2013		 * @see    this._submenuRowZindexFix()
2014		 * @see    this._toggleForMobile()
2015		 * @since  1.6.1
2016		 * @return void
2017		 */
2018		_initMenu: function( resized = false ){
2019			this._setupSubmenu();
2020			if ( ! resized ) {
2021				this._menuOnFocus();
2022				this._menuOnClick();
2023				this._menuOnEscape();
2024			}
2025			if ( $( this.nodeClass ).length && this.type == 'horizontal' ) {
2026				this._initMegaMenus();
2027			}
2028
2029			if( this._isMenuToggle() || this.type == 'accordion' ){
2030
2031				$( this.wrapperClass ).off( 'mouseenter mouseleave' );
2032				this._clickOrHover();
2033
2034			} else {
2035				this._submenuOnRight();
2036				this._submenuRowZindexFix();
2037			}
2038
2039			if( this.mobileToggle != 'expanded' ){
2040				this._toggleForMobile();
2041			}
2042
2043			if( $( this.wrapperClass ).find( '.fl-menu-search-item' ).length ){
2044				this._toggleMenuSearch();
2045			}
2046
2047			if( $( this.wrapperClass ).find( '.fl-menu-cart-item').length ){
2048				this._wooUpdateParams();
2049			}
2050		},
2051
2052		/**
2053		 * Whether the toggle behavior for submenus is through hovering or not.
2054		 *
2055		 * @since  2.5
2056		 * @return void
2057		 */
2058		_setupSubmenu: function() {
2059			if ( ! this._isMouseAvailable() || this._isMenuToggle() || this.type === 'accordion' ) {
2060				$( this.wrapperClass ).addClass( 'no-hover' );
2061			}
2062			else {
2063				$( this.wrapperClass ).removeClass( 'no-hover' );
2064			}
2065		},
2066
2067		/**
2068		 * Logic for menu items when focused.
2069		 *
2070		 * @since  1.9.0
2071		 * @return void
2072		 */
2073		_menuOnFocus: function(){
2074			$( this.wrapperClass ).on( 'focus', 'a:not(.fl-button), .fl-menu-toggle', $.proxy( function( event ) {
2075				const focusedMenuItem = $( event.currentTarget ).closest( '.menu-item' );
2076				const blurredMenuItem = $( event.relatedTarget ).closest( '.menu-item' );
2077				// In case the blurred & focused items are siblings
2078				if ( focusedMenuItem.closest( 'ul' ).is( blurredMenuItem.closest( 'ul' ) ) )	{
2079					// Check if the focus event is not between the link & submenu icon of the same menu item
2080					if ( ! focusedMenuItem.is( blurredMenuItem ) ) {
2081						this._toggleSubmenu( blurredMenuItem, false );
2082					}
2083				}
2084				// In case neither items are child & parent nor vice versa
2085				else if ( focusedMenuItem.has( blurredMenuItem ).length === blurredMenuItem.has( focusedMenuItem ).length ) {
2086					// Get the blurred item parent & is the sibling of the focused item
2087					blurredMenuItem.parents( '.fl-has-submenu' ).each( ( _, parent ) => {
2088						if ( focusedMenuItem.closest( 'ul' ).is( $( parent ).closest( 'ul' ) ) ) {
2089							this._toggleSubmenu( $( parent ), false );
2090							return false;
2091						}
2092					} );
2093				}
2094				// In case the blurred item is a child of the focused item
2095				else if ( focusedMenuItem.has( blurredMenuItem ).length ) {
2096					if ( this.type !== 'accordion' && this.submenuIcon === 'none' ) {
2097						this._toggleSubmenu( blurredMenuItem, false );
2098					}
2099				}
2100			}, this ) );
2101		},
2102
2103		/**
2104		 * Logic for menu items when Escape key is pressed.
2105		 *
2106		 * @since  2.7.1
2107		 * @return void
2108		 */
2109		_menuOnEscape: function(){
2110			$( this.wrapperClass ).on( 'keydown', $.proxy( function( event ){
2111				if ( event.key !== 'Escape' ) return;
2112				const menuItem = $( event.target ).closest( '.menu-item' );
2113				const mobileToggle = $( this.wrapperClass ).find( '.fl-menu-mobile-toggle' );
2114				// In case there is a focused menu item
2115				if ( menuItem.length || $( event.target ).hasClass( 'fl-menu-mobile-close' ) ) {
2116					// Close the search form if it is open
2117					if ( menuItem.hasClass( 'fl-menu-search-item' ) && $( this.wrapperClass ).find('.fl-search-form-input-wrap').is( ':visible' ) ) {
2118						$( this.wrapperClass ).find('.fl-menu-search-item .fl-button:is(a, button:not([type="submit"]))').trigger( 'focus' );
2119					}
2120					// Close all the submenus of the focused menu item
2121					else if ( menuItem.hasClass( 'fl-has-submenu' ) && menuItem.find( '.sub-menu' ).first().is( ':visible' ) ) {
2122						this._toggleSubmenu( menuItem, false );
2123					}
2124					else {
2125						// Shift focus to the parent while closing all its submenus
2126						const parentMenuItem = menuItem.parents( '.fl-has-submenu' ).not( '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading' ).first();
2127						// Close the mobile menu if there is no parent menu item and the mobile toggle is active
2128						if ( parentMenuItem.length === 0 && this._isMenuToggle() && mobileToggle.hasClass( 'fl-active' ) ) {
2129							// Blur to trigger the focus-out event for closing the menu
2130							mobileToggle.trigger( 'blur' ).trigger( 'focus' );
2131						}
2132						// Close the parent submenu and shift focus to its link
2133						else if ( parentMenuItem.length !== 0 ) {
2134							this._toggleSubmenu( parentMenuItem, false );
2135							parentMenuItem.find( 'a' ).first().trigger( 'focus' );
2136						}
2137					}
2138				}
2139				// Close the mobile menu if the mobile toggle is active
2140				else if ( $( event.target ).hasClass( 'fl-menu-mobile-toggle' ) && mobileToggle.hasClass( 'fl-active' ) ) {
2141					// Blur to trigger the focus-out event for closing the menu
2142					mobileToggle.trigger( 'blur' ).trigger( 'focus' );
2143				}
2144			}, this ) );
2145		},
2146
2147		/**
2148		 * Logic for menu items when clicked.
2149		 *
2150		 * @since  1.6.1
2151		 * @return void
2152		 */
2153		_menuOnClick: function(){
2154			// Fallback for span elements and fake links to interact with the keyboard
2155			$( this.wrapperClass ).on( 'keydown', 'a:not(.fl-button, [href]), span.fl-menu-toggle', $.proxy( function( event ) {
2156				if ( event.key === 'Enter' || event.key === ' ' ) {
2157					event.preventDefault();
2158					$( event.currentTarget ).trigger( 'click' );
2159				}
2160			}, this ) );
2161			$( this.wrapperClass ).on( 'click', 'a, .fl-menu-toggle', $.proxy( function( event ) {
2162				// Only allow mouse clicks with accordion & mobile menus
2163				if ( this._isMouseAvailable() && ! this._isMenuToggle() && event.detail && this.type !== 'accordion' ) return;
2164				// Links only open & do not toggle submenus if there is either a submenu icon or an accordion layout
2165				if ( $( event.currentTarget ).is( 'a' ) && ( this.submenuIcon !== 'none' || this.type === 'accordion' ) ) return;
2166				const menuItem = $( event.currentTarget ).closest( '.menu-item, .fl-menu-logo' );
2167				const menuLink = menuItem.find( 'a' ).first().attr( 'href' );
2168				const submenuHidden = menuItem.find( '.sub-menu' ).first().is( ':hidden' );
2169				if ( typeof menuLink === 'undefined' || menuLink === '#' || submenuHidden ) {
2170					event.preventDefault();
2171				}
2172				if ( $( event.currentTarget ).hasClass( 'fl-menu-toggle' ) || submenuHidden ) {
2173					this._toggleSubmenu( menuItem, submenuHidden );
2174				}
2175			}, this ) );
2176		},
2177
2178		/**
2179		 * Controls toggling the visibility of all submenu items for desktop & mobile.
2180		 *
2181		 * @since  2.10
2182		 * @return void
2183		 */
2184		_toggleSubmenu: function ( menuItem, opened ) {
2185			const togglingClass = this._isMenuToggle() || this.type === 'accordion' ? 'fl-active' : 'focus';
2186			const toggleElement = this.submenuIcon === 'none' ? 'a' : '.fl-menu-toggle';
2187			const hiddenMenu = '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading';
2188			if ( opened && menuItem.hasClass( 'fl-has-submenu' ) && ! menuItem.is( hiddenMenu ) ) {
2189				menuItem.addClass( togglingClass );
2190				menuItem.find( toggleElement ).first().attr( 'aria-expanded', true );
2191				if ( this._isMenuToggle() || this.type === 'accordion' ) {
2192					menuItem.find( '.sub-menu' ).first().filter( ':hidden' ).slideDown();
2193				}
2194			}
2195			else {
2196				menuItem.parent().find( '.menu-item' ).removeClass( togglingClass );
2197				menuItem.parent().find( '.fl-has-submenu' ).not( hiddenMenu ).find( toggleElement ).attr( 'aria-expanded', false );
2198				if ( this._isMenuToggle() || this.type === 'accordion' ) {
2199					menuItem.find( '.sub-menu' ).filter( ':visible' ).slideUp();
2200				}
2201			}
2202		},
2203
2204		/**
2205		 * Changes general styling and behavior of menus based on mobile / desktop viewport.
2206		 *
2207		 * @see    this._isMenuToggle()
2208		 * @since  1.6.1
2209		 * @return void
2210		 */
2211		_clickOrHover: function( clear = false ){
2212			const selector = this._isMobileBelowRowEnabled() ? this.nodeClass + '-clone' : this.nodeClass;
2213			this.$submenus = this.$submenus || $( selector ).find( '.sub-menu' );
2214
2215			const className = this._isMenuToggle() || this.type === 'accordion' ? 'fl-active' : 'focus';
2216			const toggleElement = this.submenuIcon === 'none' ? 'a' : '.fl-menu-toggle';
2217			const hiddenMenu = '.mega-menu.hide-heading, .mega-menu-disabled.hide-heading';
2218			$( selector ).find( '.fl-has-submenu' ).not( hiddenMenu ).each( function() {
2219				if( clear || ! $ ( this ).hasClass( className ) ){
2220					if ( clear ) $( this ).removeClass( className );
2221					$( this ).find( toggleElement ).first().attr( 'aria-expanded', false );
2222					if ( className === 'fl-active' ) {
2223						$( this ).find( '.sub-menu' ).fadeOut();
2224					} else if ( className === 'focus' ) {
2225						$( this ).find( '.sub-menu' ).css( {
2226							'display' : '',
2227							'opacity' : ''
2228						} );
2229					}
2230				}
2231			} );
2232		},
2233
2234		/**
2235		 * Logic to prevent submenus to go outside viewport boundaries.
2236		 *
2237		 * @since  1.6.1
2238		 * @return void
2239		 */
2240		_submenuOnRight: function(){
2241
2242			$( this.wrapperClass )
2243				.on( 'mouseenter focus', '.fl-has-submenu', $.proxy( function( e ){
2244
2245					if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) {
2246						return;
2247					}
2248
2249					var $link           = $( e.currentTarget ),
2250						$parent         = $link.parent(),
2251						$subMenu        = $link.find( '.sub-menu' ),
2252						subMenuWidth    = $subMenu.width(),
2253						subMenuPos      = 0,
2254						bodyWidth       = $( 'body' ).width();
2255
2256					if( $link.closest( '.fl-menu-submenu-right' ).length !== 0) {
2257
2258						$link.addClass( 'fl-menu-submenu-right' );
2259
2260					} else if( $( 'body' ).hasClass( 'rtl' ) ) {
2261
2262						subMenuPos = $parent.is( '.sub-menu' ) ?
2263									 $parent.offset().left - subMenuWidth:
2264									 $link.offset().left - $link.width() - subMenuWidth;
2265
2266						if( subMenuPos <= 0 ) {
2267							$link.addClass( 'fl-menu-submenu-right' );
2268						}
2269
2270					} else {
2271
2272						subMenuPos = $parent.is( '.sub-menu' ) ?
2273									 $parent.offset().left + $parent.width() + subMenuWidth :
2274									 $link.offset().left + $link.width() + subMenuWidth;
2275
2276						if( subMenuPos > bodyWidth ) {
2277							$link.addClass('fl-menu-submenu-right');
2278						}
2279					}
2280				}, this ) )
2281				.on( 'mouseleave', '.fl-has-submenu', $.proxy( function( e ){
2282					$( e.currentTarget ).removeClass( 'fl-menu-submenu-right' );
2283				}, this ) );
2284
2285		},
2286
2287		/**
2288		 * Logic to prevent submenus to go behind the next overlay row.
2289		 *
2290		 * @since  1.10.9
2291		 * @return void
2292		 */
2293		_submenuRowZindexFix: function(){
2294
2295			$( this.wrapperClass )
2296				.on( 'mouseenter', 'ul.menu > .fl-has-submenu', $.proxy( function( e ){
2297
2298					if( $ ( e.currentTarget ).find('.sub-menu').length === 0 ) {
2299						return;
2300					}
2301
2302					$( this.nodeClass )
2303						.closest( '.fl-row' )
2304						.find( '.fl-row-content' )
2305						.css( 'z-index', '10' );
2306
2307				}, this ) )
2308				.on( 'mouseleave', 'ul.menu > .fl-has-submenu', $.proxy( function(){
2309
2310					$( this.nodeClass )
2311						.closest( '.fl-row' )
2312						.find( '.fl-row-content' )
2313						.css( 'z-index', '' );
2314
2315				}, this ) );
2316		},
2317
2318		/**
2319		 * Logic for the mobile menu button.
2320		 *
2321		 * @since  1.6.1
2322		 * @return void
2323		 */
2324		_toggleForMobile: function(){
2325
2326			var $wrapper = null,
2327				$menu    = null,
2328				self     = this;
2329
2330			$( this.wrapperClass ).find( '.fl-menu-mobile-toggle' ).attr('aria-controls', $( this.wrapperClass ).find( 'ul.menu' ).attr('id'));
2331
2332			if( this._isMenuToggle() ){
2333
2334				if ( this._isMobileBelowRowEnabled() ) {
2335					this._placeMobileMenuBelowRow();
2336					$wrapper = $( this.wrapperClass );
2337					$menu    = $( this.nodeClass + '-clone' );
2338					$menu.find( 'ul.menu' ).show();
2339				}
2340				else {
2341					$wrapper = $( this.wrapperClass );
2342					$menu    = $wrapper.find( '.menu' );
2343				}
2344
2345				if( !$wrapper.find( '.fl-menu-mobile-toggle' ).hasClass( 'fl-active' ) && ! self.mobileFlyout ){
2346					$menu.css({ display: 'none' });
2347				}
2348
2349				// Flayout Menu
2350				if ( self.mobileFlyout ) {
2351					this._initFlyoutMenu();
2352				}
2353
2354				$wrapper.on( 'click', '.fl-menu-mobile-toggle', function( e ){
2355					e.stopImmediatePropagation();
2356
2357					$( this ).toggleClass( 'fl-active' );
2358
2359					if ( self.mobileFlyout ) {
2360						self._toggleFlyoutMenu();
2361						const flyoutWrapper = $( '.fl-menu-mobile-flyout' );
2362						if ( $( this ).hasClass( 'fl-active' ) ) {
2363							flyoutWrapper.attr( 'aria-hidden', false );
2364							flyoutWrapper.find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex="-1"]' ).attr( 'tabindex', 0 );
2365						}
2366						else {
2367							flyoutWrapper.attr( 'aria-hidden', true );
2368							flyoutWrapper.find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex]:not
2368([tabindex="-1"])' ).attr( 'tabindex', -1 );
2369						}
2370					}
2371					else {
2372						var targetMenu = null;
2373
2374						if ( self.mobileBelowRow ) {
2375							var $closestCol = $( this ).parents( '.fl-col, .fl-module-box' ),
2376								$closestColGroup = $closestCol.length ? $closestCol.parent( '.fl-col-group' ) : null;
2377								targetMenu  = $closestCol.length ? $closestCol.last().next( '.fl-menu-mobile-clone' ) : null;
2378
2379							if ( $closestColGroup.length ) {
2380								if ( $closestColGroup.hasClass( 'fl-col-group-responsive-reversed' ) ) {
2381									$closestColGroup.find( '.fl-menu-mobile-clone' ).css( 'order', -1 );
2382								} else if ( $closestColGroup ) {
2383									$closestColGroup.find( '.fl-menu-mobile-clone' ).css( 'order', 2 );
2384								}
2385							}
2386						} else {
2387							targetMenu = $( this ).closest( '.fl-menu' ).find( 'ul.menu' );
2388						}
2389						
2390						if ( targetMenu.length ) {
2391							$menu = $( targetMenu );
2392						}
2393
2394						$menu.slideToggle();
2395					}
2396
2397					e.stopPropagation();
2398				} );
2399
2400				// Hide active menu when click on anchor link ID that exists on a page
2401				$menu.off().on( 'click', '.menu-item > a[href*="#"]:not([href="#"])', function(){
2402					var $href = $(this).attr('href'),
2403						$targetID = $href.split('#')[1],
2404						element = $('#' + $targetID);
2405					if ( $('body').find(element).length > 0 ) {
2406						$( this ).toggleClass( 'fl-active' );
2407						FLBuilderLayout._scrollToElement( element );
2408						if ( ! self._isMenuToggle() ) {
2409							$menu.slideToggle();
2410						}
2411					}
2412				});
2413			}
2414			else {
2415
2416				if ( this._isMobileBelowRowEnabled() ) {
2417					this._removeMenuFromBelowRow();
2418				}
2419
2420				$wrapper = $( this.wrapperClass ),
2421				$menu    = $wrapper.find( 'ul.menu' );
2422				$wrapper.find( '.fl-menu-mobile-toggle' ).removeClass( 'fl-active' );
2423				$menu.css({ display: '' });
2424
2425				if ( ! this._isMobileBelowRowEnabled() ) {
2426					$menu.off( 'click', '.menu-item > a[href*="#"]:not([href="#"])' );
2427				}
2428
2429				if ( this.mobileFlyout && $wrapper.find( '.fl-menu-mobile-flyout' ).length > 0 ) {
2430					$( 'body' ).css( 'margin', '' );
2431					$( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' );
2432					$menu.unwrap();
2433					$wrapper.find( '.fl-menu-mobile-close' ).remove();
2434					$wrapper.find( '.fl-menu-mobile-opacity' ).remove();
2435				}
2436			}
2437		},
2438
2439		/**
2440		 * Init any mega menus that exist.
2441		 *
2442		 * @see 	 this._isMenuToggle()
2443		 * @since  1.10.4
2444		 * @return void
2445		 */
2446		_initMegaMenus: function(){
2447
2448			var module     = $( this.nodeClass ),
2449				rowContent = module.closest( '.fl-row-content' ),
2450				rowWidth   = rowContent.width(),
2451				megas      = module.find( '.mega-menu' ),
2452				disabled   = module.find( '.mega-menu-disabled' ),
2453				isToggle   = this._isMenuToggle();
2454
2455			if ( isToggle ) {
2456				megas.removeClass( 'mega-menu' ).addClass( 'mega-menu-disabled' );
2457				module.find( 'li.mega-menu-disabled > ul.sub-menu' ).css( 'width', '' );
2458				rowContent.css( 'position', '' );
2459			} else {
2460				disabled.removeClass( 'mega-menu-disabled' ).addClass( 'mega-menu' );
2461				module.find( 'li.mega-menu > ul.sub-menu' ).css( 'width', rowWidth + 'px' );
2462				rowContent.css( 'position', 'relative' );
2463			}
2464		},
2465
2466		/**
2467		 * Check to see if Below Row should be enabled.
2468		 *
2469		 * @since  1.11
2470		 * @return boolean
2471		 */
2472		_isMobileBelowRowEnabled: function() {
2473			return this.mobileBelowRow && ( $( this.nodeClass ).parents( '.fl-col, .fl-module-box' ).length );
2474		},
2475
2476		/**
2477		 * Logic for putting the mobile menu below the menu's
2478		 * column so it spans the full width of the page.
2479		 *
2480		 * @since  1.10
2481		 * @return void
2482		 */
2483		_placeMobileMenuBelowRow: function(){
2484
2485			if ( $( this.nodeClass + '-clone' ).length ) {
2486				return;
2487			}
2488
2489			var module = $( this.nodeClass ),
2490				clone  = null,
2491				col    = module.parents( '.fl-col, .fl-module-box' ).last();
2492
2493			if ( module.length < 1 ) {
2494				return;
2495			}
2496
2497			clone = ( module.length > 1 ) ? $( module[0] ).clone() : module.clone();
2498			module.find( 'ul.menu' ).remove();
2499			clone.addClass( ( this.nodeClass + '-clone' ).replace( '.', '' ) );
2500			clone.addClass( 'fl-menu-mobile-clone' );
2501			clone.find( '.fl-menu-mobile-toggle' ).remove();
2502			col.after( clone );
2503
2504			// Removes animation when enabled
2505			if ( module.hasClass( 'fl-animation' ) ) {
2506				clone.removeClass( 'fl-animation' );
2507			}
2508
2509			this._menuOnFocus();
2510			this._menuOnClick();
2511			this._menuOnEscape();
2512		},
2513
2514		/**
2515		 * Logic for removing the mobile menu from below the menu's
2516		 * column and putting it back in the main wrapper.
2517		 *
2518		 * @since  1.10
2519		 * @return void
2520		 */
2521		_removeMenuFromBelowRow: function(){
2522
2523			if ( ! $( this.nodeClass + '-clone' ).length ) {
2524				return;
2525			}
2526
2527			var module = $( this.nodeClass ),
2528				clone  = $( this.nodeClass + '-clone' ),
2529				menu   = clone.find( 'ul.menu' ),
2530				nav    = module.find( 'nav' );
2531
2532			if ( nav.length ) {
2533				nav.append( menu );
2534			} else {
2535				module.find( '.fl-menu-mobile-toggle' ).after( menu );
2536			}
2537			clone.remove();
2538			menu.find( 'a' ).each( FLBuilderLayout._initAnchorLink );
2539		},
2540
2541		/**
2542		 * Logic for Flyout responsive menu.
2543		 *
2544		 * @since  2.2
2545		 * @return void
2546		 */
2547		_initFlyoutMenu: function(){
2548			var wrapper = $( this.wrapperClass ),
2549				menu  	= wrapper.find( 'ul.menu' ),
2550				button	= wrapper.find( '.fl-menu-mobile-toggle' );
2551
2552			if ( 0 === wrapper.find( '.fl-menu-mobile-flyout' ).length ) {
2553				menu.wrap( '<div class="fl-menu-mobile-flyout" aria-hidden="true"></div>' );
2554			}
2555
2556			if ( 0 === wrapper.find( '.fl-menu-mobile-close' ).length ) {
2557				var close = window.fl_responsive_close || 'Close'
2558				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>' );
2559			}
2560
2561			// Push with opacity
2562			if ( wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ) && 0 === wrapper.find( '.fl-menu-mobile-opacity' ).length ) {
2563				wrapper.append( '<div class="fl-menu-mobile-opacity"></div>' );
2564			}
2565
2566			wrapper.off( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close' ).on( 'click', '.fl-menu-mobile-opacity, .fl-menu-mobile-close', function(e){
2567				button.trigger('focus').trigger( 'click' );
2568				e.stopPropagation();
2569			});
2570
2571			if ( 'undefined' !== typeof FLBuilder ) {
2572				FLBuilder.addHook('restartEditingSession', function(){
2573					$( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', '' );
2574
2575					// Toggle active menu
2576					if ( button.hasClass( 'fl-active' ) ) {
2577						button.trigger( 'click' );
2578					}
2579				});
2580			}
2581			$( '.fl-menu-mobile-flyout' ).find( 'a[href], button, input, select, textarea, span.fl-menu-toggle, [tabindex]:not([tabindex="-1"])' ).attr( 'tabindex', -1 );
2582		},
2583
2584		/**
2585		 * Logic to enable/disable the Flyout menu on button click.
2586		 *
2587		 * @since  2.2
2588		 * @return void
2589		 */
2590		_toggleFlyoutMenu: function(){
2591			var wrapper		= $( this.wrapperClass ),
2592				button		= wrapper.find( '.fl-menu-mobile-toggle' ),
2593				position 	= wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left',
2594				pushMenu 	= wrapper.hasClass( 'fl-menu-responsive-flyout-push' ) || wrapper.hasClass( 'fl-menu-responsive-flyout-push-opacity' ),
2595				opacity		= wrapper.find( '.fl-menu-mobile-opacity' ),
2596				marginPos	= {},
2597				fixedPos 	= {},
2598				fixedHeader	= $('header, header > div');
2599
2600			this._resizeFlyoutMenuPanel();
2601
2602			// Fix the push menu when builder ui panel is pinned
2603			if ( $( '.fl-builder-ui-pinned-content-transform' ).length > 0 && ! $( 'body' ).hasClass( 'fl-builder-edit' ) ) {
2604				$( '.fl-builder-ui-pinned-content-transform' ).css( 'transform', 'none' );
2605			}
2606
2607			if ( pushMenu ) {
2608				marginPos[ 'margin-' + position ] = button.hasClass( 'fl-active' ) ? this.flyoutWidth + 'px' : '0px';
2609				$( 'body' ).animate( marginPos, 200);
2610
2611				// Fixed header
2612				if ( fixedHeader.length > 0 ) {
2613					fixedPos[ position] = button.hasClass( 'fl-active' ) ? this.flyoutWidth + 'px' : '0px';
2614					fixedHeader.each(function(){
2615						if ( 'fixed' == $( this ).css( 'position' ) ) {
2616							$( this ).css({ 'transition' : 'none' });
2617							$( this ).animate( fixedPos, 200 );
2618						}
2619					});
2620				}
2621			}
2622
2623			if ( opacity.length > 0 && button.hasClass( 'fl-active' ) ) {
2624				opacity.show();
2625			}
2626			else {
2627				opacity.hide();
2628			}
2629		},
2630
2631		/**
2632		 * Resize or reposition the Flyout Menu Panel.
2633		 * 
2634		 * @since  2.8.1
2635		 * @return void
2636		 */
2637		_resizeFlyoutMenuPanel: function(){
2638			const wrapper    = $( this.wrapperClass );
2639			const wrapFlyout = wrapper.find( '.fl-menu-mobile-flyout' );
2640				
2641			if ( wrapFlyout.length > 0 ) {
2642				wrapFlyout.css( this._getFlyoutMenuPanelPosition() );
2643			}
2644		},
2645
2646		/**
2647		 * Compute the Flyout Menu Panel's position on the screen.
2648		 * 
2649		 * @since  2.8.1
2650		 * @return object
2651		 */
2652		_getFlyoutMenuPanelPosition: function() {
2653			var wrapper        = $( this.wrapperClass ),
2654				button         = wrapper.find( '.fl-menu-mobile-toggle' ),
2655				side           = wrapper.hasClass( 'fl-flyout-right' ) ? 'right' : 'left',
2656				winHeight      = $(window).outerHeight(),
2657				winTop         = $(window).scrollTop(),
2658				adminBarHeight = $( '#wpadminbar' ).length ? $( '#wpadminbar' ).height() : 0,
2659				flyoutPosition = {};
2660
2661			flyoutPosition[ side ]  = '-' + ( parseInt( this.flyoutWidth ) + 15 ) + 'px';
2662			if ( ! button.hasClass( 'fl-active' ) ) {
2663				return flyoutPosition;
2664			}
2665
2666			flyoutPosition[ side ]  = '0px';
2667			flyoutPosition[ 'height' ]  = winHeight + 'px';
2668			flyoutPosition[ 'top' ] = '0px';
2669			
2670			if ( adminBarHeight > 0 ) {
2671				const diff = adminBarHeight - winTop;
2672				flyoutPosition[ 'top' ] = diff <= 0 ? '0px' : (diff) + 'px';
2673			}
2674
2675			return flyoutPosition;
2676		},
2677
2678		/**
2679		 * Shows or hides the nav search form.
2680		 *
2681		 * @since  2.5
2682		 * @method _toggleMenuSearch
2683		 */
2684		_toggleMenuSearch: function(){
2685			const form   = $( this.wrapperClass ).find('.fl-menu-search-item .fl-search-form-input-wrap'); 
2686			const button = $( this.wrapperClass ).find('.fl-menu-search-item .fl-button:is(a, button:not([type="submit"]))');
2687			form.on('submit', () => form.stop().fadeToggle('fast'));
2688			// Close the search form when focus is lost
2689			form.on('focusout', (event) => {
2690				if (form.is(':visible') && form.has($(event.relatedTarget)).length === 0) {
2691					button.trigger('click');
2692				}
2693			});
2694			button.attr('aria-expanded', false);
2695			// Close other open submenus when focusing on the search button
2696			button.on('focus', (event) => {
2697				const parentMenus = $(event.relatedTarget).parents('.menu-item.fl-has-submenu');
2698				if (event.relatedTarget && parentMenus.length) {
2699					this._toggleSubmenu(parentMenus, false);
2700				}
2701			});
2702			button.on('click', (event) => {
2703				// Prevent toggling when clicking with mouse while the form is already open
2704				if (event.detail && event.type === 'click' && form.is(':visible')) return;
2705				form.stop().fadeToggle('fast', () => {
2706					button.attr('aria-expanded', form.is(':visible'));
2707					if(form.is(':visible')) {
2708						form.find('.fl-search-text').focus();
2709					}
2710				});
2711			});
2712		},
2713
2714		/**
2715		 * Adds menu node and post ID to WooCommerce ajax URL requests.
2716		 *
2717		 * @since  2.5
2718		 * @return void
2719		 */
2720		_wooUpdateParams: function() {
2721			if ( 'undefined' !== typeof wc_cart_fragments_params ) {
2722				wc_cart_fragments_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId;
2723			}
2724			if ( 'undefined' !== typeof wc_add_to_cart_params ) {
2725				wc_add_to_cart_params.wc_ajax_url += '&fl-menu-node='+ this.nodeId +'&post-id='+ this.postId;
2726			}
2727		},
2728	};
2729
2730})(jQuery);
2731
2732(function($) {
2733
2734	$(function() {
2735
2736		new FLBuilderMenu({
2737			id: '5b4e4504e6e84',
2738			type: 'horizontal',
2739			mobile: 'expanded',
2740			mobileBelowRow: false,
2741			mobileFlyout: false,
2742			breakPoints: {
2743				large: 1200,
2744				medium: 992,
2745				small: 768			},
2746			mobileBreakpoint: 'mobile',
2747			postId : '793',
2748			mobileStacked: true,
2749			submenuIcon: 'none',
2750			flyoutWidth: '250',
2751		});
2752
2753	});
2754
2755})(jQuery);
2756
2757/* Start Layout Custom JS */
2758
2759/* End Layout Custom JS */
2760
2761
2762jQuery(function($) {
2763	
2764		$(function() {
2765		$( '.fl-node-5da892bbc0b4e .fl-photo-img' )
2766			.on( 'mouseenter', function( e ) {
2767				$( this ).data( 'title', $( this ).attr( 'title' ) ).removeAttr( 'title' );
2768			} )
2769			.on( 'mouseleave', function( e ){
2770				$( this ).attr( 'title', $( this ).data( 'title' ) ).data( 'title', null );
2771			} );
2772	});
2773		window._fl_string_to_slug_regex = 'a-zA-Z0-9';
2774});
2775
2776(function($) {
2777
2778	$(function() {
2779
2780		new FLBuilderMenu({
2781			id: '5da892bbc0b4a',
2782			type: 'horizontal',
2783			mobile: 'hamburger',
2784			mobileBelowRow: true,
2785			mobileFlyout: false,
2786			breakPoints: {
2787				large: 1200,
2788				medium: 992,
2789				small: 768			},
2790			mobileBreakpoint: 'medium-mobile',
2791			postId : '15756',
2792			mobileStacked: true,
2793			submenuIcon: 'none',
2794			flyoutWidth: '250',
2795		});
2796
2797	});
2798
2799})(jQuery);
2800
2801/* Start Layout Custom JS */
2802
2803/* End Layout Custom JS */
2804
2805(function($){
2806
2807	/**
2808	 * Helper class for header layout logic.
2809	 *
2810	 * @since 1.0
2811	 * @class FLThemeBuilderHeaderLayout
2812	 */
2813	FLThemeBuilderHeaderLayout = {
2814
2815		/**
2816		 * A reference to the window object for this page.
2817		 *
2818		 * @since 1.0
2819		 * @property {Object} win
2820		 */
2821		win : null,
2822
2823		/**
2824		 * A reference to the body object for this page.
2825		 *
2826		 * @since 1.0
2827		 * @property {Object} body
2828		 */
2829		body : null,
2830
2831		/**
2832		 * A reference to the header object for this page.
2833		 *
2834		 * @since 1.0
2835		 * @property {Object} header
2836		 */
2837		header : null,
2838
2839		/**
2840		 * Whether this header overlays the content or not.
2841		 *
2842		 * @since 1.0
2843		 * @property {Boolean} overlay
2844		 */
2845		overlay : false,
2846
2847		/**
2848		 * Whether the page has the WP admin bar or not.
2849		 *
2850		 * @since 1.0
2851		 * @property {Boolean} hasAdminBar
2852		 */
2853		hasAdminBar : false,
2854
2855		/**
2856		 * Breakpoint for when the sticky header should apply.
2857		 *
2858		 * @since 1.4
2859		 * @property {String} stickyOn
2860		 */
2861		stickyOn: '',
2862
2863		/**
2864		 * A reference of the sticky and shrink header breakpoint.
2865		 *
2866		 * @since 1.2.5
2867		 * @property {Number} breakpointWidth
2868		 */
2869		breakpointWidth: 0,
2870
2871		/**
2872		 * Initializes header layout logic.
2873		 *
2874		 * @since 1.0
2875		 * @method init
2876		 */
2877		init: function()
2878		{
2879			var editing          = $( 'html.fl-builder-edit' ).length,
2880				header           = $( '.fl-builder-content[data-type=header]' ),
2881				menuModule       = header.find( '.fl-module-menu' ),
2882				breakpoint       = null;
2883
2884			if ( ! editing && header.length ) {
2885
2886				header.imagesLoaded( $.proxy( function() {
2887
2888					this.win         = $( window );
2889					this.body        = $( 'body' );
2890					this.header      = header.eq( 0 );
2891					this.overlay     = !! Number( header.attr( 'data-overlay' ) );
2892					this.hasAdminBar = !! $( 'body.admin-bar' ).length;
2893					this.stickyOn    = this.header.data( 'sticky-on' );
2894					breakpoint       = this.header.data( 'sticky-breakpoint' );
2895
2896					if ( '' == this.stickyOn ) {
2897						if ( typeof FLBuilderLayoutConfig.breakpoints[ breakpoint ] !== undefined ) {
2898							this.breakpointWidth = FLBuilderLayoutConfig.breakpoints[ breakpoint ];
2899						}
2900						else {
2901							this.breakpointWidth = FLBuilderLayoutConfig.breakpoints.medium;
2902						}
2903					}
2904
2905					if ( Number( header.attr( 'data-sticky' ) ) ) {
2906
2907						this.header.data( 'original-top', this.header.offset().top );
2908						this.win.on( 'resize', $.throttle( 500, $.proxy( this._initSticky, this ) ) );
2909						this._initSticky();
2910
2911					}
2912
2913				}, this ) );
2914			}
2915		},
2916
2917		/**
2918		 * Initializes sticky logic for a header.
2919		 *
2920		 * @since 1.0
2921		 * @access private
2922		 * @method _initSticky
2923		 */
2924		_initSticky: function( e )
2925		{
2926			var header     = $('.fl-builder-content[data-type=header]'),
2927				windowSize = this.win.width(),
2928				makeSticky = false;
2929
2930			makeSticky = this._makeWindowSticky( windowSize );
2931			if ( makeSticky || ( this.breakpointWidth > 0 && windowSize >= this.breakpointWidth ) ) {
2932				this.win.on( 'scroll.fl-theme-builder-header-sticky', $.proxy( this._doSticky, this ) );
2933				//
2934				// Check if Event Type is 'resize' then invoke this._doSticky()
2935				// only if the 'fl-theme-builder-header-sticky' class is already present.
2936				//
2937				if ( e && 'resize' === e.type ) {
2938					if ( this.header.hasClass( 'fl-theme-builder-header-sticky' ) ) {
2939						this._doSticky( e );
2940					}
2941					this._adjustStickyHeaderWidth();
2942				}
2943
2944				if ( Number( header.attr( 'data-shrink' ) ) ) {
2945					this.header.data( 'original-height', this.header.outerHeight() );
2946					this.win.on( 'resize', $.throttle( 500, $.proxy( this._initShrink, this ) ) );
2947					this._initShrink();
2948				}
2949
2950				this._initFlyoutMenuFix( e );
2951			} else {
2952				this.win.off( 'scroll.fl-theme-builder-header-sticky' );
2953				this.win.off( 'resize.fl-theme-builder-header-sticky' );
2954
2955				this.header.removeClass( 'fl-theme-builder-header-sticky' );
2956				this.header.removeAttr( 'style' );
2957				this.header.parent().css( 'padding-top', '0' );
2958			}
2959		},
2960
2961		/**
2962		 * Check if Header should be sticky at a particular Window size.
2963		 *
2964		 * @since 1.4
2965		 * @access private
2966		 * @param  widowSize
2967		 * @method _makeWindowSticky
2968		 */
2969		_makeWindowSticky: function ( windowSize )
2970		{
2971			var makeSticky = false;
2972
2973			switch (this.stickyOn) {
2974				case 'xl':
2975					makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['large'];
2976					break;
2977				case '': // Default
2978				case 'desktop':
2979					makeSticky = windowSize >= FLBuilderLayoutConfig.breakpoints['medium'];
2980					break;
2981				case 'desktop-medium':
2982					makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small'];
2983					break;
2984				case 'large':
2985					makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['medium'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large'];
2986					break;
2987				case 'large-medium':
2988					makeSticky = windowSize > FLBuilderLayoutConfig.breakpoints['small'] && windowSize <= FLBuilderLayoutConfig.breakpoints['large'];
2989					break;
2990				case 'medium':
2991					makeSticky = ( windowSize <= FLBuilderLayoutConfig.breakpoints['medium'] && windowSize > FLBuilderLayoutConfig.breakpoints['small'] );
2992					break;
2993				case 'medium-mobile':
2994					makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['medium']);
2995					break;
2996				case 'mobile':
2997					makeSticky = (windowSize <= FLBuilderLayoutConfig.breakpoints['small']);
2998					break;
2999				case 'all':
3000					makeSticky = true;
3001					break;
3002			}
3003
3004			return makeSticky;
3005		},
3006
3007		/**
3008		 * Sticks the header when the page is scrolled.
3009		 *
3010		 * @since 1.0
3011		 * @access private
3012		 * @method _doSticky
3013		 */
3014		_doSticky: function( e )
3015		{
3016			var winTop    		  = Math.floor( this.win.scrollTop() ),
3017				headerTop 		  = Math.floor( this.header.data( 'original-top' ) ),
3018				hasStickyClass    = this.header.hasClass( 'fl-theme-builder-header-sticky' ),
3019				hasScrolledClass  = this.header.hasClass( 'fl-theme-builder-header-scrolled' ),
3020				beforeHeader      = this.header.prevAll( '.fl-builder-content' ),
3021				bodyTopPadding    = parseInt( jQuery('body').css('padding-top') ),
3022				winBarHeight      = $('#wpadminbar').length ? $('#wpadminbar').outerHeight() : 0,
3023				headerHeight      = 0;
3024
3025			if ( isNaN( bodyTopPadding ) ) {
3026				bodyTopPadding = 0;
3027			}
3028
3029			if ( this.hasAdminBar && this.win.width() > 600 ) {
3030				winTop += Math.floor( winBarHeight );
3031			}
3032
3033			if ( winTop > headerTop ) {
3034				if ( ! hasStickyClass ) {
3035					if ( e && ( 'scroll' === e.type || 'smartscroll' === e.type ) ) {
3036					 	this.header.addClass( 'fl-theme-builder-header-sticky' );
3037						if ( this.overlay && beforeHeader.length ) {
3038							this.header.css( 'top', winBarHeight);
3039						}
3040					}
3041
3042					if ( ! this.overlay ) {
3043						this._adjustHeaderHeight();
3044					}
3045				}
3046			}
3047			else if ( hasStickyClass ) {
3048				this.header.removeClass( 'fl-theme-builder-header-sticky' );
3049				this.header.removeAttr( 'style' );
3050				this.header.parent().css( 'padding-top', '0' );
3051			}
3052
3053			this._adjustStickyHeaderWidth();
3054
3055			if ( winTop > headerTop ) {
3056				if ( ! hasScrolledClass ) {
3057					this.header.addClass( 'fl-theme-builder-header-scrolled' );
3058				}
3059			} else if ( hasScrolledClass ) {
3060				this.header.removeClass( 'fl-theme-builder-header-scrolled' );
3061			}
3062
3063			this._flyoutMenuFix( e );
3064		},
3065
3066		/**
3067		 * Initializes flyout menu fixes on sticky header.
3068		 *
3069		 * @since 1.4.1
3070		 * @method _initFlyoutMenuFix
3071		 */
3072		_initFlyoutMenuFix: function( e ) {
3073			var header       = this.header,
3074				menuModule   = header.closest( '.fl-menu' ),
3075				flyoutMenu   = menuModule.find( '.fl-menu-mobile-flyout' ),
3076				isPushMenu   = menuModule.hasClass( 'fl-menu-responsive-flyout-push' ) || menuModule.hasClass( 'fl-menu-responsive-flyout-push-opacity' ),
3077				isOverlay    = menuModule.hasClass( 'fl-menu-responsive-flyout-overlay' ),
3078				flyoutPos    = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left',
3079				flyoutParent = header.parent().is( 'header' ) ? header.parent().parent() : header.parent();
3080				isFullWidth  = this.win.width() === header.width(),
3081				flyoutLayout = '',
3082				activePos    = 250,
3083				headerPos    = 0;
3084
3085			if ( ! flyoutMenu.length ) {
3086				return;
3087			}
3088
3089			if ( this.win.width() > header.parent().width() ) {
3090				headerPos = ( this.win.width() - header.width() ) / 2;
3091			}
3092
3093			if ( isOverlay ) {
3094				activePos = headerPos;
3095			}
3096			else if ( isPushMenu ) {
3097				activePos = activePos + headerPos;
3098			}
3099			flyoutMenu.data( 'activePos', activePos );
3100
3101			if ( isPushMenu ) {
3102				flyoutLayout = 'push-' + flyoutPos;
3103			}
3104			else if ( isOverlay ) {
3105				flyoutLayout = 'overlay-' + flyoutPos;
3106			}
3107
3108			if ( isPushMenu && ! $( 'html' ).hasClass( 'fl-theme-builder-has-flyout-menu' ) ) {
3109				$( 'html' ).addClass( 'fl-theme-builder-has-flyout-menu' );
3110			}
3111
3112			if ( ! flyoutParent.hasClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout ) ) {
3113				flyoutParent.addClass( 'fl-theme-builder-flyout-menu-' + flyoutLayout );
3114			}
3115
3116			if ( ! header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && isOverlay ) {
3117				header.addClass( 'fl-theme-builder-flyout-menu-overlay' );
3118			}
3119
3120			if ( ! header.hasClass( 'fl-theme-builder-header-full-width' ) && isFullWidth ) {
3121			   header.addClass( 'fl-theme-builder-header-full-width' );
3122		    }
3123			else if ( ! isFullWidth ) {
3124				header.removeClass( 'fl-theme-builder-header-full-width' );
3125			}
3126
3127			menuModule.on( 'click', '.fl-menu-mobile-toggle', $.proxy( function( event ){
3128				if ( menuModule.find( '.fl-menu-mobile-toggle.fl-active' ).length ) {
3129					$( 'html' ).addClass( 'fl-theme-builder-flyout-menu-active' );
3130					event.stopImmediatePropagation();
3131				}
3132				else {
3133					$( 'html' ).removeClass( 'fl-theme-builder-flyout-menu-active' );
3134				}
3135
3136				this._flyoutMenuFix( event );
3137			}, this ) );
3138		},
3139
3140		/**
3141		 * Fix flyout menu inside the sticky header.
3142		 *
3143		 * @since 1.4.1
3144		 * @method _flyoutMenuFix
3145		 */
3146		_flyoutMenuFix: function( e ){
3147			var header      = this.header,
3148			    menuModule  = $( e.target ).closest( '.fl-menu' ),
3149				flyoutMenu  = menuModule.find( '.fl-menu-mobile-flyout' ),
3150				flyoutPos   = menuModule.hasClass( 'fl-flyout-right' ) ? 'right' : 'left',
3151				menuOpacity = menuModule.find( '.fl-menu-mobile-opacity' ),
3152				isScroll    = 'undefined' !== typeof e && 'scroll' === e.handleObj.type,
3153				activePos   = 'undefined' !== typeof flyoutMenu.data( 'activePos' ) ? flyoutMenu.data( 'activePos' ) : 0,
3154				headerPos   = ( this.win.width() - header.width() ) / 2,
3155				inactivePos = headerPos > 0 ? activePos + 4 : 254;
3156
3157			if ( ! flyoutMenu.length ) {
3158				return;
3159			}
3160
3161			if ( this.overlay ) {
3162				return;
3163			}
3164
3165			if( $( '.fl-theme-builder-flyout-menu-active' ).length ) {
3166
3167				if ( isScroll && ! flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) {
3168					flyoutMenu.addClass( 'fl-menu-disable-transition' );
3169				}
3170
3171				if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) {
3172					if ( ! isScroll ) {
3173						setTimeout( $.proxy( function(){
3174							flyoutMenu.css( flyoutPos, '-' + activePos + 'px' );
3175						}, this ), 1 );
3176					}
3177					else {
3178						flyoutMenu.css( flyoutPos, '-' + activePos + 'px' );
3179					}
3180				}
3181				else {
3182					flyoutMenu.css( flyoutPos, '0px' );
3183				}
3184			}
3185			else {
3186				if ( flyoutMenu.hasClass( 'fl-menu-disable-transition' ) ) {
3187					flyoutMenu.removeClass( 'fl-menu-disable-transition' );
3188				}
3189
3190				if ( header.hasClass( 'fl-theme-builder-flyout-menu-overlay' ) && headerPos > 0 && headerPos < 250 ) {
3191					if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) {
3192						inactivePos = headerPos + 254;
3193					}
3194					else {
3195						inactivePos = 254;
3196					}
3197				}
3198
3199				if ( e && e.type === 'resize' ) {
3200					inactivePos = headerPos + 254;
3201				}
3202
3203				flyoutMenu.css( flyoutPos, '-' + inactivePos + 'px' );
3204			}
3205
3206			if ( e && menuModule.is('.fl-menu-responsive-flyout-overlay') && $.infinitescroll ) {
3207				e.stopImmediatePropagation();
3208			}
3209
3210			if( menuOpacity.length ) {
3211				if ( header.hasClass( 'fl-theme-builder-header-sticky' ) ) {
3212					if ( '0px' === menuOpacity.css( 'left' ) ) {
3213						menuOpacity.css( 'left', '-' + headerPos + 'px' );
3214					}
3215				}
3216				else {
3217					menuOpacity.css( 'left', '' );
3218				}
3219			}
3220		},
3221
3222		/**
3223		 * Adjust sticky header width if BB Theme Boxed Layout is used.
3224		 *
3225		 * @since 1.4
3226		 * @access private
3227		 * @method _adjustStickyHeaderWidth
3228		 */
3229		_adjustStickyHeaderWidth: function () {
3230			if ( $('body').hasClass( 'fl-fixed-width' ) ) {
3231				var parentWidth = this.header.parent().width();
3232
3233				// Better if this is set in the stylesheet file.
3234				if ( this.win.width() >= 992 ) {
3235					this.header.css({
3236						'margin': '0 auto',
3237						'max-width': parentWidth,
3238					});
3239				}
3240				else {
3241					this.header.css({
3242						'margin': '',
3243						'max-width': '',
3244					});
3245				}
3246			}
3247		},
3248
3249		/**
3250		 * Adjust Sticky Header Height
3251		 *
3252		 * @since 1.4
3253		 * @access private
3254		 * @method _adjustHeaderHeight
3255		 */
3256		_adjustHeaderHeight: function () {
3257			var beforeHeader = this.header.prevAll('.fl-builder-content'),
3258				beforeHeaderHeight = 0,
3259				beforeHeaderFix = 0,
3260				headerHeight = Math.floor( this.header.outerHeight() ),
3261				bodyTopPadding = parseInt( $( 'body' ).css( 'padding-top' ) ),
3262				wpAdminBarHeight = 0,
3263				totalHeaderHeight = 0;
3264
3265			if ( isNaN( bodyTopPadding ) ) {
3266				bodyTopPadding = 0;
3267			}
3268
3269			if ( beforeHeader.length ) {
3270				$.each( beforeHeader, function() {
3271					beforeHeaderHeight += Math.floor( $(this).outerHeight() );
3272				});
3273				// Subtract this value from the header parent's top padding.
3274				beforeHeaderFix = 2;
3275			}
3276
3277			if ( this.hasAdminBar && this.win.width() <= 600 ) {
3278				wpAdminBarHeight = Math.floor( $('#wpadminbar').outerHeight() );
3279			}
3280
3281			totalHeaderHeight = Math.floor( beforeHeaderHeight + headerHeight);
3282
3283			if ( headerHeight > 0 ) {
3284				var headerParent = this.header.parent(),
3285					headerParentTopPadding = 0;
3286
3287				// If the header's parent container is the BODY tag ignore its top padding.
3288				if ( $( headerParent ).is('body') ) {
3289					headerParentTopPadding = Math.floor( headerHeight - wpAdminBarHeight );
3290				} else {
3291					headerParentTopPadding = Math.floor( headerHeight - bodyTopPadding - wpAdminBarHeight );
3292				}
3293
3294				$( headerParent ).css( 'padding-top',  ( headerParentTopPadding - beforeHeaderFix ) + 'px' );
3295
3296				this.header.css({
3297					'-webkit-transform': 'translate(0px, -' + totalHeaderHeight + 'px)',
3298					'-ms-transform': 'translate(0px, -' + totalHeaderHeight + 'px)',
3299					'transform': 'translate(0px, -' + totalHeaderHeight + 'px)'
3300				});
3301
3302			}
3303
3304		},
3305
3306		/**
3307		 * Initializes shrink logic for a header.
3308		 *
3309		 * @since 1.0
3310		 * @access private
3311		 * @method _initShrink
3312		 */
3313		_initShrink: function( e )
3314		{
3315			if ( this.win.width() >= this.breakpointWidth ) {
3316				this.win.on( 'scroll.fl-theme-builder-header-shrink', $.proxy( this._doShrink, this ) );
3317				this._setImageMaxHeight();
3318
3319				if ( this.win.scrollTop() > 0 ){
3320					this._doShrink();
3321				}
3322
3323			} else {
3324				this.header.parent().css( 'padding-top', '0' );
3325				this.win.off( 'scroll.fl-theme-builder-header-shrink' );
3326				this._removeShrink();
3327				this._removeImageMaxHeight();
3328			}
3329		},
3330
3331		/**
3332		 * Shrinks the header when the page is scrolled.
3333		 *
3334		 * @since 1.0
3335		 * @access private
3336		 * @method _doShrink
3337		 */
3338		_doShrink: function( e )
3339		{
3340			var winTop 			  = this.win.scrollTop(),
3341				headerTop 		  = this.header.data('original-top'),
3342				headerHeight 	  = this.header.data('original-height'),
3343				shrinkImageHeight = this.header.data('shrink-image-height'),
3344				windowSize   	  = this.win.width(),
3345				makeSticky   	  = this._makeWindowSticky( windowSize ),
3346				hasClass     	  = this.header.hasClass( 'fl-theme-builder-header-shrink' );
3347
3348
3349			if ( this.hasAdminBar ) {
3350				winTop += 32;
3351			}
3352
3353			if ( makeSticky && ( winTop > headerTop + headerHeight ) ) {
3354				if ( ! hasClass ) {
3355
3356					this.header.addClass( 'fl-theme-builder-header-shrink' );
3357
3358					// Shrink images but don't include lightbox and menu images.
3359					this.header.find('img').each( function( i ) {
3360						var image           = $( this ),
3361							maxMegaMenu     = image.closest( '.max-mega-menu' ).length,
3362							imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length,
3363							imageInNavMenu  = image.closest( 'li.menu-item' ).length;
3364
3365						if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu ) ) {
3366							image.css( 'max-height', shrinkImageHeight );
3367						}
3368
3369					});
3370
3371					this.header.find( '.fl-row-content-wrap' ).each( function() {
3372
3373						var row = $( this );
3374
3375						if ( parseInt( row.css( 'padding-bottom' ) ) > 5 ) {
3376							row.addClass( 'fl-theme-builder-header-shrink-row-bottom' );
3377						}
3378
3379						if ( parseInt( row.css( 'padding-top' ) ) > 5 ) {
3380							row.addClass( 'fl-theme-builder-header-shrink-row-top' );
3381						}
3382					} );
3383
3384					this.header.find( '.fl-module' ).each( function() {
3385
3386						var module = $( this ).find( '.fl-module-content' ).length ? $( this ).find( '.fl-module-content' ) : $( this );
3387
3388						if ( parseInt( module.css( 'margin-bottom' ) ) > 5 ) {
3389							module.addClass( 'fl-theme-builder-header-shrink-module-bottom' );
3390						}
3391
3392						if ( parseInt( module.css( 'margin-top' ) ) > 5 ) {
3393							module.addClass( 'fl-theme-builder-header-shrink-module-top' );
3394						}
3395					} );
3396				}
3397			} else if (hasClass) {
3398				this.header.find( 'img' ).css( 'max-height', '' );
3399				this._removeShrink();
3400			}
3401
3402			// Fixes Shrink header issue with BB Theme when window is scrolled then resized and back.
3403			if ( 'undefined' === typeof( e ) && $('body').hasClass( 'fl-fixed-width' ) ) {
3404				if ( ! this.overlay ) {
3405					this._adjustHeaderHeight();
3406				}
3407			}
3408
3409		},
3410
3411		/**
3412		 * Removes the header shrink effect.
3413		 *
3414		 * @since 1.0
3415		 * @access private
3416		 * @method _removeShrink
3417		 */
3418		_removeShrink: function()
3419		{
3420			var rows    = this.header.find( '.fl-row-content-wrap' ),
3421				modules = this.header.find('.fl-module, .fl-module-content');
3422
3423			rows.removeClass( 'fl-theme-builder-header-shrink-row-bottom' );
3424			rows.removeClass( 'fl-theme-builder-header-shrink-row-top' );
3425			modules.removeClass( 'fl-theme-builder-header-shrink-module-bottom' );
3426			modules.removeClass( 'fl-theme-builder-header-shrink-module-top' );
3427			this.header.removeClass( 'fl-theme-builder-header-shrink' );
3428		},
3429
3430		/**
3431		 * Adds max height to images in modules for smooth scrolling.
3432		 *
3433		 * @since 1.1.1
3434		 * @access private
3435		 * @method _setImageMaxHeight
3436		 */
3437		_setImageMaxHeight: function()
3438		{
3439			var head = $( 'head' ),
3440				stylesId = 'fl-header-styles-' + this.header.data( 'post-id' ),
3441				styles = '',
3442				images = this.header.find( '.fl-module img' );
3443
3444			if ( $( '#' + stylesId ).length ) {
3445				return;
3446			}
3447
3448			images.each( function( i ) {
3449				var image           = $( this ),
3450					height          = image.height(),
3451					node            = image.closest( '.fl-module' ).data( 'node' ),
3452					className       = 'fl-node-' + node + '-img-' + i,
3453					maxMegaMenu     = image.closest( '.max-mega-menu' ).length,
3454					imageInLightbox = image.closest( '.fl-button-lightbox-content' ).length,
3455					imageInNavMenu  = image.closest( 'li.menu-item' ).length;
3456
3457				if ( ! ( imageInLightbox || imageInNavMenu || maxMegaMenu  ) ) {
3458					image.addClass( className );
3459					styles += '.' + className + ' { max-height: ' + ( height ? height : image[0].height )  + 'px }';
3460				}
3461
3462			} );
3463
3464			if ( '' !== styles ) {
3465				head.append( '<style id="' + stylesId + '">' + styles + '</style>' );
3466			}
3467		},
3468
3469		/**
3470		 * Removes max height on images in modules for smooth scrolling.
3471		 *
3472		 * @since 1.1.1
3473		 * @access private
3474		 * @method _removeImageMaxHeight
3475		 */
3476		_removeImageMaxHeight: function()
3477		{
3478			$( '#fl-header-styles-' + this.header.data( 'post-id' ) ).remove();
3479		},
3480	};
3481
3482	$( function() { FLThemeBuilderHeaderLayout.init(); } );
3483
3484})(jQuery);
3485

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.