PageSourceSearch

https://www.obdlink.com/wp-content/uploads/bb-plugin/cache/1382313…7d7d373-layout-bundle.js?ver=2.11.1.1-1.6.1

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

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.