Skip to content

Instantly share code, notes, and snippets.

@alex-wdmg
Forked from cferdinandi/umd-script-boilerplate.js
Last active October 29, 2020 15:54
Show Gist options
  • Save alex-wdmg/86e761e86e57b4b833c26f50ab8d0924 to your computer and use it in GitHub Desktop.
Save alex-wdmg/86e761e86e57b4b833c26f50ab8d0924 to your computer and use it in GitHub Desktop.
A simple boilerplate for UMD JS modules.
(function (root, factory) {
if (typeof define === 'function' && define.amd)
define([], factory(root));
else if (typeof exports === 'object')
module.exports = factory(root);
else
root.myPlugin = factory(root);
})(typeof global !== "undefined" ? global : this.window || this.global, function (root) {
'use strict';
//
// Variables
//
let myPlugin = {}; // Object for public APIs
let settings, eventTimeout;
// Default settings
let defaults = {
someVar: 123,
initClass: 'js-myplugin',
callbackBefore: function () {},
callbackAfter: function () {}
};
//
// Methods
//
/**
* A simple forEach() implementation for Arrays, Objects and NodeLists
* @private
* @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`)
*/
let forEach = function (collection, callback, scope) {
if (Object.prototype.toString.call(collection) === '[object Object]') {
for (let prop in collection) {
if (Object.prototype.hasOwnProperty.call(collection, prop)) {
callback.call(scope, collection[prop], prop, collection);
}
}
} else {
for (let i = 0, len = collection.length; i < len; i++) {
callback.call(scope, collection[i], i, collection);
}
}
};
/**
* Check for plugin support features
* @returns {boolean}
*/
let supports = function () {
if (!!document.querySelector && !!root.addEventListener)
return false;
return true;
};
/**
* Merge defaults with user options
* @private
* @param {Object} defaults Default settings
* @param {Object} options User options
* @returns {Object} Merged values of defaults and options
*/
let extend = function (defaults, options) {
let extended = {};
forEach(defaults, function (value, prop) {
extended[prop] = defaults[prop];
});
forEach(options, function (value, prop) {
extended[prop] = options[prop];
});
return extended;
};
/**
* Remove whitespace from a string
* @private
* @param {String} string
* @returns {String}
*/
let trim = function (string) {
return string.replace(/^\s+|\s+$/g, '');
};
/**
* Convert data-options attribute into an object of key/value pairs
* @private
* @param {String} options Link-specific options as a data attribute string
* @returns {Object}
*/
let getDataOptions = function (options) {
if (!options || !(typeof JSON === 'object' && typeof JSON.parse === 'function'))
return {};
else
return JSON.parse(options);
};
/**
* Destroy the current initialization.
* @public
*/
myPlugin.destroy = function () {
// If plugin isn't already initialized, stop
if (!settings)
return;
// Remove init class for conditional CSS
document.documentElement.classList.remove(settings.initClass);
// @todo Undo any other init functions...
// Remove event listeners
document.removeEventListener('click', someEventHandler, false);
// Reset variables
settings = null;
eventTimeout = null;
};
/**
* On window scroll and resize, only run events at a rate of 15fps for better performance
* @private
* @param {Function} eventTimeout Timeout function
* @param {Object} settings
*/
let eventThrottler = function () {
if (!eventTimeout) {
eventTimeout = setTimeout(function() {
eventTimeout = null;
//actualMethod(settings);
}, 69);
}
};
// @todo Do something...
/**
* Get the closest matching element up the DOM tree
* @param {Element} elem Starting element
* @param {String} selector Selector to match against (class, ID, or data attribute)
* @return {Boolean|Element} Returns false if not match found
*/
let getClosest = function (elem, selector) {
let firstChar = selector.charAt(0);
for (; elem && elem !== document; elem = elem.parentNode) {
switch (firstChar) {
case '.':
if (elem.classList.contains(selector.substr(1)))
return elem;
break;
case '#':
if (elem.id === selector.substr(1))
return elem;
break;
case '[':
if (elem.hasAttribute(selector.substr(1, selector.length - 2)))
return elem;
break;
default:
return false;
}
}
};
/**
* Some Handle Event
* @private
*/
let someEventHandler = function (event) {
let toggle = event.target;
let closest = getClosest(toggle, '[data-some-selector]');
if (closest) {
// run some methods
}
};
/**
* Initialize Plugin
* @public
* @param {Object} options User settings
*/
myPlugin = function (options) {
// Features test
if (!supports)
return;
else
myPlugin.destroy(); // Destroy any existing initializations
// Merge options with defaults
settings = extend(defaults, options || {});
// Add class to HTML element to activate conditional CSS
document.documentElement.classList.add( settings.initClass );
// @todo Do something...
// Listen for events
document.addEventListener('click', someEventHandler, false);
};
//
// Public APIs
//
return myPlugin;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment