PageSourceSearch

https://leme.gov.pt/modules/contrib/blazy/js/blazy.load.js?r9atlm

js leme.gov.pt collected 2026-09-24 11:37:59 UTC 14,068 bytes, 417 lines download raw bytes

1/**
2 * @file
3 * Provides Intersection Observer API, or bLazy loader.
4 */
5
6(function (Drupal, drupalSettings, _db, window, document) {
7
8  'use strict';
9
10  var _dataAnimation = 'data-animation';
11  var _dataDimensions = 'data-dimensions';
12  var _dataBg = 'data-backgrounds';
13  var _dataRatio = 'data-ratio';
14  var _firstBlazy = 'blazy--first';
15  var _isNativeExecuted = false;
16  var _isPictureExecuted = false;
17  var _resizeTick = 0;
18
19  /**
20   * Blazy public methods.
21   *
22   * @namespace
23   */
24  Drupal.blazy = Drupal.blazy || {
25    context: null,
26    init: null,
27    items: [],
28    ratioItems: [],
29    windowWidth: 0,
30    blazySettings: drupalSettings.blazy || {},
31    ioSettings: drupalSettings.blazyIo || {},
32    revalidate: false,
33    options: {},
34    globals: function () {
35      var me = this;
36      var commons = {
37        isUniform: false,
38        success: me.clearing.bind(me),
39        error: me.clearing.bind(me),
40        selector: '.b-lazy',
41        errorClass: 'b-error',
42        successClass: 'b-loaded'
43      };
44
45      return _db.extend(me.blazySettings, me.ioSettings, commons);
46    },
47
48    clearing: function (el) {
49      var me = this;
50      var cn = _db.closest(el, '.media');
51      var an = _db.closest(el, '[' + _dataAnimation + ']');
52
53      // Clear loading classes.
54      me.clearLoading(el);
55
56      // Reevaluate the element.
57      me.reevaluate(el);
58
59      // Container might be the el itself for BG, do not NULL check here.
60      me.updateContainer(el, cn);
61
62      // Supports blur, animate.css for CSS background, picture, image, media.
63      if (an !== null || me.has(el, _dataAnimation)) {
64        _db.animate(an !== null ? an : el);
65      }
66
67      // Provides event listeners for easy overrides without full overrides.
68      _db.trigger(el, 'blazy.done', {options: me.options});
69
70      // Initializes the native lazy loading once the first found is loaded.
71      if (!_isNativeExecuted) {
72        _db.trigger(me.context, 'blazy.native', {options: me.options});
73
74        _isNativeExecuted = true;
75      }
76    },
77
78    clearLoading: function (el) {
79      // The .b-lazy element can be attached to IMG, or DIV as CSS background.
80      // The .(*)loading can be .media, .grid, .slide__content, .box, etc.
81      var loaders = [
82        el,
83        _db.closest(el, '.is-loading'),
84        _db.closest(el, '[class*="loading"]')
85      ];
86
87      _db.forEach(loaders, function (loader) {
88        if (loader !== null) {
89          loader.className = loader.className.replace(/(\S+)loading/, '');
90        }
91      });
92    },
93
94    isLoaded: function (el) {
95      return el !== null && el.classList.contains(this.options.successClass);
96    },
97
98    reevaluate: function (el) {
99      var me = this;
100      var ie = el.classList.contains('b-responsive') && el.hasAttribute('data-pfsrc');
101
102      // In case an error, try forcing it.
103      if (me.init !== null && _db.hasClass(el, me.options.errorClass)) {
104        el.classList.remove(me.options.errorClass);
105
106        // This is a rare case, hardly called, just nice to have for errors.
107        window.setTimeout(function () {
108          me.init.load(el);
109        }, 10);
110      }
111
112      // @see http://scottjehl.github.io/picturefill/
113      if (window.picturefill && ie) {
114        window.picturefill({
115          reevaluate: true,
116          elements: [el]
117        });
118      }
119    },
120
121    has: function (el, attribute) {
122      return el !== null && el.hasAttribute(attribute);
123    },
124
125    contains: function (el, name) {
126      return el !== null && el.classList.contains(name);
127    },
128
129    updateContainer: function (el, cn) {
130      var me = this;
131      var isPicture = _db.equal(el.parentNode, 'picture') && me.has(cn, _dataDimensions);
132
133      // Fixed for effect Blur messes up Aspect ratio Fluid calculation.
134      window.setTimeout(function () {
135        if (me.isLoaded(el)) {
136          // Adds context for effetcs: blur, etc. considering BG, or just media.
137          (me.contains(cn, 'media') ? cn : el).classList.add('is-b-loaded');
138
139          if (isPicture) {
140            me.updatePicture(el, cn);
141          }
142
143          if (me.has(el, _dataBg)) {
144            _db.updateBg(el, me.options.mobileFirst);
145          }
146        }
147      });
148    },
149
150    updatePicture: function (el, cn) {
151      var me = this;
152      var pad = Math.round(((el.naturalHeight / el.naturalWidth) * 100), 2);
153
154      cn.style.paddingBottom = pad + '%';
155
156      // Swap all aspect ratio once to reduce abrupt ratio changes for the rest.
157      if (!_isPictureExecuted) {
158        _db.trigger(me.context, 'blazy.uniform', {pad: pad});
159        _isPictureExecuted = true;
160      }
161    },
162
163    /**
164     * Updates the dynamic multi-breakpoint aspect ratio: bg, picture or image.
165     *
166     * This only applies to Responsive images with aspect ratio fluid.
167     * Static ratio (media--ratio--169, etc.) is ignored and uses CSS instead.
168     *
169     * @param {HTMLElement} cn
170     *   The .media--ratio--fluid container HTML element.
171     */
172    updateRatio: function (cn) {
173      var me = this;
174      var dimensions = _db.parse(cn.getAttribute(_dataDimensions)) || ('dimensions' in me.options ? me.options.dimensions : false);
175
176      if (!dimensions) {
177        me.updateFallbackRatio(cn);
178        return;
179      }
180
181      // For picture, this is more a dummy space till the image is downloaded.
182      var isPicture = cn.querySelector('picture') !== null && _resizeTick > 0;
183      var pad = _db.activeWidth(dimensions, isPicture);
184
185      if (pad !== 'undefined') {
186        cn.style.paddingBottom = pad + '%';
187      }
188
189      // Fix for picture or bg element with resizing.
190      if (_resizeTick > 0 && (isPicture || me.has(cn, _dataBg))) {
191        me.updateContainer((isPicture ? cn.querySelector('img') : cn), cn);
192      }
193    },
194
195    updateFallbackRatio: function (cn) {
196      // Only rewrites if the style is indeed stripped out by Twig, and not set.
197      if (!cn.hasAttribute('style') && cn.hasAttribute(_dataRatio)) {
198        cn.style.paddingBottom = cn.getAttribute(_dataRatio) + '%';
199      }
200    },
201
202    doNativeLazy: function () {
203      var me = this;
204      var doNative = function (el) {
205        // Reset attributes, and let supportive browsers lazy load natively.
206        _db.setAttrs(el, ['srcset', 'src'], true);
207
208        // Also supports PICTURE or (future) VIDEO which contains SOURCEs.
209        _db.setAttrsWithSources(el, false, true);
210
211        // Mark it loaded to prevent Blazy/IO to do any further work.
212        el.classList.add(me.options.successClass);
213        me.clearing(el);
214      };
215
216      var onNative = function () {
217        _db.forEach(me.items, doNative);
218      };
219
220      _db.bindEvent(me.context, 'blazy.native', onNative, {once: true});
221    },
222
223    isNativeLazy: function () {
224      return 'loading' in HTMLImageElement.prototype;
225    },
226
227    isIo: function () {
228      return this.ioSettings && this.ioSettings.enabled && 'IntersectionObserver' in window;
229    },
230
231    isBlazy: function () {
232      return !this.isIo() && 'Blazy' in window;
233    },
234
235    forEach: function (context) {
236      var el = context.querySelector('[data-blazy]');
237      var blazies = context.querySelectorAll('.blazy:not(.blazy--on)');
238
239      // Various use cases: w/o formaters, custom, or basic, and mixed.
240      // The [data-blazy] is set by the module for formatters, or Views gallery.
241      if (blazies.length > 0) {
242        _db.forEach(blazies, doBlazy, context);
243      }
244
245      // Runs basic Blazy if no [data-blazy] found, probably a single image or
246      // a theme that does not use field attributes, or (non-grid) BlazyFilter.
247      if (el === null) {
248        initBlazy(context);
249      }
250    },
251
252    run: function (opts) {
253      return this.isIo() ? new BioMedia(opts) : new Blazy(opts);
254    },
255
256    afterInit: function (context) {
257      var me = this;
258      me.ratioItems = context.querySelector('.media--ratio') === null ? [] : context.querySelectorAll('.media--ratio');
259      var shouldLoop = me.ratioItems.length > 0;
260
261      var swapRatio = function (e) {
262        var pad = e.detail.pad;
263
264        if (pad > 10) {
265          _db.forEach(me.ratioItems, function (cn) {
266            cn.style.paddingBottom = pad + '%';
267          }, context);
268        }
269      };
270
271      var checkRatio = function () {
272        me.windowWidth = _db.windowWidth();
273
274        if (shouldLoop) {
275          _db.forEach(me.ratioItems, me.updateRatio.bind(me), context);
276        }
277
278        // BC with bLazy, native/IO doesn't need to revalidate, bLazy does.
279        // Scenarios: long horizontal containers, Slick carousel slidesToShow >
280        // 3. If any issue, add a class `blazy--revalidate` manually to .blazy.
281        if (!me.isNativeLazy() && (me.isBlazy() || me.revalidate)) {
282          me.init.revalidate(true);
283        }
284
285        // Provides event listeners for easy overrides without full overrides.
286        // Checks for weird contexts, in case spit out during AJAX, etc.
287        if (context.classList && context.classList.contains(_firstBlazy)) {
288          _db.trigger(context, 'blazy.afterInit', {
289            items: me.items || me.ratioItems,
290            windowWidth: me.windowWidth
291          });
292        }
293        _resizeTick++;
294      };
295
296      // Checks for aspect ratio, onload event is a bit later.
297      // @todo use Drupal.debounce if it makes any difference.
298      checkRatio();
299      _db.bindEvent(window, 'resize', Drupal.debounce(checkRatio, 200, true));
300
301      // Reduces abrupt ratio changes for the rest after the first loaded.
302      if (me.options.isUniform && shouldLoop) {
303        _db.bindEvent(context, 'blazy.uniform', swapRatio, {once: true});
304      }
305    }
306
307  };
308
309  /**
310   * Initialize the blazy instance, either basic, advanced, or native.
311   *
312   * The initialization may take once for basic (not using module formatters),
313   * or per .blazy/[data-blazy] formatter when there are one or many on a page.
314   *
315   * @param {HTMLElement} context
316   *   This can be document, or .blazy container w/o [data-blazy].
317   * @param {Object} opts
318   *   The options might be empty for basic blazy, not using formatters.
319   */
320  var initBlazy = function (context, opts) {
321    var me = Drupal.blazy;
322    // Set docroot in case we are in an iframe.
323    var documentElement = context instanceof HTMLDocument ? context : _db.closest(context, 'html');
324
325    opts = opts || {};
326    opts.mobileFirst = opts.mobileFirst || false;
327    documentElement = documentElement || document;
328    if (!document.documentElement.isSameNode(documentElement)) {
329      opts.root = documentElement;
330    }
331
332    me.options = _db.extend({}, me.globals(), opts);
333    me.context = context;
334
335    // Old bLazy, not IO, might need scrolling CSS selector like Modal library.
336    // A scrolling modal with an iframe like Entity Browser has no issue since
337    // the scrolling container is the entire DOM. Another use case is parallax.
338    var scrollElms = '#drupal-modal, .is-b-scroll';
339    if (me.options.container) {
340      scrollElms += ', ' + me.options.container.trim();
341    }
342    me.options.container = scrollElms;
343
344    // Swap lazy attributes to let supportive browsers lazy load them.
345    // This means Blazy and even IO should not lazy-load them any more.
346    // Ensures to not touch lazy-loaded AJAX, or likely non-supported elements:
347    // Video, DIV, etc. Only IMG and IFRAME are supported for now.
348    var nativeSelector = me.options.selector + '[loading]:not(.' + me.options.successClass + ')';
349    me.items = documentElement.querySelector(nativeSelector) === null ? [] : documentElement.querySelectorAll(nativeSelector);
350    if (me.isNativeLazy()) {
351      // Intentionally on the second line to not hit it till verified.
352      if (me.items.length > 0) {
353        me.doNativeLazy();
354      }
355    }
356
357    // Put the blazy/IO instance into a public object for references/ overrides.
358    // If native lazy load is supported, the following will skip internally.
359    me.init = me.run(me.options);
360
361    // Reacts on resizing per 200ms.
362    me.afterInit(context);
363  };
364
365  /**
366   * Blazy utility functions.
367   *
368   * @param {HTMLElement} elm
369   *   The .blazy/[data-blazy] container, not the lazyloaded .b-lazy element.
370   */
371  function doBlazy(elm) {
372    var me = Drupal.blazy;
373    var dataAttr = elm.getAttribute('data-blazy');
374    var opts = (!dataAttr || dataAttr === '1') ? {} : (_db.parse(dataAttr) || {});
375
376    me.revalidate = me.revalidate || elm.classList.contains('blazy--revalidate');
377    elm.classList.add('blazy--on');
378
379    // Initializes native, IntersectionObserver, or Blazy instance.
380    // @todo attempts to optimize nested blazies, remove check if any issue.
381    if (_db.closest(elm, '.blazy') === null) {
382      elm.classList.add(_firstBlazy);
383      opts.isUniform = me.contains(elm, 'blazy--field') || me.contains(elm, 'blazy--grid') || me.contains(elm, 'blazy--uniform');
384      initBlazy(elm, opts);
385    }
386  }
387
388  /**
389   * Attaches blazy behavior to HTML element identified by .blazy/[data-blazy].
390   *
391   * The .blazy/[data-blazy] is the .b-lazy container, might be .field, etc.
392   * The .b-lazy is the individual IMG, IFRAME, PICTURE, VIDEO, DIV, BODY, etc.
393   * The lazy-loaded element is .b-lazy, not its container. Note the hypen (b-)!
394   *
395   * @type {Drupal~behavior}
396   */
397  Drupal.behaviors.blazy = {
398    attach: function (context) {
399      // Drupal.attachBehaviors already does this so if this is necessary,
400      // someone does an invalid call. But let's be robust here.
401      // Note: context can be unexpected <script> element with Media library.
402      context = context || document;
403
404      // Originally identified at D7, yet might happen at D8 with AJAX.
405      // Prevents jQuery AJAX messes up where context might be an array.
406      if ('length' in context) {
407        context = context[0];
408      }
409
410      // Runs Blazy with multi-serving images, and aspect ratio supports.
411      // W/o [data-blazy] to address various scenarios like custom simple works,
412      // or within Views UI which is not easy to set [data-blazy] via UI.
413      _db.once(Drupal.blazy.forEach(context));
414    }
415  };
416
417}(Drupal, drupalSettings, dBlazy, this, this.document));

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.