PageSourceSearch

https://wolfoffranchises.com/wp-content/uploads/sites/2/bb-plugin/…42598ce5-layout-bundle.js?ver=2.6.1.4-1.4.4

js wolfoffranchises.com collected 2026-10-02 03:35:15 UTC 81,516 bytes, 2,989 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.