// global sekFrontLocalized, nimbleListenTo window.nb_ = {}; // Jquery agnostic (function(w, d){ window.nb_ = { isArray : function(obj) { return Array.isArray(obj) || toString.call(obj) === '[object Array]'; }, inArray : function(obj, value) { if ( !nb_.isArray(obj) || nb_.isUndefined(value) ) return false; return obj.indexOf(value) > -1; }, isUndefined : function(obj) { return obj === void 0; }, isObject : function(obj) { var type = typeof obj; return type === 'function' || type === 'object' && !!obj; }, // safe console log for errorLog : function() { //fix for IE, because console is only defined when in F12 debugging mode in IE if ( nb_.isUndefined( console ) || 'function' != typeof window.console.log ) return; console.log.apply(console,arguments); }, hasPreloadSupport : function( browser ) { var link = document.createElement('link'); var relList = link.relList; if (!relList || !relList.supports) return false; return relList.supports('preload'); }, listenTo : function( evt, func ) { // store it, so if the event has been emitted before the listener is fired, we know it's been emitted nb_.eventsListenedTo.push(evt); var canWeFireCallbackForEvent = { 'nb-jquery-loaded' : function() { return typeof undefined !== typeof jQuery; }, 'nb-app-ready' : function() { return ( typeof undefined !== typeof window.nb_ ) && nb_.wasListenedTo('nb-jquery-loaded'); }, 'nb-swipebox-parsed' : function() { return ( typeof undefined !== typeof jQuery ) && ( typeof undefined !== typeof jQuery.fn.swipebox ); }, 'nb-main-swiper-parsed' : function() { return typeof undefined !== typeof window.Swiper; } }; // e is the event object passed // it is possible to add params but we need to use new CustomEvent with a polyfill for IE // see : https://stackoverflow.com/questions/18613456/trigger-event-with-parameters var _executeAndLog = function(e) { if ( !nb_.isUndefined(canWeFireCallbackForEvent[evt]) && false === canWeFireCallbackForEvent[evt]() ) { nb_.errorLog('Nimble error => an event callback could not be fired because conditions not met => ', evt, nb_.eventsListenedTo, func ); return; } func(); // // store it, so if the event has been emitted before the listener is fired, we know it's been emitted // nb_.eventsListenedTo.push(evt); }; // if the event requires a condition to be executed let's check it // if the event has alreay been listened to, let's fire the func, otherwise wait for its emission if ( 'function' === typeof func ) { if ( nb_.wasEmitted(evt) ) { _executeAndLog(); } else { document.addEventListener(evt,_executeAndLog); } } else { nb_.errorLog('Nimble error => listenTo func param is not a function for event => ', evt ); } }, eventsEmitted : [], eventsListenedTo : [], // @param params { fire_once : false } // fire_once is used in nb_.maybeLoadAssetsWhenSelectorInScreen() emit : function(evt, params ) { var _fire_once = nb_.isUndefined( params ) || params.fire_once; if ( _fire_once && nb_.wasEmitted(evt) ) return; // it is possible to add params when dispatching the event, but we need to use new CustomEvent with a polyfill for IE // see : https://stackoverflow.com/questions/18613456/trigger-event-with-parameters var _evt = document.createEvent('Event'); _evt.initEvent(evt, true, true); //can bubble, and is cancellable document.dispatchEvent(_evt); nb_.eventsEmitted.push(evt); }, wasListenedTo : function( evt ) { return ('string' === typeof evt) && nb_.inArray( nb_.eventsListenedTo, evt ); }, wasEmitted : function( evt ) { return ('string' === typeof evt) && nb_.inArray( nb_.eventsEmitted, evt ); }, // https://stackoverflow.com/questions/5353934/check-if-element-is-visible-on-screen isInScreen : function(el) { if ( !nb_.isObject( el ) ) return false; var rect = el.getBoundingClientRect(), viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight); return !(rect.bottom < 0 || rect.top - viewHeight >= 0); }, isCustomizing : function() { return true == ''; }, isLazyLoadEnabled : function() { return !nb_.isCustomizing() && true == ''; }, // params = { // id : 'nb-animate-css', // as : 'style', // href : "", // onEvent : 'nb-docready', // scriptEl : document.currentScript, // eventOnLoad : 'animate-css-loaded' // } // About preloading : rel="preload" tells the browser to start loading an important assets in priority // example : // - load late-discovered resources early // - early loading of fonts // NB asset strategy : // - use rel="preload" for webfonts like Font Awesome ( stylesheet + fonts ) // - use defer attribute for all javascript files( see https://flaviocopes.com/javascript-async-defer/ ) "The best thing to do to speed up your page loading when using scripts is to put them in the head, and add a defer attribute to your script tag:" // see https://www.smashingmagazine.com/2016/02/preload-what-is-it-good-for/ preloadOrDeferAsset : function(params) { params = params || {}; // bail if preloaded already ? nb_.preloadedAssets = nb_.preloadedAssets || []; if ( nb_.inArray( nb_.preloadedAssets, params.id ) ) return; var headTag = document.getElementsByTagName('head')[0], link, _injectFinalAsset = function() { var link = this; // this is the link element if ( 'style' === params.as ) { link.setAttribute('rel', 'stylesheet'); link.setAttribute('type', 'text/css'); link.setAttribute('media', 'all'); } else { var _script = document.createElement("script"); _script.setAttribute('src', params.href ); _script.setAttribute('id', params.id ); if ( 'script' === params.as ) { _script.setAttribute('defer', 'defer'); } headTag.appendChild(_script); // clean the loader link _maybeRemoveScriptEl.call(link); } if ( params.eventOnLoad ) { nb_.emit( params.eventOnLoad ); } }, _maybeRemoveScriptEl = function() { var _el = this; if ( _el && _el.parentNode && _el.parentNode.contains(_el) ) { try{_el.parentNode.removeChild(_el);} catch(er) { nb_.errorLog('NB error when removing a script el', el); } } }; // terminate here in the case of a font preload when preload not supported if ( 'font' === params.as && !nb_.hasPreloadSupport() ) return; link = document.createElement('link'); // script without preload support if ( 'script' === params.as ) { if ( params.onEvent ) { nb_.listenTo( params.onEvent, function() { _injectFinalAsset.call(link); }); } else { _injectFinalAsset.call(link); } } else { // script, font and stylesheet link.setAttribute('href', params.href); if ( 'style' === params.as ) { link.setAttribute('rel', nb_.hasPreloadSupport() ? 'preload' : 'stylesheet' ); } else if ( 'font' === params.as && nb_.hasPreloadSupport() ) { link.setAttribute('rel', 'preload' ); } link.setAttribute('id', params.id ); link.setAttribute('as', params.as); // attributes specific to fonts if ( 'font' === params.as ) { link.setAttribute('type', params.type); link.setAttribute('crossorigin', 'anonymous'); } // watch load events link.onload = function() { this.onload=null; // if this is a font, let's only check if an event is scheduled on load if ( 'font' === params.as ) { if ( params.eventOnLoad ) { nb_.emit( params.eventOnLoad ); } // nothing left to do if this is a font. It can now be used by the stylesheet return; } if ( params.onEvent ) { nb_.listenTo( params.onEvent, function() { _injectFinalAsset.call(link); }); } else { _injectFinalAsset.call(link); } }; link.onerror = function(er) { nb_.errorLog('Nimble preloadOrDeferAsset error', er, params ); }; } // append link now headTag.appendChild(link); // store the asset as done nb_.preloadedAssets.push( params.id ); // clean the script element from which preload has been requested _maybeRemoveScriptEl.call(params.scriptEl); }, mayBeRevealBG : function() { var imgSrc = this.getAttribute('data-sek-src'); if ( imgSrc ) { this.setAttribute( 'style', 'background-image:url("' + this.getAttribute('data-sek-src') +'")' ); this.className += ' sek-lazy-loaded';//<= so we don't parse it twice when lazyload is active // clean css loader var css_loaders = this.querySelectorAll('.sek-css-loader'); css_loaders.forEach( function(_cssl) { if ( nb_.isObject(_cssl) ) { _cssl.parentNode.removeChild(_cssl); } }); } } };//window.nb_ // forEach not supported by IE // This polyfill adds compatibility to all Browsers supporting ES5: if (window.NodeList && !NodeList.prototype.forEach) { NodeList.prototype.forEach = function (callback, thisArg) { thisArg = thisArg || window; for (var i = 0; i < this.length; i++) { callback.call(thisArg, this[i], i, this); } }; } // maybe reveal bg images on dom ready // if lazyload is not loaded yet, and container is visible // Sept 2020 : if lazyload disabled, make sure all background get revealed // because background are always printed as data-sek-src attribute for a level, lazyload or not, and therefore need to be inlined styled with javascript nb_.listenTo('nb-docready', function() { var matches = document.querySelectorAll('div.sek-has-bg'); if ( !nb_.isObject( matches ) || matches.length < 1 ) return; var imgSrc; matches.forEach( function(el) { if ( !nb_.isObject(el) ) return; if ( window.sekFrontLocalized && window.sekFrontLocalized.lazyload_enabled ) { if ( nb_.isInScreen(el) ) { nb_.mayBeRevealBG.call(el); } } else { nb_.mayBeRevealBG.call(el); } }); }); // Add an internal document ready listener the jquery way // Catch cases where $(document).ready() is called // after the browser event has already occurred. // Support: IE <=9 - 10 only // Older IE sometimes signals "interactive" too soon if ( document.readyState === "complete" || ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { nb_.emit('nb-docready'); } else { var _docReady = function() { if ( !nb_.wasEmitted('nb-docready') ) { nb_.emit('nb-docready'); } }; // Use the handy event callback document.addEventListener( "DOMContentLoaded", _docReady ); // A fallback to window.onload, that will always work window.addEventListener( "load", _docReady ); } }(window, document )); // introduced for https://github.com/presscustomizr/nimble-builder/issues/626 // jQuery can potentially be loaded async, so let's react to its load or the presence of window.jQuery // This relies on the fact that we use add_filter( 'script_loader_tag', array( $this, 'sek_filter_script_loader_tag' ), 10, 2 ); to add id 'nb-jquery' ( function() { var _maybeEmit = function() { var evt = 'nb-jquery-loaded'; if ( !nb_.wasEmitted(evt) ) { nb_.emit(evt); } }; // recursively try to load jquery every 200ms during 6s ( max 30 times ) var _emitWhenJqueryIsReady = function( attempts ) { attempts = attempts || 0; if ( typeof undefined !== typeof window.jQuery ) { _maybeEmit(); } else if ( attempts < 30 ) { setTimeout( function() { attempts++; _emitWhenJqueryIsReady( attempts ); }, 200 ); } else { if ( window.console && window.console.log ) { console.log('Nimble Builder problem : jQuery.js was not detected on your website'); } } }; // if jQuery has already be printed, let's listen to the load event var jquery_script_el = document.getElementById('nb-jquery'); if ( jquery_script_el ) { jquery_script_el.addEventListener('load', function() { _maybeEmit(); }); } _emitWhenJqueryIsReady(); })(); //printed in sek_maybe_load_scripts_in_ajax() (function(w, d){ nb_.listenTo( 'nb-jquery-loaded', function() { if ( !sekFrontLocalized.load_front_assets_on_dynamically ) return; // params = { // path : 'js/libs/swiper-bundle.min.js' // complete : function() { // $.ajax( { // url : sekFrontLocalized.frontAssetsPath + 'js/prod-front-simple-slider-module.min.js?'+sekFrontLocalized.assetVersion, // cache : true,// use the browser cached version when available // dataType: "script" // }).done(function() { // }).fail( function() { // nb_.errorLog('script instantiation failed'); // }); // } // loadcheck : 'function' === typeof( window.Swiper ) // } nb_.scriptsLoadingStatus = {}; nb_.ajaxLoadScript = function( params ) { jQuery(function($){ params = $.extend( { path : '', complete : '', loadcheck : false }, params ); // Bail if the load request has already been made, but not yet finished. if ( nb_.scriptsLoadingStatus[params.path] && 'pending' === nb_.scriptsLoadingStatus[params.path].state() ) { return; } // set the script loading status now to avoid several calls nb_.scriptsLoadingStatus[params.path] = nb_.scriptsLoadingStatus[params.path] || $.Deferred(); jQuery.ajax( { url : sekFrontLocalized.frontAssetsPath + params.path + '?'+ sekFrontLocalized.assetVersion, cache : true,// use the browser cached version when available dataType: "script" }).done(function() { if ( ('function' === typeof params.loadcheck) && !params.loadcheck() ) { nb_.errorLog('ajaxLoadScript success but loadcheck failed for => ' + params.path ); return; } if ( 'function' === typeof params.complete ) { params.complete(); } }).fail( function() { nb_.errorLog('ajaxLoadScript failed for => ' + params.path ); }); }); };//ajaxLoadScript });/////////////// callbackFunc nb_.listenTo('nb-jquery-loaded', function() { jQuery(function($){ if ( !sekFrontLocalized.load_front_assets_on_dynamically ) return; // Main script nb_.ajaxLoadScript({ path : sekFrontLocalized.isDevMode ? 'js/ccat-nimble-front.js' : 'js/ccat-nimble-front.min.js'}); // Partial scripts $.each( sekFrontLocalized.partialFrontScripts, function( _name, _event ){ nb_.listenTo( _event, function() { nb_.ajaxLoadScript({ path : sekFrontLocalized.isDevMode ? 'js/partials/' + _name + '.js' : 'js/partials/' + _name + '.min.js'}); }); }); }); }); }(window, document));