PageSourceSearch

https://willzies.com/wp-content/uploads/bb-plugin/cache/148-layout.js?ver=f449b98db65791d3c99855f834f945bb

js willzies.com collected 2026-10-10 02:16:37 UTC 70,960 bytes, 2,551 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    if( typeof bowser !== 'undefined' && bowser !== null ) {
610
611      var uabb_browser   = bowser.name,
612          uabb_browser_v = bowser.version,
613          uabb_browser_class = uabb_browser.replace(/\s+/g, '-').toLowerCase(),
614          uabb_browser_v_class = uabb_browser_class + parseInt( uabb_browser_v );
615      
616      $('html').addClass(uabb_browser_class).addClass(uabb_browser_v_class);
617      
618    }
619
620    $('.uabb-row-separator').parents('html').css('overflow-x', 'hidden');
621});
622var wpAjaxUrl = 'https://willzies.com/wp-admin/admin-ajax.php';var flBuilderUrl = 'https://willzies.com/wp-content/plugins/bb-plugin/';var FLBuilderLayoutConfig = {
623	anchorLinkAnimations : {
624		duration 	: 1000,
625		easing		: 'swing',
626		offset 		: 100
627	},
628	paths : {
629		pluginUrl : 'https://willzies.com/wp-content/plugins/bb-plugin/',
630		wpAjaxUrl : 'https://willzies.com/wp-admin/admin-ajax.php'
631	},
632	breakpoints : {
633		small  : 768,
634		medium : 992,
635		large : 1200	},
636	waypoint: {
637		offset: 80
638	},
639	emptyColWidth: '0%'
640};
641(function($){
642
643	if(typeof FLBuilderLayout != 'undefined') {
644		return;
645	}
646
647	/**
648	 * Helper class with generic logic for a builder layout.
649	 *
650	 * @class FLBuilderLayout
651	 * @since 1.0
652	 */
653	FLBuilderLayout = {
654
655		/**
656		 * Initializes a builder layout.
657		 *
658		 * @since 1.0
659		 * @method init
660		 */
661		init: function()
662		{
663			// Destroy existing layout events.
664			FLBuilderLayout._destroy();
665
666			// Init CSS classes.
667			FLBuilderLayout._initClasses();
668
669			// Init backgrounds.
670			FLBuilderLayout._initBackgrounds();
671
672			// Init buttons.
673			FLBuilderLayout._initButtons();
674
675			// Init row shape layer height.
676			FLBuilderLayout._initRowShapeLayerHeight();
677
678			// Only init if the builder isn't active.
679			if ( 0 === $('.fl-builder-edit').length ) {
680
681				// Init anchor links.
682				FLBuilderLayout._initAnchorLinks();
683
684				// Init the browser hash.
685				FLBuilderLayout._initHash();
686
687				// Init forms.
688				FLBuilderLayout._initForms();
689
690				FLBuilderLayout._reorderMenu();
691			}
692			else {
693				FLBuilderLayout._initNestedColsWidth();
694			}
695			$('body').removeClass( 'fl-no-js' );
696		},
697
698		/**
699		 * Public method for refreshing Wookmark or MosaicFlow galleries
700		 * within an element.
701		 *
702		 * @since 1.7.4
703		 * @method refreshGalleries
704		 */
705		refreshGalleries: function( element )
706		{
707			var $element  = 'undefined' == typeof element ? $( 'body' ) : $( element ),
708				mfContent = $element.find( '.fl-mosaicflow-content' ),
709				wmContent = $element.find( '.fl-gallery' ),
710				mfObject  = null;
711
712			if ( mfContent ) {
713
714				mfObject = mfContent.data( 'mosaicflow' );
715
716				if ( mfObject ) {
717					mfObject.columns = $( [] );
718					mfObject.columnsHeights = [];
719					mfContent.data( 'mosaicflow', mfObject );
720					mfContent.mosaicflow( 'refill' );
721				}
722			}
723			if ( wmContent ) {
724				wmContent.trigger( 'refreshWookmark' );
725			}
726		},
727
728		/**
729		 * Public method for refreshing Masonry within an element
730		 *
731		 * @since 1.8.1
732		 * @method refreshGridLayout
733		 */
734		refreshGridLayout: function( element )
735		{
736			var $element 		= 'undefined' == typeof element ? $( 'body' ) : $( element ),
737				msnryContent	= $element.find('.masonry');
738
739			if ( msnryContent.length )	{
740				msnryContent.masonry('layout');
741			}
742		},
743
744		/**
745		 * Public method for reloading BxSlider within an element
746		 *
747		 * @since 1.8.1
748		 * @method reloadSlider
749		 */
750		reloadSlider: function( content )
751		{
752			var $content = 'undefined' == typeof content ? $('body') : $(content);
753
754			// reload sliders.
755			if ($content.find('.bx-viewport > div').length > 0) {
756				$.each($content.find('.bx-viewport > div'), function (key, slider) {
757					setTimeout(function () {
758						$(slider).data('bxSlider').reloadSlider();
759					}, 100);
760				});
761			}
762		},
763
764		/**
765		 * Public method for resizing WP audio player
766		 *
767		 * @since 1.8.2
768		 * @method resizeAudio
769		 */
770		resizeAudio: function( element )
771		{
772			var $element 	 	= 'undefined' == typeof element ? $( 'body' ) : $( element ),
773				audioPlayers 	= $element.find('.wp-audio-shortcode.mejs-audio'),
774				player 		 	= null,
775				mejsPlayer 	 	= null,
776				rail 			= null,
777				railWidth 		= 400;
778
779			if ( audioPlayers.length && typeof mejs !== 'undefined' ) {
780            	audioPlayers.each(function(){
781	            	player 		= $(this);
782	            	mejsPlayer 	= mejs.players[player.attr('id')];
783	            	rail 		= player.find('.mejs-controls .mejs-time-rail');
784	            	var innerMejs = player.find('.mejs-inner'),
785	            		total 	  = player.find('.mejs-controls .mejs-time-total');
786
787	            	if ( typeof mejsPlayer !== 'undefined' ) {
788	            		railWidth = Math.ceil(player.width() * 0.8);
789
790	            		if ( innerMejs.length ) {
791
792		            		rail.css('width', railWidth +'px!important');
793		            		//total.width(rail.width() - 10);
794
795		            		mejsPlayer.options.autosizeProgress = true;
796
797		            		// webkit has trouble doing this without a delay
798							setTimeout(function () {
799								mejsPlayer.setControlsSize();
800							}, 50);
801
802			            	player.find('.mejs-inner').css({
803			            		visibility: 'visible',
804			            		height: 'inherit'
805			            	});
806		            	}
807		           	}
808	            });
809	        }
810		},
811
812		/**
813		 * Public method for preloading WP audio player when it's inside the hidden element
814		 *
815		 * @since 1.8.2
816		 * @method preloadAudio
817		 */
818		preloadAudio: function(element)
819		{
820			var $element 	 = 'undefined' == typeof element ? $( 'body' ) : $( element ),
821				contentWrap  = $element.closest('.fl-accordion-item'),
822				audioPlayers = $element.find('.wp-audio-shortcode.mejs-audio');
823
824			if ( ! contentWrap.hasClass('fl-accordion-item-active') && audioPlayers.find('.mejs-inner').length ) {
825				audioPlayers.find('.mejs-inner').css({
826					visibility : 'hidden',
827					height: 0
828				});
829			}
830		},
831
832		/**
833		 * Public method for resizing slideshow momdule within the tab
834		 *
835		 * @since 1.10.5
836		 * @method resizeSlideshow
837		 */
838		resizeSlideshow: function(){
839			if(typeof YUI !== 'undefined') {
840				YUI().use('node-event-simulate', function(Y) {
841					Y.one(window).simulate("resize");
842				});
843			}
844		},
845
846		/**
847		 * Public method for reloading an embedded Google Map within the tabs or hidden element.
848		 *
849		 * @since 2.2
850		 * @method reloadGoogleMap
851		 */
852		reloadGoogleMap: function(element){
853			var $element  = 'undefined' == typeof element ? $( 'body' ) : $( element ),
854			    googleMap = $element.find( 'iframe[src*="google.com/maps"]' );
855
856			if ( googleMap.length ) {
857			    googleMap.attr( 'src', function(i, val) {
858			        return val;
859			    });
860			}
861		},
862
863		/**
864		 * Unbinds builder layout events.
865		 *
866		 * @since 1.0
867		 * @access private
868		 * @method _destroy
869		 */
870		_destroy: function()
871		{
872			var win = $(window);
873
874			win.off('scroll.fl-bg-parallax');
875			win.off('resize.fl-bg-video');
876		},
877
878		/**
879		 * Checks to see if the current device has touch enabled.
880		 *
881		 * @since 1.0
882		 * @access private
883		 * @method _isTouch
884		 * @return {Boolean}
885		 */
886		_isTouch: function()
887		{
888			if(('ontouchstart' in window) || (window.DocumentTouch && document instanceof DocumentTouch)) {
889				return true;
890			}
891
892			return false;
893		},
894
895		/**
896		 * Checks to see if the current device is mobile.
897		 *
898		 * @since 1.7
899		 * @access private
900		 * @method _isMobile
901		 * @return {Boolean}
902		 */
903		_isMobile: function()
904		{
905			return /Mobile|Android|Silk\/|Kindle|BlackBerry|Opera Mini|Opera Mobi|webOS/i.test( navigator.userAgent );
906		},
907
908		/**
909		 * Initializes builder body classes.
910		 *
911		 * @since 1.0
912		 * @access private
913		 * @method _initClasses
914		 */
915		_initClasses: function()
916		{
917			var body = $( 'body' ),
918				ua   = navigator.userAgent;
919
920			// Add the builder body class.
921			if ( ! body.hasClass( 'archive' ) && $( '.fl-builder-content-primary' ).length > 0 ) {
922				body.addClass('fl-builder');
923			}
924
925			// Add the builder touch body class.
926			if(FLBuilderLayout._isTouch()) {
927				body.addClass('fl-builder-touch');
928			}
929
930			// Add the builder mobile body class.
931			if(FLBuilderLayout._isMobile()) {
932				body.addClass('fl-builder-mobile');
933			}
934
935			if ( $(window).width() < FLBuilderLayoutConfig.breakpoints.small ) {
936				body.addClass( 'fl-builder-breakpoint-small' );
937			}
938
939			if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.small && $(window).width() < FLBuilderLayoutConfig.breakpoints.medium ) {
940				body.addClass( 'fl-builder-breakpoint-medium' );
941			}
942
943			if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.medium && $(window).width() < FLBuilderLayoutConfig.breakpoints.large ) {
944				body.addClass( 'fl-builder-breakpoint-large' );
945			}
946
947			if ( $(window).width() > FLBuilderLayoutConfig.breakpoints.large ) {
948				body.addClass( 'fl-builder-breakpoint-default' );
949			}
950
951			// IE11 body class.
952			if ( ua.indexOf( 'Trident/7.0' ) > -1 && ua.indexOf( 'rv:11.0' ) > -1 ) {
953				body.addClass( 'fl-builder-ie-11' );
954			}
955		},
956
957		/**
958		 * Initializes builder node backgrounds that require
959		 * additional JavaScript logic such as parallax.
960		 *
961		 * @since 1.1.4
962		 * @access private
963		 * @method _initBackgrounds
964		 */
965		_initBackgrounds: function()
966		{
967			var win = $(window);
968
969			// Init parallax backgrounds.
970			if($('.fl-row-bg-parallax').length > 0 && !FLBuilderLayout._isMobile()) {
971				FLBuilderLayout._scrollParallaxBackgrounds();
972				FLBuilderLayout._initParallaxBackgrounds();
973				win.on('resize.fl-bg-parallax', FLBuilderLayout._initParallaxBackgrounds);
974				win.on('scroll.fl-bg-parallax', FLBuilderLayout._scrollParallaxBackgrounds);
975			}
976
977			// Init video backgrounds.
978			if($('.fl-bg-video').length > 0) {
979				FLBuilderLayout._initBgVideos();
980				FLBuilderLayout._resizeBgVideos();
981
982				// Ensure FLBuilderLayout._resizeBgVideos() is only called once on window resize.
983				var resizeBGTimer = null;
984				win.on('resize.fl-bg-video', function(e){
985					clearTimeout( resizeBGTimer );
986					resizeBGTimer = setTimeout(function() {
987						FLBuilderLayout._resizeBgVideos(e);
988					}, 100 );
989				});
990			}
991		},
992
993		/**
994		 * Initializes all buttons in a layout.
995		 *
996		 * @since 2.10
997		 * @access private
998		 * @method _initButtons
999		 */
1000		_initButtons: function()
1001		{
1002			// Trigger click event on Enter or Space key press for deprecated button markup.
1003			$('a.fl-button[role="button"]').on('keydown', function(event) {
1004				if (event.key === 'Enter' || event.key === ' ') {
1005					// Necessary to prevent the default behavior of the space key from scrolling the page
1006					event.preventDefault();
1007					$(this).trigger('click');
1008				}
1009			});
1010		},
1011
1012		/**
1013		 * Initializes all parallax backgrounds in a layout.
1014		 *
1015		 * @since 1.1.4
1016		 * @access private
1017		 * @method _initParallaxBackgrounds
1018		 */
1019		_initParallaxBackgrounds: function()
1020		{
1021			$('.fl-row-bg-parallax').each(FLBuilderLayout._initParallaxBackground);
1022		},
1023
1024		/**
1025		 * Initializes a single parallax background.
1026		 *
1027		 * @since 1.1.4
1028		 * @access private
1029		 * @method _initParallaxBackgrounds
1030		 */
1031		_initParallaxBackground: function()
1032		{
1033			var row     = $(this),
1034				content = row.find('> .fl-row-content-wrap'),
1035				winWidth = $(window).width(),
1036				screenSize = '',
1037				imageSrc = {
1038					default: '',
1039					medium: '',
1040					responsive: '',
1041				};
1042
1043			imageSrc.default = row.data('parallax-image') || '';
1044			imageSrc.medium = row.data('parallax-image-medium') || imageSrc.default;
1045			imageSrc.responsive = row.data('parallax-image-responsive') || imageSrc.medium;
1046
1047			if (winWidth > FLBuilderLayoutConfig.breakpoints.medium) {
1048				screenSize = 'default';
1049			} else if (winWidth > FLBuilderLayoutConfig.breakpoints.small && winWidth <= FLBuilderLayoutConfig.breakpoints.medium ) {
1050				screenSize = 'medium';
1051			} else if (winWidth <= FLBuilderLayoutConfig.breakpoints.small) {
1052				screenSize = 'responsive';
1053			}
1054
1055			content.css('background-image', 'url(' + imageSrc[screenSize] + ')');
1056			row.data('current-image-loaded', screenSize );
1057
1058		},
1059
1060		/**
1061		 * Fires when the window is scrolled to adjust
1062		 * parallax backgrounds.
1063		 *
1064		 * @since 1.1.4
1065		 * @access private
1066		 * @method _scrollParallaxBackgrounds
1067		 */
1068		_scrollParallaxBackgrounds: function()
1069		{
1070			$('.fl-row-bg-parallax').each(FLBuilderLayout._scrollParallaxBackground);
1071		},
1072
1073		/**
1074		 * Fires when the window is scrolled to adjust
1075		 * a single parallax background.
1076		 *
1077		 * @since 1.1.4
1078		 * @access private
1079		 * @method _scrollParallaxBackground
1080		 */
1081		_scrollParallaxBackground: function()
1082		{
1083			var win     	  = $(window),
1084				row     	  = $(this),
1085				content 	  = row.find('> .fl-row-content-wrap'),
1086				speed   	  = row.data('parallax-speed'),
1087				offset  	  = content.offset(),
1088				yPos		  = -((win.scrollTop() - offset.top) / speed),
1089				initialOffset = ( row.data('parallax-offset') != null ) ? row.data('parallax-offset') : 0,
1090				totalOffset   = yPos - initialOffset;
1091
1092			content.css('background-position', 'center ' + totalOffset + 'px');
1093		},
1094
1095		/**
1096		 * Initializes all video backgrounds.
1097		 *
1098		 * @since 1.6.3.3
1099		 * @access private
1100		 * @method _initBgVideos
1101		 */
1102		_initBgVideos: function()
1103		{
1104			$('.fl-bg-video').each(FLBuilderLayout._initBgVideo);
1105		},
1106
1107		/**
1108		 * Initializes a video background.
1109		 *
1110		 * @since 1.6.3.3
1111		 * @access private
1112		 * @method _initBgVideo
1113		 */
1114		_initBgVideo: function()
1115		{
1116			var wrap   = $( this ),
1117				width       = wrap.data( 'width' ),
1118				height      = wrap.data( 'height' ),
1119				mp4         = wrap.data( 'mp4' ),
1120				youtube     = wrap.data( 'youtube'),
1121				vimeo       = wrap.data( 'vimeo'),
1122				mp4Type     = wrap.data( 'mp4-type' ),
1123				webm        = wrap.data( 'webm' ),
1124				webmType    = wrap.data( 'webm-type' ),
1125				fallback    = wrap.data( 'fallback' ),
1126				loaded      = wrap.data( 'loaded' ),
1127				videoMobile = wrap.data( 'video-mobile' ),
1128				playPauseButton = wrap.find('.fl-bg-video-play-pause-control'),
1129				fallbackTag = '',
1130				videoTag    = null,
1131				mp4Tag      = null,
1132				webmTag     = null;
1133
1134			// Return if the video has been loaded for this row.
1135			if ( loaded ) {
1136				return;
1137			}
1138
1139			videoTag  = $( '<video autoplay loop muted playsinline></video>' );
1140
1141			/**
1142			 * Add poster image (fallback image)
1143			 */
1144			if( 'undefined' != typeof fallback && '' != fallback ) {
1145				videoTag.attr( 'poster', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' )
1146				videoTag.css({
1147					backgroundImage: 'url("' + fallback + '")',
1148					backgroundColor: 'transparent',
1149					backgroundRepeat: 'no-repeat',
1150					backgroundSize: 'cover',
1151					backgroundPosition: 'center center',
1152				})
1153			}
1154
1155			// MP4 Source Tag
1156			if ( 'undefined' != typeof mp4 && '' != mp4 ) {
1157
1158				mp4Tag = $( '<source />' );
1159				mp4Tag.attr( 'src', mp4 );
1160				mp4Tag.attr( 'type', mp4Type );
1161
1162				videoTag.append( mp4Tag );
1163			}
1164			// WebM Source Tag
1165			if ( 'undefined' != typeof webm && '' != webm ) {
1166
1167				webmTag = $( '<source />' );
1168				webmTag.attr( 'src', webm );
1169				webmTag.attr( 'type', webmType );
1170
1171				videoTag.append( webmTag );
1172			}
1173
1174			// This is either desktop, or mobile is enabled.
1175			if ( ! FLBuilderLayout._isMobile() || ( FLBuilderLayout._isMobile() && "yes" == videoMobile ) ) {
1176				if ( 'undefined' != typeof youtube ) {
1177					FLBuilderLayout._initYoutubeBgVideo.apply( this );
1178				}
1179				else if ( 'undefined' != typeof vimeo ) {
1180					FLBuilderLayout._initVimeoBgVideo.apply( this );
1181				}
1182				else {
1183					wrap.append( videoTag );
1184
1185					if ( playPauseButton.length > 0 ) {
1186						var video = videoTag[0];
1187
1188						playPauseButton.on( 'click', { video: video }, function(e) {
1189							var video = e.data.video;
1190
1191							if ( video.paused ) {
1192								video.play();
1193							} else {
1194								video.pause();
1195							}
1196						} );
1197
1198						$( video ).on( 'play playing', function () {
1199							playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
1200						} );
1201						
1202						$( video ).on( 'pause ended waiting', function () {
1203							playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1204						} );
1205					}
1206				}
1207			}
1208			else {
1209				// if we are here, it means we are on mobile and NO is set so remove video src and use fallback
1210				videoTag.attr('src', '')
1211				wrap.append( videoTag );
1212			}
1213
1214			// Mark this video as loaded.
1215			wrap.data('loaded', true);
1216		},
1217
1218		/**
1219		 * Initializes Youtube video background
1220		 *
1221		 * @since 1.9
1222		 * @access private
1223		 * @method _initYoutubeBgVideo
1224		 */
1225		_initYoutubeBgVideo: function()
1226		{
1227			var playerWrap  = $(this),
1228				videoId     = playerWrap.data('video-id'),
1229				videoPlayer = playerWrap.find('.fl-bg-video-player'),
1230				enableAudio = playerWrap.data('enable-audio'),
1231				audioButton = playerWrap.find('.fl-bg-video-audio'),
1232				playPauseButton = playerWrap.find('.fl-bg-video-play-pause-control'),
1233				startTime   = 'undefined' !== typeof playerWrap.data('start') ? playerWrap.data('start') : 0,
1234				startTime   = 'undefined' !== typeof playerWrap.data('t') && startTime === 0 ? playerWrap.data('t') : startTime,
1235				endTime     = 'undefined' !== typeof playerWrap.data('end') ? playerWrap.data('end') : 0,
1236				loop        = 'undefined' !== typeof playerWrap.data('loop') ? playerWrap.data('loop') : 1,
1237				stateCount  = 0,
1238				player,fallback_showing;
1239
1240			if ( videoId ) {
1241				fallback = playerWrap.data('fallback') || false
1242				if( fallback ) {
1243					playerWrap.find('iframe').remove()
1244					fallbackTag = $( '<div></div>' );
1245					fallbackTag.addClass( 'fl-bg-video-fallback' );
1246					fallbackTag.css( 'background-image', 'url(' + playerWrap.data('fallback') + ')' );
1247					fallbackTag.css( 'background-size', 'cover' );
1248					fallbackTag.css( 'transition', 'background-image 1s')
1249					playerWrap.append( fallbackTag );
1250					fallback_showing = true;
1251				}
1252				FLBuilderLayout._onYoutubeApiReady( function( YT ) {
1253					setTimeout( function() {
1254
1255						player = new YT.Player( videoPlayer[0], {
1256							videoId: videoId,
1257							events: {
1258								onReady: function(event) {
1259									if ( "no" === enableAudio || FLBuilderLayout._isMobile() ) {
1260										event.target.mute();
1261									}
1262									else if ( "yes" === enableAudio && event.target.isMuted ) {
1263										event.target.unMute();
1264									}
1265
1266									// Store an instance to a parent
1267									playerWrap.data('YTPlayer', player);
1268									FLBuilderLayout._resizeYoutubeBgVideo.apply(playerWrap);
1269
1270									// Queue the video.
1271									event.target.playVideo();
1272
1273									if ( audioButton.length > 0 && ! FLBuilderLayout._isMobile() ) {
1274										audioButton.on( 'click', {button: audioButton, player: player}, FLBuilderLayout._toggleBgVideoAudio );
1275									}
1276
1277									if ( playPauseButton.length > 0 ) {
1278										playPauseButton.on( 'click', {player: player}, function(e) {
1279											var player = e.data.player;
1280			
1281											if ( 1 === player.getPlayerState() ) {
1282												player.pauseVideo();
1283											} else {
1284												player.playVideo();
1285											}
1286										});
1287									}
1288								},
1289								onStateChange: function( event ) {
1290
1291									if ( event.data === 1 ) {
1292										if ( fallback_showing ) {
1293											$( '.fl-bg-video-fallback' ).css( 'background-image', 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)' )
1294										}
1295									}
1296									// Manual check if video is not playable in some browsers.
1297									// StateChange order: [-1, 3, -1]
1298									if ( stateCount < 4 ) {
1299										stateCount++;
1300									}
1301
1302									// Comply with the audio policy in some browsers like Chrome and Safari.
1303									if ( stateCount > 1 && -1 === event.data && "yes" === enableAudio ) {
1304										player.mute();
1305										player.playVideo();
1306										audioButton.show();
1307									}
1308
1309									if ( event.data === YT.PlayerState.ENDED && 1 === loop ) {
1310										if ( startTime > 0 ) {
1311											player.seekTo( startTime );
1312										}
1313										else {
1314											player.playVideo();
1315										}
1316									}
1317
1318									if ( event.data === YT.PlayerState.PLAYING ) {
1319										playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
1320									} else if ( event.data === YT.PlayerState.PAUSED ) {
1321										playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1322									} else if ( event.data === YT.PlayerState.BUFFERING ) {
1323										playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
1324									} else if ( event.data === YT.PlayerState.CUED ) {
1325										playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1326									} else if ( event.data === YT.PlayerState.ENDED ) {
1327										playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1328									}
1329								},
1330								onError: function(event) {
1331									console.info('YT Error: ' + event.data)
1332									FLBuilderLayout._onErrorYoutubeVimeo(playerWrap)
1333								}
1334							},
1335							playerVars: {
1336								playsinline: FLBuilderLayout._isMobile() ? 1 : 0,
1337								controls: 0,
1338								showinfo: 0,
1339								rel : 0,
1340								start: startTime,
1341								end: endTime,
1342							}
1343						} );
1344					}, 1 );
1345				} );
1346			}
1347		},
1348
1349		/**
1350		 * On youtube or vimeo error show the fallback image if available.
1351		 * @since 2.0.7
1352		 */
1353		_onErrorYoutubeVimeo: function(playerWrap) {
1354
1355			fallback = playerWrap.data('fallback') || false
1356			if( ! fallback ) {
1357				return false;
1358			}
1359			playerWrap.find('iframe').remove()
1360			fallbackTag = $( '<div></div>' );
1361			fallbackTag.addClass( 'fl-bg-video-fallback' );
1362			fallbackTag.css( 'background-image', 'url(' + playerWrap.data('fallback') + ')' );
1363			playerWrap.append( fallbackTag );
1364		},
1365
1366		/**
1367		 * Check if Youtube API has been downloaded
1368		 *
1369		 * @since 1.9
1370		 * @access private
1371		 * @method _onYoutubeApiReady
1372		 * @param  {Function} callback Method to call when YT API has been loaded
1373		 */
1374		_onYoutubeApiReady: function( callback ) {
1375			if ( window.YT && YT.loaded ) {
1376				callback( YT );
1377			} else {
1378				// If not ready check again by timeout..
1379				setTimeout( function() {
1380					FLBuilderLayout._onYoutubeApiReady( callback );
1381				}, 350 );
1382			}
1383		},
1384
1385		/**
1386		 * Initializes Vimeo video background
1387		 *
1388		 * @since 1.9
1389		 * @access private
1390		 * @method _initVimeoBgVideo
1391		 */
1392		_initVimeoBgVideo: function()
1393		{
1394			var playerWrap	= $(this),
1395				videoId 	= playerWrap.data('video-id'),
1396				videoHash 	= playerWrap.data('video-hash'),
1397				videoPlayer = playerWrap.find('.fl-bg-video-player'),
1398				enableAudio = playerWrap.data('enable-audio'),
1399				audioButton = playerWrap.find('.fl-bg-video-audio'),
1400				playPauseButton = playerWrap.find('.fl-bg-video-play-pause-control'),
1401				playerState = '',
1402				player,
1403				width = playerWrap.outerWidth(),
1404				ua    = navigator.userAgent;
1405
1406			if ( typeof Vimeo !== 'undefined' && videoId )	{
1407				
1408				const vimOptions = {
1409					loop       : true,
1410					title      : false,
1411					portrait   : false,
1412					background : true,
1413					autopause  : false,
1414					muted      : true,
1415				};
1416
1417				if ( videoHash.length ) {
1418					vimOptions.url = `https://player.vimeo.com/video/${ videoId }?h=${ videoHash }`;
1419				} else {
1420					vimOptions.id = videoId;
1421				}
1422
1423				player = new Vimeo.Player(videoPlayer[0], vimOptions );
1424				playerWrap.data('VMPlayer', player);
1425				if ( "no" === enableAudio ) {
1426					player.setVolume(0);
1427				}
1428				else if ("yes" === enableAudio ) {
1429					// Chrome, Safari, Firefox have audio policy restrictions for autoplay videos.
1430					if ( ua.indexOf("Safari") > -1 || ua.indexOf("Chrome") > -1 || ua.indexOf("Firefox") > -1 ) {
1431						player.setVolume(0);
1432						audioButton.show();
1433					}
1434					else {
1435						player.setVolume(1);
1436					}
1437				}
1438
1439				player.play().catch(function(error) {
1440					FLBuilderLayout._onErrorYoutubeVimeo(playerWrap)
1441				});
1442
1443				if ( audioButton.length > 0 ) {
1444					audioButton.on( 'click', {button: audioButton, player: player}, FLBuilderLayout._toggleBgVideoAudio );
1445				}
1446
1447				player.on( 'play', function() {
1448					playerState = 'play';
1449					playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
1450				} );
1451				player.on( 'pause', function() {
1452					playerState = 'pause';
1453					playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1454				} );
1455				player.on( 'ended', function() {
1456					playerState = 'ended';
1457					playPauseButton.removeClass( 'fa-pause' ).addClass( 'fa-play' );
1458				} );
1459				player.on( 'bufferstart', function() {
1460					playerState = 'bufferstart';
1461					playPauseButton.removeClass( 'fa-play' ).addClass( 'fa-pause' );
1462				} );
1463
1464				if ( playPauseButton.length > 0 ) {
1465					playPauseButton.on( 'click', { player: player }, function( e ) {
1466						var player = e.data.player;
1467
1468						if ( playerState === 'play' ) {
1469							player.pause();
1470						} else {
1471							player.play();
1472						}
1473					} );
1474				}
1475			}
1476		},
1477
1478		/**
1479		 * Mute / unmute audio on row's video background.
1480		 * It works for both Youtube and Vimeo.
1481		 *
1482		 * @since 2.1.3
1483		 * @access private
1484		 * @method _toggleBgVideoAudio
1485		 * @param {Object} e Method arguments
1486		 */
1487		_toggleBgVideoAudio: function( e ) {
1488			var player  = e.data.player,
1489			    control = e.data.button.find('.fl-audio-control');
1490
1491			if ( control.hasClass( 'fa-volume-off' ) ) {
1492				// Unmute
1493				control
1494					.removeClass( 'fa-volume-off' )
1495					.addClass( 'fa-volume-up' );
1496				e.data.button.find( '.fa-times' ).hide();
1497
1498				if ( 'function' === typeof player.unMute ) {
1499					player.unMute();
1500				}
1501				else {
1502					player.setVolume( 1 );
1503				}
1504			}
1505			else {
1506				// Mute
1507				control
1508					.removeClass( 'fa-volume-up' )
1509					.addClass( 'fa-volume-off' );
1510				e.data.button.find( '.fa-times' ).show();
1511
1512				if ( 'function' === typeof player.unMute ) {
1513					player.mute();
1514				}
1515				else {
1516					player.setVolume( 0 );
1517				}
1518			}
1519		},
1520
1521		/**
1522		 * Fires when there is an error loading a video
1523		 * background source and shows the fallback.
1524		 *
1525		 * @since 1.6.3.3
1526		 * @access private
1527		 * @method _videoBgSourceError
1528		 * @param {Object} e An event object
1529		 * @deprecated 2.0.3
1530		 */
1531		_videoBgSourceError: function( e )
1532		{
1533			var source 		= $( e.target ),
1534				wrap   		= source.closest( '.fl-bg-video' ),
1535				vid		    = wrap.find( 'video' ),
1536				fallback  	= wrap.data( 'fallback' ),
1537				fallbackTag = '';
1538			source.remove();
1539
1540			if ( vid.find( 'source' ).length ) {
1541				// Don't show the fallback if we still have other sources to check.
1542				return;
1543			} else if ( '' !== fallback ) {
1544				fallbackTag = $( '<div></div>' );
1545				fallbackTag.addClass( 'fl-bg-video-fallback' );
1546				fallbackTag.css( 'background-image', 'url(' + fallback + ')' );
1547				wrap.append( fallbackTag );
1548				vid.remove();
1549			}
1550		},
1551
1552		/**
1553		 * Fires when the window is resized to resize
1554		 * all video backgrounds.
1555		 *
1556		 * @since 1.1.4
1557		 * @access private
1558		 * @method _resizeBgVideos
1559		 */
1560		_resizeBgVideos: function()
1561		{
1562			$('.fl-bg-video').each( function() {
1563
1564				FLBuilderLayout._resizeBgVideo.apply( this );
1565
1566				if ( $( this ).parent().find( 'img' ).length > 0 ) {
1567					$( this ).parent().imagesLoaded( $.proxy( FLBuilderLayout._resizeBgVideo, this ) );
1568				}
1569			} );
1570		},
1571
1572		/**
1573		 * Fires when the window is resized to resize
1574		 * a single video background.
1575		 *
1576		 * @since 1.1.4
1577		 * @access private
1578		 * @method _resizeBgVideo
1579		 */
1580		_resizeBgVideo: function()
1581		{
1582			if ( 0 === $( this ).find( 'video' ).length && 0 === $( this ).find( 'iframe' ).length ) {
1583				return;
1584			}
1585
1586			var wrap        = $(this),
1587				wrapHeight  = wrap.outerHeight(),
1588				wrapWidth   = wrap.outerWidth(),
1589				vid         = wrap.find('video'),
1590				vidHeight   = wrap.data('height'),
1591				vidWidth    = wrap.data('width'),
1592				newWidth    = wrapWidth,
1593				newHeight   = Math.round(vidHeight * wrapWidth/vidWidth),
1594				newLeft     = 0,
1595				newTop      = 0,
1596				iframe 		= wrap.find('iframe'),
1597				isRowFullHeight = $(this).closest('.fl-row-bg-video').hasClass('fl-row-full-height'),
1598				vidCSS          = {
1599					top:       '50%',
1600					left:      '50%',
1601					transform: 'translate(-50%,-50%)',
1602				};
1603
1604			if ( vid.length ) {
1605				if(vidHeight === '' || typeof vidHeight === 'undefined' || vidWidth === '' || typeof vidWidth === 'undefined') {
1606					vid.css({
1607						'left'      : '0px',
1608						'top'       : '0px',
1609						'width'     : newWidth + 'px'
1610					});
1611
1612					// Try to set the actual video dimension on 'loadedmetadata' when using URL as video source
1613					vid.on('loadedmetadata', FLBuilderLayout._resizeOnLoadedMeta);
1614
1615					return;
1616				}
1617
1618				if ( ! isRowFullHeight ) {
1619					if ( newHeight < wrapHeight ) {
1620						newHeight = wrapHeight;
1621						newLeft   = -((newWidth - wrapWidth) / 2);
1622						newWidth  = vidHeight ? Math.round(vidWidth * wrapHeight/vidHeight) : newWidth;
1623					}
1624					else {
1625						newTop = -((newHeight - wrapHeight)/2);
1626					}
1627					vidCSS = {
1628						left   : newLeft + 'px',
1629						top    : newTop + 'px',
1630						height : newHeight + 'px',
1631						width  : newWidth + 'px',
1632					}
1633				}
1634
1635				vid.css( vidCSS );
1636
1637			}
1638			else if ( iframe.length ) {
1639
1640				// Resize Youtube video player within iframe tag
1641				if ( typeof wrap.data('youtube') !== 'undefined' ) {
1642					FLBuilderLayout._resizeYoutubeBgVideo.apply(this);
1643				}
1644			}
1645		},
1646
1647		/**
1648		 * Fires when video meta has been loaded.
1649		 * This will be Triggered when width/height attributes were not specified during video background resizing.
1650		 *
1651		 * @since 1.8.5
1652		 * @access private
1653		 * @method _resizeOnLoadedMeta
1654		 */
1655		_resizeOnLoadedMeta: function(){
1656			var video 		= $(this),
1657				wrapHeight 	= video.parent().outerHeight(),
1658				wrapWidth 	= video.parent().outerWidth(),
1659				vidWidth 	= video[0].videoWidth,
1660				vidHeight 	= video[0].videoHeight,
1661				newHeight   = Math.round(vidHeight * wrapWidth/vidWidth),
1662				newWidth    = wrapWidth,
1663				newLeft     = 0,
1664				newTop 		= 0;
1665
1666			if(newHeight < wrapHeight) {
1667				newHeight   = wrapHeight;
1668				newWidth    = Math.round(vidWidth * wrapHeight/vidHeight);
1669				newLeft     = -((newWidth - wrapWidth)/2);
1670			}
1671			else {
1672				newTop      = -((newHeight - wrapHeight)/2);
1673			}
1674
1675			video.parent().data('width', vidWidth);
1676			video.parent().data('height', vidHeight);
1677
1678			video.css({
1679				'left'      : newLeft + 'px',
1680				'top'       : newTop + 'px',
1681				'width'     : newWidth + 'px',
1682				'height' 	: newHeight + 'px'
1683			});
1684		},
1685
1686		/**
1687		 * Fires when the window is resized to resize
1688		 * a single Youtube video background.
1689		 *
1690		 * @since 1.9
1691		 * @access private
1692		 * @method _resizeYoutubeBgVideo
1693		 */
1694		_resizeYoutubeBgVideo: function()
1695		{
1696			var wrap				= $(this),
1697				wrapWidth 			= wrap.outerWidth(),
1698				wrapHeight 			= wrap.outerHeight(),
1699				player 				= wrap.data('YTPlayer'),
1700				video 				= player ? player.getIframe() : null,
1701				aspectRatioSetting 	= '16:9', // Medium
1702				aspectRatioArray 	= aspectRatioSetting.split( ':' ),
1703				aspectRatio 		= aspectRatioArray[0] / aspectRatioArray[1],
1704				ratioWidth 			= wrapWidth / aspectRatio,
1705				ratioHeight 		= wrapHeight * aspectRatio,
1706				isWidthFixed 		= wrapWidth / wrapHeight > aspectRatio,
1707				width 				= isWidthFixed ? wrapWidth : ratioHeight,
1708				height 				= isWidthFixed ? ratioWidth : wrapHeight;
1709
1710			if ( video ) {
1711				$(video).width( width ).height( height );
1712			}
1713		},
1714
1715		/**
1716		 * Opens a tab or accordion item if the browser hash is set
1717		 * to the ID of one on the page.
1718		 *
1719		 * @since 1.6.0
1720		 * @access private
1721		 * @method _initHash
1722		 */
1723		_initHash: function()
1724		{
1725			var hash 			= window.location.hash.replace( '#', '' ).split( '/' ).shift(),
1726				element 		= null,
1727				tabs			= null,
1728				responsiveLabel	= null,
1729				tabIndex		= null,
1730				label			= null;
1731
1732			if ( '' !== hash ) {
1733
1734				try {
1735
1736					element = $( '#' + hash );
1737
1738					if ( element.length > 0 ) {
1739
1740						if ( element.hasClass( 'fl-accordion-item' ) ) {
1741							setTimeout( function() {
1742								element.find( '.fl-accordion-button' ).trigger( 'click' );
1743							}, 100 );
1744						}
1745						if ( element.hasClass( 'fl-tabs-panel' ) ) {
1746							setTimeout( function() {
1747								tabs 			= element.closest( '.fl-tabs' );
1748								responsiveLabel = element.find( '.fl-tabs-panel-label' );
1749								tabIndex 		= responsiveLabel.data( 'index' );
1750								label 			= tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' );
1751
1752								label[0].click();
1753								FLBuilderLayout._scrollToElement(element);
1754							}, 100 );
1755						}
1756					}
1757				}
1758				catch( e ) {}
1759			}
1760		},
1761
1762		/**
1763		 * Initializes all anchor links on the page for smooth scrolling.
1764		 *
1765		 * @since 1.4.9
1766		 * @access private
1767		 * @method _initAnchorLinks
1768		 */
1769		_initAnchorLinks: function()
1770		{
1771			$( 'a' ).each( FLBuilderLayout._initAnchorLink );
1772		},
1773
1774		/**
1775		 * Initializes a single anchor link for smooth scrolling.
1776		 *
1777		 * @since 1.4.9
1778		 * @access private
1779		 * @method _initAnchorLink
1780		 */
1781		_initAnchorLink: function()
1782		{
1783			var link    = $( this ),
1784				href    = link.attr( 'href' ),
1785				loc     = window.location,
1786				id      = null,
1787				element = null,
1788				flNode  = false;
1789
1790			if ( 'undefined' != typeof href && href.indexOf( '#' ) > -1 && link.closest('svg').length < 1 ) {
1791
1792				if ( loc.pathname.replace( /^\//, '' ) == this.pathname.replace( /^\//, '' ) && loc.hostname == this.hostname ) {
1793
1794					try {
1795
1796						id      = href.split( '#' ).pop();
1797						// If there is no ID then we have nowhere to look
1798						// Fixes a quirk in jQuery and FireFox
1799						if( ! id ) {
1800							return;
1801						}
1802						element = $( '#' + id );
1803
1804						if ( element.length > 0 ) {
1805							flNode = element.hasClass( 'fl-row' ) || element.hasClass( 'fl-col' ) || element.hasClass( 'fl-module' );
1806							if ( !element.hasClass( 'fl-no-scroll' ) && ( link.hasClass( 'fl-scroll-link' ) || flNode ) ) {
1807								$( link ).on( 'click', FLBuilderLayout._scrollToElementOnLinkClick );
1808							}
1809							if ( element.hasClass( 'fl-accordion-item' ) ) {
1810								$( link ).on( 'click', FLBuilderLayout._scrollToAccordionOnLinkClick );
1811							}
1812							if ( element.hasClass( 'fl-tabs-panel' ) ) {
1813								$( link ).on( 'click', FLBuilderLayout._scrollToTabOnLinkClick );
1814							}
1815						}
1816					}
1817					catch( e ) {}
1818				}
1819			}
1820		},
1821
1822		/**
1823		 * Scrolls to an element when an anchor link is clicked.
1824		 *
1825		 * @since 1.4.9
1826		 * @access private
1827		 * @method _scrollToElementOnLinkClick
1828		 * @param {Object} e An event object.
1829		 * @param {Function} callback A function to call when the scroll is complete.
1830		 */
1831		_scrollToElementOnLinkClick: function( e, callback )
1832		{
1833			var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() );
1834
1835			FLBuilderLayout._scrollToElement( element, callback );
1836
1837			e.preventDefault();
1838		},
1839
1840		/**
1841		 * Scrolls to an element.
1842		 *
1843		 * @since 1.6.4.5
1844		 * @access private
1845		 * @method _scrollToElement
1846		 * @param {Object} element The element to scroll to.
1847		 * @param {Function} callback A function to call when the scroll is complete.
1848		 */
1849		_scrollToElement: function( element, callback )
1850		{
1851			var config  = FLBuilderLayoutConfig.anchorLinkAnimations,
1852				dest    = 0,
1853				win     = $( window ),
1854				doc     = $( document );
1855
1856			if ( element.length > 0 ) {
1857
1858				if ( 'fixed' === element.css('position') || 'fixed' === element.parent().css('position') ) {
1859					dest = element.position().top;
1860				}
1861				else if ( element.offset().top > doc.height() - win.height() ) {
1862					dest = doc.height() - win.height();
1863				}
1864				else {
1865					dest = element.offset().top - config.offset;
1866				}
1867
1868				$( 'html, body' ).stop( true ).animate( { scrollTop: dest }, config.duration, config.easing, function() {
1869
1870					if ( 'undefined' != typeof callback ) {
1871						callback();
1872					}
1873
1874					if ( undefined != element.attr( 'id' ) && window.location.hash !== '#' + element.attr( 'id' ) ) {
1875
1876						var firefox_version = window.navigator.userAgent.match( /Firefox\/(\d+)\./ ),
1877							firefox_version = firefox_version ? parseInt( firefox_version[1], 10 ) : null;
1878
1879						if ( firefox_version !== null && firefox_version < 135 ) {
1880							window.location.hash = element.attr( 'id' );
1881						} else {
1882							if ( history.pushState ) {
1883								history.pushState( null, null, '#' + element.attr( 'id' ) );
1884							} else {
1885								window.location.hash = element.attr( 'id' );
1886							}
1887						}
1888					}
1889				} );
1890			}
1891		},
1892
1893		/**
1894		 * Scrolls to an accordion item when a link is clicked.
1895		 *
1896		 * @since 1.5.9
1897		 * @access private
1898		 * @method _scrollToAccordionOnLinkClick
1899		 * @param {Object} e An event object.
1900		 */
1901		_scrollToAccordionOnLinkClick: function( e )
1902		{
1903			var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() );
1904
1905			if ( element.length > 0 ) {
1906
1907				var callback = function() {
1908					if ( element ) {
1909						element.find( '.fl-accordion-button' ).trigger( 'click' );
1910						element = false;
1911					}
1912				};
1913
1914				FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback );
1915			}
1916		},
1917
1918		/**
1919		 * Scrolls to a tab panel when a link is clicked.
1920		 *
1921		 * @since 1.5.9
1922		 * @access private
1923		 * @method _scrollToTabOnLinkClick
1924		 * @param {Object} e An event object.
1925		 */
1926		_scrollToTabOnLinkClick: function( e )
1927		{
1928			var element 		= $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() ),
1929				tabs			= null,
1930				label   		= null,
1931				responsiveLabel = null;
1932
1933			if ( element.length > 0 ) {
1934
1935				tabs 			= element.closest( '.fl-tabs' );
1936				responsiveLabel = element.find( '.fl-tabs-panel-label' );
1937				tabIndex 		= responsiveLabel.data( 'index' );
1938				label 			= tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' );
1939
1940				if ( responsiveLabel.is( ':visible' ) ) {
1941
1942					var callback = function() {
1943						if ( element ) {
1944							responsiveLabel.trigger( $.Event( 'click', { which: 1 } ) );
1945						}
1946					};
1947
1948					FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback );
1949				}
1950				else {
1951					label[0].click();
1952					FLBuilderLayout._scrollToElement( element );
1953				}
1954
1955				e.preventDefault();
1956			}
1957		},
1958
1959		/**
1960		 * Initializes all builder forms on a page.
1961		 *
1962		 * @since 1.5.4
1963		 * @access private
1964		 * @method _initForms
1965		 */
1966		_initForms: function()
1967		{
1968			if ( ! FLBuilderLayout._hasPlaceholderSupport ) {
1969				$( '.fl-form-field input' ).each( FLBuilderLayout._initFormFieldPlaceholderFallback );
1970			}
1971
1972			$( '.fl-form-field input' ).on( 'focus', FLBuilderLayout._clearFormFieldError );
1973		},
1974
1975		/**
1976		 * Checks to see if the current device has HTML5
1977		 * placeholder support.
1978		 *
1979		 * @since 1.5.4
1980		 * @access private
1981		 * @method _hasPlaceholderSupport
1982		 * @return {Boolean}
1983		 */
1984		_hasPlaceholderSupport: function()
1985		{
1986			var input = document.createElement( 'input' );
1987
1988			return 'undefined' != input.placeholder;
1989		},
1990
1991		/**
1992		 * Initializes the fallback for when placeholders aren't supported.
1993		 *
1994		 * @since 1.5.4
1995		 * @access private
1996		 * @method _initFormFieldPlaceholderFallback
1997		 */
1998		_initFormFieldPlaceholderFallback: function()
1999		{
2000			var field       = $( this ),
2001				val         = field.val(),
2002				placeholder = field.attr( 'placeholder' );
2003
2004			if ( 'undefined' != placeholder && '' === val ) {
2005				field.val( placeholder );
2006				field.on( 'focus', FLBuilderLayout._hideFormFieldPlaceholderFallback );
2007				field.on( 'blur', FLBuilderLayout._showFormFieldPlaceholderFallback );
2008			}
2009		},
2010
2011		/**
2012		 * Hides a fallback placeholder on focus.
2013		 *
2014		 * @since 1.5.4
2015		 * @access private
2016		 * @method _hideFormFieldPlaceholderFallback
2017		 */
2018		_hideFormFieldPlaceholderFallback: function()
2019		{
2020			var field       = $( this ),
2021				val         = field.val(),
2022				placeholder = field.attr( 'placeholder' );
2023
2024			if ( val == placeholder ) {
2025				field.val( '' );
2026			}
2027		},
2028
2029		/**
2030		 * Shows a fallback placeholder on blur.
2031		 *
2032		 * @since 1.5.4
2033		 * @access private
2034		 * @method _showFormFieldPlaceholderFallback
2035		 */
2036		_showFormFieldPlaceholderFallback: function()
2037		{
2038			var field       = $( this ),
2039				val         = field.val(),
2040				placeholder = field.attr( 'placeholder' );
2041
2042			if ( '' === val ) {
2043				field.val( placeholder );
2044			}
2045		},
2046
2047		/**
2048		 * Clears a form field error message.
2049		 *
2050		 * @since 1.5.4
2051		 * @access private
2052		 * @method _clearFormFieldError
2053		 */
2054		_clearFormFieldError: function()
2055		{
2056			var field = $( this );
2057
2058			field.removeAttr( 'aria-invalid' );
2059			field.removeClass( 'fl-form-error' );
2060			const message = field.attr('aria-describedby');
2061			message ? $( '#' + message ).hide() : field.siblings( '.fl-form-error-message' ).hide();
2062		},
2063
2064		/**
2065		 * Init Row Shape Layer's height.
2066		 *
2067		 * @since 2.5.3
2068		 * @access private
2069		 * @method _initRowShapeLayerHeight
2070		 */
2071		_initRowShapeLayerHeight: function () {
2072			FLBuilderLayout._adjustRowShapeLayerHeight();
2073			$( window ).on( 'resize', FLBuilderLayout._adjustRowShapeLayerHeight );
2074		},
2075
2076		/**
2077		 * Set parent column width of nested columns when it's zero or blank.
2078		 *
2079		 * @since 2.7.4
2080		 * @access private
2081		 * @method _initNestedColsWidth
2082		 */
2083		_initNestedColsWidth: function()
2084		{
2085			var nestedCols = $( '.fl-col-has-cols' );
2086
2087			if ( nestedCols.length <= 0 ) {
2088				return;
2089			}
2090
2091			$( nestedCols ).each( function(index, col ){
2092				if ( $( col ).width() <= 0 ) {
2093					$( col ).css( 'width', FLBuilderLayoutConfig.emptyColWidth );
2094				}
2095			});
2096		},
2097
2098		/**
2099		 * Adjust Row Shape Layer's height to fix to remove the fine line that appears on certain screen sizes.
2100		 *
2101		 * @since 2.5.3
2102		 * @access private
2103		 * @method _adjustRowShapeLayerHeight
2104		 */
2105		_adjustRowShapeLayerHeight: function() {
2106			var rowShapeLayers = $('.fl-builder-shape-layer');
2107
2108			$( rowShapeLayers ).each(function (index) {
2109				var rowShapeLayer = $(this),
2110					shape = $(rowShapeLayer).find('svg'),
2111					height = shape.height(),
2112					excludeShapes = '.fl-builder-shape-circle, .fl-builder-shape-dot-cluster, .fl-builder-shape-topography, .fl-builder-shape-rect';
2113
2114				if ( ! rowShapeLayer.is( excludeShapes ) ) {
2115					$(shape).css('height', Math.ceil( height ) );
2116				}
2117			});
2118		},
2119		_string_to_slug: function( str ) {
2120			str = str.replace(/^\s+|\s+$/g, ''); // trim
2121			if ( 'undefined' == typeof window._fl_string_to_slug_regex ) {
2122				regex = new RegExp('[^a-zA-Z0-9\'":() !.,-_|]', 'g');
2123			} else {
2124				regex = new RegExp('[^' + window._fl_string_to_slug_regex + '\'":\(\) !.,-_|\\\p{Letter}]', 'ug');
2125			}
2126			str = str.replace(regex, '') // remove invalid chars
2127				.replace(/\s+/g, ' '); // collapse whitespace and replace by a space
2128			return str;
2129		},
2130		_reorderMenu: function() {
2131			if ( $('#wp-admin-bar-fl-builder-frontend-edit-link-default li').length > 1 ) {
2132					$( '#wp-admin-bar-fl-builder-frontend-duplicate-link' )
2133					.appendTo('#wp-admin-bar-fl-builder-frontend-edit-link-default')
2134					.css( 'padding-top', '5px' )
2135					.css( 'border-top', '2px solid #1D2125' )
2136					.css( 'margin-top', '5px' )
2137				}
2138		}
2139	};
2140
2141	/* Initializes the builder layout. */
2142	$(function(){
2143		FLBuilderLayout.init();
2144	});
2145
2146})(jQuery);
2147(function($){
2148
2149	if(typeof FLBuilderLayoutModules !== 'undefined') {
2150		return;
2151	}
2152
2153	/**
2154	 * Helper class with generic logic for builder modules.
2155	 * If generic module code needs to work in both the block
2156	 * editor and builder, it should go here. Otherwise, it
2157	 * should go on FLBuilderLayout.
2158	 *
2159	 * @since 2.9
2160	 */
2161	FLBuilderLayoutModules = {
2162
2163		/**
2164		 * Initializes builder module logic.
2165		 *
2166		 * @since 2.9
2167		 * @method init
2168		 */
2169		init: function()
2170		{
2171			// Only init if the builder isn't active.
2172			if ( 0 === $('.fl-builder-edit').length ) {
2173
2174				// Init module animations.
2175				FLBuilderLayoutModules._initModuleAnimations();
2176			}
2177		},
2178
2179		/**
2180		 * Initializes module animations.
2181		 *
2182		 * @since 1.1.9
2183		 * @access private
2184		 * @method _initModuleAnimations
2185		 */
2186		_initModuleAnimations: function()
2187		{
2188			if(typeof jQuery.fn.waypoint !== 'undefined') {
2189				$('.fl-animation').each( function() {
2190					var node = $( this ),
2191						nodeTop = node.offset().top,
2192						winHeight = $( window ).height(),
2193						bodyHeight = $( 'body' ).height(),
2194						waypoint = FLBuilderLayoutConfig.waypoint,
2195						offset = '80%';
2196
2197					if ( typeof waypoint.offset !== undefined ) {
2198						offset = FLBuilderLayoutConfig.waypoint.offset + '%';
2199					}
2200
2201					if ( bodyHeight - nodeTop < winHeight * 0.2 ) {
2202						offset = '100%';
2203					}
2204
2205					node.waypoint({
2206						offset: offset,
2207						handler: FLBuilderLayoutModules._doModuleAnimation
2208					});
2209				} );
2210			}
2211		},
2212
2213		/**
2214		 * Runs a module animation.
2215		 *
2216		 * @since 1.1.9
2217		 * @access private
2218		 * @method _doModuleAnimation
2219		 */
2220		_doModuleAnimation: function()
2221		{
2222			var module = 'undefined' == typeof this.element ? $(this) : $(this.element),
2223				delay = parseFloat(module.data('animation-delay')),
2224				duration = parseFloat(module.data('animation-duration'));
2225
2226			if ( ! isNaN( duration ) ) {
2227				module.css( 'animation-duration', duration + 's' );
2228			}
2229
2230			if(!isNaN(delay) && delay > 0) {
2231				setTimeout(function(){
2232					module.addClass('fl-animated');
2233				}, delay * 1000);
2234			} else {
2235				setTimeout(function(){
2236					module.addClass('fl-animated');
2237				}, 1);
2238			}
2239		}
2240	};
2241
2242	/* Initializes builder module logic. */
2243	$(function(){
2244		FLBuilderLayoutModules.init();
2245	});
2246
2247})(jQuery);
2248
2249/* Start Global JS */
2250
2251/* End Global JS */
2252
2253
2254;/**
2255 * This file should contain frontend logic for 
2256 * all module instances.
2257 */(function($) {
2258	$('.fl-node-fiyrcmq7g5np .pp-hover-card').each( function() {
2259		$( this ).on( 'focus', function() {
2260			$( this ).addClass( 'focus' );
2261		} ).on( 'blur', function(e) {
2262			if ( $( e.relatedTarget ).closest( this ).length > 0 ) {
2263				return;
2264			}
2265			$( this ).removeClass( 'focus' );
2266		} );
2267	});
2268
2269	$( document ).on( 'click focus keyup', function(e) {
2270		if ( $(e.target).closest( '.fl-node-fiyrcmq7g5np .pp-hover-card' ).length > 0 ) {
2271        	return;
2272		}
2273		$('.fl-node-fiyrcmq7g5np .pp-hover-card').removeClass('focus');
2274	} );
2275})(jQuery);(function($) {
2276	$('.fl-node-6fnm9zdvoclq .pp-hover-card').each( function() {
2277		$( this ).on( 'focus', function() {
2278			$( this ).addClass( 'focus' );
2279		} ).on( 'blur', function(e) {
2280			if ( $( e.relatedTarget ).closest( this ).length > 0 ) {
2281				return;
2282			}
2283			$( this ).removeClass( 'focus' );
2284		} );
2285	});
2286
2287	$( document ).on( 'click focus keyup', function(e) {
2288		if ( $(e.target).closest( '.fl-node-6fnm9zdvoclq .pp-hover-card' ).length > 0 ) {
2289        	return;
2290		}
2291		$('.fl-node-6fnm9zdvoclq .pp-hover-card').removeClass('focus');
2292	} );
2293})(jQuery);(function($) {
2294	$('.fl-node-gzsc3on4dfr7 .pp-hover-card').each( function() {
2295		$( this ).on( 'focus', function() {
2296			$( this ).addClass( 'focus' );
2297		} ).on( 'blur', function(e) {
2298			if ( $( e.relatedTarget ).closest( this ).length > 0 ) {
2299				return;
2300			}
2301			$( this ).removeClass( 'focus' );
2302		} );
2303	});
2304
2305	$( document ).on( 'click focus keyup', function(e) {
2306		if ( $(e.target).closest( '.fl-node-gzsc3on4dfr7 .pp-hover-card' ).length > 0 ) {
2307        	return;
2308		}
2309		$('.fl-node-gzsc3on4dfr7 .pp-hover-card').removeClass('focus');
2310	} );
2311})(jQuery);(function($) {
2312	$('.fl-node-4yrtdupebnc6 .pp-hover-card').each( function() {
2313		$( this ).on( 'focus', function() {
2314			$( this ).addClass( 'focus' );
2315		} ).on( 'blur', function(e) {
2316			if ( $( e.relatedTarget ).closest( this ).length > 0 ) {
2317				return;
2318			}
2319			$( this ).removeClass( 'focus' );
2320		} );
2321	});
2322
2323	$( document ).on( 'click focus keyup', function(e) {
2324		if ( $(e.target).closest( '.fl-node-4yrtdupebnc6 .pp-hover-card' ).length > 0 ) {
2325        	return;
2326		}
2327		$('.fl-node-4yrtdupebnc6 .pp-hover-card').removeClass('focus');
2328	} );
2329})(jQuery);(function($) {
2330	$('.fl-node-49k6v53numwe .pp-hover-card').each( function() {
2331		$( this ).on( 'focus', function() {
2332			$( this ).addClass( 'focus' );
2333		} ).on( 'blur', function(e) {
2334			if ( $( e.relatedTarget ).closest( this ).length > 0 ) {
2335				return;
2336			}
2337			$( this ).removeClass( 'focus' );
2338		} );
2339	});
2340
2341	$( document ).on( 'click focus keyup', function(e) {
2342		if ( $(e.target).closest( '.fl-node-49k6v53numwe .pp-hover-card' ).length > 0 ) {
2343        	return;
2344		}
2345		$('.fl-node-49k6v53numwe .pp-hover-card').removeClass('focus');
2346	} );
2347})(jQuery);
2348;( function( $ ) {
2349
2350	UABBSubscribeFormModule = function( settings )
2351	{
2352		this.settings	= settings;
2353		this.nodeClass	= '.fl-node-' + settings.id;
2354		this.form 		= $( this.nodeClass + ' .uabb-subscribe-form' );
2355		this.button		= this.form.find( 'a.uabb-button' );
2356		this.btn_width	= settings.btn_width;
2357		this.btn_padding = settings.btn_padding;
2358		this.layout = settings.layout;
2359		this._init();
2360	};
2361
2362	UABBSubscribeFormModule.prototype = {
2363	
2364		settings	: {},
2365		nodeClass	: '',
2366		form		: null,
2367		button		: null,
2368		
2369		_init: function()
2370		{
2371			this.button.on( 'click', $.proxy( this._submitForm, this ) );
2372			var form = $( '.uabb-form-wrap' ),
2373				inputFName = form.find( 'input[name=uabb-subscribe-form-fname]' ),
2374				inputLName = form.find( 'input[name=uabb-subscribe-form-lname]' ),
2375				inputEmail = form.find( 'input[name=uabb-subscribe-form-email]' );
2376
2377				inputFName.on('focusout', this._focusOut);
2378				inputLName.on('focusout', this._focusOut);
2379				inputEmail.on('focusout', this._focusOut);
2380
2381				inputFName.on('focus', this._removeErrorClass);
2382				inputLName.on('focus', this._removeErrorClass);
2383				inputEmail.on('focus', this._removeErrorClass);
2384
2385			if( this.btn_width != 'custom' && this.layout == 'inline' ) {
2386				var height = $( this.nodeClass + ' .uabb-form-field input[type=text]' ).outerHeight(true),
2387					line_height = ( height - ( 2 * this.btn_padding ) );
2388				$( this.nodeClass + ' .uabb-form-button a' ).css( 'height', height );
2389				$( this.nodeClass + ' .uabb-form-button a' ).css( 'line-height', line_height + 'px' );
2390			}
2391
2392			const $scope = jQuery(".uabb-subscribe-form"); 
2393			const inputs = $scope.find(".uabb-terms-checkbox-sf");
2394
2395			inputs.each(function () {
2396				const input = jQuery(this);
2397
2398				input.on("focus", function () {
2399					const label = jQuery(`label[for="${this.id}"]`);
2400					if (label.length) {
2401						label.addClass("uabb-sf-checkbox-focus");
2402					}
2403				});
2404
2405				input.on("blur", function () {
2406					const label = jQuery(`label[for="${this.id}"]`);
2407					if (label.length) {
2408						label.removeClass("uabb-sf-checkbox-focus");
2409					}
2410				});
2411
2412			});
2413		},
2414
2415		_focusOut: function( e ) {
2416			if( $( this ).val().length !== 0 ) {
2417				$( this ).parent().addClass( 'open' );
2418			} else {
2419				$( this ).parent().removeClass( 'open' );
2420			}
2421		},
2422		
2423		_removeErrorClass: function(){
2424			$( this ).removeClass('uabb-form-error');
2425		},
2426
2427		_submitForm: function( e )
2428		{
2429			var submitButton		= $( e.currentTarget ),
2430				currentForm     	= submitButton.closest( '.uabb-subscribe-form' ),
2431				postId      		= currentForm.closest( '.fl-builder-content' ).data( 'post-id' ),
2432				templateId 	        = currentForm.data( 'template-id' ),
2433				templateNodeId		= currentForm.data( 'template-node-id' ),
2434				nodeId      		= currentForm.closest( '.fl-module' ).data( 'node' ),
2435				buttonText  		= submitButton.find( '.uabb-button-text' ).text(),
2436				waitText    		= submitButton.closest( '.uabb-form-button' ).data( 'wait-text' ),
2437				fname        		= currentForm.find( 'input[name=uabb-subscribe-form-fname]' ),
2438				lname        		= currentForm.find( 'input[name=uabb-subscribe-form-lname]' ),
2439				email       		= currentForm.find( 'input[name=uabb-subscribe-form-email]' ),
2440				termsCheckbox   	= currentForm.find( 'input[name=uabb-terms-checkbox]'),
2441				_nonce              = currentForm.find( '.uabb-form-wrap' ).data('nonce'),
2442				re          		= /\S+@\S+\.\S+/,
2443				valid       		= true;
2444
2445			e.preventDefault();
2446
2447			if ( submitButton.hasClass( 'uabb-form-button-disabled' ) ) {
2448				return; // Already submitting
2449			}
2450			/*if ( name.length > 0 && name.val() == '' ) {
2451				name.addClass( 'uabb-form-error' );
2452				name.siblings( '.uabb-form-error-message' ).show();
2453				valid = false;
2454			}*/
2455			if ( '' == email.val() || ! re.test( email.val() ) ) {
2456				email.addClass( 'uabb-form-error' );
2457				email.siblings( '.uabb-form-error-message' ).show();
2458				valid = false;
2459			}
2460
2461			if ( termsCheckbox.val() ) {
2462				if ( ! termsCheckbox.is(':checked') ) {
2463					valid = false;
2464					termsCheckbox.closest('.uabb-terms-wrap').addClass( 'uabb-form-error' );
2465					termsCheckbox.parent().siblings( '.uabb-form-error-message' ).show();
2466				}
2467				else {
2468					termsCheckbox.removeClass( 'uabb-form-error-message' );
2469					termsCheckbox.parent().siblings( '.uabb-form-error-message' ).hide();
2470				}
2471			}
2472			
2473			if ( valid ) {
2474				
2475				currentForm.find( '> .uabb-form-error-message' ).hide();
2476				submitButton.find( '.uabb-button-text' ).text( waitText );
2477				submitButton.data( 'original-text', buttonText );
2478				submitButton.addClass( 'uabb-form-button-disabled' );
2479				
2480					ajaxData = {
2481					action  			: 'uabb_subscribe_form_submit',
2482					security            : _nonce,
2483					lname    			: lname.val(),
2484					fname    			: fname.val(),
2485					email   			: email.val(),
2486					post_id 			: postId,
2487					template_id 		: templateId,
2488					template_node_id 	: templateNodeId,
2489					node_id 			: nodeId
2490				};
2491
2492				$.post( FLBuilderLayoutConfig.paths.wpAjaxUrl, ajaxData, $.proxy( function( response ){
2493					this._submitFormComplete( response, submitButton );
2494				}, this ));
2495
2496			}
2497		},
2498		
2499		_submitFormComplete: function( response , button )
2500		{
2501
2502			var data        = response,
2503				buttonText  = button.data( 'original-text' ),
2504				form        = button.closest( '.uabb-subscribe-form' );
2505			if ( data.error ) {
2506				
2507				form.find( '> .uabb-form-error-message' ).text( data.error );
2508				form.find( '> .uabb-form-error-message' ).show();
2509				button.removeClass( 'uabb-form-button-disabled' );
2510				button.find( '.uabb-button-text' ).text( buttonText );
2511			} else {
2512				
2513				button.removeClass( 'uabb-form-button-disabled' );
2514				button.find( '.uabb-button-text' ).text( buttonText );
2515				if ( 'message' == data.action ) {
2516					form.find( '> *' ).hide();
2517					form.append( '<div class="fl-form-success-message">' + data.message + '</div>' );
2518				}
2519				else if ( 'redirect' == data.action ) {
2520					window.location.href = data.url;
2521				}
2522			}
2523
2524		}
2525	}
2526	
2527})( jQuery );
2528(function($) {
2529
2530	$(function() {
2531		jQuery( document ).ready(function($) {
2532			new UABBSubscribeFormModule({
2533				id: 'i5fyaos0k8w3',
2534				btn_width: 'auto',
2535				btn_padding: '12',
2536				layout: 'stacked',
2537			});
2538		});
2539
2540	});
2541})(jQuery);
2542
2543/* Start Global Node Custom JS */
2544
2545/* End Global Node Custom JS */
2546
2547
2548/* Start Layout Custom JS */
2549
2550/* End Layout Custom JS */
2551

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.