Files
CHIEFSOFT\ameye b114fdf4fa first commit
2023-12-28 16:20:07 -05:00

1234 lines
59 KiB
JavaScript

// global sekFrontLocalized, nb_
if ( window.nb_ === void 0 && window.console && window.console.log ) {
console.log('Nimble error => window.nb_ global not instantiated');
}
// add an helper to get the query variable
// used for grid module
window.nb_.getQueryVariable = function(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
};
// adds jQuery dependant methods to window.nb_
(function(w, d){
var callbackFunc = function() {
jQuery( function($){
// Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError, isMap, isWeakMap, isSet, isWeakSet
// see https://underscorejs.org/docs/underscore.html#section-149
jQuery.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error', 'Symbol', 'Map', 'WeakMap', 'Set', 'WeakSet'], function(index, name) {
window.nb_['is' + name] = function(obj) {
// https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Object/toString
var _toString = Object.prototype.toString;
return _toString.call(obj) === '[object ' + name + ']';
};
});
//https://underscorejs.org/docs/underscore.html#section-17
//helper for nb_.delay
var _restArguments = function(func, startIndex) {
startIndex = startIndex == null ? func.length - 1 : +startIndex;
return function() {
var length = Math.max(arguments.length - startIndex, 0),
rest = Array(length),
index = 0;
for (; index < length; index++) {
rest[index] = arguments[index + startIndex];
}
switch (startIndex) {
case 0: return func.call(this, rest);
case 1: return func.call(this, arguments[0], rest);
case 2: return func.call(this, arguments[0], arguments[1], rest);
}
var args = Array(startIndex + 1);
for (index = 0; index < startIndex; index++) {
args[index] = arguments[index];
}
args[startIndex] = rest;
return func.apply(this, args);
};
};
// helper for nb_.throttle()
var _now = function() {
return Date.now || new Date().getTime();
};
$.extend( nb_, {
cachedElements : {
$window : $(window),
$body : $('body')
},
isMobile : function() {
return ( nb_.isFunction( window.matchMedia ) && matchMedia( 'only screen and (max-width: 768px)' ).matches ) || ( this.isCustomizing() && 'desktop' != this.previewedDevice );
},
isCustomizing : function() {
return this.cachedElements.$body.hasClass('is-customizing') || ( 'undefined' !== typeof wp && 'undefined' !== typeof wp.customize );
},
previewedDevice : 'desktop',
//Simple Utility telling if a given Dom element is currently in the window <=> visible.
//Useful to mimic a very basic WayPoint
elOrFirstVisibleParentIsInWindow : function( element, threshold ) {
var $_el = !( element instanceof $ ) ? $(element) : element;
if ( !( $_el instanceof $ ) ) {
nb_.errorLog('invalid element in nb_.elOrFirstVisibleParentIsInWindow', $_el );
return;
}
if ( threshold && !nb_.isNumber( threshold ) ) {
nb_.errorLog('invalid threshold in nb_.elOrFirstVisibleParentIsInWindow');
return;
}
var sniffFirstVisiblePrevElement = function( $el ) {
if ( $el.length > 0 && $el.is(':visible') )
return $el;
var $prev = $el.prev();
// if there's a previous sibling and this sibling is visible, use it
if ( $prev.length > 0 && $prev.is(':visible') ) {
return $prev;
}
// if there's a previous sibling but it's not visible, let's try the next previous sibling
if ( $prev.length > 0 && !$prev.is(':visible') ) {
return sniffFirstVisiblePrevElement( $prev );
}
// if no previous sibling visible, let's go up the parent level
var $parent = $el.parent();
if ( $parent.length > 0 ) {
return sniffFirstVisiblePrevElement( $parent );
}
// we don't have siblings or parent
return null;
};
// Is the candidate visible ? <= not display:none
// If not visible, we can't determine the offset().top because of https://github.com/presscustomizr/nimble-builder/issues/363
// So let's sniff up in the DOM to find the first visible sibling or container
var $el_candidate = sniffFirstVisiblePrevElement( $_el );
if ( !$el_candidate || $el_candidate.length < 1 )
return false;
var wt = this.cachedElements.$window.scrollTop(),
wb = wt + this.cachedElements.$window.height(),
it = $el_candidate.offset().top,
ib = it + $el_candidate.height(),
th = threshold || 0;
return ib >= wt - th && it <= wb + th;
},//elOrFirstVisibleParentIsInWindow
// HELPERS COPIED FROM UNDERSCORE
has : function(obj, path) {
if (!_.isArray(path)) {
return obj != null && hasOwnProperty.call(obj, path);
}
var length = path.length;
for (var i = 0; i < length; i++) {
var key = path[i];
if (obj == null || !Object.prototype.hasOwnProperty.call(obj, key)) {
return false;
}
obj = obj[key];
}
return !!length;
},
// https://davidwalsh.name/javascript-debounce-function
debounce : function(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
},
// https://underscorejs.org/docs/underscore.html#section-85
throttle : function(func, wait, options) {
var timeout, context, args, result;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : _now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function() {
var now = _now();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
throttled.cancel = function() {
clearTimeout(timeout);
previous = 0;
timeout = context = args = null;
};
return throttled;
},
delay : _restArguments(function(func, wait, args) {
return setTimeout(function() {
return func.apply(null, args);
}, wait);
})
// Browser detection
// @see https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser#9851769
// browserIs : function( browser ) {
// var bool = false,
// isIE = false || !!document.documentMode;
// switch( browser) {
// case 'safari' :
// bool = /constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window.safari || (typeof safari !== 'undefined' && safari.pushNotification));
// break;
// case 'firefox' :
// bool = typeof InstallTrigger !== 'undefined';
// break;
// case 'IE' :
// // https://stackoverflow.com/questions/19999388/check-if-user-is-using-ie
// bool = isIE && /MSIE|Trident/.test(window.navigator.userAgent);
// break;
// case 'edge' :
// bool = !isIE && !!window.StyleMedia;
// break;
// case 'chrome' :
// bool = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
// break;
// }
// return bool;
// },
});//$.extend( nb_
// now that nb_ has been populated, let's say it to the app
nb_.emit('nb-app-ready');
});// jQuery( function($){
};
// 'nb-jquery-loaded' is fired @'wp_footer' see inline script in ::_schedule_front_assets_printing()
nb_.listenTo('nb-jquery-loaded', callbackFunc );
}(window, document));/*global jQuery */
/*!
* FitText.js 1.2
*
* Copyright 2011, Dave Rupert http://daverupert.com
* Released under the WTFPL license
* http://sam.zoy.org/wtfpl/
*
* Date: Thu May 05 14:23:00 2011 -0600
*/
// global sekFrontLocalized, nimbleListenTo
(function(w, d){
var callbackFunc = function() {
(function( $ ){
$.fn.fitText = function( kompressor, options ) {
// Setup options
var compressor = kompressor || 1,
settings = $.extend({
'minFontSize' : Number.NEGATIVE_INFINITY,
'maxFontSize' : Number.POSITIVE_INFINITY
}, options);
return this.each(function(){
// Store the object
var $this = $(this);
// Resizer() resizes items based on the object width divided by the compressor * 10
var resizer = function () {
$this.css('font-size', Math.max(Math.min($this.width() / (compressor*10), parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)) + 'px');
};
// Call once to set.
resizer();
// Call on resize. Opera debounces their resize by default.
nb_.cachedElements.$window.on('resize.fittext orientationchange.fittext', resizer);
});
};
})( jQuery );
var doFitText = function() {
$(".sek-module-placeholder").each( function() {
$(this).fitText( 0.4, { minFontSize: '50px', maxFontSize: '300px' } ).data('sek-fittext-done', true );
});
// Delegate instantiation
$('.sektion-wrapper').on(
'sek-columns-refreshed sek-modules-refreshed sek-section-added sek-level-refreshed',
'div[data-sek-level="section"]',
function( evt ) {
$(this).find(".sek-module-placeholder").fitText( 0.4, { minFontSize: '50px', maxFontSize: '300px' } ).data('sek-fittext-done', true );
}
);
};
//doFitText();
// if ( 'function' == typeof(_) && window.wp && ! nb_.isUndefined( wp.customize ) ) {
// wp.customize.selectiveRefresh.bind('partial-content-rendered' , function() {
// doFitText();
// });
// }
};// onJQueryReady
// on 'nb-app-ready', jQuery is loaded
nb_.listenTo('nb-app-ready', callbackFunc );
}(window, document));// global sekFrontLocalized, nimbleListenTo
/* ------------------------------------------------------------------------- *
* SCROLL TO ANCHOR
/* ------------------------------------------------------------------------- */
(function(w, d){
var callbackFunc = function() {
jQuery( function($){
// does the same as new URL(url)
// but support IE.
// @see https://stackoverflow.com/questions/736513/how-do-i-parse-a-url-into-hostname-and-path-in-javascript
// @see https://gist.github.com/acdcjunior/9820040
// @see https://developer.mozilla.org/en-US/docs/Web/API/URL#Properties
var parseURL = function(url) {
var parser = document.createElement("a");
parser.href = url;
// IE 8 and 9 dont load the attributes "protocol" and "host" in case the source URL
// is just a pathname, that is, "/example" and not "http://domain.com/example".
parser.href = parser.href;
// copies all the properties to this object
var properties = ['host', 'hostname', 'hash', 'href', 'port', 'protocol', 'search'];
for (var i = 0, n = properties.length; i < n; i++) {
this[properties[i]] = parser[properties[i]];
}
// pathname is special because IE takes the "/" of the starting of pathname
this.pathname = (parser.pathname.charAt(0) !== "/" ? "/" : "") + parser.pathname;
};
var $root = $('html, body');
window.nb_allImagesLazyLoadedForScrollToAnchor = false;
// this = $nimbleTargetCandidate
var _doAnimateToTarget = function() {
var $target = $(this);
// Check is scrollIntoView is fully supported, in particular the options for smooth behavior
// https://stackoverflow.com/questions/46919627/is-it-possible-to-test-for-scrollintoview-browser-compatibility
// if not, fallback on jQuery animate()
if( 'scrollBehavior' in document.documentElement.style ) {
$target[0].scrollIntoView( { behavior: "smooth" } );
} else {
$root.animate({ scrollTop : $target.offset().top - 150 }, 400 );
}
};
var runTime = 0;
// this = $nimbleTargetCandidate
var _checkThatAllImgAreLoaded = function() {
var $el = $(this);
// If all images (except the ones in error ) are loaded animate
// if not, loop until images are loaded
// do not loop more than 2000 ms
if ( $('img[data-sek-src]').not('.sek-lazy-load-error').length < 1 ) {
window.nb_allImagesLazyLoadedForScrollToAnchor = true;
_doAnimateToTarget.call($el);
} else if ( runTime < 20 ) {
runTime++;
// Loop on myself, maximum 20 times until all images are lazyloaded
nb_.delay( function() {
_checkThatAllImgAreLoaded.call($el);
}, 100 );
// Start animating after 200ms so that user doesn't wait too long
// even if another animation may take over after all remaining images have been loaded
nb_.delay( function() {
_doAnimateToTarget.call($el);
}, 200 );
} else {
_doAnimateToTarget.call($el);
}
};
var maybeScrollToAnchor = function( evt ){
// problem to solve : users want to define anchor links that work inside a page, but also from other pages.
// @see https://github.com/presscustomizr/nimble-builder/issues/413
var clickedItemUrl = $(this).attr('href');
if ( '' === clickedItemUrl || null === clickedItemUrl || 'string' !== typeof( clickedItemUrl ) || -1 === clickedItemUrl.indexOf('#') )
return;
// an anchor link looks like this : http://mysite.com/contact/#anchor
var itemURLObject = new parseURL( clickedItemUrl ),
_currentPageUrl = new parseURL( window.document.location.href );
if( itemURLObject.pathname !== _currentPageUrl.pathname )
return;
if( 'string' !== typeof(itemURLObject.hash) || '' === itemURLObject.hash )
return;
var $nimbleTargetCandidate = $('[data-sek-level="location"]' ).find( '[id="' + itemURLObject.hash.replace('#','') + '"]');
if ( 1 !== $nimbleTargetCandidate.length )
return;
evt.preventDefault();
// Sept 2020 => LAYOUT SHIFT PROBLEMS
// => if lazy load is enabled and there are still images to load, make sure all images are loaded before scrolling to an anchor
// => lazyload all images + add a tiny delay before scrolling
// otherwise, the scroll might no land to the right place, due to image dimensions not OK ( occurs on chrome and edge at least )
// see https://github.com/presscustomizr/nimble-builder/issues/744
// additional issue : https://github.com/presscustomizr/nimble-builder/issues/748
var _scrollDelay = 0;
if ( sekFrontLocalized.lazyload_enabled && false === window.nb_allImagesLazyLoadedForScrollToAnchor && $('img[data-sek-src]').not('.sek-lazy-load-error').length > 0 ) {
$('body').one( 'smartload', 'img', function() { _checkThatAllImgAreLoaded.call( $nimbleTargetCandidate );} );
$('img[data-sek-src]').trigger('sek_load_img');
} else {
_doAnimateToTarget.call( $nimbleTargetCandidate );
}
};
// animate menu item to Nimble anchors
nb_.cachedElements.$body.find('.menu-item' ).on( 'click', 'a', maybeScrollToAnchor );
// animate an anchor link inside Nimble sections
// fixes https://github.com/presscustomizr/nimble-builder/issues/443
$('[data-sek-level="location"]' ).on( 'click', 'a', maybeScrollToAnchor );
});
};/////////////// callbackFunc
nb_.listenTo('nb-app-ready', callbackFunc );
}(window, document));/* ===================================================
* jquerynimbleLazyLoad.js v1.0.0
* ===================================================
*
* Replace all img src placeholder in the $element by the real src on scroll window event
* Handles background image for sections
* Hacked to lazyload iframes
*
* Note : the data-src (data-srcset) attr has to be pre-processed before the actual page load
* Example of regex to pre-process img server side with php :
* preg_replace_callback('#<img([^>]+?)src=[\'"]?([^\'"\s>]+)[\'"]?([^>]*)>#', 'regex_callback' , $_html)
*
* Note May 2020 : lazyload can be skipped by adding data-skip-lazyload="true" to the img src when generating the HTML markup
*
* (c) 2020 Nicolas Guillaume, Nice, France
*
* Example of gif 1px x 1px placeholder :
* 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'
*
* inspired by the work of Luís Almeida
* http://luis-almeida.github.com/unveil
*
* Requires requestAnimationFrame polyfill:
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/
*
* Feb 2019 : added support for iframe lazyloading for https://github.com/presscustomizr/nimble-builder/issues/361
* =================================================== */
// global sekFrontLocalized, nimbleListenTo
(function(w, d){
var callbackFunc = function() {
(function ( $, window ) {
//defaults
var pluginName = 'nimbleLazyLoad',
defaults = {
load_all_images_on_first_scroll : false,
//attribute : [ 'data-sek-src' ],
threshold : 100,
fadeIn_options : { duration : 400 },
delaySmartLoadEvent : 0,
candidateSelectors : '[data-sek-src], [data-sek-iframe-src]',
force:false//<= can be useful when nb_.isCustomizing()
},
//- to avoid multi processing in general
_skipLoadClass = 'sek-lazy-loaded';
function Plugin( element, options ) {
this.element = element;
this.options = $.extend( {}, defaults, options);
var allowLazyLoad = sekFrontLocalized.lazyload_enabled;
if ( this.options.force ) {
allowLazyLoad = true;
}
if ( !allowLazyLoad )
return;
// Do we already have an instance for this element ?
if ( $(this.element).data('nimbleLazyLoadDone') ) {
$(this.element).trigger('nb-trigger-lazyload' );
return;
}
this._defaults = defaults;
this._name = pluginName;
var self = this;
// 'nb-trigger-lazyload' can be fired from the slider module
$(this.element).on('nb-trigger-lazyload', function() {
self._maybe_trigger_load( 'nb-trigger-lazyload' );
});
this.init();
}
Plugin.prototype._getCandidateEls = function() {
return $( this.options.candidateSelectors, this.element );
};
//can access this.element and this.option
Plugin.prototype.init = function () {
var self = this;
// img to be lazy loaded looks like data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7
// [src*="data:image"] =>
// [data-sek-src*="http"] => background images, images in image modules, wp editor module, post grids, slider module, etc..
// [data-sek-iframe-src] => ?
// Bind with delegation
// April 2020 : implemented for https://github.com/presscustomizr/nimble-builder/issues/669
$('body').on( 'sek_load_img sek_load_iframe', self.options.candidateSelectors , function( evt ) {
// has this image been lazy loaded ?
if ( true === $(this).data( 'sek-lazy-loaded' ) )
return;
if ( 'sek_load_img' === evt.type ) {
self._load_img(this);
} else if ( 'sek_load_iframe' === evt.type ) {
self._load_iframe(this);
}
});
//the scroll event gets throttled with the requestAnimationFrame
nb_.cachedElements.$window.on('scroll', function( _evt ) {
self._better_scroll_event_handler( _evt );
});
//debounced resize event
nb_.cachedElements.$window.on('resize', nb_.debounce( function( _evt ) {
self._maybe_trigger_load( _evt );
}, 100 ) );
// on DOM ready
this._maybe_trigger_load('dom-ready');
// Wait and trigger the dom-ready again, so we don't miss any image initially below the viewport
// ( can happen if the height of a page element like a slider is modified at dom ready )
setTimeout( function() {
self._maybe_trigger_load('dom-ready');
}, 1000 );
// flag so we can check whether his element has been lazyloaded
$(this.element).data('nimbleLazyLoadDone', true );
};
/*
* @param : array of $img
* @param : current event
* @return : void
* scroll event performance enhancer => avoid browser stack if too much scrolls
*/
Plugin.prototype._better_scroll_event_handler = function( _evt ) {
var self = this;
if ( ! this.doingAnimation ) {
this.doingAnimation = true;
window.requestAnimationFrame(function() {
self._maybe_trigger_load(_evt );
self.doingAnimation = false;
});
}
};
/*
* @param : array of $img
* @param : current event
* @return : void
*/
Plugin.prototype._maybe_trigger_load = function(_evt ) {
var self = this,
$_imgs = self._getCandidateEls(),
// get the visible images list
// don't apply a threshold on page load so that Google audit is happy
// for https://github.com/presscustomizr/nimble-builder/issues/619
threshold = ( _evt && 'scroll' === _evt.type ) ? this.options.threshold : 0;
_visible_list = $_imgs.filter( function( ind, _el ) {
//force all images to visible if first scroll option enabled
if ( _evt && 'scroll' == _evt.type && self.options.load_all_images_on_first_scroll )
return true;
return nb_.elOrFirstVisibleParentIsInWindow( _el, threshold );
});
//trigger load_img event for visible images
_visible_list.map( function( ind, _el ) {
// trigger a lazy load if image not processed yet
if ( true !== $(_el).data( 'sek-lazy-loaded' ) ) {
if ( 'IFRAME' === $(_el).prop("tagName") ) {
$(_el).trigger( 'sek_load_iframe' );
} else {
$(_el).trigger( 'sek_load_img' );
}
}
});
};
/*
* @param single $img object
* @return void
* replace src place holder by data-src attr val which should include the real src
*/
Plugin.prototype._load_img = function( _el_ ) {
var $_el = $(_el_);
// Stop here if
// - the image has no data-sek-src attribute
// - the image has already been lazyloaded
// - the image is being lazyloaded
if ( !$_el.attr( 'data-sek-src' ) || $_el.hasClass( _skipLoadClass ) || $_el.hasClass( 'lazy-loading' ) )
return;
var _src = $_el.attr( 'data-sek-src' ),
_src_set = $_el.attr( 'data-sek-srcset' ),
_sizes = $_el.attr( 'data-sek-sizes' ),
self = this,
$jQueryImgToLoad = $("<img />", { src : _src } );
$_el.addClass('lazy-loading');
$_el.off('sek_load_img');
$jQueryImgToLoad
// .hide()
.on( 'load', function () {
//https://api.jquery.com/removeAttr/
//An attribute to remove; as of version 1.7, it can be a space-separated list of attributes.
//minimum supported wp version (3.4+) embeds jQuery 1.7.2
$_el.removeAttr( [ 'data-sek-src', 'data-sek-srcset', 'data-sek-sizes' ].join(' ') );
// Case of a lazyloaded background
if( $_el.data("sek-lazy-bg") ){
$_el.css('backgroundImage', 'url('+_src+')');
} else {
// Case of a regular image
$_el.attr("src", _src );
if ( _src_set ) {
$_el.attr("srcset", _src_set );
}
if ( _sizes ) {
$_el.attr("sizes", _sizes );
}
}
//prevent executing this twice on an already smartloaded img
if ( ! $_el.hasClass(_skipLoadClass) ) {
$_el.addClass(_skipLoadClass);
}
//Following would be executed twice if needed, as some browsers at the
//first execution of the load callback might still have not actually loaded the img
$_el.trigger('smartload');
//flag to avoid double triggering
$_el.data('sek-lazy-loaded', true );
self._clean_css_loader( $_el );
})//<= create a load() fn
.on('error', function( evt, error ) {
$_el.addClass('sek-lazy-load-error');
});// on error
//http://stackoverflow.com/questions/1948672/how-to-tell-if-an-image-is-loaded-or-cached-in-jquery
if ( $jQueryImgToLoad[0].complete ) {
$jQueryImgToLoad.trigger( 'load' );
}
$_el.removeClass('lazy-loading');
};
// Remove CSS loaded markup close to the element if any
Plugin.prototype._clean_css_loader = function( $_el ) {
// maybe remove the CSS loader
$.each( [ $_el.find('.sek-css-loader'), $_el.parent().find('.sek-css-loader') ], function( k, $_el ) {
if ( $_el.length > 0 )
$_el.remove();
});
};
/*
* @param single iframe el object
* @return void
*/
Plugin.prototype._load_iframe = function( _el_ ) {
var $_el = $(_el_),
self = this;
//$_el.addClass('lazy-loading');
$_el.off('sek_load_iframe');
$_el.attr( 'src', function() {
var src = $(this).attr('data-sek-iframe-src');
$(this).removeAttr('data-sek-iframe-src');
$_el.data('sek-lazy-loaded', true );
$_el.trigger('smartload');
if ( ! $_el.hasClass(_skipLoadClass) ) {
$_el.addClass(_skipLoadClass);
}
return src;
});
//$_el.removeClass('lazy-loading');
};
// prevents against multiple instantiations
$.fn[pluginName] = function ( options ) {
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName,
new Plugin( this, options ));
}
});
};
})( jQuery, window );
};////////////// callbackFunc
// on 'nb-app-ready', jQuery is loaded
nb_.listenTo('nb-app-ready', function(){
callbackFunc();
// Sept 2020 => always emit lazyload parsed event when customizing
if ( sekFrontLocalized.lazyload_enabled || nb_.isCustomizing() ) { nb_.emit('nb-lazyload-parsed'); }
});
}(window, document));// global sekFrontLocalized, nimbleListenTo
/* ------------------------------------------------------------------------- *
* SCROLL LISTENER FOR DYNAMIC ASSET LOADING
/* ------------------------------------------------------------------------- */
(function(w, d){
// Fire now or schedule when becoming visible.
nb_.loadAssetWhenElementVisible = function( id, handlerParams ) {
jQuery(function($){
if ( nb_.scrollHandlers[id].loaded )
return;
nb_.scrollHandlers[id].loaded = false;
var $elements = handlerParams.elements,
loaderFunc = handlerParams.func;
$.each( $elements, function( k, el ) {
if ( !nb_.scrollHandlers[id].loaded && nb_.elOrFirstVisibleParentIsInWindow($(el) ) ) {
loaderFunc();
nb_.scrollHandlers[id].loaded = true;
}
});
if ( handlerParams.scrollHandler && nb_.scrollHandlers[id].loaded ) {
nb_.cachedElements.$window.off('scroll', handlerParams.scrollHandler );
}
});
};//_loadAssetWhenElementVisible
nb_.loopOnScrollHandlers = function() {
var _scrollHandler;
jQuery(function($){
$.each( nb_.scrollHandlers, function( id, handlerParams ) {
// has it been loaded already ?
if ( handlerParams.loaded )
return true;//<=> continue see https://api.jquery.com/jquery.each/
// do nothing if dynamic asset loading is not enabled for js and css AND the assets in not in "force" mode
var load_authorized = sekFrontLocalized.load_front_assets_on_dynamically;
if ( true === handlerParams.force_loading ) {
load_authorized = true;
}
if ( !load_authorized )
return;
if ( 1 > handlerParams.elements.length )
return true;
// try on load
try{ nb_.loadAssetWhenElementVisible( id, handlerParams ); } catch(er){
nb_.errorLog('Nimble error => nb_.loopOnScrollHandlers', er, handlerParams );
}
// schedule on scroll
// the scroll event is unbound once the scrollhandler is executed
if( nb_.isFunction( handlerParams.func ) && nb_.isUndefined( handlerParams.scrollHandler ) ) {
handlerParams.scrollHandler = nb_.throttle( function() {
try{ nb_.loadAssetWhenElementVisible( id, handlerParams ); } catch(er){
nb_.errorLog('Nimble error => nb_.loopOnScrollHandlers', er, handlerParams );
}
}, 100 );
nb_.cachedElements.$window.on( 'scroll', handlerParams.scrollHandler );
} else if ( !nb_.isFunction( handlerParams.func ) ) {
nb_.errorLog('Nimble error => nb_.loopOnScrollHandlers => wrong callback func param', handlerParams );
}
});
});
};
nb_.listenTo('nb-app-ready', function() {
jQuery(function($){
// nb_.scrollHandlers = [
// { id : 'swiper', elements : $(), func : function(){} }
// ...
// ]
// each time a new scroll handler is added, it emits the event 'nimble-new-scroll-handler-added'
// so when caught, let's try to detect any dependant element is visible in the page
// and if so, load.
// Typically useful on page load if for example the slider is on top of the page and we need to load swiper-bundle.js right away before scrolling
nb_.listenTo('nimble-new-scroll-handler-added', nb_.loopOnScrollHandlers );
});//jQuery
});
}(window, document));// global sekFrontLocalized, nimbleListenTo, nb_
(function(w, d){
nb_.listenTo( 'nb-app-ready', function() {
jQuery(function($){
// params = {
// elements : $swiperCandidate,
// func : function() {}
// }
nb_.maybeLoadAssetsWhenSelectorInScreen = function( params ) {
params = $.extend( { id : '', elements : '', func : '' }, params );
if ( 1 > params.id.length ) {
nb_.errorLog('Nimble error => maybeLoadAssetsWhenSelectorInScreen => missing id', params );
return;
}
if ( 1 > $(params.elements).length )
return;
if ( !nb_.isFunction( params.func ) )
return;
// populate the collection of scroll handlers looped on ::loopOnScrollHandlers()
// + emit
nb_.scrollHandlers = nb_.scrollHandlers || {};
var handlerParams = { elements : params.elements, func : params.func, force_loading : params.force_loading };
nb_.scrollHandlers[params.id] = handlerParams;
nb_.emit('nimble-new-scroll-handler-added', { fire_once : false } );
};
nb_.emit('nimble-ready-to-load-assets-on-scroll');
});//jQuery(function($){})
});//'nb-app-ready'
}(window, document));
/* ------------------------------------------------------------------------- *
* LOAD SWIPEBOX
/* ------------------------------------------------------------------------- */
(function(w, d){
var callbackFunc = function() {
jQuery(function($){
if ( !sekFrontLocalized.load_front_assets_on_dynamically )
return;
var $linkCandidates = $('[data-sek-module-type="czr_image_module"]').find('.sek-link-to-img-lightbox');
$linkCandidates = $linkCandidates.add($('[data-sek-level="module"]').find('.sek-gal-link-to-img-lightbox'));
// Abort if no link candidate, or if the link href looks like :javascript:void(0) <= this can occur with the default image for example.
if ( $linkCandidates.length < 1 )
return;
var doLoad = function() {
//Load the style
if ( $('head').find( '#nb-swipebox' ).length < 1 ) {
$('head').append( $('<link/>' , {
rel : 'stylesheet',
id : 'nb-swipebox',
type : 'text/css',
href : sekFrontLocalized.frontAssetsPath + 'css/libs/swipebox.min.css?' + sekFrontLocalized.assetVersion
}) );
}
if ( !nb_.isFunction( $.fn.swipebox ) && sekFrontLocalized.load_front_assets_on_dynamically ) {
nb_.ajaxLoadScript({
path : 'js/libs/jquery-swipebox.min.js',
loadcheck : function() { return nb_.isFunction( $.fn.swipebox ); }
});
}
};// doLoad
// Load js plugin if needed
// when the plugin is loaded => it emits 'nb-swipebox-parsed' listened to by nb_.listenTo()
nb_.maybeLoadAssetsWhenSelectorInScreen( {
id : 'swipebox',
elements : $linkCandidates,
func : doLoad
});
});//jQuery(function($){})
};/////////////// callbackFunc
//When loaded with defer, we can not be sure that jQuery will be loaded before
nb_.listenTo( 'nb-app-ready', function() {
nb_.listenTo( 'nb-needs-swipebox', callbackFunc );
});
}(window, document));
/* ------------------------------------------------------------------------- *
* MAYBE LOAD SWIPER ON SCROLL
/* ------------------------------------------------------------------------- */
(function(w, d){
var callbackFunc = function() {
jQuery(function($){
if ( !sekFrontLocalized.load_front_assets_on_dynamically )
return;
// Load js plugin if needed
// // when the plugin is loaded => it emits 'nimble-swiper-ready' listened to by nb_.listenTo()
var doLoad = function() {
//Load the style
if ( $('head').find( '#czr-swiper' ).length < 1 ) {
$('head').append( $('<link/>' , {
rel : 'stylesheet',
id : 'czr-swiper',
type : 'text/css',
href : sekFrontLocalized.frontAssetsPath + 'css/libs/swiper-bundle.min.css?'+sekFrontLocalized.assetVersion
}) );
}
nb_.ajaxLoadScript({
path : 'js/libs/swiper-bundle.min.js?'+sekFrontLocalized.assetVersion,
loadcheck : function() { return nb_.isFunction( window.Swiper ); },
// complete : function() {
// nb_.ajaxLoadScript({
// path : 'js/prod-front-simple-slider-module.min.js',
// });
// }
});
};// doLoad
// is it already loaded ?
if ( nb_.isFunction( window.Swiper ) )
return;
// do we have candidate selectors printed on page ?
var $swiperCandidates = $('[data-sek-module-type="czr_img_slider_module"]');
if ( $swiperCandidates.length < 1 )
return;
nb_.maybeLoadAssetsWhenSelectorInScreen( {
id : 'swiper',
elements : $swiperCandidates,
func : doLoad
});
});//jQuery(function($){})
};/////////////// callbackFunc
// When loaded with defer, we can not be sure that jQuery will be loaded before
// on 'nb-app-ready', jQuery is loaded
nb_.listenTo( 'nb-app-ready', function() {
nb_.listenTo('nb-needs-swiper', callbackFunc );
});
}(window, document));
/* ------------------------------------------------------------------------- *
* LOAD VIDEO BACKGROUND JS
/* ------------------------------------------------------------------------- */
(function(w, d){
var callbackFunc = function() {
jQuery(function($){
if ( !sekFrontLocalized.load_front_assets_on_dynamically )
return;
var $candidates = $('[data-sek-video-bg-src]');
// Abort if no link candidate, or if the link href looks like :javascript:void(0) <= this can occur with the default image for example.
if ( $candidates.length < 1 )
return;
// Load js plugin if needed
// when the plugin is loaded => it emits 'nb-..-parsed' listened to by nb_.listenTo()
nb_.maybeLoadAssetsWhenSelectorInScreen( {
id : 'nb-video-bg',
elements : $candidates,
func : function() {
//Load js
nb_.ajaxLoadScript({
path : 'js/libs/nimble-video-bg.min.js?'+sekFrontLocalized.assetVersion
});
}// doLoad
});
});// jQuery
};/////////////// callbackFunc
nb_.listenTo('nb-app-ready', function() {
nb_.listenTo('nb-needs-videobg-js', callbackFunc );
});
}(window, document));
/* ------------------------------------------------------------------------- *
* MAYBE LOAD FONTAWESOME ON SCROLL
/* ------------------------------------------------------------------------- */
(function(w, d){
var callbackFunc = function() {
jQuery(function($){
// we don't need to inject font awesome if already enqueued by a theme
if ( sekFrontLocalized.fontAwesomeAlreadyEnqueued )
return;
if ( !sekFrontLocalized.load_front_assets_on_dynamically )
return;
var $candidates = $('i[class*=fa-]');
if ( $candidates.length < 1 )
return;
// Load js plugin if needed
// when the plugin is loaded => it emits "nb-needs-fa" listened to by nb_.listenTo()
var doLoad = function() {
//Load the style
if ( $('head').find( '#nb-font-awesome' ).length < 1 ) {
var link = document.createElement('link');
link.setAttribute('href', sekFrontLocalized.frontAssetsPath + 'fonts/css/fontawesome-all.min.css?'+sekFrontLocalized.assetVersion );
link.setAttribute('id', 'nb-font-awesome');
link.setAttribute('data-sek-injected-dynamically', 'yes');
link.setAttribute('rel', nb_.hasPreloadSupport() ? 'preload' : 'stylesheet' );
link.setAttribute('as', 'style');
link.onload = function() {
this.onload=null;
if ( nb_.hasPreloadSupport() ) {
this.rel='stylesheet';
}
};
document.getElementsByTagName('head')[0].appendChild(link);
}
};// doLoad
// Load js plugin if needed
// when the plugin is loaded => it emits 'nb-...-parsed' listened to by nb_.listenTo()
nb_.maybeLoadAssetsWhenSelectorInScreen({
id : 'font-awesome',
elements : $candidates,
func : doLoad
});
});//jQuery(function($){})
};/////////////// callbackFunc
// When loaded with defer, we can not be sure that jQuery will be loaded before
// on 'nb-app-ready', jQuery is loaded
nb_.listenTo( 'nb-app-ready', function() {
nb_.listenTo( 'nb-needs-fa', callbackFunc );
});
}(window, document));// global sekFrontLocalized, nimbleListenTo
/* ------------------------------------------------------------------------- *
* LIGHT BOX SWIPEBOX ( April 2022 for #886)
/* ------------------------------------------------------------------------- */
(function(w, d){
nb_.listenTo('nb-swipebox-parsed', function() {
jQuery(function($){
if ( nb_.isCustomizing() )
return;
var $linkCandidates = [
$('[data-sek-level="module"]').find('.sek-link-to-img-lightbox'),// image module
$('[data-sek-level="module"]').find('.sek-gal-link-to-img-lightbox')// gallery module
];
//https://github.com/brutaldesign/swipebox
var _params = {
loopAtEnd: true
};
//var $linkCand;
$.each( $linkCandidates, function(_k, $linkCand) {
// Abort if no link candidate
if ( $linkCand.length < 1 ) {
return;
}
// Abort if candidate already setup
if ( $linkCand.data('nimble-swiperbox-done') )
return;
try { $linkCand.swipebox( _params ); } catch( er ) {
nb_.errorLog( 'error in callback of nb-swipebox-parsed => ', er );
}
$linkCand.data('nimble-swiperbox-done', true );
});
// July 2021, prevent gallery images to be clicked when no link is specified
$('.sek-gallery-lightbox').on('click', '.sek-no-img-link', function(evt) {
evt.preventDefault();
});
});//jQuery(function($){})
});
}(window, document));
/* ------------------------------------------------------------------------- *
* SMARTLOAD
/* ------------------------------------------------------------------------- */
// nimble-lazyload-parsed is fired in lazyload plugin, only when sekFrontLocalized.lazyload_enabled OR when nb_.isCustomizing()
(function(w, d){
nb_.listenTo('nb-lazyload-parsed', function() {
jQuery(function($){
var _do = function(evt) {
$(this).each( function() {
var _maybeDoLazyLoad = function() {
// if the element already has an instance of nimbleLazyLoad, simply trigger an event
if ( !$(this).data('nimbleLazyLoadDone') ) {
$(this).nimbleLazyLoad({force : nb_.isCustomizing()});
} else {
$(this).trigger('nb-trigger-lazyload');
}
};
try { _maybeDoLazyLoad.call($(this)); } catch( er ) {
nb_.errorLog( 'error with nimbleLazyLoad => ', er );
}
});
};
// on page load
_do.call( $('.sektion-wrapper') );
// when customizing
nb_.cachedElements.$body.on( 'sek-section-added sek-level-refreshed sek-location-refreshed sek-columns-refreshed sek-modules-refreshed', '[data-sek-level="location"]', function(evt) {
_do.call( $(this), evt );
_.delay( function() {
nb_.cachedElements.$window.trigger('resize');
}, 200 );
});
// TO EXPLORE : implement a mutation observer like in Hueman theme for images dynamically inserted in the DOM via ajax ?
// Is it really needed now that lazyload uses event delegation to trigger image loading ?
// ( see https://github.com/presscustomizr/nimble-builder/issues/669 )
// Observer Mutations of the DOM for a given element selector
// <=> of previous $(document).bind( 'DOMNodeInserted', fn );
// implemented to fix https://github.com/presscustomizr/hueman/issues/880
// see https://stackoverflow.com/questions/10415400/jquery-detecting-div-of-certain-class-has-been-added-to-dom#10415599
// observeAddedNodesOnDom : function(containerSelector, elementSelector, callback) {
// var onMutationsObserved = function(mutations) {
// mutations.forEach(function(mutation) {
// if (mutation.addedNodes.length) {
// var elements = $(mutation.addedNodes).find(elementSelector);
// for (var i = 0, len = elements.length; i < len; i++) {
// callback(elements[i]);
// }
// }
// });
// },
// target = $(containerSelector)[0],
// config = { childList: true, subtree: true },
// MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
// observer = new MutationObserver(onMutationsObserved);
// observer.observe(target, config);
// }
// Observer Mutations off the DOM to detect images
// <=> of previous $(document).bind( 'DOMNodeInserted', fn );
// implemented to fix https://github.com/presscustomizr/hueman/issues/880
// this.observeAddedNodesOnDom('body', 'img', _.debounce( function(element) {
// _doLazyLoad();
// }, 50 ));
});
});
}(window, document));
/* ------------------------------------------------------------------------- *
* BG PARALLAX
/* ------------------------------------------------------------------------- */
(function(w, d){
nb_.listenTo('nb-parallax-parsed', function() {
jQuery(function($){
$('[data-sek-bg-parallax="true"]').each( function() {
$(this).parallaxBg( { parallaxForce : $(this).data('sek-parallax-force') } );
});
var _setParallaxWhenCustomizing = function() {
$(this).parallaxBg( { parallaxForce : $(this).data('sek-parallax-force') } );
// hack => always trigger a 'resize' event with a small delay to make sure bg positions are ok
setTimeout( function() {
nb_.cachedElements.$body.trigger('resize');
}, 500 );
};
// When previewing, react to level refresh
// This can occur to any level. We listen to the bubbling event on 'body' tag
// and salmon up to maybe instantiate any missing candidate
// Example : when a preset_section is injected
nb_.cachedElements.$body.on('sek-level-refreshed sek-section-added', function( evt ){
if ( "true" === $(this).data('sek-bg-parallax') ) {
_setParallaxWhenCustomizing.call(this);
} else {
$(this).find('[data-sek-bg-parallax="true"]').each( function() {
_setParallaxWhenCustomizing.call(this);
});
}
});
});
});
}(window, document));
/* ------------------------------------------------------------------------- *
* GRID MODULE
/* ------------------------------------------------------------------------- */
// June 2020 : added for https://github.com/presscustomizr/nimble-builder/issues/716
nb_.listenTo('nb-docready', function() {
if ( window.nb_ && window.nb_.getQueryVariable ) {
var anchorId = window.nb_.getQueryVariable('nb_grid_module_go_to'),
el = document.getElementById(anchorId);
// Then clean the url
var _cleanUrl = function() {
var currPathName = window.location.pathname; //get current address
//1- get the part before '?go_to'
var beforeQueryString = currPathName.split("?go_to")[0];
window.history.replaceState({}, document.title, beforeQueryString );
};
if( anchorId && el ) {
setTimeout( function() { el.scrollIntoView();}, 200 );
try{ _cleanUrl(); } catch(er) {
if( window.console && window.console.log ) {
console.log( 'NB => error when cleaning url "go_to" param');
}
}
}
}
});
// September 2021 => Solves the problem of CSS loaders not cleaned
// see https://github.com/presscustomizr/nimble-builder/issues/874
nb_.listenTo('nb-app-ready', function() {
jQuery(function($){
var $cssLoaders = $('.sek-css-loader');
if ( $cssLoaders.length < 1 )
return;
var $el,
removeCssLoaderAfterADelay = nb_.throttle( function() {
$cssLoaders = $('.sek-css-loader');
$.each($cssLoaders, function(){
$el = $(this);
if ( nb_.elOrFirstVisibleParentIsInWindow($el) ) {
nb_.delay( function() {
if ( $el.length > 0 ) {
$el.remove();
}
}, 1000);
}
});
if ( $cssLoaders.length < 1 ) {
// When no more loaders to remove, remove scroll listener
nb_.cachedElements.$window.off('scroll', removeCssLoaderAfterADelay );
}
}, 200 );
nb_.cachedElements.$window.on('scroll', removeCssLoaderAfterADelay );
});
});