v1/web/modules/contrib/blazy/js/blazy.compat.js

252 lines
7.0 KiB
JavaScript

/**
* @file
* Provides compat methods between Native and lazyload script.
*
* This file is not loaded if all below are not enabled.
*
* Mostly to fix for lost module features due to lazyload script being ditched:
* - Blur or animation in general with animate.css.
* - Multiple-breakpoint CSS background (DIV).
* - Multiple-breakpoint dynamic, or named Fluid, aspect ratio.
* - Local video.
* - Extra features: sub-module requirements. If using Slick/ Splide, etc., be
* sure to disable loading their loaders globally at their UIs as needed.
*/
(function ($, Drupal, _win) {
'use strict';
var _id = 'blazy';
var _data = 'data-';
var _dataRatios = _data + 'ratios';
var _dataRatio = _data + 'ratio';
var _media = 'media';
var _picture = 'picture';
var _elMedia = '.' + _media;
var _elRatio = _elMedia + '--ratio';
var _isAnimated = 'is-b-animated';
var _winData = {};
var _opts = {};
var _ww = 0;
/**
* Blazy public compat methods.
*
* @namespace
*/
Drupal.blazy = $.extend(Drupal.blazy || {}, {
clearCompat: function (el) {
var me = this;
var old = $.isBg(el) && (me.isBlazy() || $.ie);
// Compatibility with old bLazy. Moved into fork bLazy.
// if (old) {
// bio.setImage(el, true);
// }
// Only animate when the image is fully loaded, else nonsense.
me.pad(el, animate, old ? 50 : 0);
},
checkResize: function (items, cb, root, onDone) {
var me = this;
var bio = me.init;
var check = function (e) {
var details = e && e.detail ? e.detail : {};
_winData = details.winData || me.windowData();
var isResized = _ww > 0 && _ww !== _winData.ww;
if (isResized) {
me.resizeTick = bio && bio.resizeTick || 0;
if ($.isFun(cb)) {
$.each(items, function (entry, i) {
var el = entry.target || entry;
return cb.call(me, el, i, isResized);
});
}
}
_ww = _winData.ww;
};
// Already throttled for oldies, or RO/RAF for modern browsers.
$.on(_win, _id + '.resizing', check);
// When images are loaded, Flexbox or Native Grid as Masonry might need
// info about the loaded image dimensions to calculate gaps or positions.
if (onDone && $.isFun(onDone)) {
me.rebind(root, onDone, me.roObserver);
}
me.destroyed = false;
return _winData;
},
unresize: function () {
$.unload(this);
}
});
// Private non-reusable functions.
/**
* Callback function to animate blur, or any animated, element, if any.
*
* @param {Element} el
* The DIV or image element.
*/
function animate(el) {
// Blur, animate.css, for CSS background, picture, image, media.
var an = $.aniElement && $.aniElement(el);
// Animate if any.
if ($.animate && $.isElm(an) && !$.hasClass(an, _isAnimated)) {
setTimeout(function () {
$.animate(an);
}, 60);
}
}
/**
* Updates the dynamic multi-breakpoint aspect ratio: bg, picture or image.
*
* Even Native needs help since browsers do not auto-update dynamic ratio.
*
* This only applies to Responsive images with aspect ratio fluid.
* Static ratio (media--ratio--169, etc.) is ignored and uses CSS instead.
* The dimensions here are pre-determined server-side per image styles.
* Called during window.resize and window.onload to have a frame (setup
* dimensions) to minimize reflows. The real frame will be set after the
* image.onload/ decoded moment at blazy.drupal.js ::pad() method for more
* precise dimensions based on image natural dimensions, not server-side ones.
*
* @param {Element} cn
* The .media--ratio[--fluid] container HTML element.
* @param {int} i
* The element index.
* @param {bool} isResized
* If the resize event is triggered.
*
* @todo this should be at bio.js, but bLazy has no support which prevents it.
* Unless made generic for a ping-pong.
*/
function updateRatio(cn, i, isResized) {
cn = cn.target || cn;
// The actual third argument is object collections, unless being resized.
isResized = $.isBool(isResized) ? isResized : false;
if (!$.isElm(cn)) {
return;
}
// Blazy container (via formatter or Views style) is not always there.
var root = $.closest(cn, '.' + _id);
var ratios = $.parse($.attr(cn, _dataRatios));
// Bail out if a static/ non-fluid aspect ratio.
if ($.isEmpty(ratios)) {
fallbackRatio(cn);
return;
}
// For picture, this is more a dummy space till the image is downloaded.
var isPicture = $.isElm($.find(cn, _picture)) && isResized;
var data = $.extend(_winData, {
up: isPicture
});
var pad = $.activeWidth(ratios, data);
// Provides marker for grouping between multiple instances.
cn.dblazy = $.isElm(root) && root.dblazy;
if (!$.isUnd(pad)) {
cn.style.paddingBottom = pad + '%';
}
// @todo remove, already moved into bio.media.js for multi-breakpoint BG.
// Update multi-breakpoint CSS background.
// @todo move it out of ratio. ATM, requires ratio to update multi-BG.
// if (isResized) {
// me.update(cn, false, _winData);
// }
// @todo refactor or remove into IO.
// Fix for picture or bg element with resizing.
// if (isResized && (isPicture || $.hasAttr(cn, _dataBg))) {
// me.onIntersecting((isPicture ? $.find(cn, 'img') : cn), cn);
// }
}
// Only rewrites if the style is indeed stripped out, and not set.
// View rewrite result stripped out style attribute required by fluid ratio.
function fallbackRatio(cn) {
var value = $.attr(cn, _dataRatio);
if (!$.hasAttr(cn, 'style') && value) {
cn.style.paddingBottom = value + '%';
}
}
/**
* Resize Fluid aspect ratio.
*
* @todo this should be at bio.js, but bLazy has no support which prevents it.
*/
function resize() {
var me = this;
var doc = me.context;
var els = $.findAll(doc, _elRatio);
// Update multi-breakpoint fluid aspect ratio, if any.
if (els.length) {
$.each(els, updateRatio.bind(me));
me.checkResize(els, updateRatio, doc);
}
}
/**
* Processes DOM observations.
*/
function process() {
var me = this;
// Mount extensions.
me.mount(true);
_opts = me.options;
// ::init will/not be overridden by blazy/load, no problem since 2.6.
if ($.isNull(me.init)) {
me.init = me.run(_opts);
}
resize.call(me);
}
/**
* Attaches blazy behavior to HTML elements.
*
* @type {Drupal~behavior}
*/
Drupal.behaviors.blazyCompat = {
attach: function (context) {
var me = Drupal.blazy;
me.context = $.context(context);
// No bind without extra arguments, call me.
$.once(process.call(me));
},
detach: function (context, settings, trigger) {
if (trigger === 'unload') {
var me = Drupal.blazy;
me.unresize();
}
}
};
}(dBlazy, Drupal, this));