PageSourceSearch

https://www.maeoe.org/wp-content/uploads/bb-plugin/cache/3776-layout.js?ver=55ecb182ce9cc60aaa63ddbd100338b4

js maeoe.org collected 2026-09-24 09:47:50 UTC 70,448 bytes, 2,472 lines download raw bytes

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

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.