PageSourceSearch

https://peprofessional.com/wp-content/uploads/bb-plugin/cache/2327…?ver=307b93d6271e7515ae2b261fc415992d

js peprofessional.com collected 2026-09-25 02:38:35 UTC 62,333 bytes, 2,266 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://peprofessional.com/wp-admin/admin-ajax.php';var flBuilderUrl = 'https://peprofessional.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://peprofessional.com/wp-content/plugins/bb-plugin/',
630		wpAjaxUrl : 'https://peprofessional.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 (skip on block-only frontend to avoid layout break).
921			if ( ! body.hasClass( 'fl-builder-blocks-only' ) && ! 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, [role="link"]' ).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.data( 'url' ) ? link.data( 'url' ) : link.attr( 'href' ),
1785				target  = link.data( 'url' ) ? new URL( href, window.location.href ) : this,
1786				loc     = window.location,
1787				id      = null,
1788				element = null,
1789				flNode  = false;
1790
1791			if ( 'undefined' != typeof href && href.indexOf( '#' ) > -1 && link.closest('svg').length < 1 ) {
1792
1793				if ( loc.pathname.replace( /^\//, '' ) == target.pathname.replace( /^\//, '' ) && loc.hostname == target.hostname ) {
1794
1795					try {
1796
1797						id      = href.split( '#' ).pop();
1798						// If there is no ID then we have nowhere to look
1799						// Fixes a quirk in jQuery and FireFox
1800						if( ! id ) {
1801							return;
1802						}
1803						element = $( '#' + id );
1804
1805						if ( element.length > 0 ) {
1806							flNode = element.hasClass( 'fl-row' ) || element.hasClass( 'fl-col' ) || element.hasClass( 'fl-module' );
1807							if ( !element.hasClass( 'fl-no-scroll' ) && ( link.hasClass( 'fl-scroll-link' ) || flNode ) ) {
1808								$( link ).on( 'click', FLBuilderLayout._scrollToElementOnLinkClick );
1809							}
1810							if ( element.hasClass( 'fl-accordion-item' ) ) {
1811								$( link ).on( 'click', FLBuilderLayout._scrollToAccordionOnLinkClick );
1812							}
1813							if ( element.hasClass( 'fl-tabs-panel' ) ) {
1814								$( link ).on( 'click', FLBuilderLayout._scrollToTabOnLinkClick );
1815							}
1816						}
1817					}
1818					catch( e ) {}
1819				}
1820			}
1821		},
1822
1823		/**
1824		 * Scrolls to an element when an anchor link is clicked.
1825		 *
1826		 * @since 1.4.9
1827		 * @access private
1828		 * @method _scrollToElementOnLinkClick
1829		 * @param {Object} e An event object.
1830		 * @param {Function} callback A function to call when the scroll is complete.
1831		 */
1832		_scrollToElementOnLinkClick: function( e, callback )
1833		{
1834			var attribute = $( this ).data( 'url' ) ? $( this ).data( 'url' ) : $( this ).attr( 'href' );
1835			var element = $( '#' + attribute.split( '#' ).pop() );
1836
1837			FLBuilderLayout._scrollToElement( element, callback );
1838
1839			e.preventDefault();
1840		},
1841
1842		/**
1843		 * Scrolls to an element.
1844		 *
1845		 * @since 1.6.4.5
1846		 * @access private
1847		 * @method _scrollToElement
1848		 * @param {Object} element The element to scroll to.
1849		 * @param {Function} callback A function to call when the scroll is complete.
1850		 */
1851		_scrollToElement: function( element, callback )
1852		{
1853			var config  = FLBuilderLayoutConfig.anchorLinkAnimations,
1854				dest    = 0,
1855				win     = $( window ),
1856				doc     = $( document );
1857
1858			if ( element.length > 0 ) {
1859
1860				if ( 'fixed' === element.css('position') || 'fixed' === element.parent().css('position') ) {
1861					dest = element.position().top;
1862				}
1863				else if ( element.offset().top > doc.height() - win.height() ) {
1864					dest = doc.height() - win.height();
1865				}
1866				else {
1867					dest = element.offset().top - config.offset;
1868				}
1869
1870				$( 'html, body' ).stop( true ).animate( { scrollTop: dest }, config.duration, config.easing, function() {
1871
1872					if ( 'undefined' != typeof callback ) {
1873						callback();
1874					}
1875
1876					if ( undefined != element.attr( 'id' ) && window.location.hash !== '#' + element.attr( 'id' ) ) {
1877
1878						var firefox_version = window.navigator.userAgent.match( /Firefox\/(\d+)\./ ),
1879							firefox_version = firefox_version ? parseInt( firefox_version[1], 10 ) : null;
1880
1881						if ( firefox_version !== null && firefox_version < 135 ) {
1882							window.location.hash = element.attr( 'id' );
1883						} else {
1884							if ( history.pushState ) {
1885								history.pushState( null, null, '#' + element.attr( 'id' ) );
1886							} else {
1887								window.location.hash = element.attr( 'id' );
1888							}
1889						}
1890					}
1891				} );
1892			}
1893		},
1894
1895		/**
1896		 * Scrolls to an accordion item when a link is clicked.
1897		 *
1898		 * @since 1.5.9
1899		 * @access private
1900		 * @method _scrollToAccordionOnLinkClick
1901		 * @param {Object} e An event object.
1902		 */
1903		_scrollToAccordionOnLinkClick: function( e )
1904		{
1905			var element = $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() );
1906
1907			if ( element.length > 0 ) {
1908
1909				var callback = function() {
1910					if ( element ) {
1911						element.find( '.fl-accordion-button' ).trigger( 'click' );
1912						element = false;
1913					}
1914				};
1915
1916				FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback );
1917			}
1918		},
1919
1920		/**
1921		 * Scrolls to a tab panel when a link is clicked.
1922		 *
1923		 * @since 1.5.9
1924		 * @access private
1925		 * @method _scrollToTabOnLinkClick
1926		 * @param {Object} e An event object.
1927		 */
1928		_scrollToTabOnLinkClick: function( e )
1929		{
1930			var element 		= $( '#' + $( this ).attr( 'href' ).split( '#' ).pop() ),
1931				tabs			= null,
1932				label   		= null,
1933				responsiveLabel = null;
1934
1935			if ( element.length > 0 ) {
1936
1937				tabs 			= element.closest( '.fl-tabs' );
1938				responsiveLabel = element.find( '.fl-tabs-panel-label' );
1939				tabIndex 		= responsiveLabel.data( 'index' );
1940				label 			= tabs.find( '.fl-tabs-labels .fl-tabs-label[data-index=' + tabIndex + ']' );
1941
1942				if ( responsiveLabel.is( ':visible' ) ) {
1943
1944					var callback = function() {
1945						if ( element ) {
1946							responsiveLabel.trigger( $.Event( 'click', { which: 1 } ) );
1947						}
1948					};
1949
1950					FLBuilderLayout._scrollToElementOnLinkClick.call( this, e, callback );
1951				}
1952				else {
1953					label[0].click();
1954					FLBuilderLayout._scrollToElement( element );
1955				}
1956
1957				e.preventDefault();
1958			}
1959		},
1960
1961		/**
1962		 * Initializes all builder forms on a page.
1963		 *
1964		 * @since 1.5.4
1965		 * @access private
1966		 * @method _initForms
1967		 */
1968		_initForms: function()
1969		{
1970			if ( ! FLBuilderLayout._hasPlaceholderSupport ) {
1971				$( '.fl-form-field input' ).each( FLBuilderLayout._initFormFieldPlaceholderFallback );
1972			}
1973
1974			$( '.fl-form-field input' ).on( 'focus', FLBuilderLayout._clearFormFieldError );
1975		},
1976
1977		/**
1978		 * Checks to see if the current device has HTML5
1979		 * placeholder support.
1980		 *
1981		 * @since 1.5.4
1982		 * @access private
1983		 * @method _hasPlaceholderSupport
1984		 * @return {Boolean}
1985		 */
1986		_hasPlaceholderSupport: function()
1987		{
1988			var input = document.createElement( 'input' );
1989
1990			return 'undefined' != input.placeholder;
1991		},
1992
1993		/**
1994		 * Initializes the fallback for when placeholders aren't supported.
1995		 *
1996		 * @since 1.5.4
1997		 * @access private
1998		 * @method _initFormFieldPlaceholderFallback
1999		 */
2000		_initFormFieldPlaceholderFallback: function()
2001		{
2002			var field       = $( this ),
2003				val         = field.val(),
2004				placeholder = field.attr( 'placeholder' );
2005
2006			if ( 'undefined' != placeholder && '' === val ) {
2007				field.val( placeholder );
2008				field.on( 'focus', FLBuilderLayout._hideFormFieldPlaceholderFallback );
2009				field.on( 'blur', FLBuilderLayout._showFormFieldPlaceholderFallback );
2010			}
2011		},
2012
2013		/**
2014		 * Hides a fallback placeholder on focus.
2015		 *
2016		 * @since 1.5.4
2017		 * @access private
2018		 * @method _hideFormFieldPlaceholderFallback
2019		 */
2020		_hideFormFieldPlaceholderFallback: function()
2021		{
2022			var field       = $( this ),
2023				val         = field.val(),
2024				placeholder = field.attr( 'placeholder' );
2025
2026			if ( val == placeholder ) {
2027				field.val( '' );
2028			}
2029		},
2030
2031		/**
2032		 * Shows a fallback placeholder on blur.
2033		 *
2034		 * @since 1.5.4
2035		 * @access private
2036		 * @method _showFormFieldPlaceholderFallback
2037		 */
2038		_showFormFieldPlaceholderFallback: function()
2039		{
2040			var field       = $( this ),
2041				val         = field.val(),
2042				placeholder = field.attr( 'placeholder' );
2043
2044			if ( '' === val ) {
2045				field.val( placeholder );
2046			}
2047		},
2048
2049		/**
2050		 * Clears a form field error message.
2051		 *
2052		 * @since 1.5.4
2053		 * @access private
2054		 * @method _clearFormFieldError
2055		 */
2056		_clearFormFieldError: function()
2057		{
2058			var field = $( this );
2059
2060			field.removeAttr( 'aria-invalid' );
2061			field.removeClass( 'fl-form-error' );
2062			const message = field.attr('aria-describedby');
2063			message ? $( '#' + message ).hide() : field.siblings( '.fl-form-error-message' ).hide();
2064		},
2065
2066		/**
2067		 * Init Row Shape Layer's height.
2068		 *
2069		 * @since 2.5.3
2070		 * @access private
2071		 * @method _initRowShapeLayerHeight
2072		 */
2073		_initRowShapeLayerHeight: function () {
2074			FLBuilderLayout._adjustRowShapeLayerHeight();
2075			$( window ).on( 'resize', FLBuilderLayout._adjustRowShapeLayerHeight );
2076		},
2077
2078		/**
2079		 * Set parent column width of nested columns when it's zero or blank.
2080		 *
2081		 * @since 2.7.4
2082		 * @access private
2083		 * @method _initNestedColsWidth
2084		 */
2085		_initNestedColsWidth: function()
2086		{
2087			var nestedCols = $( '.fl-col-has-cols' );
2088
2089			if ( nestedCols.length <= 0 ) {
2090				return;
2091			}
2092
2093			$( nestedCols ).each( function(index, col ){
2094				if ( $( col ).width() <= 0 ) {
2095					$( col ).css( 'width', FLBuilderLayoutConfig.emptyColWidth );
2096				}
2097			});
2098		},
2099
2100		/**
2101		 * Adjust Row Shape Layer's height to fix to remove the fine line that appears on certain screen sizes.
2102		 *
2103		 * @since 2.5.3
2104		 * @access private
2105		 * @method _adjustRowShapeLayerHeight
2106		 */
2107		_adjustRowShapeLayerHeight: function() {
2108			var rowShapeLayers = $('.fl-builder-shape-layer');
2109
2110			$( rowShapeLayers ).each(function (index) {
2111				var rowShapeLayer = $(this),
2112					shape = $(rowShapeLayer).find('svg'),
2113					height = shape.height(),
2114					excludeShapes = '.fl-builder-shape-circle, .fl-builder-shape-dot-cluster, .fl-builder-shape-topography, .fl-builder-shape-rect';
2115
2116				if ( ! rowShapeLayer.is( excludeShapes ) ) {
2117					$(shape).css('height', Math.ceil( height ) );
2118				}
2119			});
2120		},
2121		_string_to_slug: function( str ) {
2122			str = str.replace(/^\s+|\s+$/g, ''); // trim
2123			if ( 'undefined' == typeof window._fl_string_to_slug_regex ) {
2124				regex = new RegExp('[^a-zA-Z0-9\'":() !.,-_|]', 'g');
2125			} else {
2126				regex = new RegExp('[^' + window._fl_string_to_slug_regex + '\'":\(\) !.,-_|\\\p{Letter}]', 'ug');
2127			}
2128			str = str.replace(regex, '') // remove invalid chars
2129				.replace(/\s+/g, ' '); // collapse whitespace and replace by a space
2130			return str;
2131		},
2132		_reorderMenu: function() {
2133			if ( $('#wp-admin-bar-fl-builder-frontend-edit-link-default li').length > 1 ) {
2134					$( '#wp-admin-bar-fl-builder-frontend-duplicate-link' )
2135					.appendTo('#wp-admin-bar-fl-builder-frontend-edit-link-default')
2136					.css( 'padding-top', '5px' )
2137					.css( 'border-top', '2px solid #1D2125' )
2138					.css( 'margin-top', '5px' )
2139				}
2140		}
2141	};
2142
2143	/* Initializes the builder layout. */
2144	$(function(){
2145		FLBuilderLayout.init();
2146	});
2147
2148})(jQuery);
2149(function($){
2150
2151	if(typeof FLBuilderLayoutModules !== 'undefined') {
2152		return;
2153	}
2154
2155	/**
2156	 * Helper class with generic logic for builder modules.
2157	 * If generic module code needs to work in both the block
2158	 * editor and builder, it should go here. Otherwise, it
2159	 * should go on FLBuilderLayout.
2160	 *
2161	 * @since 2.9
2162	 */
2163	FLBuilderLayoutModules = {
2164
2165		/**
2166		 * Initializes builder module logic.
2167		 *
2168		 * @since 2.9
2169		 * @method init
2170		 */
2171		init: function()
2172		{
2173			// Only init if the builder isn't active.
2174			if ( 0 === $('.fl-builder-edit').length ) {
2175
2176				// Init module animations.
2177				FLBuilderLayoutModules._initModuleAnimations();
2178			}
2179		},
2180
2181		/**
2182		 * Initializes module animations.
2183		 *
2184		 * @since 1.1.9
2185		 * @access private
2186		 * @method _initModuleAnimations
2187		 */
2188		_initModuleAnimations: function()
2189		{
2190			if(typeof jQuery.fn.waypoint !== 'undefined') {
2191				$('.fl-animation').each( function() {
2192					var node = $( this ),
2193						nodeTop = node.offset().top,
2194						winHeight = $( window ).height(),
2195						bodyHeight = $( 'body' ).height(),
2196						waypoint = FLBuilderLayoutConfig.waypoint,
2197						offset = '80%';
2198
2199					if ( typeof waypoint.offset !== undefined ) {
2200						offset = FLBuilderLayoutConfig.waypoint.offset + '%';
2201					}
2202
2203					if ( bodyHeight - nodeTop < winHeight * 0.2 ) {
2204						offset = '100%';
2205					}
2206
2207					node.waypoint({
2208						offset: offset,
2209						handler: FLBuilderLayoutModules._doModuleAnimation
2210					});
2211				} );
2212			}
2213		},
2214
2215		/**
2216		 * Runs a module animation.
2217		 *
2218		 * @since 1.1.9
2219		 * @access private
2220		 * @method _doModuleAnimation
2221		 */
2222		_doModuleAnimation: function()
2223		{
2224			var module = 'undefined' == typeof this.element ? $(this) : $(this.element),
2225				delay = parseFloat(module.data('animation-delay')),
2226				duration = parseFloat(module.data('animation-duration'));
2227
2228			if ( ! isNaN( duration ) ) {
2229				module.css( 'animation-duration', duration + 's' );
2230			}
2231
2232			if(!isNaN(delay) && delay > 0) {
2233				setTimeout(function(){
2234					module.addClass('fl-animated');
2235				}, delay * 1000);
2236			} else {
2237				setTimeout(function(){
2238					module.addClass('fl-animated');
2239				}, 1);
2240			}
2241		}
2242	};
2243
2244	/* Initializes builder module logic. */
2245	$(function(){
2246		FLBuilderLayoutModules.init();
2247	});
2248
2249})(jQuery);
2250
2251/* Start Global JS */
2252
2253/* End Global JS */
2254
2255(function($){
2256	})(jQuery);
2257
2258/* Start Global Node Custom JS */
2259
2260/* End Global Node Custom JS */
2261
2262
2263/* Start Layout Custom JS */
2264
2265/* End Layout Custom JS */
2266

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.