PageSourceSearch

https://lynnco.com/wp-content/uploads/bb-plugin/cache/311-layout.js?ver=fb5504dfc9fab8380948c555f3b67a51

js lynnco.com collected 2026-10-04 11:09:43 UTC 69,513 bytes, 2,495 lines download raw bytes

vendor: 14,874 bytes, lines 1-513
1/*!
2 * Bowser - a browser detector
3 * https://github.com/ded/bowser
4 * MIT License | (c) Dustin Diaz 2015
5 */
6
7!function (name, definition) {
8  if (typeof module != 'undefined' && module.exports) module.exports = definition()
9  else if (typeof define == 'function' && define.amd) define(name, definition)
10  else this[name] = definition()
11}('bowser', function () {
12  /**
13    * See useragents.js for examples of navigator.userAgent
14    */
15
16  var t = true
17
18  function detect(ua) {
19
20    function getFirstMatch(regex) {
21      var match = ua.match(regex);
22      return (match && match.length > 1 && match[1]) || '';
23    }
24
25    function getSecondMatch(regex) {
26      var match = ua.match(regex);
27      return (match && match.length > 1 && match[2]) || '';
28    }
29
30    var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase()
31      , likeAndroid = /like android/i.test(ua)
32      , android = !likeAndroid && /android/i.test(ua)
33      , nexusMobile = /nexus\s*[0-6]\s*/i.test(ua)
34      , nexusTablet = !nexusMobile && /nexus\s*[0-9]+/i.test(ua)
35      , chromeos = /CrOS/.test(ua)
36      , silk = /silk/i.test(ua)
37      , sailfish = /sailfish/i.test(ua)
38      , tizen = /tizen/i.test(ua)
39      , webos = /(web|hpw)os/i.test(ua)
40      , windowsphone = /windows phone/i.test(ua)
41      , windows = !windowsphone && /windows/i.test(ua)
42      , mac = !iosdevice && !silk && /macintosh/i.test(ua)
43      , linux = !android && !sailfish && !tizen && !webos && /linux/i.test(ua)
44      , edgeVersion = getFirstMatch(/edge\/(\d+(\.\d+)?)/i)
45      , versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i)
46      , tablet = /tablet/i.test(ua)
47      , mobile = !tablet && /[^-]mobi/i.test(ua)
48      , xbox = /xbox/i.test(ua)
49      , result
50
51    if (/opera|opr|opios/i.test(ua)) {
52      result = {
53        name: 'Opera'
54      , opera: t
55      , version: versionIdentifier || getFirstMatch(/(?:opera|opr|opios)[\s\/](\d+(\.\d+)?)/i)
56      }
57    }
58    else if (/coast/i.test(ua)) {
59      result = {
60        name: 'Opera Coast'
61        , coast: t
62        , version: versionIdentifier || getFirstMatch(/(?:coast)[\s\/](\d+(\.\d+)?)/i)
63      }
64    }
65    else if (/yabrowser/i.test(ua)) {
66      result = {
67        name: 'Yandex Browser'
68      , yandexbrowser: t
69      , version: versionIdentifier || getFirstMatch(/(?:yabrowser)[\s\/](\d+(\.\d+)?)/i)
70      }
71    }
72    else if (/ucbrowser/i.test(ua)) {
73      result = {
74          name: 'UC Browser'
75        , ucbrowser: t
76        , version: getFirstMatch(/(?:ucbrowser)[\s\/](\d+(?:\.\d+)+)/i)
77      }
78    }
79    else if (/mxios/i.test(ua)) {
80      result = {
81        name: 'Maxthon'
82        , maxthon: t
83        , version: getFirstMatch(/(?:mxios)[\s\/](\d+(?:\.\d+)+)/i)
84      }
85    }
86    else if (/epiphany/i.test(ua)) {
87      result = {
88        name: 'Epiphany'
89        , epiphany: t
90        , version: getFirstMatch(/(?:epiphany)[\s\/](\d+(?:\.\d+)+)/i)
91      }
92    }
93    else if (/puffin/i.test(ua)) {
94      result = {
95        name: 'Puffin'
96        , puffin: t
97        , version: getFirstMatch(/(?:puffin)[\s\/](\d+(?:\.\d+)?)/i)
98      }
99    }
100    else if (/sleipnir/i.test(ua)) {
101      result = {
102        name: 'Sleipnir'
103        , sleipnir: t
104        , version: getFirstMatch(/(?:sleipnir)[\s\/](\d+(?:\.\d+)+)/i)
105      }
106    }
107    else if (/k-meleon/i.test(ua)) {
108      result = {
109        name: 'K-Meleon'
110        , kMeleon: t
111        , version: getFirstMatch(/(?:k-meleon)[\s\/](\d+(?:\.\d+)+)/i)
112      }
113    }
114    else if (windowsphone) {
115      result = {
116        name: 'Windows Phone'
117      , windowsphone: t
118      }
119      if (edgeVersion) {
120        result.msedge = t
121        result.version = edgeVersion
122      }
123      else {
124        result.msie = t
125        result.version = getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i)
126      }
127    }
128    else if (/msie|trident/i.test(ua)) {
129      result = {
130        name: 'Internet Explorer'
131      , msie: t
132      , version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i)
133      }
134    } else if (chromeos) {
135      result = {
136        name: 'Chrome'
137      , chromeos: t
138      , chromeBook: t
139      , chrome: t
140      , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
141      }
142    } else if (/chrome.+? edge/i.test(ua)) {
143      result = {
144        name: 'Microsoft Edge'
145      , msedge: t
146      , version: edgeVersion
147      }
148    }
149    else if (/vivaldi/i.test(ua)) {
150      result = {
151        name: 'Vivaldi'
152        , vivaldi: t
153        , version: getFirstMatch(/vivaldi\/(\d+(\.\d+)?)/i) || versionIdentifier
154      }
155    }
156    else if (sailfish) {
157      result = {
158        name: 'Sailfish'
159      , sailfish: t
160      , version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i)
161      }
162    }
163    else if (/seamonkey\//i.test(ua)) {
164      result = {
165        name: 'SeaMonkey'
166      , seamonkey: t
167      , version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i)
168      }
169    }
170    else if (/firefox|iceweasel|fxios/i.test(ua)) {
171      result = {
172        name: 'Firefox'
173      , firefox: t
174      , version: getFirstMatch(/(?:firefox|iceweasel|fxios)[ \/](\d+(\.\d+)?)/i)
175      }
176      if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) {
177        result.firefoxos = t
178      }
179    }
180    else if (silk) {
181      result =  {
182        name: 'Amazon Silk'
183      , silk: t
184      , version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i)
185      }
186    }
187    else if (/phantom/i.test(ua)) {
188      result = {
189        name: 'PhantomJS'
190      , phantom: t
191      , version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i)
192      }
193    }
194    else if (/slimerjs/i.test(ua)) {
195      result = {
196        name: 'SlimerJS'
197        , slimer: t
198        , version: getFirstMatch(/slimerjs\/(\d+(\.\d+)?)/i)
199      }
200    }
201    else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) {
202      result = {
203        name: 'BlackBerry'
204      , blackberry: t
205      , version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i)
206      }
207    }
208    else if (webos) {
209      result = {
210        name: 'WebOS'
211      , webos: t
212      , version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)
213      };
214      if( /touchpad\//i.test(ua) ){
215        result.touchpad = t;
216      }
217    }
218    else if (/bada/i.test(ua)) {
219      result = {
220        name: 'Bada'
221      , bada: t
222      , version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i)
223      };
224    }
225    else if (tizen) {
226      result = {
227        name: 'Tizen'
228      , tizen: t
229      , version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier
230      };
231    }
232    else if (/qupzilla/i.test(ua)) {
233      result = {
234        name: 'QupZilla'
235        , qupzilla: t
236        , version: getFirstMatch(/(?:qupzilla)[\s\/](\d+(?:\.\d+)+)/i) || versionIdentifier
237      }
238    }
239    else if (/chromium/i.test(ua)) {
240      result = {
241        name: 'Chromium'
242        , chromium: t
243        , version: getFirstMatch(/(?:chromium)[\s\/](\d+(?:\.\d+)?)/i) || versionIdentifier
244      }
245    }
246    else if (/chrome|crios|crmo/i.test(ua)) {
247      result = {
248        name: 'Chrome'
249        , chrome: t
250        , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
251      }
252    }
253    else if (android) {
254      result = {
255        name: 'Android'
256        , version: versionIdentifier
257      }
258    }
259    else if (/safari|applewebkit/i.test(ua)) {
260      result = {
261        name: 'Safari'
262      , safari: t
263      }
264      if (versionIdentifier) {
265        result.version = versionIdentifier
266      }
267    }
268    else if (iosdevice) {
269      result = {
270        name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod'
271      }
272      // WTF: version is not part of user agent in web apps
273      if (versionIdentifier) {
274        result.version = versionIdentifier
275      }
276    }
277    else if(/googlebot/i.test(ua)) {
278      result = {
279        name: 'Googlebot'
280      , googlebot: t
281      , version: getFirstMatch(/googlebot\/(\d+(\.\d+))/i) || versionIdentifier
282      }
283    }
284    else {
285      result = {
286        name: getFirstMatch(/^(.*)\/(.*) /),
287        version: getSecondMatch(/^(.*)\/(.*) /)
288     };
289   }
290
291    // set webkit or gecko flag for browsers based on these engines
292    if (!result.msedge && /(apple)?webkit/i.test(ua)) {
293      if (/(apple)?webkit\/537\.36/i.test(ua)) {
294        result.name = result.name || "Blink"
295        result.blink = t
296      } else {
297        result.name = result.name || "Webkit"
298        result.webkit = t
299      }
300      if (!result.version && versionIdentifier) {
301        result.version = versionIdentifier
302      }
303    } else if (!result.opera && /gecko\//i.test(ua)) {
304      result.name = result.name || "Gecko"
305      result.gecko = t
306      result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i)
307    }
308
309    // set OS flags for platforms that have multiple browsers
310    if (!result.msedge && (android || result.silk)) {
311      result.android = t
312    } else if (iosdevice) {
313      result[iosdevice] = t
314      result.ios = t
315    } else if (mac) {
316      result.mac = t
317    } else if (xbox) {
318      result.xbox = t
319    } else if (windows) {
320      result.windows = t
321    } else if (linux) {
322      result.linux = t
323    }
324
325    // OS version extraction
326    var osVersion = '';
327    if (result.windowsphone) {
328      osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i);
329    } else if (iosdevice) {
330      osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i);
331      osVersion = osVersion.replace(/[_\s]/g, '.');
332    } else if (android) {
333      osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i);
334    } else if (result.webos) {
335      osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i);
336    } else if (result.blackberry) {
337      osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i);
338    } else if (result.bada) {
339      osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i);
340    } else if (result.tizen) {
341      osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i);
342    }
343    if (osVersion) {
344      result.osversion = osVersion;
345    }
346
347    // device type extraction
348    var osMajorVersion = osVersion.split('.')[0];
349    if (
350         tablet
351      || nexusTablet
352      || iosdevice == 'ipad'
353      || (android && (osMajorVersion == 3 || (osMajorVersion >= 4 && !mobile)))
354      || result.silk
355    ) {
356      result.tablet = t
357    } else if (
358         mobile
359      || iosdevice == 'iphone'
360      || iosdevice == 'ipod'
361      || android
362      || nexusMobile
363      || result.blackberry
364      || result.webos
365      || result.bada
366    ) {
367      result.mobile = t
368    }
369
370    // Graded Browser Support
371    // http://developer.yahoo.com/yui/articles/gbs
372    if (result.msedge ||
373        (result.msie && result.version >= 10) ||
374        (result.yandexbrowser && result.version >= 15) ||
375		    (result.vivaldi && result.version >= 1.0) ||
376        (result.chrome && result.version >= 20) ||
377        (result.firefox && result.version >= 20.0) ||
378        (result.safari && result.version >= 6) ||
379        (result.opera && result.version >= 10.0) ||
380        (result.ios && result.osversion && result.osversion.split(".")[0] >= 6) ||
381        (result.blackberry && result.version >= 10.1)
382        || (result.chromium && result.version >= 20)
383        ) {
384      result.a = t;
385    }
386    else if ((result.msie && result.version < 10) ||
387        (result.chrome && result.version < 20) ||
388        (result.firefox && result.version < 20.0) ||
389        (result.safari && result.version < 6) ||
390        (result.opera && result.version < 10.0) ||
391        (result.ios && result.osversion && result.osversion.split(".")[0] < 6)
392        || (result.chromium && result.version < 20)
393        ) {
394      result.c = t
395    } else result.x = t
396
397    return result
398  }
399
400  var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent : '')
401
402  bowser.test = function (browserList) {
403    for (var i = 0; i < browserList.length; ++i) {
404      var browserItem = browserList[i];
405      if (typeof browserItem=== 'string') {
406        if (browserItem in bowser) {
407          return true;
408        }
409      }
410    }
411    return false;
412  }
413
414  /**
415   * Get version precisions count
416   *
417   * @example
418   *   getVersionPrecision("1.10.3") // 3
419   *
420   * @param  {string} version
421   * @return {number}
422   */
423  function getVersionPrecision(version) {
424    return version.split(".").length;
425  }
426
427  /**
428   * Array::map polyfill
429   *
430   * @param  {Array} arr
431   * @param  {Function} iterator
432   * @return {Array}
433   */
434  function map(arr, iterator) {
435    var result = [], i;
436    if (Array.prototype.map) {
437      return Array.prototype.map.call(arr, iterator);
438    }
439    for (i = 0; i < arr.length; i++) {
440      result.push(iterator(arr[i]));
441    }
442    return result;
443  }
444
445  /**
446   * Calculate browser version weight
447   *
448   * @example
449   *   compareVersions(['1.10.2.1',  '1.8.2.1.90'])    // 1
450   *   compareVersions(['1.010.2.1', '1.09.2.1.90']);  // 1
451   *   compareVersions(['1.10.2.1',  '1.10.2.1']);     // 0
452   *   compareVersions(['1.10.2.1',  '1.0800.2']);     // -1
453   *
454   * @param  {Array<String>} versions versions to compare
455   * @return {Number} comparison result
456   */
457  function compareVersions(versions) {
458    // 1) get common precision for both versions, for example for "10.0" and "9" it should be 2
459    var precision = Math.max(getVersionPrecision(versions[0]), getVersionPrecision(versions[1]));
460    var chunks = map(versions, function (version) {
461      var delta = precision - getVersionPrecision(version);
462
463      // 2) "9" -> "9.0" (for precision = 2)
464      version = version + new Array(delta + 1).join(".0");
465
466      // 3) "9.0" -> ["000000000"", "000000009"]
467      return map(version.split("."), function (chunk) {
468        return new Array(20 - chunk.length).join("0") + chunk;
469      }).reverse();
470    });
471
472    // iterate in reverse order by reversed chunks array
473    while (--precision >= 0) {
474      // 4) compare: "000000009" > "000000010" = false (but "9" > "10" = true)
475      if (chunks[0][precision] > chunks[1][precision]) {
476        return 1;
477      }
478      else if (chunks[0][precision] === chunks[1][precision]) {
479        if (precision === 0) {
480          // all version chunks are same
481          return 0;
482        }
483      }
484      else {
485        return -1;
486      }
487    }
488  }
489
490  /**
491   * Check if browser is unsupported
492   *
493   * @example
494   *   bowser.isUnsupportedBrowser({
495   *     msie: "10",
496   *     firefox: "23",
497   *     chrome: "29",
498   *     safari: "5.1",
499   *     opera: "16",
500   *     phantom: "534"
501   *   });
502   *
503   * @param  {Object}  minVersions map of minimal version to browser
504   * @param  {Boolean} [strictMode = false] flag to return false if browser wasn't found in map
505   * @param  {String}  [ua] user agent string
506   * @return {Boolean}
507   */
508  function isUnsupportedBrowser(minVersions, strictMode, ua) {
509    var _bowser = bowser;
510
511    // make strictMode param optional with ua param usage
512    if (typeof strictMode === 'string') {
513      ua = strictMode;
514      strictMode = void(0);
515    }
516
517    if (strictMode === void(0)) {
518      strictMode = false;
519    }
520    if (ua) {
521      _bowser = detect(ua);
522    }
523
524    var version = "" + _bowser.version;
525    for (var browser in minVersions) {
526      if (minVersions.hasOwnProperty(browser)) {
527        if (_bowser[browser]) {
528          // browser version and min supported version.
529          return compareVersions([version, minVersions[browser]]) < 0;
530        }
531      }
532    }
533
534    return strictMode; // not found
535  }
536
537  /**
538   * Check if browser is supported
539   *
540   * @param  {Object} minVersions map of minimal version to browser
541   * @param  {Boolean} [strictMode = false] flag to return false if browser wasn't found in map
542   * @param  {String}  [ua] user agent string
543   * @return {Boolean}
544   */
545  function check(minVersions, strictMode, ua) {
546    return !isUnsupportedBrowser(minVersions, strictMode, ua);
547  }
548
549  bowser.isUnsupportedBrowser = isUnsupportedBrowser;
550  bowser.compareVersions = compareVersions;
551  bowser.check = check;
552
553  /*
554   * Set our detect method to the main bowser object so we can
555   * reuse it to test other user agents.
556   * This is needed to implement future tests.
557   */
558  bowser._detect = detect;
559
560  return bowser
561});
562
563(function($){
564  UABBTrigger = {
565
566      /**
567       * Trigger a hook.
568       *
569       * @since 1.1.0.3
570       * @method triggerHook
571       * @param {String} hook The hook to trigger.
572       * @param {Array} args An array of args to pass to the hook.
573       */
574      triggerHook: function( hook, args )
575      {
576        $( 'body' ).trigger( 'uabb-trigger.' + hook, args );
577      },
578    
579      /**
580       * Add a hook.
581       *
582       * @since 1.1.0.3
583       * @method addHook
584       * @param {String} hook The hook to add.
585       * @param {Function} callback A function to call when the hook is triggered.
586       */
587      addHook: function( hook, callback )
588      {
589        $( 'body' ).on( 'uabb-trigger.' + hook, callback );
590      },
591    
592      /**
593       * Remove a hook.
594       *
595       * @since 1.1.0.3
596       * @method removeHook
597       * @param {String} hook The hook to remove.
598       * @param {Function} callback The callback function to remove.
599       */
600      removeHook: function( hook, callback )
601      {
602        $( 'body' ).off( 'uabb-trigger.' + hook, callback );
603      },
604  };
605})(jQuery);
606
607jQuery(document).ready(function( $ ) {
608
609  var uabb_browser   = bowser.name,
610      uabb_browser_v = bowser.version,
611      uabb_browser_class = uabb_browser.replace(/\s+/g, '-').toLowerCase(),
612      uabb_browser_v_class = uabb_browser_class + parseInt( uabb_browser_v );
613
614      $('html').addClass(uabb_browser_class).addClass(uabb_browser_v_class); 
615});
616var wpAjaxUrl = 'https://lynnco.com/wp-admin/admin-ajax.php';var flBuilderUrl = 'https://lynnco.com/wp-content/plugins/bb-plugin/';var FLBuilderLayoutConfig = {
617	anchorLinkAnimations : {
618		duration 	: 1000,
619		easing		: 'swing',
620		offset 		: 100
621	},
622	paths : {
623		pluginUrl : 'https://lynnco.com/wp-content/plugins/bb-plugin/',
624		wpAjaxUrl : 'https://lynnco.com/wp-admin/admin-ajax.php'
625	},
626	breakpoints : {
627		small  : 768,
628		medium : 992,
629		large : 1200	},
630	waypoint: {
631		offset: 80
632	},
633	emptyColWidth: '0%'
634};
635(function($){
636
637	if(typeof FLBuilderLayout != 'undefined') {
638		return;
639	}
640
641	/**
642	 * Helper class with generic logic for a builder layout.
643	 *
644	 * @class FLBuilderLayout
645	 * @since 1.0
646	 */
647	FLBuilderLayout = {
648
649		/**
650		 * Initializes a builder layout.
651		 *
652		 * @since 1.0
653		 * @method init
654		 */
655		init: function()
656		{
657			// Destroy existing layout events.
658			FLBuilderLayout._destroy();
659
660			// Init CSS classes.
661			FLBuilderLayout._initClasses();
662
663			// Init backgrounds.
664			FLBuilderLayout._initBackgrounds();
665
666			// Init buttons.
667			FLBuilderLayout._initButtons();
668
669			// Init row shape layer height.
670			FLBuilderLayout._initRowShapeLayerHeight();
671
672			// Only init if the builder isn't active.
673			if ( 0 === $('.fl-builder-edit').length ) {
674
675				// Init anchor links.
676				FLBuilderLayout._initAnchorLinks();
677
678				// Init the browser hash.
679				FLBuilderLayout._initHash();
680
681				// Init forms.
682				FLBuilderLayout._initForms();
683
684				FLBuilderLayout._reorderMenu();
685			}
686			else {
687				FLBuilderLayout._initNestedColsWidth();
688			}
689			$('body').removeClass( 'fl-no-js' );
690		},
691
692		/**
693		 * Public method for refreshing Wookmark or MosaicFlow galleries
694		 * within an element.
695		 *
696		 * @since 1.7.4
697		 * @method refreshGalleries
698		 */
699		refreshGalleries: function( element )
700		{
701			var $element  = 'undefined' == typeof element ? $( 'body' ) : $( element ),
702				mfContent = $element.find( '.fl-mosaicflow-content' ),
703				wmContent = $element.find( '.fl-gallery' ),
704				mfObject  = null;
705
706			if ( mfContent ) {
707
708				mfObject = mfContent.data( 'mosaicflow' );
709
710				if ( mfObject ) {
711					mfObject.columns = $( [] );
712					mfObject.columnsHeights = [];
713					mfContent.data( 'mosaicflow', mfObject );
714					mfContent.mosaicflow( 'refill' );
715				}
716			}
717			if ( wmContent ) {
718				wmContent.trigger( 'refreshWookmark' );
719			}
720		},
721
722		/**
723		 * Public method for refreshing Masonry within an element
724		 *
725		 * @since 1.8.1
726		 * @method refreshGridLayout
727		 */
728		refreshGridLayout: function( element )
729		{
730			var $element 		= 'undefined' == typeof element ? $( 'body' ) : $( element ),
731				msnryContent	= $element.find('.masonry');
732
733			if ( msnryContent.length )	{
734				msnryContent.masonry('layout');
735			}
736		},
737
738		/**
739		 * Public method for reloading BxSlider within an element
740		 *
741		 * @since 1.8.1
742		 * @method reloadSlider
743		 */
744		reloadSlider: function( content )
745		{
746			var $content = 'undefined' == typeof content ? $('body') : $(content);
747
748			// reload sliders.
749			if ($content.find('.bx-viewport > div').length > 0) {
750				$.each($content.find('.bx-viewport > div'), function (key, slider) {
751					setTimeout(function () {
752						$(slider).data('bxSlider').reloadSlider();
753					}, 100);
754				});
755			}
756		},
757
758		/**
759		 * Public method for resizing WP audio player
760		 *
761		 * @since 1.8.2
762		 * @method resizeAudio
763		 */
764		resizeAudio: function( element )
765		{
766			var $element 	 	= 'undefined' == typeof element ? $( 'body' ) : $( element ),
767				audioPlayers 	= $element.find('.wp-audio-shortcode.mejs-audio'),
768				player 		 	= null,
769				mejsPlayer 	 	= null,
770				rail 			= null,
771				railWidth 		= 400;
772
773			if ( audioPlayers.length && typeof mejs !== 'undefined' ) {
774            	audioPlayers.each(function(){
775	            	player 		= $(this);
776	            	mejsPlayer 	= mejs.players[player.attr('id')];
777	            	rail 		= player.find('.mejs-controls .mejs-time-rail');
778	            	var innerMejs = player.find('.mejs-inner'),
779	            		total 	  = player.find('.mejs-controls .mejs-time-total');
780
781	            	if ( typeof mejsPlayer !== 'undefined' ) {
782	            		railWidth = Math.ceil(player.width() * 0.8);
783
784	            		if ( innerMejs.length ) {
785
786		            		rail.css('width', railWidth +'px!important');
787		            		//total.width(rail.width() - 10);
788
789		            		mejsPlayer.options.autosizeProgress = true;
790
791		            		// webkit has trouble doing this without a delay
792							setTimeout(function () {
793								mejsPlayer.setControlsSize();
794							}, 50);
795
796			            	player.find('.mejs-inner').css({
797			            		visibility: 'visible',
798			            		height: 'inherit'
799			            	});
800		            	}
801		           	}
802	            });
803	        }
804		},
805
806		/**
807		 * Public method for preloading WP audio player when it's inside the hidden element
808		 *
809		 * @since 1.8.2
810		 * @method preloadAudio
811		 */
812		preloadAudio: function(element)
813		{
814			var $element 	 = 'undefined' == typeof element ? $( 'body' ) : $( element ),
815				contentWrap  = $element.closest('.fl-accordion-item'),
816				audioPlayers = $element.find('.wp-audio-shortcode.mejs-audio');
817
818			if ( ! contentWrap.hasClass('fl-accordion-item-active') && audioPlayers.find('.mejs-inner').length ) {
819				audioPlayers.find('.mejs-inner').css({
820					visibility : 'hidden',
821					height: 0
822				});
823			}
824		},
825
826		/**
827		 * Public method for resizing slideshow momdule within the tab
828		 *
829		 * @since 1.10.5
830		 * @method resizeSlideshow
831		 */
832		resizeSlideshow: function(){
833			if(typeof YUI !== 'undefined') {
834				YUI().use('node-event-simulate', function(Y) {
835					Y.one(window).simulate("resize");
836				});
837			}
838		},
839
840		/**
841		 * Public method for reloading an embedded Google Map within the tabs or hidden element.
842		 *
843		 * @since 2.2
844		 * @method reloadGoogleMap
845		 */
846		reloadGoogleMap: function(element){
847			var $element  = 'undefined' == typeof element ? $( 'body' ) : $( element ),
848			    googleMap = $element.find( 'iframe[src*="google.com/maps"]' );
849
850			if ( googleMap.length ) {
851			    googleMap.attr( 'src', function(i, val) {
852			        return val;
853			    });
854			}
855		},
856
857		/**
858		 * Unbinds builder layout events.
859		 *
860		 * @since 1.0
861		 * @access private
862		 * @method _destroy
863		 */
864		_destroy: function()
865		{
866			var win = $(window);
867
868			win.off('scroll.fl-bg-parallax');
869			win.off('resize.fl-bg-video');
870		},
871
872		/**
873		 * Checks to see if the current device has touch enabled.
874		 *
875		 * @since 1.0
876		 * @access private
877		 * @method _isTouch
878		 * @return {Boolean}
879		 */
880		_isTouch: function()
881		{
882			if(('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)) {
883				return true;
884			}
885
886			return false;
887		},
888
889		/**
890		 * Checks to see if the current device is mobile.
891		 *
892		 * @since 1.7
893		 * @access private
894		 * @method _isMobile
895		 * @return {Boolean}
896		 */
897		_isMobile: function()
898		{
899			return /Mobile|Android|Silk\/|Kindle|BlackBerry|Opera Mini|Opera Mobi|webOS/i.test( navigator.userAgent );
900		},
901
902		/**
903		 * Initializes builder body classes.
904		 *
905		 * @since 1.0
906		 * @access private
907		 * @method _initClasses
908		 */
909		_initClasses: function()
910		{
911			var body = $( 'body' ),
912				ua   = navigator.userAgent;
913
914			// Add the builder body class (skip on block-only frontend to avoid layout break).
915			if ( ! body.hasClass( 'fl-builder-blocks-only' ) && ! body.hasClass( 'archive' ) && $( '.fl-builder-content-primary' ).length > 0 ) {
916				body.addClass('fl-builder');
917			}
918
919			// Add the builder touch body class.
920			if(FLBuilderLayout._isTouch()) {
921				body.addClass('fl-builder-touch');
922			}
923
924			// Add the builder mobile body class.
925			if(FLBuilderLayout._isMobile()) {
926				body.addClass('fl-builder-mobile');
927			}
928
929			if ( $(window).width() < FLBuilderLayoutConfig.breakpoints.small ) {
930				body.addClass( 'fl-builder-breakpoint-small' );
931			}
932
933			if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.small && $(window).width() < FLBuilderLayoutConfig.breakpoints.medium ) {
934				body.addClass( 'fl-builder-breakpoint-medium' );
935			}
936
937			if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.medium && $(window).width() < FLBuilderLayoutConfig.breakpoints.large ) {
938				body.addClass( 'fl-builder-breakpoint-large' );
939			}
940
941			if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.large ) {
942				body.addClass( 'fl-builder-breakpoint-default' );
943			}
944
945			// IE11 body class.
946			if ( ua.indexOf( 'Trident/7.0' ) > -1 && ua.indexOf( 'rv:11.0' ) > -1 ) {
947				body.addClass( 'fl-builder-ie-11' );
948			}
949		},
950
951		/**
952		 * Initializes builder node backgrounds that require
953		 * additional JavaScript logic such as parallax.
954		 *
955		 * @since 1.1.4
956		 * @access private
957		 * @method _initBackgrounds
958		 */
959		_initBackgrounds: function()
960		{
961			var win = $(window);
962
963			// Init parallax backgrounds.
964			if($('.fl-row-bg-parallax').length > 0 && !FLBuilderLayout._isMobile()) {
965				FLBuilderLayout._scrollParallaxBackgrounds();
966				FLBuilderLayout._initParallaxBackgrounds();
967				win.on('resize.fl-bg-parallax', FLBuilderLayout._initParallaxBackgrounds);
968				win.on('scroll.fl-bg-parallax', FLBuilderLayout._scrollParallaxBackgrounds);
969			}
970
971			// Init video backgrounds.
972			if($('.fl-bg-video').length > 0) {
973				FLBuilderLayout._initBgVideos();
974				FLBuilderLayout._resizeBgVideos();
975
976				// Ensure FLBuilderLayout._resizeBgVideos() is only called once on window resize.
977				var resizeBGTimer = null;
978				win.on('resize.fl-bg-video', function(e){
979					clearTimeout( resizeBGTimer );
980					resizeBGTimer = setTimeout(function() {
981						FLBuilderLayout._resizeBgVideos(e);
982					}, 100 );
983				});
984			}
985		},
986
987		/**
988		 * Initializes all buttons in a layout.
989		 *
990		 * @since 2.10
991		 * @access private
992		 * @method _initButtons
993		 */
994		_initButtons: function()
995		{
996			// Trigger click event on Enter or Space key press for deprecated button markup.
997			$('a.fl-button[role="button"]').on('keydown', function(event) {
998				if (event.key === 'Enter' || event.key === ' ') {
999					// Necessary to prevent the default behavior of the space key from scrolling the page
1000					event.preventDefault();
1001					$(this).trigger('click');
1002				}
1003			});
1004		},
1005
1006		/**
1007		 * Initializes all parallax backgrounds in a layout.
1008		 *
1009		 * @since 1.1.4
1010		 * @access private
1011		 * @method _initParallaxBackgrounds
1012		 */
1013		_initParallaxBackgrounds: function()
1014		{
1015			$('.fl-row-bg-parallax').each(FLBuilderLayout._initParallaxBackground);
1016		},
1017
1018		/**
1019		 * Initializes a single parallax background.
1020		 *
1021		 * @since 1.1.4
1022		 * @access private
1023		 * @method _initParallaxBackgrounds
1024		 */
1025		_initParallaxBackground: function()
1026		{
1027			var row     = $(this),
1028				content = row.find('> .fl-row-content-wrap'),
1029				winWidth = $(window).width(),
1030				screenSize = '',
1031				imageSrc = {
1032					default: '',
1033					medium: '',
1034					responsive: '',
1035				};
1036
1037			imageSrc.default = row.data('parallax-image') || '';
1038			imageSrc.medium = row.data('parallax-image-medium') || imageSrc.default;
1039			imageSrc.responsive = row.data('parallax-image-responsive') || imageSrc.medium;
1040
1041			if (winWidth > FLBuilderLayoutConfig.breakpoints.medium) {
1042				screenSize = 'default';
1043			} else if (winWidth > FLBuilderLayoutConfig.breakpoints.small && winWidth <= FLBuilderLayoutConfig.breakpoints.medium ) {
1044				screenSize = 'medium';
1045			} else if (winWidth <= FLBuilderLayoutConfig.breakpoints.small) {
1046				screenSize = 'responsive';
1047			}
1048
1049			content.css('background-image', 'url(' + imageSrc[screenSize] + ')');
1050			row.data('current-image-loaded', screenSize );
1051
1052		},
1053
1054		/**
1055		 * Fires when the window is scrolled to adjust
1056		 * parallax backgrounds.
1057		 *
1058		 * @since 1.1.4
1059		 * @access private
1060		 * @method _scrollParallaxBackgrounds
1061		 */
1062		_scrollParallaxBackgrounds: function()
1063		{
1064			$('.fl-row-bg-parallax').each(FLBuilderLayout._scrollParallaxBackground);
1065		},
1066
1067		/**
1068		 * Fires when the window is scrolled to adjust
1069		 * a single parallax background.
1070		 *
1071		 * @since 1.1.4
1072		 * @access private
1073		 * @method _scrollParallaxBackground
1074		 */
1075		_scrollParallaxBackground: function()
1076		{
1077			var win     	  = $(window),
1078				row     	  = $(this),
1079				content 	  = row.find('> .fl-row-content-wrap'),
1080				speed   	  = row.data('parallax-speed'),
1081				offset  	  = content.offset(),
1082				yPos		  = -((win.scrollTop() - offset.top) / speed),
1083				initialOffset = ( row.data('parallax-offset') != null ) ? row.data('parallax-offset') : 0,
1084				totalOffset   = yPos - initialOffset;
1085
1086			content.css('background-position', 'center ' + totalOffset + 'px');
1087		},
1088
1089		/**
1090		 * Initializes all video backgrounds.
1091		 *
1092		 * @since 1.6.3.3
1093		 * @access private
1094		 * @method _initBgVideos
1095		 */
1096		_initBgVideos: function()
1097		{
1098			$('.fl-bg-video').each(FLBuilderLayout._initBgVideo);
1099		},
1100
1101		/**
1102		 * Initializes a video background.
1103		 *
1104		 * @since 1.6.3.3
1105		 * @access private
1106		 * @method _initBgVideo
1107		 */
1108		_initBgVideo: function()
1109		{
1110			var wrap   = $( this ),
1111				width       = wrap.data( 'width' ),
1112				height      = wrap.data( 'height' ),
1113				mp4         = wrap.data( 'mp4' ),
1114				youtube     = wrap.data( 'youtube'),
1115				vimeo       = wrap.data( 'vimeo'),
1116				mp4Type     = wrap.data( 'mp4-type' ),
1117				webm        = wrap.data( 'webm' ),
1118				webmType    = wrap.data( 'webm-type' ),
1119				fallback    = wrap.data( 'fallback' ),
1120				loaded      = wrap.data( 'loaded' ),
1121				videoMobile = wrap.data( 'video-mobile' ),
1122				playPauseButton = wrap.find('.fl-bg-video-play-pause-control'),
1123				fallbackTag = '',
1124				videoTag    = null,
1125				mp4Tag      = null,
1126				webmTag     = null;
1127
1128			// Return if the video has been loaded for this row.
1129			if ( loaded ) {
1130				return;
1131			}
1132
1133			videoTag  = $( '<video autoplay loop muted playsinline></video>' );
1134
1135			/**
1136			 * Add poster image (fallback image)
1137			 */
1138			if( 'undefined' != typeof fallback && '' != fallback ) {
1139				videoTag.attr( 'poster', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' )
1140				videoTag.css({
1141					backgroundImage: 'url("' + fallback + '")',
1142					backgroundColor: 'transparent',
1143					backgroundRepeat: 'no-repeat',
1144					backgroundSize: 'cover',
1145					backgroundPosition: 'center center',
1146				})
1147			}
1148
1149			// MP4 Source Tag
1150			if ( 'undefined' != typeof mp4 && '' != mp4 ) {
1151
1152				mp4Tag = $( '<source />' );
1153				mp4Tag.attr( 'src', mp4 );
1154				mp4Tag.attr( 'type', mp4Type );
1155
1156				videoTag.append( mp4Tag );
1157			}
1158			// WebM Source Tag
1159			if ( 'undefined' != typeof webm && '' != webm ) {
1160
1161				webmTag = $( '<source />' );
1162				webmTag.attr( 'src', webm );
1163				webmTag.attr( 'type', webmType );
1164
1165				videoTag.append( webmTag );
1166			}
1167
1168			// This is either desktop, or mobile is enabled.
1169			if ( ! FLBuilderLayout._isMobile() || ( FLBuilderLayout._isMobile() && "yes" == videoMobile ) ) {
1170				if ( 'undefined' != typeof youtube ) {
1171					FLBuilderLayout._initYoutubeBgVideo.apply( this );
1172				}
1173				else if ( 'undefined' != typeof vimeo ) {
1174					FLBuilderLayout._initVimeoBgVideo.apply( this );
1175				}
1176				else {
1177					wrap.append( videoTag );
1178
1179					if ( playPauseButton.length > 0 ) {
1180						var video = videoTag[0];
1181
1182						playPauseButton.on( 'click', { video: video }, function(e) {
1183							var video = e.data.video;
1184
1185							if ( video.paused ) {
1186								video.play();
1187							} else {
1188								video.pause();
1189							}
1190						} );
1191
1192						$( video ).on( 'play playing', function () {
1193							playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
1194						} );
1195						
1196						$( video ).on( 'pause ended waiting', function () {
1197							playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1198						} );
1199					}
1200				}
1201			}
1202			else {
1203				// if we are here, it means we are on mobile and NO is set so remove video src and use fallback
1204				videoTag.attr('src', '')
1205				wrap.append( videoTag );
1206			}
1207
1208			// Mark this video as loaded.
1209			wrap.data('loaded', true);
1210		},
1211
1212		/**
1213		 * Initializes Youtube video background
1214		 *
1215		 * @since 1.9
1216		 * @access private
1217		 * @method _initYoutubeBgVideo
1218		 */
1219		_initYoutubeBgVideo: function()
1220		{
1221			var playerWrap  = $(this),
1222				videoId     = playerWrap.data('video-id'),
1223				videoPlayer = playerWrap.find('.fl-bg-video-player'),
1224				enableAudio = playerWrap.data('enable-audio'),
1225				audioButton = playerWrap.find('.fl-bg-video-audio'),
1226				playPauseButton = playerWrap.find('.fl-bg-video-play-pause-control'),
1227				startTime   = 'undefined' !== typeof playerWrap.data('start') ? playerWrap.data('start') : 0,
1228				startTime   = 'undefined' !== typeof playerWrap.data('t') && startTime === 0 ? playerWrap.data('t') : startTime,
1229				endTime     = 'undefined' !== typeof playerWrap.data('end') ? playerWrap.data('end') : 0,
1230				loop        = 'undefined' !== typeof playerWrap.data('loop') ? playerWrap.data('loop') : 1,
1231				stateCount  = 0,
1232				player,fallback_showing;
1233
1234			if ( videoId ) {
1235				fallback = playerWrap.data('fallback') || false
1236				if( fallback ) {
1237					playerWrap.find('iframe').remove()
1238					fallbackTag = $( '<div></div>' );
1239					fallbackTag.addClass( 'fl-bg-video-fallback' );
1240					fallbackTag.css( 'background-image', 'url(' + playerWrap.data('fallback') + ')' );
1241					fallbackTag.css( 'background-size', 'cover' );
1242					fallbackTag.css( 'transition', 'background-image 1s')
1243					playerWrap.append( fallbackTag );
1244					fallback_showing = true;
1245				}
1246				FLBuilderLayout._onYoutubeApiReady( function( YT ) {
1247					setTimeout( function() {
1248
1249						player = new YT.Player( videoPlayer[0], {
1250							videoId: videoId,
1251							events: {
1252								onReady: function(event) {
1253									if ( "no" === enableAudio || FLBuilderLayout._isMobile() ) {
1254										event.target.mute();
1255									}
1256									else if ( "yes" === enableAudio && event.target.isMuted ) {
1257										event.target.unMute();
1258									}
1259
1260									// Store an instance to a parent
1261									playerWrap.data('YTPlayer', player);
1262									FLBuilderLayout._resizeYoutubeBgVideo.apply(playerWrap);
1263
1264									// Queue the video.
1265									event.target.playVideo();
1266
1267									if ( audioButton.length > 0 && ! FLBuilderLayout._isMobile() ) {
1268										audioButton.on( 'click', {button: audioButton, player: player}, FLBuilderLayout._toggleBgVideoAudio );
1269									}
1270
1271									if ( playPauseButton.length > 0 ) {
1272										playPauseButton.on( 'click', {player: player}, function(e) {
1273											var player = e.data.player;
1274			
1275											if ( 1 === player.getPlayerState() ) {
1276												player.pauseVideo();
1277											} else {
1278												player.playVideo();
1279											}
1280										});
1281									}
1282								},
1283								onStateChange: function( event ) {
1284
1285									if ( event.data === 1 ) {
1286										if ( fallback_showing ) {
1287											$( '.fl-bg-video-fallback' ).css( 'background-image', 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)' )
1288										}
1289									}
1290									// Manual check if video is not playable in some browsers.
1291									// StateChange order: [-1, 3, -1]
1292									if ( stateCount < 4 ) {
1293										stateCount++;
1294									}
1295
1296									// Comply with the audio policy in some browsers like Chrome and Safari.
1297									if ( stateCount > 1 && -1 === event.data && "yes" === enableAudio ) {
1298										player.mute();
1299										player.playVideo();
1300										audioButton.show();
1301									}
1302
1303									if ( event.data === YT.PlayerState.ENDED && 1 === loop ) {
1304										if ( startTime > 0 ) {
1305											player.seekTo( startTime );
1306										}
1307										else {
1308											player.playVideo();
1309										}
1310									}
1311
1312									if ( event.data === YT.PlayerState.PLAYING ) {
1313										playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
1314									} else if ( event.data === YT.PlayerState.PAUSED ) {
1315										playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1316									} else if ( event.data === YT.PlayerState.BUFFERING ) {
1317										playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
1318									} else if ( event.data === YT.PlayerState.CUED ) {
1319										playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1320									} else if ( event.data === YT.PlayerState.ENDED ) {
1321										playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1322									}
1323								},
1324								onError: function(event) {
1325									console.info('YT Error: ' + event.data)
1326									FLBuilderLayout._onErrorYoutubeVimeo(playerWrap)
1327								}
1328							},
1329							playerVars: {
1330								playsinline: FLBuilderLayout._isMobile() ? 1 : 0,
1331								controls: 0,
1332								showinfo: 0,
1333								rel : 0,
1334								start: startTime,
1335								end: endTime,
1336							}
1337						} );
1338					}, 1 );
1339				} );
1340			}
1341		},
1342
1343		/**
1344		 * On youtube or vimeo error show the fallback image if available.
1345		 * @since 2.0.7
1346		 */
1347		_onErrorYoutubeVimeo: function(playerWrap) {
1348
1349			fallback = playerWrap.data('fallback') || false
1350			if( ! fallback ) {
1351				return false;
1352			}
1353			playerWrap.find('iframe').remove()
1354			fallbackTag = $( '<div></div>' );
1355			fallbackTag.addClass( 'fl-bg-video-fallback' );
1356			fallbackTag.css( 'background-image', 'url(' + playerWrap.data('fallback') + ')' );
1357			playerWrap.append( fallbackTag );
1358		},
1359
1360		/**
1361		 * Check if Youtube API has been downloaded
1362		 *
1363		 * @since 1.9
1364		 * @access private
1365		 * @method _onYoutubeApiReady
1366		 * @param  {Function} callback Method to call when YT API has been loaded
1367		 */
1368		_onYoutubeApiReady: function( callback ) {
1369			if ( window.YT && YT.loaded ) {
1370				callback( YT );
1371			} else {
1372				// If not ready check again by timeout..
1373				setTimeout( function() {
1374					FLBuilderLayout._onYoutubeApiReady( callback );
1375				}, 350 );
1376			}
1377		},
1378
1379		/**
1380		 * Initializes Vimeo video background
1381		 *
1382		 * @since 1.9
1383		 * @access private
1384		 * @method _initVimeoBgVideo
1385		 */
1386		_initVimeoBgVideo: function()
1387		{
1388			var playerWrap	= $(this),
1389				videoId 	= playerWrap.data('video-id'),
1390				videoHash 	= playerWrap.data('video-hash'),
1391				videoPlayer = playerWrap.find('.fl-bg-video-player'),
1392				enableAudio = playerWrap.data('enable-audio'),
1393				audioButton = playerWrap.find('.fl-bg-video-audio'),
1394				playPauseButton = playerWrap.find('.fl-bg-video-play-pause-control'),
1395				playerState = '',
1396				player,
1397				width = playerWrap.outerWidth(),
1398				ua    = navigator.userAgent;
1399
1400			if ( typeof Vimeo !== 'undefined' && videoId )	{
1401				
1402				const vimOptions = {
1403					loop       : true,
1404					title      : false,
1405					portrait   : false,
1406					background : true,
1407					autopause  : false,
1408					muted      : true,
1409				};
1410
1411				if ( videoHash.length ) {
1412					vimOptions.url = `https://player.vimeo.com/video/${ videoId }?h=${ videoHash }`;
1413				} else {
1414					vimOptions.id = videoId;
1415				}
1416
1417				player = new Vimeo.Player(videoPlayer[0], vimOptions );
1418				playerWrap.data('VMPlayer', player);
1419				if ( "no" === enableAudio ) {
1420					player.setVolume(0);
1421				}
1422				else if ("yes" === enableAudio ) {
1423					// Chrome, Safari, Firefox have audio policy restrictions for autoplay videos.
1424					if ( ua.indexOf("Safari") > -1 || ua.indexOf("Chrome") > -1 || ua.indexOf("Firefox") > -1 ) {
1425						player.setVolume(0);
1426						audioButton.show();
1427					}
1428					else {
1429						player.setVolume(1);
1430					}
1431				}
1432
1433				player.play().catch(function(error) {
1434					FLBuilderLayout._onErrorYoutubeVimeo(playerWrap)
1435				});
1436
1437				if ( audioButton.length > 0 ) {
1438					audioButton.on( 'click', {button: audioButton, player: player}, FLBuilderLayout._toggleBgVideoAudio );
1439				}
1440
1441				player.on( 'play', function() {
1442					playerState = 'play';
1443					playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
1444				} );
1445				player.on( 'pause', function() {
1446					playerState = 'pause';
1447					playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1448				} );
1449				player.on( 'ended', function() {
1450					playerState = 'ended';
1451					playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1452				} );
1453				player.on( 'bufferstart', function() {
1454					playerState = 'bufferstart';
1455					playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
1456				} );
1457
1458				if ( playPauseButton.length > 0 ) {
1459					playPauseButton.on( 'click', { player: player }, function( e ) {
1460						var player = e.data.player;
1461
1462						if ( playerState === 'play' ) {
1463							player.pause();
1464						} else {
1465							player.play();
1466						}
1467					} );
1468				}
1469			}
1470		},
1471
1472		/**
1473		 * Mute / unmute audio on row's video background.
1474		 * It works for both Youtube and Vimeo.
1475		 *
1476		 * @since 2.1.3
1477		 * @access private
1478		 * @method _toggleBgVideoAudio
1479		 * @param {Object} e Method arguments
1480		 */
1481		_toggleBgVideoAudio: function( e ) {
1482			var player  = e.data.player,
1483			    control = e.data.button.find('.fl-audio-control');
1484
1485			if ( control.hasClass( 'fa-volume-off' ) ) {
1486				// Unmute
1487				control
1488					.removeClass( 'fa-volume-off' )
1489					.addClass( 'fa-volume-up' );
1490				e.data.button.find( '.fa-times' ).hide();
1491
1492				if ( 'function' === typeof player.unMute ) {
1493					player.unMute();
1494				}
1495				else {
1496					player.setVolume( 1 );
1497				}
1498			}
1499			else {
1500				// Mute
1501				control
1502					.removeClass( 'fa-volume-up' )
1503					.addClass( 'fa-volume-off' );
1504				e.data.button.find( '.fa-times' ).show();
1505
1506				if ( 'function' === typeof player.unMute ) {
1507					player.mute();
1508				}
1509				else {
1510					player.setVolume( 0 );
1511				}
1512			}
1513		},
1514
1515		/**
1516		 * Fires when there is an error loading a video
1517		 * background source and shows the fallback.
1518		 *
1519		 * @since 1.6.3.3
1520		 * @access private
1521		 * @method _videoBgSourceError
1522		 * @param {Object} e An event object
1523		 * @deprecated 2.0.3
1524		 */
1525		_videoBgSourceError: function( e )
1526		{
1527			var source 		= $( e.target ),
1528				wrap   		= source.closest( '.fl-bg-video' ),
1529				vid		    = wrap.find( 'video' ),
1530				fallback  	= wrap.data( 'fallback' ),
1531				fallbackTag = '';
1532			source.remove();
1533
1534			if ( vid.find( 'source' ).length ) {
1535				// Don't show the fallback if we still have other sources to check.
1536				return;
1537			} else if ( '' !== fallback ) {
1538				fallbackTag = $( '<div></div>' );
1539				fallbackTag.addClass( 'fl-bg-video-fallback' );
1540				fallbackTag.css( 'background-image', 'url(' + fallback + ')' );
1541				wrap.append( fallbackTag );
1542				vid.remove();
1543			}
1544		},
1545
1546		/**
1547		 * Fires when the window is resized to resize
1548		 * all video backgrounds.
1549		 *
1550		 * @since 1.1.4
1551		 * @access private
1552		 * @method _resizeBgVideos
1553		 */
1554		_resizeBgVideos: function()
1555		{
1556			$('.fl-bg-video').each( function() {
1557
1558				FLBuilderLayout._resizeBgVideo.apply( this );
1559
1560				if ( $( this ).parent().find( 'img' ).length > 0 ) {
1561					$( this ).parent().imagesLoaded( $.proxy( FLBuilderLayout._resizeBgVideo, this ) );
1562				}
1563			} );
1564		},
1565
1566		/**
1567		 * Fires when the window is resized to resize
1568		 * a single video background.
1569		 *
1570		 * @since 1.1.4
1571		 * @access private
1572		 * @method _resizeBgVideo
1573		 */
1574		_resizeBgVideo: function()
1575		{
1576			if ( 0 === $( this ).find( 'video' ).length && 0 === $( this ).find( 'iframe' ).length ) {
1577				return;
1578			}
1579
1580			var wrap        = $(this),
1581				wrapHeight  = wrap.outerHeight(),
1582				wrapWidth   = wrap.outerWidth(),
1583				vid         = wrap.find('video'),
1584				vidHeight   = wrap.data('height'),
1585				vidWidth    = wrap.data('width'),
1586				newWidth    = wrapWidth,
1587				newHeight   = Math.round(vidHeight * wrapWidth/vidWidth),
1588				newLeft     = 0,
1589				newTop      = 0,
1590				iframe 		= wrap.find('iframe'),
1591				isRowFullHeight = $(this).closest('.fl-row-bg-video').hasClass('fl-row-full-height'),
1592				vidCSS          = {
1593					top:       '50%',
1594					left:      '50%',
1595					transform: 'translate(-50%,-50%)',
1596				};
1597
1598			if ( vid.length ) {
1599				if(vidHeight === '' || typeof vidHeight === 'undefined' || vidWidth === '' || typeof vidWidth === 'undefined') {
1600					vid.css({
1601						'left'      : '0px',
1602						'top'       : '0px',
1603						'width'     : newWidth + 'px'
1604					});
1605
1606					// Try to set the actual video dimension on 'loadedmetadata' when using URL as video source
1607					vid.on('loadedmetadata', FLBuilderLayout._resizeOnLoadedMeta);
1608
1609					return;
1610				}
1611
1612				if ( ! isRowFullHeight ) {
1613					if ( newHeight < wrapHeight ) {
1614						newHeight = wrapHeight;
1615						newLeft   = -((newWidth - wrapWidth) / 2);
1616						newWidth  = vidHeight ? Math.round(vidWidth * wrapHeight/vidHeight) : newWidth;
1617					}
1618					else {
1619						newTop = -((newHeight - wrapHeight)/2);
1620					}
1621					vidCSS = {
1622						left   : newLeft + 'px',
1623						top    : newTop + 'px',
1624						height : newHeight + 'px',
1625						width  : newWidth + 'px',
1626					}
1627				}
1628
1629				vid.css( vidCSS );
1630
1631			}
1632			else if ( iframe.length ) {
1633
1634				// Resize Youtube video player within iframe tag
1635				if ( typeof wrap.data('youtube') !== 'undefined' ) {
1636					FLBuilderLayout._resizeYoutubeBgVideo.apply(this);
1637				}
1638			}
1639		},
1640
1641		/**
1642		 * Fires when video meta has been loaded.
1643		 * This will be Triggered when width/height attributes were not specified during video background resizing.
1644		 *
1645		 * @since 1.8.5
1646		 * @access private
1647		 * @method _resizeOnLoadedMeta
1648		 */
1649		_resizeOnLoadedMeta: function(){
1650			var video 		= $(this),
1651				wrapHeight 	= video.parent().outerHeight(),
1652				wrapWidth 	= video.parent().outerWidth(),
1653				vidWidth 	= video[0].videoWidth,
1654				vidHeight 	= video[0].videoHeight,
1655				newHeight   = Math.round(vidHeight * wrapWidth/vidWidth),
1656				newWidth    = wrapWidth,
1657				newLeft     = 0,
1658				newTop 		= 0;
1659
1660			if(newHeight < wrapHeight) {
1661				newHeight   = wrapHeight;
1662				newWidth    = Math.round(vidWidth * wrapHeight/vidHeight);
1663				newLeft     = -((newWidth - wrapWidth)/2);
1664			}
1665			else {
1666				newTop      = -((newHeight - wrapHeight)/2);
1667			}
1668
1669			video.parent().data('width', vidWidth);
1670			video.parent().data('height', vidHeight);
1671
1672			video.css({
1673				'left'      : newLeft + 'px',
1674				'top'       : newTop + 'px',
1675				'width'     : newWidth + 'px',
1676				'height' 	: newHeight + 'px'
1677			});
1678		},
1679
1680		/**
1681		 * Fires when the window is resized to resize
1682		 * a single Youtube video background.
1683		 *
1684		 * @since 1.9
1685		 * @access private
1686		 * @method _resizeYoutubeBgVideo
1687		 */
1688		_resizeYoutubeBgVideo: function()
1689		{
1690			var wrap				= $(this),
1691				wrapWidth 			= wrap.outerWidth(),
1692				wrapHeight 			= wrap.outerHeight(),
1693				player 				= wrap.data('YTPlayer'),
1694				video 				= player ? player.getIframe() : null,
1695				aspectRatioSetting 	= '16:9', // Medium
1696				aspectRatioArray 	= aspectRatioSetting.split( ':' ),
1697				aspectRatio 		= aspectRatioArray[0] / aspectRatioArray[1],
1698				ratioWidth 			= wrapWidth / aspectRatio,
1699				ratioHeight 		= wrapHeight * aspectRatio,
1700				isWidthFixed 		= wrapWidth / wrapHeight > aspectRatio,
1701				width 				= isWidthFixed ? wrapWidth : ratioHeight,
1702				height 				= isWidthFixed ? ratioWidth : wrapHeight;
1703
1704			if ( video ) {
1705				$(video).width( width ).height( height );
1706			}
1707		},
1708
1709		/**
1710		 * Opens a tab or accordion item if the browser hash is set
1711		 * to the ID of one on the page.
1712		 *
1713		 * @since 1.6.0
1714		 * @access private
1715		 * @method _initHash
1716		 */
1717		_initHash: function()
1718		{
1719			var hash 			= window.location.hash.replace( '#', '' ).split( '/' ).shift(),
1720				element 		= null,
1721				tabs			= null,
1722				responsiveLabel	= null,
1723				tabIndex		= null,
1724				label			= null;
1725
1726			if ( '' !== hash ) {
1727
1728				try {
1729
1730					element = $( '#' + hash );
1731
1732					if ( element.length > 0 ) {
1733
1734						if ( element.hasClass( 'fl-accordion-item' ) ) {
1735							setTimeout( function() {
1736								element.find( '.fl-accordion-button' ).trigger( 'click' );
1737							}, 100 );
1738						}
1739						if ( element.hasClass( 'fl-tabs-panel' ) ) {
1740							setTimeout( function() {
1741								tabs 			= element.closest( '.fl-tabs' );
1742								responsiveLabel = element.find( '.fl-tabs-panel-label' );
1743								tabIndex 		= responsiveLabel.data( 'index' );
1744								label 			= tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' );
1745
1746								label[0].click();
1747								FLBuilderLayout._scrollToElement(element);
1748							}, 100 );
1749						}
1750					}
1751				}
1752				catch( e ) {}
1753			}
1754		},
1755
1756		/**
1757		 * Initializes all anchor links on the page for smooth scrolling.
1758		 *
1759		 * @since 1.4.9
1760		 * @access private
1761		 * @method _initAnchorLinks
1762		 */
1763		_initAnchorLinks: function()
1764		{
1765			$( 'a, [role="link"]' ).each( FLBuilderLayout._initAnchorLink );
1766		},
1767
1768		/**
1769		 * Initializes a single anchor link for smooth scrolling.
1770		 *
1771		 * @since 1.4.9
1772		 * @access private
1773		 * @method _initAnchorLink
1774		 */
1775		_initAnchorLink: function()
1776		{
1777			var link    = $( this ),
1778				href    = link.data( 'url' ) ? link.data( 'url' ) : link.attr( 'href' ),
1779				target  = link.data( 'url' ) ? new URL( href, window.location.href ) : this,
1780				loc     = window.location,
1781				id      = null,
1782				element = null,
1783				flNode  = false;
1784
1785			if ( 'undefined' != typeof href && href.indexOf( '#' ) > -1 && link.closest('svg').length < 1 ) {
1786
1787				if ( loc.pathname.replace( /^\//, '' ) == target.pathname.replace( /^\//, '' ) && loc.hostname == target.hostname ) {
1788
1789					try {
1790
1791						id      = href.split( '#' ).pop();
1792						// If there is no ID then we have nowhere to look
1793						// Fixes a quirk in jQuery and FireFox
1794						if( ! id ) {
1795							return;
1796						}
1797						element = $( '#' + id );
1798
1799						if ( element.length > 0 ) {
1800							flNode = element.hasClass( 'fl-row' ) || element.hasClass( 'fl-col' ) || element.hasClass( 'fl-module' );
1801							if ( !element.hasClass( 'fl-no-scroll' ) && ( link.hasClass( 'fl-scroll-link' ) || flNode ) ) {
1802								$( link ).on( 'click', FLBuilderLayout._scrollToElementOnLinkClick );
1803							}
1804							if ( element.hasClass( 'fl-accordion-item' ) ) {
1805								$( link ).on( 'click', FLBuilderLayout._scrollToAccordionOnLinkClick );
1806							}
1807							if ( element.hasClass( 'fl-tabs-panel' ) ) {
1808								$( link ).on( 'click', FLBuilderLayout._scrollToTabOnLinkClick );
1809							}
1810						}
1811					}
1812					catch( e ) {}
1813				}
1814			}
1815		},
1816
1817		/**
1818		 * Scrolls to an element when an anchor link is clicked.
1819		 *
1820		 * @since 1.4.9
1821		 * @access private
1822		 * @method _scrollToElementOnLinkClick
1823		 * @param {Object} e An event object.
1824		 * @param {Function} callback A function to call when the scroll is complete.
1825		 */
1826		_scrollToElementOnLinkClick: function( e, callback )
1827		{
1828			var attribute = $( this ).data( 'url' ) ? $( this ).data( 'url' ) : $( this ).attr( 'href' );
1829			var element = $( '#' + attribute.split( '#' ).pop() );
1830
1831			FLBuilderLayout._scrollToElement( element, callback );
1832
1833			e.preventDefault();
1834		},
1835
1836		/**
1837		 * Scrolls to an element.
1838		 *
1839		 * @since 1.6.4.5
1840		 * @access private
1841		 * @method _scrollToElement
1842		 * @param {Object} element The element to scroll to.
1843		 * @param {Function} callback A function to call when the scroll is complete.
1844		 */
1845		_scrollToElement: function( element, callback )
1846		{
1847			var config  = FLBuilderLayoutConfig.anchorLinkAnimations,
1848				dest    = 0,
1849				win     = $( window ),
1850				doc     = $( document );
1851
1852			if ( element.length > 0 ) {
1853
1854				if ( 'fixed' === element.css('position') || 'fixed' === element.parent().css('position') ) {
1855					dest = element.position().top;
1856				}
1857				else if ( element.offset().top > doc.height() - win.height() ) {
1858					dest = doc.height() - win.height();
1859				}
1860				else {
1861					dest = element.offset().top - config.offset;
1862				}
1863
1864				$( 'html, body' ).stop( true ).animate( { scrollTop: dest }, config.duration, config.easing, function() {
1865
1866					if ( 'undefined' != typeof callback ) {
1867						callback();
1868					}
1869
1870					if ( undefined != element.attr( 'id' ) && window.location.hash !== '#' + element.attr( 'id' ) ) {
1871
1872						var firefox_version = window.navigator.userAgent.match( /Firefox\/(\d+)\./ ),
1873							firefox_version = firefox_version ? parseInt( firefox_version[1], 10 ) : null;
1874
1875						if ( firefox_version !== null && firefox_version < 135 ) {
1876							window.location.hash = element.attr( 'id' );
1877						} else {
1878							if ( history.pushState ) {
1879								history.pushState( null, null, '#' + element.attr( 'id' ) );
1880							} else {
1881								window.location.hash = element.attr( 'id' );
1882							}
1883						}
1884					}
1885				} );
1886			}
1887		},
1888
1889		/**
1890		 * Scrolls to an accordion item when a link is clicked.
1891		 *
1892		 * @since 1.5.9
1893		 * @access private
1894		 * @method _scrollToAccordionOnLinkClick
1895		 * @param {Object} e An event object.
1896		 */
1897		_scrollToAccordionOnLinkClick: function( e )
1898		{
1899			var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() );
1900
1901			if ( element.length > 0 ) {
1902
1903				var callback = function() {
1904					if ( element ) {
1905						element.find( '.fl-accordion-button' ).trigger( 'click' );
1906						element = false;
1907					}
1908				};
1909
1910				FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback );
1911			}
1912		},
1913
1914		/**
1915		 * Scrolls to a tab panel when a link is clicked.
1916		 *
1917		 * @since 1.5.9
1918		 * @access private
1919		 * @method _scrollToTabOnLinkClick
1920		 * @param {Object} e An event object.
1921		 */
1922		_scrollToTabOnLinkClick: function( e )
1923		{
1924			var element 		= $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() ),
1925				tabs			= null,
1926				label   		= null,
1927				responsiveLabel = null;
1928
1929			if ( element.length > 0 ) {
1930
1931				tabs 			= element.closest( '.fl-tabs' );
1932				responsiveLabel = element.find( '.fl-tabs-panel-label' );
1933				tabIndex 		= responsiveLabel.data( 'index' );
1934				label 			= tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' );
1935
1936				if ( responsiveLabel.is( ':visible' ) ) {
1937
1938					var callback = function() {
1939						if ( element ) {
1940							responsiveLabel.trigger( $.Event( 'click', { which: 1 } ) );
1941						}
1942					};
1943
1944					FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback );
1945				}
1946				else {
1947					label[0].click();
1948					FLBuilderLayout._scrollToElement( element );
1949				}
1950
1951				e.preventDefault();
1952			}
1953		},
1954
1955		/**
1956		 * Initializes all builder forms on a page.
1957		 *
1958		 * @since 1.5.4
1959		 * @access private
1960		 * @method _initForms
1961		 */
1962		_initForms: function()
1963		{
1964			if ( ! FLBuilderLayout._hasPlaceholderSupport ) {
1965				$( '.fl-form-field input' ).each( FLBuilderLayout._initFormFieldPlaceholderFallback );
1966			}
1967
1968			$( '.fl-form-field input' ).on( 'focus', FLBuilderLayout._clearFormFieldError );
1969		},
1970
1971		/**
1972		 * Checks to see if the current device has HTML5
1973		 * placeholder support.
1974		 *
1975		 * @since 1.5.4
1976		 * @access private
1977		 * @method _hasPlaceholderSupport
1978		 * @return {Boolean}
1979		 */
1980		_hasPlaceholderSupport: function()
1981		{
1982			var input = document.createElement( 'input' );
1983
1984			return 'undefined' != input.placeholder;
1985		},
1986
1987		/**
1988		 * Initializes the fallback for when placeholders aren't supported.
1989		 *
1990		 * @since 1.5.4
1991		 * @access private
1992		 * @method _initFormFieldPlaceholderFallback
1993		 */
1994		_initFormFieldPlaceholderFallback: function()
1995		{
1996			var field       = $( this ),
1997				val         = field.val(),
1998				placeholder = field.attr( 'placeholder' );
1999
2000			if ( 'undefined' != placeholder && '' === val ) {
2001				field.val( placeholder );
2002				field.on( 'focus', FLBuilderLayout._hideFormFieldPlaceholderFallback );
2003				field.on( 'blur', FLBuilderLayout._showFormFieldPlaceholderFallback );
2004			}
2005		},
2006
2007		/**
2008		 * Hides a fallback placeholder on focus.
2009		 *
2010		 * @since 1.5.4
2011		 * @access private
2012		 * @method _hideFormFieldPlaceholderFallback
2013		 */
2014		_hideFormFieldPlaceholderFallback: function()
2015		{
2016			var field       = $( this ),
2017				val         = field.val(),
2018				placeholder = field.attr( 'placeholder' );
2019
2020			if ( val == placeholder ) {
2021				field.val( '' );
2022			}
2023		},
2024
2025		/**
2026		 * Shows a fallback placeholder on blur.
2027		 *
2028		 * @since 1.5.4
2029		 * @access private
2030		 * @method _showFormFieldPlaceholderFallback
2031		 */
2032		_showFormFieldPlaceholderFallback: function()
2033		{
2034			var field       = $( this ),
2035				val         = field.val(),
2036				placeholder = field.attr( 'placeholder' );
2037
2038			if ( '' === val ) {
2039				field.val( placeholder );
2040			}
2041		},
2042
2043		/**
2044		 * Clears a form field error message.
2045		 *
2046		 * @since 1.5.4
2047		 * @access private
2048		 * @method _clearFormFieldError
2049		 */
2050		_clearFormFieldError: function()
2051		{
2052			var field = $( this );
2053
2054			field.removeAttr( 'aria-invalid' );
2055			field.removeClass( 'fl-form-error' );
2056			const message = field.attr('aria-describedby');
2057			message ? $( '#' + message ).hide() : field.siblings( '.fl-form-error-message' ).hide();
2058		},
2059
2060		/**
2061		 * Init Row Shape Layer's height.
2062		 *
2063		 * @since 2.5.3
2064		 * @access private
2065		 * @method _initRowShapeLayerHeight
2066		 */
2067		_initRowShapeLayerHeight: function () {
2068			FLBuilderLayout._adjustRowShapeLayerHeight();
2069			$( window ).on( 'resize', FLBuilderLayout._adjustRowShapeLayerHeight );
2070		},
2071
2072		/**
2073		 * Set parent column width of nested columns when it's zero or blank.
2074		 *
2075		 * @since 2.7.4
2076		 * @access private
2077		 * @method _initNestedColsWidth
2078		 */
2079		_initNestedColsWidth: function()
2080		{
2081			var nestedCols = $( '.fl-col-has-cols' );
2082
2083			if ( nestedCols.length <= 0 ) {
2084				return;
2085			}
2086
2087			$( nestedCols ).each( function(index, col ){
2088				if ( $( col ).width() <= 0 ) {
2089					$( col ).css( 'width', FLBuilderLayoutConfig.emptyColWidth );
2090				}
2091			});
2092		},
2093
2094		/**
2095		 * Adjust Row Shape Layer's height to fix to remove the fine line that appears on certain screen sizes.
2096		 *
2097		 * @since 2.5.3
2098		 * @access private
2099		 * @method _adjustRowShapeLayerHeight
2100		 */
2101		_adjustRowShapeLayerHeight: function() {
2102			var rowShapeLayers = $('.fl-builder-shape-layer');
2103
2104			$( rowShapeLayers ).each(function (index) {
2105				var rowShapeLayer = $(this),
2106					shape = $(rowShapeLayer).find('svg'),
2107					height = shape.height(),
2108					excludeShapes = '.fl-builder-shape-circle, .fl-builder-shape-dot-cluster, .fl-builder-shape-topography, .fl-builder-shape-rect';
2109
2110				if ( ! rowShapeLayer.is( excludeShapes ) ) {
2111					$(shape).css('height', Math.ceil( height ) );
2112				}
2113			});
2114		},
2115		_string_to_slug: function( str ) {
2116			str = str.replace(/^\s+|\s+$/g, ''); // trim
2117			if ( 'undefined' == typeof window._fl_string_to_slug_regex ) {
2118				regex = new RegExp('[^a-zA-Z0-9\'":() !.,-_|]', 'g');
2119			} else {
2120				regex = new RegExp('[^' + window._fl_string_to_slug_regex + '\'":\(\) !.,-_|\\\p{Letter}]', 'ug');
2121			}
2122			str = str.replace(regex, '') // remove invalid chars
2123				.replace(/\s+/g, ' '); // collapse whitespace and replace by a space
2124			return str;
2125		},
2126		_reorderMenu: function() {
2127			if ( $('#wp-admin-bar-fl-builder-frontend-edit-link-default li').length > 1 ) {
2128					$( '#wp-admin-bar-fl-builder-frontend-duplicate-link' )
2129					.appendTo('#wp-admin-bar-fl-builder-frontend-edit-link-default')
2130					.css( 'padding-top', '5px' )
2131					.css( 'border-top', '2px solid #1D2125' )
2132					.css( 'margin-top', '5px' )
2133				}
2134		}
2135	};
2136
2137	/* Initializes the builder layout. */
2138	$(function(){
2139		FLBuilderLayout.init();
2140	});
2141
2142})(jQuery);
2143(function($){
2144
2145	if(typeof FLBuilderLayoutModules !== 'undefined') {
2146		return;
2147	}
2148
2149	/**
2150	 * Helper class with generic logic for builder modules.
2151	 * If generic module code needs to work in both the block
2152	 * editor and builder, it should go here. Otherwise, it
2153	 * should go on FLBuilderLayout.
2154	 *
2155	 * @since 2.9
2156	 */
2157	FLBuilderLayoutModules = {
2158
2159		/**
2160		 * Initializes builder module logic.
2161		 *
2162		 * @since 2.9
2163		 * @method init
2164		 */
2165		init: function()
2166		{
2167			// Only init if the builder isn't active.
2168			if ( 0 === $('.fl-builder-edit').length ) {
2169
2170				// Init module animations.
2171				FLBuilderLayoutModules._initModuleAnimations();
2172			}
2173		},
2174
2175		/**
2176		 * Initializes module animations.
2177		 *
2178		 * @since 1.1.9
2179		 * @access private
2180		 * @method _initModuleAnimations
2181		 */
2182		_initModuleAnimations: function()
2183		{
2184			if(typeof jQuery.fn.waypoint !== 'undefined') {
2185				$('.fl-animation').each( function() {
2186					var node = $( this ),
2187						nodeTop = node.offset().top,
2188						winHeight = $( window ).height(),
2189						bodyHeight = $( 'body' ).height(),
2190						waypoint = FLBuilderLayoutConfig.waypoint,
2191						offset = '80%';
2192
2193					if ( typeof waypoint.offset !== undefined ) {
2194						offset = FLBuilderLayoutConfig.waypoint.offset + '%';
2195					}
2196
2197					if ( bodyHeight - nodeTop < winHeight * 0.2 ) {
2198						offset = '100%';
2199					}
2200
2201					node.waypoint({
2202						offset: offset,
2203						handler: FLBuilderLayoutModules._doModuleAnimation
2204					});
2205				} );
2206			}
2207		},
2208
2209		/**
2210		 * Runs a module animation.
2211		 *
2212		 * @since 1.1.9
2213		 * @access private
2214		 * @method _doModuleAnimation
2215		 */
2216		_doModuleAnimation: function()
2217		{
2218			var module = 'undefined' == typeof this.element ? $(this) : $(this.element),
2219				delay = parseFloat(module.data('animation-delay')),
2220				duration = parseFloat(module.data('animation-duration'));
2221
2222			if ( ! isNaN( duration ) ) {
2223				module.css( 'animation-duration', duration + 's' );
2224			}
2225
2226			if(!isNaN(delay) && delay > 0) {
2227				setTimeout(function(){
2228					module.addClass('fl-animated');
2229				}, delay * 1000);
2230			} else {
2231				setTimeout(function(){
2232					module.addClass('fl-animated');
2233				}, 1);
2234			}
2235		}
2236	};
2237
2238	/* Initializes builder module logic. */
2239	$(function(){
2240		FLBuilderLayoutModules.init();
2241	});
2242
2243})(jQuery);
2244
2245/* Start Global JS */
2246
2247/* End Global JS */
2248
2249
2250;/**
2251 * This file should contain frontend logic for 
2252 * all module instances.
2253 */(function($) {
2254
2255		$('.fl-node-myve0ihk715u .pp-infobox').on('mouseenter', function() {
2256		$('.fl-node-myve0ihk715u .pp-icon-wrapper').addClass(' none');
2257	});
2258	$('.fl-node-myve0ihk715u .pp-infobox').on('mouseleave', function() {
2259		$('.fl-node-myve0ihk715u .pp-icon-wrapper').removeClass(' none');
2260	});
2261
2262})(jQuery);
2263(function($) {
2264
2265		$('.fl-node-5dx1jhoaqmy4 .pp-infobox').on('mouseenter', function() {
2266		$('.fl-node-5dx1jhoaqmy4 .pp-icon-wrapper').addClass(' none');
2267	});
2268	$('.fl-node-5dx1jhoaqmy4 .pp-infobox').on('mouseleave', function() {
2269		$('.fl-node-5dx1jhoaqmy4 .pp-icon-wrapper').removeClass(' none');
2270	});
2271
2272})(jQuery);
2273(function($) {
2274
2275		$('.fl-node-g0jvsf91oxi5 .pp-infobox').on('mouseenter', function() {
2276		$('.fl-node-g0jvsf91oxi5 .pp-icon-wrapper').addClass(' none');
2277	});
2278	$('.fl-node-g0jvsf91oxi5 .pp-infobox').on('mouseleave', function() {
2279		$('.fl-node-g0jvsf91oxi5 .pp-icon-wrapper').removeClass(' none');
2280	});
2281
2282})(jQuery);
2283(function($) {
2284
2285		$('.fl-node-yhro2pcujawl .pp-infobox').on('mouseenter', function() {
2286		$('.fl-node-yhro2pcujawl .pp-icon-wrapper').addClass(' none');
2287	});
2288	$('.fl-node-yhro2pcujawl .pp-infobox').on('mouseleave', function() {
2289		$('.fl-node-yhro2pcujawl .pp-icon-wrapper').removeClass(' none');
2290	});
2291
2292})(jQuery);
2293(function($) {
2294
2295		$('.fl-node-hx9b7ai0ylms .pp-infobox').on('mouseenter', function() {
2296		$('.fl-node-hx9b7ai0ylms .pp-icon-wrapper').addClass(' none');
2297	});
2298	$('.fl-node-hx9b7ai0ylms .pp-infobox').on('mouseleave', function() {
2299		$('.fl-node-hx9b7ai0ylms .pp-icon-wrapper').removeClass(' none');
2300	});
2301
2302})(jQuery);
2303(function($) {
2304
2305		$('.fl-node-9c2kgy7febl0 .pp-infobox').on('mouseenter', function() {
2306		$('.fl-node-9c2kgy7febl0 .pp-icon-wrapper').addClass(' none');
2307	});
2308	$('.fl-node-9c2kgy7febl0 .pp-infobox').on('mouseleave', function() {
2309		$('.fl-node-9c2kgy7febl0 .pp-icon-wrapper').removeClass(' none');
2310	});
2311
2312})(jQuery);
2313
2314;
2315(function($) {
2316	var fixedHeight = true;
2317	function equalheight() {
2318		if ( ! fixedHeight ) {
2319			return;
2320		}
2321		var maxHeight = 0;
2322		$('.fl-node-d5sr826g3xzc .pp-testimonial .pp-content-wrapper').each(function(index) {
2323			if(($(this).outerHeight()) > maxHeight) {
2324				maxHeight = $(this).outerHeight();
2325			}
2326		});
2327		$('.fl-node-d5sr826g3xzc .pp-testimonial .pp-content-wrapper').css('height', maxHeight + 'px');
2328	}
2329
2330	var left_arrow_svg = '<span aria-hidden="true"><svg role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 512">
2330<path fill="currentColor" d="M25.1 247.5l117.8-116c4.7-4.7 12.3-4.7 17 0l7.1 7.1c4.7 4.7 4.7 12.3 0 17L64.7 256l102.2 100.4c4.7 4.7 4.7 12.3 0 17l-7.1 7.1c-4.7 4.7-12.3 4.7-17 0L25 264.5c-4.6-4.7-4.6-12.3.1-17z"></path></svg></span><span class="sr-only">Previous</span>';
2331	var right_arrow_svg = '<span aria-hidden="true"><svg role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 192 512"><path fill="currentColor" d="M166.9 264.5l-117.8 116c-4.7 4.7-12.3 4.7-17 0l-7.1-7.1c-4.7-4.7-4.7-12.3 0-17L127.3 256 25.1 155.6c-4.7-4.7-4.7-12.3 0-17l7.1-7.1c4.7-4.7 12.3-4.7 17 0l117.8 116c4.6 4.7 4.6 12.3-.1 17z"></path></svg></span><span class="sr-only">Next</span>';
2332
2333		var setAriaHidden = function(e) {
2334		var currentIndex = e.item.index; // Get the index of the first visible slide
2335        var visibleItems = e.page.size;  // Get the number of visible slides
2336
2337		// Loop through all slides
2338        $(e.target).find('.owl-item').each(function(index) {
2339            // Set aria-hidden="false" for visible slides, aria-hidden="true" for non-visible slides
2340            if (index >= currentIndex && index < currentIndex + visibleItems) {
2341                $(this).attr('aria-hidden', 'false');
2342            } else {
2343                $(this).attr('aria-hidden', 'true');
2344            }
2345        });
2346	};
2347	var onChange = function( e ) {
2348		setTimeout(function() {
2349			$( e.target ).find( '.owl-item' ).removeClass( 'pp-testimonial--center' );
2350			var actives = $( e.target ).find( '.owl-item.active' );
2351			if ( actives.length === 3 ) {
2352				$( actives[1] ).addClass( 'pp-testimonial--center' );
2353			}
2354		}, 200);
2355
2356		$(e.target).find('.owl-dot').each(function() {
2357			if ( $(this).hasClass( 'active' ) ) {
2358				$(this).attr('aria-current', 'true');
2359			} else {
2360				$(this).attr('aria-current', 'false');
2361			}
2362		});
2363
2364		//var currentIndex = e.item.index + 1;
2365    	//$(e.target).find('.owl-item').eq(currentIndex).focus();
2366
2367		var visibleSlides = 0; // Counter for real visible slides
2368		$(e.target).find('.owl-item').each(function(index) {
2369			// Check if the item is not a clone
2370			if (!$(this).hasClass('cloned')) {
2371				visibleSlides++;
2372				$(this).attr('aria-label', 'Testimonial ' + visibleSlides + ' of ' + e.item.count);
2373			}
2374		});
2375
2376		setAriaHidden(e);
2377	};
2378
2379	var options = {
2380		items: 1,
2381		responsive: {
2382			0: {
2383				items: 1,
2384							},
2385			769: {
2386				items: 1,
2387							},
2388			993: {
2389				items: 1,
2390							},
2391			1201: {
2392				items: 1,
2393			}
2394		},
2395		dots: true,
2396		 
2397		dotsEach: true,
2398				autoplay: true,
2399		autoplayHoverPause: true,
2400		autoplayTimeout: 7000,
2401		autoplaySpeed: 500,
2402		navSpeed: 500,
2403		dotsSpeed: 500,
2404		navText: [left_arrow_svg, right_arrow_svg],
2405		navContainer: '.fl-node-d5sr826g3xzc .pp-testimonials-nav',
2406		navElement:'button type="button"',
2407		loop: true,
2408		autoHeight: ! fixedHeight,
2409				slideBy: 1,
2410		mouseDrag: true,
2411		responsiveRefreshRate: 200,
2412		responsiveBaseWidth: window,
2413		margin: 20,
2414		rtl: $('body').hasClass( 'rtl' ),
2415		onInitialized: function(e) {
2416			onChange(e);
2417			setAriaHidden(e);
2418			equalheight();
2419
2420			var count = 1;
2421			$(e.target).find('.owl-dot').each(function() {
2422				$(this).append( '<span class="sr-only">Testimonial Slide ' + count + '</span>' );
2423				if ( $(this).hasClass( 'active' ) ) {
2424					$(this).attr('aria-current', 'true');
2425				} else {
2426					$(this).attr('aria-current', 'false');
2427				}
2428				count++;
2429			});
2430
2431			$(e.target).find( '.owl-item' ).attr('role','group'); 
2432
2433			var visibleSlides = 0; // Counter for real visible slides
2434			$(e.target).find('.owl-item').each(function(index) {
2435				// Check if the item is not a clone
2436				if (!$(this).hasClass('cloned')) {
2437					visibleSlides++;
2438					$(this).attr('aria-label', 'Testimonial ' + visibleSlides + ' of ' + e.item.count);
2439				}
2440			});
2441
2442			$(e.target).parent().find('.owl-prev').attr('title','Previous testimonial');
2443			$(e.target).parent().find('.owl-next').attr('title','Next testimonial');
2444			
2445			var carousel = this;
2446			carousel.$element.on( 'focus', function() {
2447				carousel.$element.on( 'keyup', function(e) {
2448					if ( 37 === e.keyCode || 37 === e.which ) {
2449						carousel.prev();
2450					}
2451					if ( 39 === e.keyCode || 39 === e.which ) {
2452						carousel.next();
2453					}
2454				} );
2455			} ).on( 'blur', function() {
2456				carousel.$element.off( 'keyup' );
2457			} );
2458		},
2459		onResized: equalheight,
2460		onRefreshed: equalheight,
2461		onLoadedLazy: equalheight,
2462		onChanged: onChange,
2463		onDragged: function(e) {
2464			var autoplay = true;
2465
2466			if ( ! autoplay ) {
2467				$(e.target).trigger( 'stop.owl.autoplay' );
2468			}
2469		}
2470	};
2471
2472	if ( $.fn.imagesLoaded ) {
2473		$('.fl-node-d5sr826g3xzc').imagesLoaded(function() {
2474			$('.fl-node-d5sr826g3xzc .owl-carousel').owlCarousel( options );
2475		});
2476	} else {
2477		$('.fl-node-d5sr826g3xzc .owl-carousel').owlCarousel( options );
2478	}
2479
2480	if ( $('.fl-node-d5sr826g3xzc .owl-carousel').parents( '.pp-tabs-panel-content:not(:visible)' ).length > 0 ) {
2481		$('.fl-node-d5sr826g3xzc .owl-carousel').addClass( 'owl-hidden' );
2482	}
2483
2484
2485})(jQuery);
2486
2487/* Start Global Node Custom JS */
2488
2489/* End Global Node Custom JS */
2490
2491
2492/* Start Layout Custom JS */
2493
2494/* End Layout Custom JS */
2495

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.