PageSourceSearch

https://peppermintridgefarm.au/wp-content/uploads/bb-plugin/cache/…3299a20-layout-bundle.js?ver=2.11.1.2-1.6.1

js peppermintridgefarm.au collected 2026-10-10 00:08:02 UTC 107,366 bytes, 3,741 lines download raw bytes

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

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.