--- /dev/null
+/**
+ * @file
+ * Cherries by @toddmotto, @cferdinandi, @adamfschwartz, @daniellmb.
+ *
+ * @todo: Use Cash or Underscore when jQuery is dropped by supported plugins.
+ */
+
+/* global window, document, define, module */
+(function (root, factory) {
+
+ 'use strict';
+
+ // Inspired by https://github.com/addyosmani/memoize.js/blob/master/memoize.js
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define([], factory);
+ }
+ else if (typeof exports === 'object') {
+ // Node. Does not work with strict CommonJS, but only CommonJS-like
+ // environments that support module.exports, like Node.
+ module.exports = factory();
+ }
+ else {
+ // Browser globals (root is window).
+ root.dBlazy = factory();
+ }
+})(this, function () {
+
+ 'use strict';
+
+ /**
+ * Object for public APIs where dBlazy stands for drupalBlazy.
+ *
+ * @namespace
+ */
+ var dBlazy = {};
+
+ /**
+ * Check if the given element matches the selector.
+ *
+ * @name dBlazy.matches
+ *
+ * @param {Element} elem
+ * The current element.
+ * @param {String} selector
+ * Selector to match against (class, ID, data attribute, or tag).
+ *
+ * @return {Boolean}
+ * Returns true if found, else false.
+ *
+ * @see http://caniuse.com/#feat=matchesselector
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
+ */
+ dBlazy.matches = function (elem, selector) {
+ // Element.matches() polyfill.
+ var p = Element.prototype;
+ if (!p.matches) {
+ p.matches =
+ p.matchesSelector ||
+ p.mozMatchesSelector ||
+ p.msMatchesSelector ||
+ p.oMatchesSelector ||
+ p.webkitMatchesSelector ||
+ function (s) {
+ var matches = (this.document || this.ownerDocument).querySelectorAll(s);
+ var i = matches.length;
+ while (--i >= 0 && matches.item(i) !== this) {
+ // Empty block to satisfy coder and eslint.
+ }
+ return i > -1;
+ };
+ }
+
+ // Check if matches.
+ if (elem.matches(selector)) {
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * Get the closest matching element up the DOM tree.
+ *
+ * Inspired by Chris Ferdinandi, http://github.com/cferdinandi/smooth-scroll.
+ *
+ * @name dBlazy.closest
+ *
+ * @param {Element} elem
+ * Starting element.
+ * @param {String} selector
+ * Selector to match against (class, ID, data attribute, or tag).
+ *
+ * @return {Boolean|Element}
+ * Returns null if not match found.
+ *
+ * @see http://caniuse.com/#feat=element-closest
+ * @see http://caniuse.com/#feat=matchesselector
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/matches
+ */
+ dBlazy.closest = function (elem, selector) {
+ for (; elem && elem !== document; elem = elem.parentNode) {
+ if (dBlazy.matches(elem, selector)) {
+ return elem;
+ }
+ }
+
+ return null;
+ };
+
+ /**
+ * Returns a new object after merging two, or more objects.
+ *
+ * Or use https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/
+ * Global_Objects/Object/assign.
+ *
+ * @name dBlazy.extend
+ *
+ * Inspired by @adamfschwartz, @zackbloom, http://youmightnotneedjquery.com.
+ *
+ * @param {Object} out
+ * The objects to merge together.
+ *
+ * @return {Object}
+ * Merged values of defaults and options.
+ */
+ dBlazy.extend = Object.assign || function (out) {
+ out = out || {};
+
+ for (var i = 1, len = arguments.length; i < len; i++) {
+ if (!arguments[i]) {
+ continue;
+ }
+
+ for (var key in arguments[i]) {
+ if (arguments[i].hasOwnProperty(key)) {
+ out[key] = arguments[i][key];
+ }
+ }
+ }
+
+ return out;
+ };
+
+ /**
+ * A simple forEach() implementation for Arrays, Objects and NodeLists.
+ *
+ * @name dBlazy.forEach
+ *
+ * @author Todd Motto
+ * @link https://github.com/toddmotto/foreach
+ *
+ * @param {Array|Object|NodeList} collection
+ * Collection of items to iterate.
+ * @param {Function} callback
+ * Callback function for each iteration.
+ * @param {Array|Object|NodeList} scope
+ * Object/NodeList/Array that forEach is iterating over (aka `this`).
+ */
+ dBlazy.forEach = function (collection, callback, scope) {
+ var proto = Object.prototype;
+ if (proto.toString.call(collection) === '[object Object]') {
+ for (var prop in collection) {
+ if (proto.hasOwnProperty.call(collection, prop)) {
+ callback.call(scope, collection[prop], prop, collection);
+ }
+ }
+ }
+ else {
+ for (var i = 0, len = collection.length; i < len; i++) {
+ callback.call(scope, collection[i], i, collection);
+ }
+ }
+ };
+
+ /**
+ * A simple wrapper for event delegation like jQuery.on().
+ *
+ * Inspired by http://stackoverflow.com/questions/30880757/
+ * javascript-equivalent-to-on.
+ *
+ * @name dBlazy.on
+ *
+ * @param {Element} elm
+ * The parent HTML element.
+ * @param {String} eventName
+ * The event name to trigger.
+ * @param {String} childEl
+ * Child selector to match against (class, ID, data attribute, or tag).
+ * @param {Function} callback
+ * The callback function.
+ */
+ dBlazy.on = function (elm, eventName, childEl, callback) {
+ elm.addEventListener(eventName, function (event) {
+ var t = event.target;
+ while (t && t !== this) {
+ if (dBlazy.matches(t, childEl)) {
+ callback.call(t, event);
+ }
+ t = t.parentNode;
+ }
+ });
+ };
+
+ /**
+ * Executes a function once.
+ *
+ * @name dBlazy.once
+ *
+ * @author Daniel Lamb <dlamb.open.source@gmail.com>
+ * @link https://github.com/daniellmb/once.js
+ *
+ * @param {Function} fn
+ * The executed function.
+ *
+ * @return {Object}
+ * The function result.
+ */
+ dBlazy.once = function (fn) {
+ var result;
+ var ran = false;
+ return function proxy() {
+ if (ran) {
+ return result;
+ }
+ ran = true;
+ result = fn.apply(this, arguments);
+ // For garbage collection.
+ fn = null;
+ return result;
+ };
+ };
+
+ /**
+ * A simple wrapper for JSON.parse() for string within data-* attributes.
+ *
+ * @name dBlazy.parse
+ *
+ * @param {String} str
+ * The string to convert into JSON object.
+ *
+ * @return {Object|Boolean}
+ * The JSON object, or false in case invalid.
+ */
+ dBlazy.parse = function (str) {
+ try {
+ return JSON.parse(str);
+ }
+ catch (e) {
+ return false;
+ }
+ };
+
+ /**
+ * A simple wrapper to delay callback function on window resize.
+ *
+ * @name dBlazy.resize
+ *
+ * @link https://github.com/louisremi/jquery-smartresize
+ *
+ * @param {Function} c
+ * The callback function.
+ * @param {Int} t
+ * The timeout.
+ *
+ * @return {Function}
+ * The callback function.
+ */
+ dBlazy.resize = function (c, t) {
+ window.onresize = function () {
+ window.clearTimeout(t);
+ t = window.setTimeout(c, 200);
+ };
+ return c;
+ };
+
+ /**
+ * A simple wrapper for triggering event like jQuery.trigger().
+ *
+ * @name dBlazy.trigger
+ *
+ * @param {Element} elm
+ * The HTML element.
+ * @param {String} eventName
+ * The event name to trigger.
+ * @param {Object} custom
+ * The optional object passed into a custom event.
+ * @param {String} type
+ * Default to MouseEvents, can be either:
+ * MouseEvents: click, mousedown, mouseup.
+ * HTMLEvents: focus, change, blur, select.
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
+ * @todo: See if any consistent way for both custom and native events.
+ */
+ dBlazy.trigger = function (elm, eventName, custom, type) {
+ var event;
+ custom = custom || {};
+ type = type || 'MouseEvents';
+
+ var addEvent = function (eventName, data) {
+ data = data || {};
+ // @todo: Use Event constructor, pending as not supported by all IEs.
+ event = document.createEvent(data && typeof data === 'object' ? 'Event' : type);
+ event.initEvent(eventName, true, true, data);
+
+ return event;
+ };
+
+ // IE >= 9 compat, else SCRIPT445: Object doesn't support this action.
+ // https://msdn.microsoft.com/library/ff975299(v=vs.85).aspx
+ try {
+ event = custom ? new CustomEvent(eventName, {detail: custom}) : addEvent(eventName);
+ }
+ catch (e) {
+ event = addEvent(eventName, custom);
+ }
+
+ elm.dispatchEvent(event);
+ };
+
+ return dBlazy;
+
+});