/*! * DollarJS 2.2.1 -- a light, fast, modular, jQuery replacement * Github: https://github.com/seebigs/dollar-js * Released under the MIT license: https://opensource.org/licenses/MIT */ ;(function () { /*********************/ /* CORE DOLLAR */ /*********************/ var $ = function (selector, context) { return new $.fn.init(selector, context); }; var undef, strType = 'string', fnType = 'function', win = window, elemProto = win.Element.prototype, objProto = Object.prototype, objToString = objProto.toString, objHasProp = objProto.hasOwnProperty, arrProto = Array.prototype, arrSlice = arrProto.slice, docConstruct = document, docElement = document.documentElement, utils; var regExpSpacesAndBreaks = /[\s\t\r\n\f]+/g; $.isDollar = true; $.fn = { isDollar: true, indexOf: arrProto.indexOf, push: arrProto.push, pop: arrProto.pop, shift: arrProto.shift, unshift: arrProto.unshift, slice: arrProto.slice, splice: arrProto.splice // Makes console.log display selected elements as an Array }; $.fn.init = function (selector, context) { this.length = 0; // HANDLE: $(""), $(null), $(undefined), $(false) if (!selector) { return this; } if (!context) { // HANDLE: simple $("#id") for performance if ((/^#[\w-]+$/).test(selector)) { var idShortcut = docConstruct.getElementById(selector.substr(1)); if (idShortcut) { this[0] = idShortcut; this.length = 1; } return this; } // HANDLE: simple $("tag") for performance if ((/^[a-z]+$/).test(selector)) { var tags = docConstruct.getElementsByTagName(selector); var tLen = tags.length; for (var i = 0; i < tLen; i++) { this[i] = tags[i]; } this.length = tLen; return this; } } return utils.merge(this, getNodesBySelector(selector, context)); }; // Give the init function the $ prototype for later instantiation $.fn.init.prototype = $.fn; // combines collections/arrays into one dollar collection (with distinct values) function collect () { var distinct = $(); var i, len, item; utils.each(arrSlice.call(arguments), function (collection) { if (collection) { for (i = 0, len = collection.length; i < len; i++) { item = collection[i]; if (distinct.indexOf(item) === -1) { distinct.push(item); } } } }); return distinct; } var pseudoMatchers = { contains: function (tag, context, pseudoPieces) { var content = pseudoPieces[1] && pseudoPieces[1].replace(/["')]/g, ''); if (content) { return filterNodes(getNodesBySelectorString(tag, context), function (node) { return ( node.textContent || node.innerText ).indexOf(content) !== -1; }); } return []; }, hidden: function (tag, context) { return filterNodes(getNodesBySelectorString(tag, context), function (node) { return node.nodeType === 1 && !( node.offsetWidth || node.offsetHeight || node.getClientRects().length ); }); }, visible: function (tag, context) { return filterNodes(getNodesBySelectorString(tag, context), function (node) { return node.nodeType === 1 && !!( node.offsetWidth || node.offsetHeight || node.getClientRects().length ); }); }, even: function (tag, context) { return arrSlice.call(context.querySelectorAll(tag + ':nth-child(even)')); }, odd: function (tag, context) { return arrSlice.call(context.querySelectorAll(tag + ':nth-child(odd)')); }, has: function (tag, context, pseudoPieces) { var nestedSelector = typeof pseudoPieces[1] === strType && pseudoPieces[1].replace(')', ''); if (nestedSelector) { return filterNodes(getNodesBySelector(tag, context), function (node) { return node.nodeType === 1 && !!getNodesBySelector(nestedSelector, node).length; }); } return []; }, not: function (tag, context, pseudoPieces) { // set to docConstruct to include & match jQuery if (context === docElement) { context = docConstruct; } // ========================================== // given original selector "#foo :not(bar) .baz" // tag = "#foo " var preAndPostNotSelector = tag; if (tag !== '*' && tag[tag.length - 1] === ' ') { preAndPostNotSelector = tag + '*'; } // pseudoPieces = ["not", "bar) .baz"] var notAndPostNot = pseudoPieces[1].split(')'); // ["bar", ".baz"] var postNotSelector = notAndPostNot[1]; // ".baz" var notSelectors = (notAndPostNot[0] || '').split(','); // ["bar"] if (postNotSelector) { preAndPostNotSelector += postNotSelector; // #foo .baz } var filteredOnNotSelectors = []; // find all els matching #foo .baz var allMatchingPreAndPost = getNodesBySelectorString(preAndPostNotSelector, context); // filter those results for !bar utils.each(allMatchingPreAndPost, function (el) { var returnEl = true; utils.each(notSelectors, function (noMatchSelector) { if (getMatches.call(el, noMatchSelector)) { // matching bar from :not(bar)? dont return it returnEl = false; return false; // drop out of loop } }); if (returnEl) { filteredOnNotSelectors.push(el); } }); return filteredOnNotSelectors; } }; function findWithinContextIfPresent (childrenEls, context) { if (context) { var parentEls = normalizeContext(context); var found = []; utils.each(parentEls, function (parentEl) { utils.each(childrenEls, function (childEl) { if (typeof parentEl.contains === fnType && parentEl.contains(childEl)) { found.push(childEl); } }); }); return found; } else { return childrenEls; } } // takes any type of selector // returns an array of matching dom nodes function getNodesBySelector (selector, context) { // HANDLE: strings if (typeof selector === strType) { return getNodesBySelectorString(selector, context); // HANDLE: dollar instance } else if (selector.isDollar) { return findWithinContextIfPresent(selector.get(), context); // HANDLE: $(DOM Node) } else if (selector.nodeType) { return findWithinContextIfPresent([selector], context); // HANDLE: $(window) } else if (selector === selector.window) { return [selector]; // HANDLE: $([DOM Nodes]) } else if (selector.length) { var selectorEls = []; var item; for (var i = 0, len = selector.length; i < len; i++) { item = selector[i]; if (utils.isElement(item)) { selectorEls.push(item); } } return findWithinContextIfPresent(selectorEls, context); // HANDLE: dom ready } else if (typeof selector === fnType) { if (documentReady()) { selector(); } else { if (elemProto.addEventListener) { docConstruct.addEventListener('DOMContentLoaded', selector, false); } else { docConstruct.attachEvent('onreadystatechange', function () { if (documentReady()) { selector(); } }); } } } function documentReady () { var state = docConstruct.readyState; return state === 'interactive' || state === 'complete'; } return []; } // takes any String as selector // returns an array of matching dom nodes function getNodesBySelectorString (selector, context) { if (context) { var results = []; context = normalizeContext(context); if (context.length > 1) { for (var i = 0, len = context.length; i < len; i++) { utils.merge(results, getNodesBySelectorString(selector, context[i])); } return results; } else { context = context[0]; } } else { context = docElement; } if (!context) { return []; // HANDLE $('valid', $()); } // ------------------------------------------- // at this point, selector must be a string // & context must be HTML node (or doc.docElem) // ------------------------------------------- var selectorsMap = (/^\s*(?:#([\w-]+)|(\w+)|\.([\w-]+)|(<[\w\W]+>)[^>]*)\s*$/).exec(selector); // selectorsMap will return: // if id => ['#foo', 'foo', undefined, undefined, 'undefined'] // node => ['body', undefined, body, undefined', 'undefined'] // class => ['.bar', undefined, undefined, 'bar', 'undefined'] // HTML => ['HTML', undefined, undefined, undefined, 'HTML'] // else => null if (selectorsMap) { // HANDLE: $('#id') if (selector = selectorsMap[1]) { var idMatch = docConstruct.getElementById(selector); if (idMatch && context !== idMatch && context.contains(idMatch)) { return [idMatch]; } return []; // HANDLE: $('tag') } else if (selector = selectorsMap[2]) { return context.getElementsByTagName(selector); // HANDLE: $('.class') } else if (selector = selectorsMap[3]) { return typeof context.getElementsByClassName === fnType ? context.getElementsByClassName(selector) : context.querySelectorAll(selector); // HANDLE: $('
...
') } else if (selector = selectorsMap[4]) { return [htmlStringToNode(selector)]; } // HANDLE: special pseudo-selectors } else { var pseudoSelector = /(.*):(.+)/.exec(selector); if (pseudoSelector) { var tag = pseudoSelector[1] || '*'; var pseudoPieces = pseudoSelector[2].split('('); var pseudoMatcher = pseudoMatchers[pseudoPieces[0]]; if (pseudoMatcher) { return pseudoMatcher(tag, context, pseudoPieces); } } } // HANDLE: all other selectors return arrSlice.call(context.querySelectorAll(selector)); } // normalise browser nonsense var getMatches = elemProto.matches || elemProto.webkitMatchesSelector || elemProto.mozMatchesSelector || elemProto.msMatchesSelector || elemProto.oMatchesSelector || fallbackMatches; function fallbackMatches (sel) { var allMatches = getNodesBySelectorString(sel); return arrProto.indexOf.call(allMatches, this) !== -1; } // returns true if the node matches the provided selector // where node is a single node // i is index of node within the calee's collection // selector is string, dollar selection, node, or function function nodeMatchesSelector (node, selector, i) { // reject no selector, doc.frags, text, docConstruct, etc. if (!selector || !node || node.nodeType !== 1) { return false; } // handle non-string selectors if (typeof selector !== strType) { // node/element if (selector.nodeType) { return node === selector; // function } else if (typeof selector === fnType) { return !!selector.call(node, node, i); // array of elements or dollar collection } else if (selector.length) { return selector.indexOf(node) !== -1; } else { return false; } } return getMatches.call(node, selector); } function filterNodes (nodes, selector) { var matches = []; for (var i = 0, len = nodes.length; i < len; i++) { if (nodeMatchesSelector(nodes[i], selector, i)) { matches.push(nodes[i]); } } return matches; } // convert a string into DOM elements function htmlStringToNode (htmlString) { // thank you jQuery for the awesome regExp var singleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/).exec(htmlString); // HANDLE: '
', etc. if (singleTag) { return docConstruct.createElement(singleTag[1]); // HANDLE: '

', etc. } else { var disposableContainer = docConstruct.createElement('div'); disposableContainer.innerHTML = htmlString; return disposableContainer.childNodes[0]; } } // always returns an array of nodes to use as context function normalizeContext (context) { if (typeof context === strType) { return getNodesBySelectorString(context); } if (context.isDollar) { return context.get(); } // dom elements are nodeType 1, the document is nodeType 9 if (context.nodeType === 1 || context.nodeType === 9) { return [context]; } if (Array.isArray(context)) { return context; } return [docElement]; // default to the docElement, nodeType 1 } var DATA_ATTR_NAME = 'dollar-node-id'; var DATA_NEXT_ID = 1; var DATA_CACHE_PUBLIC = {}; var DATA_CACHE_PRIVATE = {}; function nodeSupportsAttrProp (node) { // don't get/set attributes or properties on text, comment and attribute nodes var nType = node && node.nodeType; return nType && nType !== 3 && nType !== 8 && nType !== 2; } function getSafeNodeForAttributeManipulation (elem) { if (elem.nodeType === 9) { elem = elem.documentElement; } return nodeSupportsAttrProp(elem) ? elem : undef; } function getAttributeSafely (elem, attr) { if (!elem) { return; } if (elem === elem.window) { // handle window return elem[attr]; } elem = getSafeNodeForAttributeManipulation(elem); return elem && elem.hasAttribute(attr) ? elem.getAttribute(attr) : undef; } function setAttributeSafely (elem, attr, value) { if (elem === elem.window) { // handle window elem[attr] = value; } elem = getSafeNodeForAttributeManipulation(elem); return elem && elem.setAttribute(attr, value); } function removeAttributeSafely (elem, attr) { if (elem === elem.window) { // handle window elem[attr] = undef; } elem = getSafeNodeForAttributeManipulation(elem); return elem && elem.removeAttribute(attr); } function getInternalElementId (elem) { return Number(getAttributeSafely(elem, DATA_ATTR_NAME)) || undef; } function setInternalElementId (elem, dollarNodeId) { return setAttributeSafely(elem, DATA_ATTR_NAME, dollarNodeId); } function getElementData (cache, elem, key) { var id = getInternalElementId(elem); if (id) { if (!key) { return cache[id]; } return cache[id] && cache[id][key]; } } function setElementData (cache, elem, key, value) { var id = getInternalElementId(elem); if (!id) { id = DATA_NEXT_ID; setInternalElementId(elem, id); DATA_NEXT_ID++; } if (!cache[id]) { cache[id] = {}; } cache[id][key] = value; } function pushElementData (cache, elem, key, value) { var valArr = getElementData(cache, elem, key) || []; valArr.push(value); setElementData(cache, elem, key, valArr); } /* * Helper Utilities * @module $.utils */ $.utils = utils = (function () { var objPrefix = '[object '; function isElement (thing) { // reject all but dom nodes & the document return !!thing && (thing.nodeType === 1 || thing.nodeType === 9); } function isObject (thing) { return objToString.call(thing) === objPrefix + 'Object]'; } function each (collection, iteratee) { if (collection) { if (collection.length !== undef) { for (var i = 0, len = collection.length; i < len; i++) { if (iteratee.call(collection[i], collection[i], i, collection) === false) { return; } } } else { for (var prop in collection) { if (objHasProp.call(collection, prop)) { if (iteratee.call(collection[prop], collection[prop], prop, collection) === false) { return; } } } } } } function extend () { var ret = arguments[0]; var assignProp = function (val, key) { if (val !== undef) { ret[key] = val; } }; each(arrSlice.call(arguments, 1), function (ext) { each(ext, assignProp); }); return ret; } function merge () { var ret = arguments[0]; var i, len; each(arrSlice.call(arguments, 1), function (collection) { if (collection) { for (i = 0, len = collection.length; i < len; i++) { if (ret.indexOf(collection[i]) === -1) { ret.push(collection[i]); } } } }); return ret; } var format = { camelToDash: function (str) { return str.replace(/([A-Z])/g, '-$1').toLowerCase(); }, dashToCamel: function (str) { return str.replace(/-(.)/g, function (all, s) { return s.charAt(0).toUpperCase(); }); } }; return { isElement: isElement, isObject: isObject, each: each, extend: extend, merge: merge, format: format }; })(); /** * Find the closest ancestor that matches a given selector * For each selected element, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree * @module core * @param {Selector} selector A selector expression to match elements against * @option {Context} context The context to use while searching for matches * @returns DollarJS (new set) * @example $('p').closest('.outer') */ $.fn.closest = function (selector, context) { if (!selector) { return $(); } var allMatches = getNodesBySelector(selector, context); var onlyClosest = []; var node; for (var i = 0, len = this.length; i < len; i++) { node = this[i]; while (node && node !== context) { if (arrProto.indexOf.call(allMatches, node) !== -1) { onlyClosest.push(node); break; } node = node.parentNode; } } return collect(onlyClosest); }; /** * Iterate over each matched element * Aliased as .forEach() for convenience * @module core * @param {Function} iteratee A function to be invoked once for each element. (element, index, collection) are passed as arguments. Within the iteratee, `this` refers to the current element. * @returns DollarJS (chainable) * @example $('p').each(function (elem) { console.log(elem); }) * @example $('p').each(function () { console.log(this); }) */ $.fn.each = $.fn.forEach = function (iteratee) { utils.each(this, iteratee); return this; }; /** * Reduce the matched set to the one element at a specific index * @module core * @param {Integer} index Indicates the position of the element to keep. Negative values count backwards from the end of the set. * @returns DollarJS (reduced set) * @example $('p').eq(3) * @example $('p').eq(-1) */ $.fn.eq = function (index) { index = Array.isArray(index) ? NaN : parseInt(index, 10); // prevent parsing array of numbers return index >= 0 ? $(this[index]) : $(this[this.length + index]); // have to + a -index in order to subtract }; /** * Reduce the matched set to the ones that match an additional selector * @module core * @param {Selector} selector A selector expression to match elements against * @returns DollarJS (reduced set) * @example $('p').filter('.foo') */ $.fn.filter = function (selector) { if (!this.length || !selector) { return $(); } return collect(filterNodes(this, selector)); }; /** * Get the descendants of each element in the matched set that match a given selector * @module core * @param {Selector} selector A selector expression to match elements against * @returns DollarJS (new set) * @example $('p').find('span') */ $.fn.find = function (selector) { if (!selector || !this.length) { return $(); } return collect(getNodesBySelector(selector, this)); }; /** * Return the actual element at a given index * If index is passed, return the one element at the specified index * If index is NOT passed, return a true Array of the selected elements * @module core * @option {Integer} index Indicates the position of the element to return. Negative values count backwards from the end of the set. * @returns Element or Array of Elements * @example $('p').get(3) * @example $('p').get(-1) * @example $('p').get() */ $.fn.get = function (index) { if (index === undef) { // Return all the elements in a clean array return arrSlice.call(this, 0); } else { // Return just the one element from the set return index < 0 ? this[index + this.length] : this[index]; } }; /** * Reverse the set of matched elements * @module core * @returns DollarJS (chainable) * @example $('p').reverse() */ $.fn.reverse = arrProto.reverse; /***************/ /* ANIMATE */ /***************/ /** * Animate styles using CSS transitions * @module animate * @param {Object} props CSS properties and values to transition into * @option {Object|Number} options Object with transition options (duration, easing, delay) / transition delay as an integer * @option {Function} complete Callback to be executed after animation is complete * @returns DollarJS (chainable) */ $.fn.animate = function (props, options, complete) { if (!utils.isObject(options)) { options = { duration: options }; } var endEvent = 'transitionend'; this.each(function (elem, index) { utils.each(props, function (val, prop) { elem.style.transition = addTransition(elem, prop, options); elem.style[prop] = val; var afterAnimate = function (propName) { elem.removeEventListener(endEvent, afterAnimate, true); elem.style.transition = removeTransition(elem, propName); if (typeof complete === fnType) { complete.call(elem, elem, index); } }; elem.addEventListener(endEvent, afterAnimate, true); }); }); return this; }; function addTransition (elem, prop, options) { var newStr = prop + ' ' + transitionOptionsAsString(options); var trans = elem.style.transition ? elem.style.transition.split(/,\s?/) : []; var existing = false; trans.forEach(function (t, i) { if (t.indexOf(prop + ' ') === 0) { trans[i] = newStr; existing = true; } }); if (!existing) { trans.push(newStr); } return trans.join(', '); } function removeTransition (elem, prop) { var trans = elem.style.transition.split(/,\s?/); var without = []; trans.forEach(function (t) { if (t.indexOf(prop + ' ') !== 0) { without.push(t); } }); return without.join(', '); } function transitionOptionsAsString (options) { var optsArr = []; optsArr.push(typeof options.duration === strType ? options.duration : ((parseInt(options.duration) || 400) + 'ms')); optsArr.push(options.easing || 'ease'); optsArr.push(typeof options.delay === strType ? options.delay : ((parseInt(options.delay) || 0) + 'ms')); return optsArr.join(' '); } /** * Slowly fade the matched elements into view * @module animate * @option {Number} duration Length of the transition * @option {Function} complete Callback to be executed after animation is complete * @returns DollarJS (chainable) */ $.fn.fadeIn = function (duration, complete) { return this.animate({ opacity: 1 }, duration, complete); }; /** * Hide the matched elements by slowly fading away * @module animate * @option {Number} duration Length of the transition * @option {Function} complete Callback to be executed after animation is complete * @returns DollarJS (chainable) */ $.fn.fadeOut = function (duration, complete) { return this.animate({ opacity: 0 }, duration, complete); }; /****************/ /* FILTER */ /****************/ /** * Add elements that match a new selector to the current set * @module filter * @param {Selector} selector A selector expression to match elements against * @option {Context} context The context to use while searching for matches * @returns DollarJS (expanded set) * @example $('p').add('span') */ $.fn.add = function (selector, context) { if (!selector) { return this; } return collect(this, $(selector, context)); }; /** * Merge an Array of Elements into the current set * @module filter * @param {Array} elements An Array of Elemenets to be merged into the current set * @option {Array} additionalElements... Additional Arrays to be merged one after another * @returns DollarJS (expanded set) * @example $('p').concat([elem1, elem2], [elem3]) */ $.fn.concat = function () { var args = arrSlice.call(arguments); args.unshift(this); return collect.apply(this, args); }; /** * Reduce the set of matched elements to those that have a descendant that matches a new selector * @module filter * @param {Selector} selector A selector expression to match elements against * @returns DollarJS (reduced set) * @example $('p').has('span') */ $.fn.has = function (selector) { if (!selector) { return $(); } return this.filter(function () { return !!getNodesBySelector(selector, this).length; }); }; /** * Is the current set of elements a match to a new selector? * Returns true if at least one of the elements in the current set matches the new selector. Returns false if otherwise. * @module filter * @param {Selector} selector A selector expression to match elements against * @returns true or false * @example $('p').is('.foo') */ $.fn.is = function (selector) { return !!(selector && this.filter(selector).length); }; /** * Create a new set by calling a function on every element in the current set * @module filter * @param {Function} iteratee A function that returns an Element for the new set when passed (currentElement, index, collection) * @returns DollarJS (new set) * @example $('p').map(function(elem){ return elem.parentNode; }) */ $.fn.map = function (iteratee) { if (typeof iteratee !== fnType) { return this; } var newSet = []; var newElem; for (var i = 0, len = this.length; i < len; i++) { newElem = iteratee.call(this[i], this[i], i, this); if (utils.isElement(newElem)) { newSet.push(newElem); } else { throw new Error('.map fn should return an Element, not ' + typeof newElem); } } return collect.call(this, newSet); }; /** * Remove elements from the current set that match a new selector * @module filter * @param {Selector} selector A selector expression to match elements against * @returns DollarJS (reduced set) * @example $('p').not('.foo') */ $.fn.not = function (selector) { if (!selector) { return this; } var criteria; if (typeof selector === fnType) { criteria = function (node, i) { return !selector.call(node, i, node); }; } else { criteria = function (node, i) { return !nodeMatchesSelector(node, selector, i); }; } return collect(this.filter(criteria)); }; /****************/ /* MUTATE */ /****************/ /** * Inserts an array of contents into the DOM * Note: if more than one elem in dollar instance, inserted Elements will be moved instead of cloned */ function domInsert (contentsArr, method) { // Flatten nested arrays contentsArr = [].concat.apply([], contentsArr); var i, j, doInsert, content, frag, generatedNode; var colLen = contentsArr.length; var elemsLen = this.length; function nodeToFrag (node) { frag.appendChild(node); doInsert = true; } for (j = 0; j < elemsLen; j++) { doInsert = false; frag = docConstruct.createDocumentFragment(); for (i = 0; i < colLen; i++) { content = contentsArr[i]; if (content) { // content is String if (typeof content === strType) { if(generatedNode = htmlStringToNode(content)) { nodeToFrag(generatedNode); } // content is Element } else if (content.nodeType === 1 || content.nodeType === 11) { nodeToFrag(content); // content is dollar collection } else if (content.isDollar) { content.each(nodeToFrag); // content is function } else if (typeof content === fnType) { generatedNode = content(this[j], j); if (typeof generatedNode === strType) { generatedNode = htmlStringToNode(generatedNode); } if (generatedNode) { nodeToFrag(generatedNode); } } } } if(doInsert) { method(this[j], frag); } } return this; } /** * Insert content after each element in the current set * @module mutate * @param {Content} content Content to be inserted. Existing nodes will be moved instead of duplicated. * @option {Content} content Additional args are handled the same as the first, each in turn * @returns DollarJS (chainable) * @example $('p').after('<div class="new-stuff">') */ $.fn.after = function () { return domInsert.call(this, arguments, function (elem, content) { var parent = elem.parentNode; if (parent) { if (elem.nextSibling) { parent.insertBefore(content, elem.nextSibling); } else { parent.appendChild(content); } } }); }; /** * Insert content into each element in the current set (at the bottom) * @module mutate * @param {Content} content Content to be inserted. Existing nodes will be moved instead of duplicated. * @option {Content} content Additional args are handled the same as the first, each in turn * @returns DollarJS (chainable) * @example $('p').append('<div class="new-stuff">') */ $.fn.append = function () { return domInsert.call(this, arguments, function (elem, content) { elem.appendChild(content); }); }; /** * Insert content before each element in the current set * @module mutate * @param {Content} content Content to be inserted. Existing nodes will be moved instead of duplicated. * @option {Content} content Additional args are handled the same as the first, each in turn * @returns DollarJS (chainable) * @example $('p').before('<div class="new-stuff">') */ $.fn.before = function () { return domInsert.call(this, arguments, function (elem, content) { if (elem.parentNode) { elem.parentNode.insertBefore(content, elem); } }); }; /** * Clone each element in the current set * Uses cloneNode with deep=true * @module mutate * @returns DollarJS (cloned set) * @example $('p').clone() */ $.fn.clone = function () { var elem, i, len = this.length; for (i = 0; i < len; i++) { elem = this[i]; if (elem.nodeType === 1 || elem.nodeType === 11) { this[i] = elem.cloneNode(true); } } return this; }; /** * Empty the contents of each element in the current set * @module mutate * @returns DollarJS (chainable) * @example $('p').empty() */ $.fn.empty = function () { var elem, i, len = this.length; for (i = 0; i < len; i++) { elem = this[i]; if (elem.nodeType === 1) { elem.textContent = ''; } } return this; }; /** * Get or set the HTML contents of the current set * If htmlString is provided, this will set the contents of each element and return the current set for chaining * If no argument is passed, this will return the contents of the first element in the current set * @module mutate * @option {HTMLString} htmlString A string of HTML markup to be created and inserted * @returns HTMLString or DollarJS (chainable) * @example $('p').html() * @example $('p').html('<div>') */ $.fn.html = function (htmlString) { var elem, i, len = this.length, first = this[0]; if (htmlString === undef) { if (first && first.nodeType === 1) { return first.innerHTML; } return undef; } try { for (i = 0; i < len; i++) { elem = this[i]; if (elem.nodeType === 1) { elem.innerHTML = htmlString; } } } catch (e) { this.empty().append(htmlString); } return this; }; /** * Insert content into each element in the current set (at the top) * @module mutate * @param {Content} content Content to be inserted. Existing nodes will be moved instead of duplicated. * @option {Content} content Additional args are handled the same as the first, each in turn * @returns DollarJS (chainable) * @example $('p').prepend('<div class="new-stuff">') */ $.fn.prepend = function () { return domInsert.call(this, arguments, function (elem, content) { if (elem.firstChild) { elem.insertBefore(content, elem.firstChild); } else { elem.appendChild(content); } }); }; /** * Remove each element in the current set from the document * If a selector is provided, only remove elements that match the new selector * @module mutate * @option {Selector} selector A selector expression to match elements against * @returns DollarJS (chainable) * @example $('p').remove('.foo') */ $.fn.remove = function (selector) { var target, i, len = this.length; if (selector === undef) { for (i = 0; i < len; i++) { target = this[i]; if (target.parentNode) { target.parentNode.removeChild(target); } } } else { for (i = 0; i < len; i++) { target = this[i]; if (nodeMatchesSelector(target, selector, i) && target.parentNode) { target.parentNode.removeChild(target); } } } return this; }; /*******************/ /* READWRITE */ /*******************/ /** * Get or set attributes on the current set * If value is provided, this will set the attribute on each element and return the current set for chaining * If value is not passed, this will return the value of the attribute for the first element in the current set * There is a difference between attr vs prop * @module readwrite * @param {String} name The name of the attribute * @option {Any} value A value to be set. Most values will be converted to a String before setting. Functions will be evaluted with (previousValue, index) and the return value will be set. * @returns Value or DollarJS (chainable) * @example $('img').attr('title') * @example $('img').attr('title', 'Click Me') * @example $('img').attr('title', function(previousValue, index){ return 'Click Me'; }) */ $.fn.attr = function (name, value) { if (value === undef) { return getAttributeSafely(this[0], name); } this.each(function (elem, i) { if (nodeSupportsAttrProp(elem)) { if (typeof value === fnType) { value = value(getAttributeSafely(elem, name), i); } elem.setAttribute(name, value); } }); return this; }; /** * Store or read arbitrary data associated with the matched elements * If key and value are provided, this will set data for each element and return the current set for chaining * If only key {Object} is provided, this will set data for each element (as key/value pairs) and return the current set for chaining * If only key {String} is provided, this will return the data stored under the given key for the first element in the current set * If no arguments are passed, this will return all of the data stored for the first element in the current set * Note: setting data through dollar does NOT create corresponding data-attributes on the element * @module readwrite * @option {Object|String} key An Object of key/value pairs to store, or the String key from which to store/read a value * @option {Any} value A value to be set. Most values will be converted to a String before setting. Functions will be evaluted with (previousValue, index) and the return value will be set. * @returns Data or DollarJS (chainable) * @example $('p').data('foo', 'bar') * @example $('p').data({ foo: 'bar' }) * @example $('p').data('foo', function(previousValue, index){ return 'foo'; }) * @example $('p').data('foo') * @example $('p').data() */ $.fn.data = function (key, value) { if (!this.length) { return undef; } var elem, map = {}; // get all data if (!key) { return utils.extend({}, getDataFromDOM(this[0]), getElementData(DATA_CACHE_PUBLIC, this[0])); } if (typeof key === strType) { // get one value if (value === undef) { var retrievedData = getElementData(DATA_CACHE_PUBLIC, this[0], key); return retrievedData === undef ? getDataFromDOM(this[0])[key] : retrievedData; } // set map with one value map[key] = value; } else if (utils.isObject(key)) { // set using provided object as map map = key; } function setDataByMap (v, k) { setElementData(DATA_CACHE_PUBLIC, elem, k, v); } for (var i = 0, len = this.length; i < len; i++) { elem = this[i]; utils.each(map, setDataByMap); } return this; }; function getDataFromDOM (elem) { // Polyfill for IE<11 and Opera Mini return elem && elem.dataset || (function () { var data = {}; var allAttr = elem.attributes; var isDataAttr = /^data-[a-z_\-\d]*$/i; var name; for (var n in allAttr) { if (allAttr.hasOwnProperty(n)) { name = allAttr[n].name; if (isDataAttr.test(name)) { name = utils.format.dashToCamel(name.substr(5)); data[name] = allAttr[n].value; } } } return data; })(); } /** * Get or set properties on the current set * If value is provided, this will set the property on each element and return the current set for chaining * If value is not passed, this will return the value of the property for the first element in the current set * There is a difference between attr vs prop * @module readwrite * @param {String} name The name of the property * @option {Any} value A value to be set. Most values will be converted to a String before setting. Functions will be evaluted with (previousValue, index) and the return value will be set. * @returns Value or DollarJS (chainable) * @example $('input').prop('checked') * @example $('input').prop('checked', true) * @example $('input').prop('checked', function(previousValue, index){ return true; }) */ $.fn.prop = function (name, value) { if (value === undef) { return getPropertyFromElem(this[0], name); } this.each(function (elem, i) { if (nodeSupportsAttrProp(elem)) { if (typeof value === fnType) { value = value(getPropertyFromElem(elem, name), i); } elem[name] = value; } }); return this; }; function getPropertyFromElem (elem, name) { return nodeSupportsAttrProp(elem) ? elem[name] : undef; } /** * Remove an attribute from each element in the current set * @module readwrite * @param {String} name The name of the attribute * @returns DollarJS (chainable) * @example $('img').removeAttr('title') */ $.fn.removeAttr = function (name) { this.each(function () { this.removeAttribute(name); }); return this; }; /** * Unset data from each element in the current set * If key is not passed, ALL data will be removed * @module readwrite * @option {String} key A key under which specific data was stored * @returns DollarJS (chainable) * @example $('p').removeData('foo') * @example $('p').removeData() */ $.fn.removeData = function (key) { var elem, id; for (var i = 0, len = this.length; i < len; i++) { elem = this[i]; id = getInternalElementId(elem); if (key) { // clean dollar data if (id) { delete DATA_CACHE_PUBLIC[id][key]; } // clean DOM data if (elem) { if (elem.dataset) { if (elem.dataset[key]) { delete elem.dataset[key]; } } else { removeAttributeSafely(elem, 'data-' + utils.format.camelToDash(key)); } } } else { DATA_CACHE_PUBLIC[id] = {}; } } return this; }; /** * Remove a property from each element in the current set * @module readwrite * @param {String} name The name of the property * @returns DollarJS (chainable) * @example $('img').removeProp('title') */ $.fn.removeProp = function (name) { this.each(function () { if (nodeSupportsAttrProp(this)) { delete this[name]; } }); return this; }; /** * Get or set text contents on the current set * If value is provided, this will set the text contents for each element and return the current set for chaining * If no arguments are passed, this will return the text contents of the first element in the current set * @module readwrite * @option {Any} value A value to be set. Functions will be evaluted with (previousValue, index) and the return value will be set. * @returns Text or DollarJS (chainable) * @example $('p').text() * @example $('p').text('foo') * @example $('p').text(function(previousValue, index){ return 'foo'; }) */ $.fn.text = function (value) { if (value !== undef) { this.each(function (elem, i) { if (elem.nodeType === 1 || elem.nodeType === 11 || elem.nodeType === 9) { if (typeof value === fnType) { elem.textContent = value(elem.textContent, i); } else { elem.textContent = value; } } }); return this; } var ret = ''; this.each(function (elem) { var nodeType = elem.nodeType; if (nodeType === 1 || nodeType === 9 || nodeType === 11) { if (typeof elem.textContent === strType) { ret += elem.textContent; } } else if (nodeType === 3 || nodeType === 4) { ret += elem.nodeValue; } }); return ret; }; /** * Get or set a value on the current set * If value is provided, this will set the value for each element and return the current set for chaining * If no arguments are passed, this will return the value of the first element in the current set * @module readwrite * @option {Any} value A value to be set. Functions will be evaluted with (previousValue, index) and the return value will be set. * @returns Value or DollarJS (chainable) * @example $('p').val() * @example $('p').val('foo') * @example $('p').val(function(previousValue, index){ return 'foo'; }) */ $.fn.val = function (value) { if (value === undef) { return this[0] ? this[0].value : undef; } for (var i = 0; i < this.length; i++) { if (this[i].nodeType !== 1) { break; } if (typeof value === fnType) { value = value.call(this[i], this[i].value, i); } this[i].value = value; } return this; }; /***************/ /* STYLE */ /***************/ // get styles across various browsers var getStyle = win.getComputedStyle !== undef ? getStyleModern : getStyleCompat; function getStyleModern (elem, prop) { if (!elem || typeof prop !== strType) { return ''; } // apparently, IE <= 11 will throw for elements in popups // and FF <= 30 will throw for elements in an iframe if (elem.ownerDocument.defaultView.opener) { return elem.ownerDocument.defaultView.getComputedStyle(elem, null)[prop] || ''; } return win.getComputedStyle(elem, null)[prop] || elem.style[prop] || ''; } function getStyleCompat (elem, rawProp) { var prop; rawProp = typeof rawProp === strType ? rawProp : ''; if (!elem) { return ''; } if (rawProp === 'float') { prop = 'styleFloat'; } else { prop = utils.format.dashToCamel(rawProp.replace(/^-ms-/, 'ms-')); } return elem.currentStyle[prop]; } function getNonHiddenDisplayValue (elem) { var disp = elem.style.display; if (!disp || disp === 'none') { disp = getElementData(DATA_CACHE_PRIVATE, elem, 'nonHiddenDisplayValue') || ''; } if (!disp && elem.parentNode) { var tmp = docConstruct.createElement(elem.nodeName); elem.parentNode.appendChild(tmp); disp = getStyle(tmp, 'display'); elem.parentNode.removeChild(tmp); setElementData(DATA_CACHE_PRIVATE, elem, 'nonHiddenDisplayValue', disp); } return disp; } function getDocumentHeight () { return Math.max(docElement.offsetHeight, docElement.scrollHeight); } function getDocumentWidth () { return Math.max(docElement.offsetWidth, docElement.scrollWidth); } function getViewportHeight () { return Math.max(docElement.clientHeight, win.innerHeight); } function getViewportWidth () { return Math.max(docElement.clientWidth, win.innerWidth); } /** * Add classes to each element in the current set * @module style * @param {String} names A space-separated list of classes to be added * @returns DollarJS (chainable) * @example $('p').addClass('one two three') */ $.fn.addClass = function (names) { if (!names) { return this; } var newClasses, oldClasses; var i, len = this.length; if (typeof names === strType) { newClasses = names.trim().split(' '); for (i = 0; i < len; i++) { oldClasses = this[i].className.trim().replace(regExpSpacesAndBreaks, ' ').split(' '); this[i].className = utils.merge([], oldClasses, newClasses).join(' '); } } else if (typeof names === fnType) { for (i = 0; i < len; i++) { newClasses = names.call(this[i], this[i].className, i).split(' '); oldClasses = this[i].className.trim().replace(regExpSpacesAndBreaks, ' ').split(' '); this[i].className = utils.merge([], oldClasses, newClasses).join(' '); } } return this; }; /** * Get or set the style of each element in the current set * If property is a String and value is NOT passed, this will return the current value for that style property on the first element in the set * If property is a String and value is provided, this will set the value for that style property on all elements in the set * If property is an Object, styles will be set for each key:value pair on all elements in the set * @module style * @param {String|Object} property The String name of a css property, or an Object with key:value pairs * @option {String} value The value to be set. Numerical values should include units. * @returns Current style value or DollarJS (chainable) * @example $('p').css('color') * @example $('p').css('color', '#336699') * @example $('p').css({ color: '#336699', fontSize: '14px' }) */ $.fn.css = function (property, value) { if (!property) { return this; } var i, len = this.length; var elem, map = {}; if (typeof property === strType) { // get one value if (value === undef) { return getStyle(this[0], property); } // set with one value map[property] = value; } else if (utils.isObject(property)) { // set using provided object as map map = property; } function setPropertyByMap (v, k) { elem.style[k] = typeof v === fnType ? v.call(elem, getStyle(elem, k), i) : v; } for (i = 0; i < len; i++) { elem = this[i]; utils.each(map, setPropertyByMap); } return this; }; /** * Do any of the matched elements have the given class name? * @module style * @param {String} className A single class name to look for * @returns True or False * @example $('p').hasClass('foo') */ $.fn.hasClass = function (className) { if (!className) { return false; } // sandwich className with one space to avoid partial matches className = ' ' + className.trim() + ' '; for (var i = 0, len = this.length; i < len; i++) { if (this[i].nodeType === 1 && (' ' + this[i].className + ' ').replace(regExpSpacesAndBreaks, ' ').indexOf(className) !== -1) { return true; } } return false; }; /** * Get the current height of the first element in the set * This method does not set values. Use .css() instead. * @module style * @returns Height * @example $('div').height() */ $.fn.height = function () { var firstEl = this[0]; if (firstEl === window) { return getViewportHeight(); } if (firstEl === document) { return getDocumentHeight(); } return parseFloat(this.eq(0).css('height')) || 0; }; /** * Hide each element in the current set * This method does not support animation. Use .fadeOut() instead. * @module style * @returns DollarJS (chainable) * @example $('p').hide() */ $.fn.hide = function () { this.each(function () { this.style.display = 'none'; }); return this; }; /** * Remove classes from each element in the current set * @module style * @param {String} names A space-separated list of classes to be removed * @returns DollarJS (chainable) * @example $('p').removeClass('one two three') */ $.fn.removeClass = function (names) { var elem, newClasses, oldClasses, doomedClasses; function removeDoomed (old) { if (doomedClasses.indexOf(old) === -1) { newClasses.push(old); } } for (var i = 0, len = this.length; i < len; i++) { elem = this[i]; newClasses = []; // remove all if (!names) { elem.className = ''; } else { if (typeof names === fnType) { doomedClasses = names.call(elem, elem.className, i); } else { doomedClasses = names; } if (doomedClasses.length) { doomedClasses = typeof doomedClasses === strType ? doomedClasses.trim().split(' ') : doomedClasses; oldClasses = elem.className.replace(regExpSpacesAndBreaks, ' ').split(' '); utils.each(oldClasses, removeDoomed); elem.className = newClasses.join(' '); } } } return this; }; /** * Display each element in the current set * This method does not support animation. Use .fadeIn() instead. * @module style * @returns DollarJS (chainable) * @example $('p').show() */ $.fn.show = function () { this.each(function () { this.style.display = getNonHiddenDisplayValue(this); this.style.visibility = 'visible'; this.style.opacity = 1; }); return this; }; /** * Get the current width of the first element in the set * This method does not set values. Use .css() instead. * @module style * @returns Width * @example $('div').width() */ $.fn.width = function () { var firstEl = this[0]; if (firstEl === window) { return getViewportWidth(); } if (firstEl === document) { return getDocumentWidth(); } return parseFloat(this.eq(0).css('width')) || 0; }; /******************/ /* TRAVERSE */ /******************/ /** * Get the children of each element in the current set * The results will only include direct children and will not traverse any deeper descendants * If selector is provided, the results will only include children that match the selector * @module traverse * @option {Selector} selector A selector expression to match elements against * @returns DollarJS (new set) * @example $('p').children() * @example $('p').children('.foo') */ $.fn.children = function (selector) { var childNodes = []; for (var i = 0, len = this.length; i < len; i++) { utils.merge(childNodes, this[i].children); } return collect(selector ? $.fn.filter.call(childNodes, selector) : childNodes); }; /** * Reduce the set of matched elements to the first in the set * This is equivalent to .eq(0) * @module traverse * @returns DollarJS (reduced set) * @example $('p').first() */ $.fn.first = function () { return this.eq(0); }; /** * Reduce the set of matched elements to the last in the set * This is equivalent to .eq(-1) * @module traverse * @returns DollarJS (reduced set) * @example $('p').last() */ $.fn.last = function () { return this.eq(-1); }; /** * Get the next sibling of each element in the current set * If selector is provided, the results will only include siblings that match the selector * @module traverse * @option {Selector} selector A selector expression to match elements against * @returns DollarJS (new set) * @example $('p').next() * @example $('p').next('.foo') */ $.fn.next = function (selector) { var subsequents = [], nextNode; for (var i = 0, len = this.length; i < len; i++) { nextNode = this[i].nextElementSibling; if (nextNode) { subsequents.push(nextNode); } } return collect(selector ? $.fn.filter.call(subsequents, selector) : subsequents); }; /** * Get the parents of each element in the current set * The results will only include direct parents and will not traverse any higher ancestors * If selector is provided, the results will only include parents that match the selector * @module traverse * @option {Selector} selector A selector expression to match elements against * @returns DollarJS (new set) * @example $('p').parent() * @example $('p').parent('.foo') */ $.fn.parent = function (selector) { var parentElems = [], parent; for (var i = 0, len = this.length; i < len; i++) { parent = this[i].parentNode; if (parent) { parentElems.push(parent); } } return collect(selector ? $.fn.filter.call(parentElems, selector) : parentElems); }; /** * Get the previous sibling of each element in the current set * If selector is provided, the results will only include siblings that match the selector * @module traverse * @option {Selector} selector A selector expression to match elements against * @returns DollarJS (new set) * @example $('p').prev() * @example $('p').prev('.foo') */ $.fn.prev = function (selector) { var previousNodes = [], prevNode; for (var i = 0, len = this.length; i < len; i++) { prevNode = this[i].previousElementSibling; if (prevNode) { previousNodes.push(prevNode); } } return collect(selector ? $.fn.filter.call(previousNodes, selector) : previousNodes); }; /** * Get the siblings of each element in the current set * If selector is provided, the results will only include siblings that match the selector * @module traverse * @option {Selector} selector A selector expression to match elements against * @returns DollarJS (new set) * @example $('p').siblings() * @example $('p').siblings('.foo') */ $.fn.siblings = function (selector) { var siblings = [], target; for (var i = 0, len = this.length; i < len; i++) { if (this[i].parentNode) { target = this[i].parentNode.firstChild; } while (target) { if (target !== this[i] && target.nodeType === 1) { siblings.push(target); } target = target.nextSibling; } } return collect(selector ? $.fn.filter.call(siblings, selector) : siblings); }; /*****************/ /* TRIGGER */ /*****************/ var activeEventListenersKey = 'activeEventListeners'; var errorHandlers = []; $.onEventError = function (errorHandler) { errorHandlers.push(errorHandler); }; function bindEventHandlers (events, handler) { if (typeof events !== strType || typeof handler !== fnType) { return this; } function wrappedHandler () { if (errorHandlers.length) { try { handler.apply(this, arrSlice.call(arguments)); } catch (err) { utils.each(errorHandlers, function (errorHandler) { if (typeof errorHandler === fnType) { errorHandler(err); } }); } } else { handler.apply(this, arrSlice.call(arguments)); } } handler.wrappedHandler = wrappedHandler; events = events.split(' '); var addEventListenerCompat, i, evLen; this.each(function () { addEventListenerCompat = this.addEventListener || this.attachEvent; for (i = 0, evLen = events.length; i < evLen; i++) { addEventListenerCompat.call(this, events[i], wrappedHandler, false); pushElementData(DATA_CACHE_PRIVATE, this, activeEventListenersKey, handler); } }); return this; } function unbindEventHandlers (events, handler) { if (typeof events !== strType) { return this; } events = events.split(' '); var i, evLen, handlers, j, hdlrLen, removeEventListenerCompat; this.each(function () { removeEventListenerCompat = this.removeEventListener || this.detachEvent; for (i = 0, evLen = events.length; i < evLen; i++) { handlers = typeof handler === fnType ? [handler] : getElementData(DATA_CACHE_PRIVATE, this, activeEventListenersKey) || []; for (j = 0, hdlrLen = handlers.length; j < hdlrLen; j++) { removeEventListenerCompat.call(this, events[i], handlers[j].wrappedHandler, false); } } }); return this; } function triggerEventsOnElements (elems, events, args) { var ev; var eventInit = { bubbles: true, cancelable: true }; if (args && args.length) { eventInit.detail = args; } utils.each(events, function (eventName) { utils.each(elems, function (elem) { if (eventName === 'click') { elem.click(); } else if (eventName === 'focus') { elem.focus(); } else if (eventName === 'blur') { elem.blur(); } else { ev = new win.CustomEvent(eventName, eventInit); elem.dispatchEvent(ev); } }); }); } function bindOrTriggerConvenience (events, handler) { // bind handler to event if (typeof handler === fnType) { return bindEventHandlers.call(this, events, handler); // trigger event } else { triggerEventsOnElements(this, events.split(' ')); return this; } } /** * Handle a "click" event on any element in the current set * Equivalent to .on('click', handler) * @module trigger * @param {Function} handler A function to execute when an element is clicked * @returns DollarJS (chainable) * @example $('div').click(function(event){ console.log(this); }) */ $.fn.click = function (handler) { return bindOrTriggerConvenience.call(this, 'click', handler); }; /** * Handle a "focus" event on any element in the current set * Equivalent to .on('focus', handler) * @module trigger * @param {Function} handler A function to execute when an element is focused * @returns DollarJS (chainable) * @example $('input').focus(function(event){ console.log(this); }) */ $.fn.focus = function (handler) { return bindOrTriggerConvenience.call(this, 'focus', handler); }; /** * Handle a "blur" event on any element in the current set * Equivalent to .on('blur', handler) * @module trigger * @param {Function} handler A function to execute when an element is unfocused * @returns DollarJS (chainable) * @example $('input').blur(function(event){ console.log(this); }) */ $.fn.blur = function (handler) { return bindOrTriggerConvenience.call(this, 'blur', handler); }; /** * Handle a "change" event on any element in the current set * Equivalent to .on('change', handler) * @module trigger * @param {Function} handler A function to execute when an element is changed * @returns DollarJS (chainable) * @example $('input').change(function(event){ console.log(this); }) */ $.fn.change = function (handler) { return bindOrTriggerConvenience.call(this, 'change', handler); }; /** * Handle a "resize" event on any element in the current set * Equivalent to .on('resize', handler) * @module trigger * @param {Function} handler A function to execute when an element is resized * @returns DollarJS (chainable) * @example $(window).resize(function(event){ console.log(document.documentElement.clientWidth); }) */ $.fn.resize = function (handler) { return bindOrTriggerConvenience.call(this, 'resize', handler); }; /** * Unbind some event handler from each element in the current set * Aliased as .unbind() for compatibility * If no handler is provided, ALL handlers will be unbound from the specified events * @module trigger * @param {String} events A space-separated list of events to unbind * @option {Function} handler A specific function to unbind * @returns DollarJS (chainable) * @example $('p').off('click') * @example $('p').off('click', justOneHandler) */ $.fn.off = $.fn.unbind = unbindEventHandlers; /** * Bind some event handler to each element in the current set * Aliased as .bind() for compatibility * @module trigger * @param {String} events A space-separated list of events to listen for * @param {Function} handler A function to execute when one of the events is triggered * @returns DollarJS (chainable) * @example $('p').on('click', function(event){ console.log(this); }) * @example $('p').on('custom', function(event){ console.log(event.detail); }) */ $.fn.on = $.fn.bind = bindEventHandlers; /** * Trigger events on each element in the current set * Executes all handlers bound to each element in the current set corresponding to the given event names * @module trigger * @param {String} events A string-separated list of event names to be triggered * @option {Any} extraParameters... Additional parameters to pass along to the event handler * @returns DollarJS (chainable) * @example $('p').trigger('click') * @example $('p').trigger('click', 'extra', 'params') * @example $('p').trigger('one two three') */ $.fn.trigger = function (events) { if (typeof events !== strType) { return this; } events = events.split(' '); triggerEventsOnElements(this, events, arrSlice.call(arguments, 1)); return this; }; /******************/ /* IE9-11 SUPPORT */ /******************/ (function (w) { function CustomEventPolyfill (event, customInit) { customInit = customInit || { bubbles: false, cancelable: false }; var evt = document.createEvent('CustomEvent'); evt.initCustomEvent(event, customInit.bubbles, customInit.cancelable, customInit.detail); return evt; } if (typeof w.CustomEvent !== fnType) { CustomEventPolyfill.prototype = w.Event.prototype; w.CustomEvent = CustomEventPolyfill; } })(win); /****************/ /* EXPORT */ /****************/ /** * Export using whatever method is best * module.exports * window.$ */ (function () { var win = window; // Node.js if (typeof module !== 'undefined' && module.exports) { module.exports = $; // AMD loader } else if (typeof win.define === fnType && win.define.amd) { win.define(function () { return $; }); // Global window } else { win.$ = $; } }.call(this)); }.call(this));