PageSourceSearch

https://nationaltrailraceway.com/modules/contrib/blazy/js/dblazy.js?tlv2c6

js nationaltrailraceway.com collected 2026-09-24 19:38:09 UTC 17,204 bytes, 658 lines download raw bytes

1/**
2 * @file
3 * Cherries by @toddmotto, @cferdinandi, @adamfschwartz, @daniellmb.
4 *
5 * @todo: Use Cash or Underscore when jQuery is dropped by supported plugins.
6 */
7
8/* global define, module */
9(function (root, factory) {
10
11  'use strict';
12
13  // Inspired by https://github.com/addyosmani/memoize.js/blob/master/memoize.js
14  if (typeof define === 'function' && define.amd) {
15    // AMD. Register as an anonymous module.
16    define([], factory);
17  }
18  else if (typeof exports === 'object') {
19    // Node. Does not work with strict CommonJS, but only CommonJS-like
20    // environments that support module.exports, like Node.
21    module.exports = factory();
22  }
23  else {
24    // Browser globals (root is window).
25    root.dBlazy = factory();
26  }
27})(this, function () {
28
29  'use strict';
30
31  /**
32   * Object for public APIs where dBlazy stands for drupalBlazy.
33   *
34   * @namespace
35   */
36  var dBlazy = {};
37
38  // See https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
39  if (!Element.prototype.matches) {
40    Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
41  }
42
43  /**
44   * Check if the given element matches the selector.
45   *
46   * @name dBlazy.matches
47   *
48   * @param {Element} elem
49   *   The current element.
50   * @param {String} selector
51   *   Selector to match against (class, ID, data attribute, or tag).
52   *
53   * @return {Boolean}
54   *   Returns true if found, else false.
55   *
56   * @see http://caniuse.com/#feat=matchesselector
57   * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
58   */
59  dBlazy.matches = function (elem, selector) {
60    // Check if matches, excluding HTMLDocument, see ::closest().
61    if (elem.matches(selector)) {
62      return true;
63    }
64
65    return false;
66  };
67
68  /**
69   * Returns device pixel ratio.
70   *
71   * @return {Integer}
72   *   Returns the device pixel ratio.
73   */
74  dBlazy.pixelRatio = function () {
75    return window.devicePixelRatio || 1;
76  };
77
78  /**
79   * Returns cross-browser window width.
80   *
81   * @return {Integer}
82   *   Returns the window width.
83   */
84  dBlazy.windowWidth = function () {
85    return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || window.screen.width;
86  };
87
88  /**
89   * Returns data from the current active window.
90   *
91   * When being resized, the browser gave no data about pixel ratio from desktop
92   * to mobile, not vice versa. Unless delayed for 4s+, not less, which is of
93   * course unacceptable.
94   *
95   * @name dBlazy.activeWidth
96   *
97   * @param {Object} dataset
98   *   The dataset object must be keyed by window width.
99   * @param {Boolean} mobileFirst
100   *   Whether to use min-width, or max-width.
101   *
102   * @return {mixed}
103   *   Returns data from the current active window.
104   */
105  dBlazy.activeWidth = function (dataset, mobileFirst) {
106    var me = this;
107    var keys = Object.keys(dataset);
108    var xs = keys[0];
109    var xl = keys[keys.length - 1];
110    var pr = (me.windowWidth() * me.pixelRatio());
111    var ww = mobileFirst ? me.windowWidth() : pr;
112    var mw = function (w) {
113      // The picture wants <= (approximate), non-picture wants >=, wtf.
114      return mobileFirst ? parseInt(w) <= ww : parseInt(w) >= ww;
115    };
116
117    var data = keys.filter(mw).map(function (v) {
118      return dataset[v];
119    })[mobileFirst ? 'pop' : 'shift']();
120
121    return typeof data === 'undefined' ? dataset[ww >= xl ? xl : xs] : data;
122  };
123
124  /**
125   * Check if the HTML tag matches a specified string.
126   *
127   * @name dBlazy.equal
128   *
129   * @param {Element} el
130   *   The element to compare.
131   * @param {String} str
132   *   HTML tag to match against.
133   *
134   * @return {Boolean}
135   *   Returns true if matches, else false.
136   */
137  dBlazy.equal = function (el, str) {
138    return el !== null && el.nodeName.toLowerCase() === str;
139  };
140
141  /**
142   * Get the closest matching element up the DOM tree.
143   *
144   * Inspired by Chris Ferdinandi, http://github.com/cferdinandi/smooth-scroll.
145   *
146   * @name dBlazy.closest
147   *
148   * @param {Element} el
149   *   Starting element.
150   * @param {String} selector
151   *   Selector to match against (class, ID, data attribute, or tag).
152   *
153   * @return {Boolean|Element}
154   *   Returns null if not match found.
155   *
156   * @see http://caniuse.com/#feat=element-closest
157   * @see http://caniuse.com/#feat=matchesselector
158   * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
159   */
160  dBlazy.closest = function (el, selector) {
161    var parent;
162    while (el) {
163      parent = el.parentElement;
164      if (parent && parent.matches(selector)) {
165        return parent;
166      }
167      el = parent;
168    }
169
170    return null;
171  };
172
173  /**
174   * Returns a new object after merging two, or more objects.
175   *
176   * Inspired by @adamfschwartz, @zackbloom, http://youmightnotneedjquery.com.
177   *
178   * @name dBlazy.extend
179   *
180   * @param {Object} out
181   *   The objects to merge together.
182   *
183   * @return {Object}
184   *   Merged values of defaults and options.
185   */
186  dBlazy.extend = Object.assign || function (out) {
187    out = out || {};
188
189    for (var i = 1, len = arguments.length; i < len; i++) {
190      if (!arguments[i]) {
191        continue;
192      }
193
194      for (var key in arguments[i]) {
195        if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
196          out[key] = arguments[i][key];
197        }
198      }
199    }
200
201    return out;
202  };
203
204  /**
205   * A simple forEach() implementation for Arrays, Objects and NodeLists.
206   *
207   * @name dBlazy.forEach
208   *
209   * @author Todd Motto
210   * @link https://github.com/toddmotto/foreach
211   *
212   * @param {Array|Object|NodeList} collection
213   *   Collection of items to iterate.
214   * @param {Function} callback
215   *   Callback function for each iteration.
216   * @param {Array|Object|NodeList} scope
217   *   Object/NodeList/Array that forEach is iterating over (aka `this`).
218   */
219  dBlazy.forEach = function (collection, callback, scope) {
220    var proto = Object.prototype;
221    if (proto.toString.call(collection) === '[object Object]') {
222      for (var prop in collection) {
223        if (proto.hasOwnProperty.call(collection, prop)) {
224          callback.call(scope, collection[prop], prop, collection);
225        }
226      }
227    }
228    else if (collection) {
229      for (var i = 0, len = collection.length; i < len; i++) {
230        callback.call(scope, collection[i], i, collection);
231      }
232    }
233  };
234
235  /**
236   * A simple hasClass wrapper.
237   *
238   * @name dBlazy.hasClass
239   *
240   * @param {Element} el
241   *   The HTML element.
242   * @param {String} name
243   *   The class name.
244   *
245   * @return {bool}
246   *   True if of of the method is supported.
247   *
248   * @todo remove for el.classList.contains() alone.
249   */
250  dBlazy.hasClass = function (el, name) {
251    if (el.classList) {
252      return el.classList.contains(name);
253    }
254    else {
255      return el.className.indexOf(name) !== -1;
256    }
257  };
258
259  /**
260   * A simple attributes wrapper.
261   *
262   * @name dBlazy.setAttr
263   *
264   * @param {Element} el
265   *   The HTML element.
266   * @param {String} attr
267   *   The attr name.
268   * @param {Boolean} remove
269   *   True if should remove.
270   */
271  dBlazy.setAttr = function (el, attr, remove) {
272    if (el.hasAttribute('data-' + attr)) {
273      var dataAttr = el.getAttribute('data-' + attr);
274      if (attr === 'src') {
275        el.src = dataAttr;
276      }
277      else {
278        el.setAttribute(attr, dataAttr);
279      }
280
281      if (remove) {
282        el.removeAttribute('data-' + attr);
283      }
284    }
285  };
286
287  /**
288   * A simple attributes wrapper looping based on the given attributes.
289   *
290   * @name dBlazy.setAttrs
291   *
292   * @param {Element} el
293   *   The HTML element.
294   * @param {Array} attrs
295   *   The attr names.
296   * @param {Boolean} remove
297   *   True if should remove.
298   */
299  dBlazy.setAttrs = function (el, attrs, remove) {
300    var me = this;
301
302    me.forEach(attrs, function (src) {
303      me.setAttr(el, src, remove);
304    });
305  };
306
307  /**
308   * A simple attributes wrapper, looping based on sources (picture/ video).
309   *
310   * @name dBlazy.setAttrsWithSources
311   *
312   * @param {Element} el
313   *   The starting HTML element.
314   * @param {String} attr
315   *   The attr name, can be SRC or SRCSET.
316   * @param {Boolean} remove
317   *   True if should remove.
318   */
319  dBlazy.setAttrsWithSources = function (el, attr, remove) {
320    var me = this;
321    var parent = el.parentNode || null;
322    var isPicture = parent && me.equal(parent, 'picture');
323    var targets = isPicture ? parent.getElementsByTagName('source') : el.getElementsByTagName('source');
324
325    attr = attr || (isPicture ? 'srcset' : 'src');
326
327    if (targets.length) {
328      me.forEach(targets, function (source) {
329        me.setAttr(source, attr, remove);
330      });
331    }
332  };
333
334  /**
335   * Updates CSS background with multi-breakpoint images.
336   *
337   * @name dBlazy.updateBg
338   *
339   * @param {Element} el
340   *   The container HTML element.
341   * @param {Boolean} mobileFirst
342   *   Whether to use min-width or max-width.
343   */
344  dBlazy.updateBg = function (el, mobileFirst) {
345    var me = this;
346    var backgrounds = me.parse(el.getAttribute('data-backgrounds'));
347
348    if (backgrounds) {
349      var bg = me.activeWidth(backgrounds, mobileFirst);
350      if (bg && bg !== 'undefined') {
351        el.style.backgroundImage = 'url("' + bg.src + '")';
352
353        // Allows to disable Aspect ratio if it has known/ fixed heights such as
354        // gridstack multi-size boxes.
355        if (bg.ratio && !el.classList.contains('b-noratio')) {
356          el.style.paddingBottom = bg.ratio + '%';
357        }
358      }
359    }
360  };
361
362  /**
363   * A simple removeAttribute wrapper.
364   *
365   * @name dBlazy.removeAttrs
366   *
367   * @param {Element} el
368   *   The HTML element.
369   * @param {Array} attrs
370   *   The attr names.
371   */
372  dBlazy.removeAttrs = function (el, attrs) {
373    this.forEach(attrs, function (attr) {
374      el.removeAttribute('data-' + attr);
375    });
376  };
377
378  /**
379   * A simple wrapper for event delegation like jQuery.on().
380   *
381   * Inspired by http://stackoverflow.com/questions/30880757/
382   * javascript-equivalent-to-on.
383   *
384   * @name dBlazy.on
385   *
386   * @param {Element} elm
387   *   The parent HTML element.
388   * @param {String} eventName
389   *   The event name to trigger.
390   * @param {String} childEl
391   *   Child selector to match against (class, ID, data attribute, or tag).
392   * @param {Function} callback
393   *   The callback function.
394   *
395   * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
396   */
397  dBlazy.on = function (elm, eventName, childEl, callback) {
398    elm.addEventListener(eventName, function (event) {
399      var t = event.target;
400      event.delegateTarget = elm;
401      while (t && t !== this) {
402        if (dBlazy.matches(t, childEl)) {
403          callback.call(t, event);
404        }
405        t = t.parentNode;
406      }
407    });
408  };
409
410  /**
411   * A simple wrapper for addEventListener.
412   *
413   * Made public from original bLazy library.
414   *
415   * @name dBlazy.bindEvent
416   *
417   * @param {Element} el
418   *   The HTML element.
419   * @param {String} type
420   *   The event name to add.
421   * @param {Function} fn
422   *   The callback function.
423   * @param {Object} params
424   *   The optional param passed into a custom event.
425   *
426   * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
427   * @todo remove old IE references after another check.
428   */
429  dBlazy.bindEvent = function (el, type, fn, params) {
430    var defaults = {capture: false, passive: true};
431    var extraParams = params ? this.extend(defaults, params) : defaults;
432    if (el.attachEvent) {
433      el.attachEvent('on' + type, fn, extraParams);
434    }
435    else {
436      el.addEventListener(type, fn, extraParams);
437    }
438  };
439
440  /**
441   * A simple wrapper for removeEventListener.
442   *
443   * Made public from original bLazy library.
444   *
445   * @name dBlazy.unbindEvent
446   *
447   * @param {Element} el
448   *   The HTML element.
449   * @param {String} type
450   *   The event name to remove.
451   * @param {Function} fn
452   *   The callback function.
453   * @param {Object} params
454   *   The optional param passed into a custom event.
455   *
456   * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
457   * @todo remove old IE references after another check.
458   */
459  dBlazy.unbindEvent = function (el, type, fn, params) {
460    var defaults = {capture: false, passive: true};
461    var extraParams = params ? this.extend(defaults, params) : defaults;
462    if (el.detachEvent) {
463      el.detachEvent('on' + type, fn, extraParams);
464    }
465    else {
466      el.removeEventListener(type, fn, extraParams);
467    }
468  };
469
470  /**
471   * Executes a function once.
472   *
473   * @name dBlazy.once
474   *
475   * @author Daniel Lamb <[email protected]>
476   * @link https://github.com/daniellmb/once.js
477   *
478   * @param {Function} fn
479   *   The executed function.
480   *
481   * @return {Object}
482   *   The function result.
483   */
484  dBlazy.once = function (fn) {
485    var result;
486    var ran = false;
487    return function proxy() {
488      if (ran) {
489        return result;
490      }
491      ran = true;
492      result = fn.apply(this, arguments);
493      // For garbage collection.
494      fn = null;
495      return result;
496    };
497  };
498
499  /**
500   * A simple wrapper for JSON.parse() for string within data-* attributes.
501   *
502   * @name dBlazy.parse
503   *
504   * @param {String} str
505   *   The string to convert into JSON object.
506   *
507   * @return {Object|Boolean}
508   *   The JSON object, or false in case invalid.
509   */
510  dBlazy.parse = function (str) {
511    try {
512      return JSON.parse(str);
513    }
514    catch (e) {
515      return false;
516    }
517  };
518
519  /**
520   * A simple wrapper to animate anything using animate.css.
521   *
522   * @name dBlazy.animate
523   *
524   * @param {Element} el
525   *   The animated HTML element.
526   * @param {String} animation
527   *   Any custom animation name, fallbacks to [data-animation].
528   */
529  dBlazy.animate = function (el, animation) {
530    var me = this;
531    var props = [
532      'animation',
533      'animation-duration',
534      'animation-delay',
535      'animation-iteration-count'
536    ];
537
538    animation = animation || el.dataset.animation;
539    el.classList.add('animated', animation);
540    me.forEach(['Duration', 'Delay', 'IterationCount'], function (key) {
541      if ('animation' + key in el.dataset) {
542        el.style['animation' + key] = el.dataset['animation' + key];
543      }
544    });
545
546    function animationEnd() {
547      me.removeAttrs(el, props);
548
549      el.classList.add('is-b-animated');
550      el.classList.remove('animated', animation);
551
552      me.forEach(props, function (key) {
553        el.style.removeProperty(key);
554      });
555
556      me.unbindEvent(el, 'animationend', animationEnd);
557    }
558
559    me.bindEvent(el, 'animationend', animationEnd);
560  };
561
562  /**
563   * A simple wrapper to delay callback function, taken out of blazy library.
564   *
565   * Alternative to core Drupal.debounce for D7 compatibility, and easy port.
566   *
567   * @name dBlazy.throttle
568   *
569   * @param {Function} fn
570   *   The callback function.
571   * @param {Int} minDelay
572   *   The execution delay in milliseconds.
573   * @param {Object} scope
574   *   The scope of the function to apply to, normally this.
575   *
576   * @return {Function}
577   *   The function executed at the specified minDelay.
578   */
579  dBlazy.throttle = function (fn, minDelay, scope) {
580    var lastCall = 0;
581    return function () {
582      var now = +new Date();
583      if (now - lastCall < minDelay) {
584        return;
585      }
586      lastCall = now;
587      fn.apply(scope, arguments);
588    };
589  };
590
591  /**
592   * A simple wrapper to delay callback function on window resize.
593   *
594   * @name dBlazy.resize
595   *
596   * @link https://github.com/louisremi/jquery-smartresize
597   *
598   * @param {Function} c
599   *   The callback function.
600   * @param {Int} t
601   *   The timeout.
602   *
603   * @return {Function}
604   *   The callback function.
605   */
606  dBlazy.resize = function (c, t) {
607    window.onresize = function () {
608      window.clearTimeout(t);
609      t = window.setTimeout(c, 200);
610    };
611    return c;
612  };
613
614  /**
615   * A simple wrapper for triggering event like jQuery.trigger().
616   *
617   * @name dBlazy.trigger
618   *
619   * @param {Element} elm
620   *   The HTML element.
621   * @param {String} eventName
622   *   The event name to trigger.
623   * @param {Object} custom
624   *   The optional object passed into a custom event.
625   * @param {Object} param
626   *   The optional param passed into a custom event.
627   *
628   * @see https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
629   * @todo: See if any consistent way for both custom and native events.
630   */
631  dBlazy.trigger = function (elm, eventName, custom, param) {
632    var event;
633    var data = {
634      detail: custom || {}
635    };
636
637    if (typeof param === 'undefined') {
638      data.bubbles = true;
639      data.cancelable = true;
640    }
641
642    // Native.
643    // IE >= 9 compat, else SCRIPT445: Object doesn't support this action.
644    // https://msdn.microsoft.com/library/ff975299(v=vs.85).aspx
645    if (typeof window.CustomEvent === 'function') {
646      event = new CustomEvent(eventName, data);
647    }
648    else {
649      event = document.createEvent('CustomEvent');
650      event.initCustomEvent(eventName, true, true, data);
651    }
652
653    elm.dispatchEvent(event);
654  };
655
656  return dBlazy;
657
658});

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.