UNPKG

emile

Version:

no-thrills stand-alone CSS animation JavaScript framework

1,593 lines (1,421 loc) 71.9 kB
/*! * Ender.js: next-level JavaScript * copyright Dustin Diaz & Jacob Thornton 2011 (@ded @fat) * https://github.com/ded/Ender.js * License MIT */ !function (context) { function aug(o, o2) { for (var k in o2) { o[k] = o2[k]; } } function _$(s, r) { this.elements = $._select(s, r); this.length = this.elements.length; for (var i = 0; i < this.length; i++) { this[i] = this.elements[i]; } } function $(s, r) { return new _$(s, r); } aug($, { ender: function (o, proto) { aug(proto ? _$.prototype : $, o); }, _select: function () { return []; } }); var old = context.$; $.noConflict = function () { context.$ = old; return this; }; (typeof module !== 'undefined') && module.exports ? (module.exports = $) : (context.$ = $); }(this);/*! * qwery.js - copyright @dedfat * https://github.com/ded/qwery * Follow our software http://twitter.com/dedfat * MIT License */ !function (context, doc) { var c, i, j, k, l, m, o, p, r, v, el, node, len, found, classes, item, items, token, collection, id = /#([\w\-]+)/, clas = /\.[\w\-]+/g, idOnly = /^#([\w\-]+$)/, classOnly = /^\.([\w\-]+)$/, tagOnly = /^([\w\-]+)$/, tagAndOrClass = /^([\w]+)?\.([\w\-]+)$/, html = doc.documentElement, tokenizr = /\s(?![\s\w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^'"]*\])/, simple = /^([a-z0-9]+)?(?:([\.\#]+[\w\-\.#]+)?)/, attr = /\[([\w\-]+)(?:([\|\^\$\*\~]?\=)['"]?([ \w\-\/\?\&\=\:\.\(\)\!,@#%<>\{\}\$\*\^]+)["']?)?\]/, chunker = new RegExp(simple.source + '(' + attr.source + ')?'); function array(ar) { r = []; for (i = 0, len = ar.length; i < len; i++) { r[i] = ar[i]; } return r; } var cache = function () { this.c = {}; }; cache.prototype = { g: function (k) { return this.c[k] || undefined; }, s: function (k, v) { this.c[k] = v; return v; } }; var classCache = new cache(), cleanCache = new cache(), attrCache = new cache(), tokenCache = new cache(); function q(query) { return query.match(chunker); } function interpret(whole, tag, idsAndClasses, wholeAttribute, attribute, qualifier, value) { var m, c, k; if (tag && this.tagName.toLowerCase() !== tag) { return false; } if (idsAndClasses && (m = idsAndClasses.match(id)) && m[1] !== this.id) { return false; } if (idsAndClasses && (classes = idsAndClasses.match(clas))) { for (i = classes.length; i--;) { c = classes[i].slice(1); if (!(classCache.g(c) || classCache.s(c, new RegExp('(^|\\s+)' + c + '(\\s+|$)'))).test(this.className)) { return false; } } } if (wholeAttribute && !value) { o = this.attributes; for (k in o) { if (Object.prototype.hasOwnProperty.call(o, k) && (o[k].name || k) == attribute) { return this; } } } if (wholeAttribute && !checkAttr(qualifier, this.getAttribute(attribute) || '', value)) { return false; } return this; } function loopAll(tokens) { var r = [], token = tokens.pop(), intr = q(token), tag = intr[1] || '*', i, l, els, root = tokens.length && (m = tokens[0].match(idOnly)) ? doc.getElementById(m[1]) : doc; if (!root) { return r; } els = root.getElementsByTagName(tag); for (i = 0, l = els.length; i < l; i++) { el = els[i]; if (item = interpret.apply(el, intr)) { r.push(item); } } return r; } function clean(s) { return cleanCache.g(s) || cleanCache.s(s, s.replace(/([.*+?\^=!:${}()|\[\]\/\\])/g, '\\$1')); } function checkAttr(qualify, actual, val) { switch (qualify) { case '=': return actual == val; case '^=': return actual.match(attrCache.g('^=' + val) || attrCache.s('^=' + val, new RegExp('^' + clean(val)))); case '$=': return actual.match(attrCache.g('$=' + val) || attrCache.s('$=' + val, new RegExp(clean(val) + '$'))); case '*=': return actual.match(attrCache.g(val) || attrCache.s(val, new RegExp(clean(val)))); case '~=': return actual.match(attrCache.g('~=' + val) || attrCache.s('~=' + val, new RegExp('(?:^|\\s+)' + clean(val) + '(?:\\s+|$)'))); case '|=': return actual.match(attrCache.g('|=' + val) || attrCache.s('|=' + val, new RegExp('^' + clean(val) + '(-|$)'))); } return false; } function _qwery(selector) { var r = [], ret = [], i, l, tokens = tokenCache.g(selector) || tokenCache.s(selector, selector.split(tokenizr)); tokens = tokens.slice(0); if (!tokens.length) { return r; } r = loopAll(tokens); if (!tokens.length) { return r; } // loop through all descendent tokens for (j = 0, l = r.length, k = 0; j < l; j++) { node = r[j]; p = node; // loop through each token for (i = tokens.length; i--;) { z: // loop through parent nodes while (p !== html && (p = p.parentNode)) { if (found = interpret.apply(p, q(tokens[i]))) { break z; } } } found && (ret[k++] = node); } return ret; } var isAncestor = 'compareDocumentPosition' in html ? function (element, container) { return (container.compareDocumentPosition(element) & 16) == 16; } : 'contains' in html ? function (element, container) { return container !== element && container.contains(element); } : function (element, container) { while (element = element.parentNode) { if (element === container) { return 1; } } return 0; }; function boilerPlate(selector, _root, fn) { var root = (typeof _root == 'string') ? fn(_root)[0] : (_root || doc); if (isNode(selector)) { return !_root || (isNode(root) && isAncestor(selector, root)) ? [selector] : []; } if (m = selector.match(idOnly)) { return (el = doc.getElementById(m[1])) ? [el] : []; } if (m = selector.match(tagOnly)) { return array(root.getElementsByTagName(m[1])); } return false; } function isNode(el) { return (el === window || el && el.nodeType && el.nodeType.toString().match(/[19]/)); } function qsa(selector, _root) { var root = (typeof _root == 'string') ? qsa(_root)[0] : (_root || doc); if (!root) { return []; } if (m = boilerPlate(selector, _root, qsa)) { return m; } if (doc.getElementsByClassName && (m = selector.match(classOnly))) { return array((root).getElementsByClassName(m[1])); } return array((root).querySelectorAll(selector)); } function uniq(ar) { var a = [], i, j; label: for (i = 0; i < ar.length; i++) { for (j = 0; j < a.length; j++) { if (a[j] == ar[i]) { continue label; } } a[a.length] = ar[i]; } return a; } var qwery = function () { // return fast. boosh. if (doc.querySelector && doc.querySelectorAll) { return qsa; } return function (selector, _root) { var root = (typeof _root == 'string') ? qwery(_root)[0] : (_root || doc); if (!root) { return []; } var i, l, result = [], collections = [], element; if (m = boilerPlate(selector, _root, qwery)) { return m; } if (m = selector.match(tagAndOrClass)) { items = root.getElementsByTagName(m[1] || '*'); r = classCache.g(m[2]) || classCache.s(m[2], new RegExp('(^|\\s+)' + m[2] + '(\\s+|$)')); for (i = 0, l = items.length, j = 0; i < l; i++) { r.test(items[i].className) && (result[j++] = items[i]); } return result; } for (i = 0, items = selector.split(','), l = items.length; i < l; i++) { collections[i] = _qwery(items[i]); } for (i = 0, l = collections.length; i < l && (collection = collections[i]); i++) { var ret = collection; if (root !== doc) { ret = []; for (j = 0, m = collection.length; j < m && (element = collection[j]); j++) { // make sure element is a descendent of root isAncestor(element, root) && ret.push(element); } } result = result.concat(ret); } return uniq(result); }; }(); // being nice var oldQwery = context.qwery; qwery.noConflict = function () { context.qwery = oldQwery; return this; }; context.qwery = qwery; }(this, document); /*! * bonzo.js - copyright @dedfat 2011 * https://github.com/ded/bonzo * Follow our software http://twitter.com/dedfat * MIT License */ !function (context) { var doc = document, html = (doc.compatMode == 'CSS1Compat') ? doc.documentElement : doc.body, specialAttributes = /^checked|value|selected$/, stateAttributes = /^checked|selected$/, ie = /msie/.test(navigator.userAgent); function classReg(c) { return new RegExp("(^|\\s+)" + c + "(\\s+|$)"); } function each(ar, fn) { for (i = 0, len = ar.length; i < len; i++) { fn(ar[i]); } } function trim(s) { return s.replace(/(^\s*|\s*$)/g, ''); } function camelize(s) { return s.replace(/-(.)/g, function (m, m1) { return m1.toUpperCase(); }); } function is(node) { return node && node.nodeName && node.nodeType == 1; } function some(ar, fn, scope) { for (var i = 0, j = ar.length; i < j; ++i) { if (fn.call(scope, ar[i], i, ar)) { return true; } } return false; } function _bonzo(elements) { this.elements = []; if (elements) { this.elements = Object.prototype.hasOwnProperty.call(elements, 'length') ? elements : [elements]; this.length = this.elements.length; for (var i = 0; i < this.length; i++) { this[i] = this.elements[i]; } } } _bonzo.prototype = { each: function (fn) { for (var i = 0; i < this.elements.length; i++) { fn.call(this, this.elements[i]); } return this; }, map: function (fn, include) { var m = [], n; for (var i = 0; i < this.elements.length; i++) { n = fn.call(this, this.elements[i]); include ? (include(n) && m.push(n)) : m.push(n); } return m; }, first: function () { this.elements = [this.elements[0]]; return this; }, last: function () { this.elements = [this.elements[this.elements.length - 1]]; return this; }, html: function (html) { return typeof html == 'string' ? this.each(function (el) { el.innerHTML = html; }) : this.elements[0].innerHTML; }, addClass: function (c) { return this.each(function (el) { this.hasClass(el, c) || (el.className = trim(el.className + ' ' + c)); }); }, removeClass: function (c) { return this.each(function (el) { this.hasClass(el, c) && (el.className = trim(el.className.replace(classReg(c), ' '))); }); }, hasClass: function (el, c) { return typeof c == 'undefined' ? some(this.elements, function (i) { return classReg(el).test(i.className); }) : classReg(c).test(el.className); }, show: function (elements) { return this.each(function (el) { el.style.display = ''; }); }, hide: function (elements) { return this.each(function (el) { el.style.display = 'none'; }); }, append: function (node) { return this.each(function (el) { each(bonzo.create(node), function (i) { el.appendChild(i); }); }); }, prepend: function (node) { return this.each(function (el) { var first = el.firstChild; each(bonzo.create(node), function (i) { el.insertBefore(i, first); }); }); }, appendTo: function (target) { return this.each(function (el) { target.appendChild(el); }); }, next: function () { return this.related('nextSibling'); }, previous: function () { return this.related('previousSibling'); }, related: function (method) { this.elements = this.map( function (el) { el = el[method]; while (el && el.nodeType !== 1) { el = el[method]; } return el || 0; }, function (el) { return el; } ); return this; }, prependTo: function (target) { return this.each(function (el) { target.insertBefore(el, bonzo.firstChild(target)); }); }, before: function (node) { return this.each(function (el) { each(bonzo.create(node), function (i) { el.parentNode.insertBefore(i, el); }); }); }, after: function (node) { return this.each(function (el) { each(bonzo.create(node), function (i) { el.parentNode.insertBefore(i, el.nextSibling); }); }); }, css: function (o, v) { var fn = typeof o == 'string' ? function (el) { el.style[camelize(o)] = v; } : function (el) { for (var k in o) { o.hasOwnProperty(k) && (el.style[camelize(k)] = o[k]); } }; return this.each(fn); }, offset: function () { var el = this.elements[0]; var width = el.offsetWidth; var height = el.offsetHeight; var top = el.offsetTop; var left = el.offsetLeft; while (el = el.offsetParent) { top = top + el.offsetTop; left = left + el.offsetLeft; } return { top: top, left: left, height: height, width: width }; }, attr: function (k, v) { var el = this.elements[0]; return typeof v == 'undefined' ? specialAttributes.test(k) ? stateAttributes.test(k) && typeof el[k] == 'string' ? true : el[k] : el.getAttribute(k) : this.each(function (el) { el.setAttribute(k, v); }); }, remove: function () { return this.each(function (el) { el.parentNode.removeChild(el); }); }, empty: function () { return this.each(function (el) { while (el.firstChild) { el.removeChild(el.firstChild); } }); }, detach: function () { return this.map(function (el) { return el.parentNode.removeChild(el); }); }, scrollTop: function (y) { return scroll.call(this, null, y, 'y'); }, scrollLeft: function (x) { return scroll.call(this, x, null, 'x'); } }; function scroll(x, y, type) { var el = this.elements[0]; if (x == null && y == null) { return (isBody(el) ? getWindowScroll() : { x: el.scrollLeft, y: el.scrollTop })[type]; } if (isBody(el)) { window.scrollTo(x, y); } else { x != null && (el.scrollLeft = x); y != null && (el.scrollTop = y); } return this; } function isBody(element) { return element === window || (/^(?:body|html)$/i).test(element.tagName); } function getWindowScroll() { return { x: window.pageXOffset || html.scrollLeft, y: window.pageYOffset || html.scrollTop }; } function bonzo(els) { return new _bonzo(els); } bonzo.aug = function (o, target) { for (var k in o) { o.hasOwnProperty(k) && ((target || _bonzo.prototype)[k] = o[k]); } }; bonzo.create = function (node) { return typeof node == 'string' ? function () { var el = doc.createElement('div'), els = []; el.innerHTML = node; var nodes = el.childNodes; el = el.firstChild; els.push(el); while (el = el.nextSibling) { (el.nodeType == 1) && els.push(el); } return els; }() : is(node) ? [node.cloneNode(true)] : []; }; bonzo.doc = function () { var w = html.scrollWidth, h = html.scrollHeight, vp = this.viewport(); return { width: Math.max(w, vp.width), height: Math.max(h, vp.height) }; }; bonzo.firstChild = function (el) { for (var c = el.childNodes, i = 0, j = (c && c.length) || 0, e; i < j; i++) { if (c[i].nodeType === 1) { e = c[j = i]; } } return e; }; bonzo.viewport = function () { var h = self.innerHeight, w = self.innerWidth; ie && (h = html.clientHeight) && (w = html.clientWidth); return { width: w, height: h }; }; bonzo.contains = 'compareDocumentPosition' in html ? function (container, element) { return (container.compareDocumentPosition(element) & 16) == 16; } : 'contains' in html ? function (container, element) { return container !== element && container.contains(element); } : function (container, element) { while (element = element.parentNode) { if (element === container) { return true; } } return false; }; var old = context.bonzo; bonzo.noConflict = function () { context.bonzo = old; return this; }; context.bonzo = bonzo; }(this);/*! * bean.js - copyright @dedfat * https://github.com/fat/bean * Follow our software http://twitter.com/dedfat * MIT License * special thanks to: * dean edwards: http://dean.edwards.name/ * dperini: https://github.com/dperini/nwevents * the entire mootools team: github.com/mootools/mootools-core */ !function (context) { var __uid = 1, registry = {}, collected = {}, overOut = /over|out/, namespace = /[^\.]*(?=\..*)\.|.*/, stripName = /\..*/, addEvent = 'addEventListener', attachEvent = 'attachEvent', removeEvent = 'removeEventListener', detachEvent = 'detachEvent'; function isDescendant(parent, child) { var node = child.parentNode; while (node != null) { if (node == parent) { return true; } node = node.parentNode; } } function retrieveEvents(element) { var uid = retrieveUid(element); return (registry[uid] = registry[uid] || {}); } function retrieveUid(obj, uid) { return (obj.__uid = uid || obj.__uid || __uid++); } function listener(element, type, fn, add, custom) { if (element[addEvent]) { element[add ? addEvent : removeEvent](type, fn, false); } else if (element[attachEvent]) { custom && add && (element['_on' + custom] = element['_on' + custom] || 0); element[add ? attachEvent : detachEvent]('on' + type, fn); } } function nativeHandler(element, fn, args) { return function (event) { event = fixEvent(event || ((this.ownerDocument || this.document || this).parentWindow || context).event); return fn.apply(element, [event].concat(args)); }; } function customHandler(element, fn, type, condition, args) { return function (event) { if (condition ? condition.call(this, event) : event && event.propertyName == '_on' + type || !event) { fn.apply(element, [event].concat(args)); } }; } function addListener(element, orgType, fn, args) { var type = orgType.replace(stripName, ''), events = retrieveEvents(element), handlers = events[type] || (events[type] = {}), uid = retrieveUid(fn, orgType.replace(namespace, '')); if (handlers[uid]) { return element; } var custom = customEvents[type]; fn = custom && custom.condition ? customHandler(element, fn, type, custom.condition) : fn; type = custom && custom.base || type; var isNative = context[addEvent] || nativeEvents.indexOf(type) > -1; fn = isNative ? nativeHandler(element, fn, args) : customHandler(element, fn, type, false, args); if (type == 'unload') { var org = fn; fn = function () { removeListener(element, type, fn) && org(); }; } listener(element, isNative ? type : 'propertychange', fn, true, !isNative && true); handlers[uid] = fn; fn.__uid = uid; return type == 'unload' ? element : (collected[retrieveUid(element)] = element); } function removeListener(element, orgType, handler) { var uid, names, uids, i, events = retrieveEvents(element), type = orgType.replace(stripName, ''); if (!events || !events[type]) { return element; } names = orgType.replace(namespace, ''); uids = names ? names.split('.') : [handler.__uid]; for (i = uids.length; i--;) { uid = uids[i]; handler = events[type][uid]; delete events[type][uid]; type = customEvents[type] ? customEvents[type].base : type; var isNative = element[addEvent] || nativeEvents.indexOf(type) > -1; listener(element, isNative ? type : 'propertychange', handler, false, !isNative && type); } return element; } function del(selector, fn, $) { return function (e) { var array = typeof selector == 'string' ? $(selector, this) : selector; for (var target = e.target; target && target != this; target = target.parentNode) { for (var i = array.length; i--;) { if (array[i] == target) { return fn.apply(target, arguments); } } } }; } function add(element, events, fn, delfn, $) { if (typeof events == 'object' && !fn) { for (var type in events) { events.hasOwnProperty(type) && add(element, type, events[type]); } } else { var isDel = typeof fn == 'string', types = (isDel ? fn : events).split(' '); fn = isDel ? del(events, delfn, $) : fn; for (var i = types.length; i--;) { addListener(element, types[i], fn, Array.prototype.slice.call(arguments, isDel ? 4 : 3)); } } return element; } function remove(element, orgEvents, fn) { var k, type, events, isString = typeof(orgEvents) == 'string', names = isString && orgEvents.replace(namespace, ''), rm = removeListener, attached = retrieveEvents(element); if (isString && /\s/.test(orgEvents)) { orgEvents = orgEvents.split(' '); var i = orgEvents.length - 1; while (remove(element, orgEvents[i]) && i--) {} return element; } events = isString ? orgEvents.replace(stripName, '') : orgEvents; if (!attached || (isString && !attached[events])) { return element; } if (typeof fn == 'function') { rm(element, events, fn); } else if (names) { rm(element, orgEvents); } else { rm = events ? rm : remove; type = isString && events; events = events ? (fn || attached[events] || events) : attached; for (k in events) { events.hasOwnProperty(k) && rm(element, type || k, events[k]); } } return element; } function fire(element, type) { var evt, k, i, types = type.split(' '); for (i = types.length; i--;) { type = types[i].replace(stripName, ''); var isNative = nativeEvents.indexOf(type) > -1, isNamespace = types[i].replace(namespace, ''), handlers = retrieveEvents(element)[type]; if (isNamespace) { isNamespace = isNamespace.split('.'); for (k = isNamespace.length; k--;) { handlers[isNamespace[k]] && handlers[isNamespace[k]](); } } else if (element[addEvent]) { evt = document.createEvent(isNative ? "HTMLEvents" : "UIEvents"); evt[isNative ? 'initEvent' : 'initUIEvent'](type, true, true, context, 1); element.dispatchEvent(evt); } else if (element[attachEvent]) { isNative ? element.fireEvent('on' + type, document.createEventObject()) : element['_on' + type]++; } else { for (k in handlers) { handlers.hasOwnProperty(k) && handlers[k](); } } } return element; } function clone(element, from, type) { var events = retrieveEvents(from), obj, k; obj = type ? events[type] : events; for (k in obj) { obj.hasOwnProperty(k) && (type ? add : clone)(element, type || from, type ? obj[k] : k); } return element; } function fixEvent(e) { var result = {}; if (!e) { return result; } var type = e.type, target = e.target || e.srcElement; result.preventDefault = e.preventDefault || fixEvent.preventDefault; result.stopPropagation = e.stopPropagation || fixEvent.stopPropagation; result.target = target && target.nodeType == 3 ? target.parentNode : target; if (type.indexOf('key') != -1) { result.keyCode = e.which || e.keyCode; } else if ((/click|mouse|menu/i).test(type)) { result.rightClick = e.which == 3 || e.button == 2; result.pos = { x: 0, y: 0 }; if (e.pageX || e.pageY) { result.pos.x = e.pageX; result.pos.y = e.pageY; } else if (e.clientX || e.clientY) { result.pos.x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; result.pos.y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; } overOut.test(type) && (result.relatedTarget = e.relatedTarget || e[(type == 'mouseover' ? 'from' : 'to') + 'Element']); } for (var k in e) { if (!(k in result)) { result[k] = e[k]; } } return result; } fixEvent.preventDefault = function () { this.returnValue = false; }; fixEvent.stopPropagation = function () { this.cancelBubble = true; }; var nativeEvents = 'click,dblclick,mouseup,mousedown,contextmenu,' + //mouse buttons 'mousewheel,DOMMouseScroll,' + //mouse wheel 'mouseover,mouseout,mousemove,selectstart,selectend,' + //mouse movement 'keydown,keypress,keyup,' + //keyboard 'orientationchange,' + // mobile 'touchstart,touchmove,touchend,touchcancel,' + // touch 'gesturestart,gesturechange,gestureend,' + // gesture 'focus,blur,change,reset,select,submit,' + //form elements 'load,unload,beforeunload,resize,move,DOMContentLoaded,readystatechange,' + //window 'error,abort,scroll'.split(','); //misc function check(event) { var related = event.relatedTarget; if (!related) { return related == null; } return (related != this && related.prefix != 'xul' && !/document/.test(this.toString()) && !isDescendant(this, related)); } var customEvents = { mouseenter: { base: 'mouseover', condition: check }, mouseleave: { base: 'mouseout', condition: check }, mousewheel: { base: /Firefox/.test(navigator.userAgent) ? 'DOMMouseScroll' : 'mousewheel' } }; var bean = { add: add, remove: remove, clone: clone, fire: fire }; var clean = function (el) { var uid = remove(el).__uid; if (uid) { delete collected[uid]; delete registry[uid]; } }; if (context[attachEvent]) { add(context, 'unload', function () { for (var k in collected) { collected.hasOwnProperty(k) && clean(collected[k]); } context.CollectGarbage && CollectGarbage(); }); } var oldBean = context.bean; bean.noConflict = function () { context.bean = oldBean; return this; }; (typeof module !== 'undefined' && module.exports) ? (module.exports = bean) : (context.bean = bean); }(this);!function () { var module = { exports: {} }; // Underscore.js 1.1.5 // (c) 2011 Jeremy Ashkenas, DocumentCloud Inc. // Underscore is freely distributable under the MIT license. // Portions of Underscore are inspired or borrowed from Prototype, // Oliver Steele's Functional, and John Resig's Micro-Templating. // For all details and documentation: // http://documentcloud.github.com/underscore (function() { // Baseline setup // -------------- // Establish the root object, `window` in the browser, or `global` on the server. var root = this; // Save the previous value of the `_` variable. var previousUnderscore = root._; // Establish the object that gets returned to break out of a loop iteration. var breaker = {}; // Save bytes in the minified (but not gzipped) version: var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; // Create quick reference variables for speed access to core prototypes. var slice = ArrayProto.slice, unshift = ArrayProto.unshift, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty; // All **ECMAScript 5** native function implementations that we hope to use // are declared here. var nativeForEach = ArrayProto.forEach, nativeMap = ArrayProto.map, nativeReduce = ArrayProto.reduce, nativeReduceRight = ArrayProto.reduceRight, nativeFilter = ArrayProto.filter, nativeEvery = ArrayProto.every, nativeSome = ArrayProto.some, nativeIndexOf = ArrayProto.indexOf, nativeLastIndexOf = ArrayProto.lastIndexOf, nativeIsArray = Array.isArray, nativeKeys = Object.keys, nativeBind = FuncProto.bind; // Create a safe reference to the Underscore object for use below. var _ = function(obj) { return new wrapper(obj); }; // Export the Underscore object for **CommonJS**, with backwards-compatibility // for the old `require()` API. If we're not in CommonJS, add `_` to the // global object. if (typeof module !== 'undefined' && module.exports) { module.exports = _; _._ = _; } else { root._ = _; } // Current version. _.VERSION = '1.1.5'; // Collection Functions // -------------------- // The cornerstone, an `each` implementation, aka `forEach`. // Handles objects implementing `forEach`, arrays, and raw objects. // Delegates to **ECMAScript 5**'s native `forEach` if available. var each = _.each = _.forEach = function(obj, iterator, context) { if (obj == null) return; if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); } else if (_.isNumber(obj.length)) { for (var i = 0, l = obj.length; i < l; i++) { if (iterator.call(context, obj[i], i, obj) === breaker) return; } } else { for (var key in obj) { if (hasOwnProperty.call(obj, key)) { if (iterator.call(context, obj[key], key, obj) === breaker) return; } } } }; // Return the results of applying the iterator to each element. // Delegates to **ECMAScript 5**'s native `map` if available. _.map = function(obj, iterator, context) { var results = []; if (obj == null) return results; if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); each(obj, function(value, index, list) { results[results.length] = iterator.call(context, value, index, list); }); return results; }; // **Reduce** builds up a single result from a list of values, aka `inject`, // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { var initial = memo !== void 0; if (obj == null) obj = []; if (nativeReduce && obj.reduce === nativeReduce) { if (context) iterator = _.bind(iterator, context); return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); } each(obj, function(value, index, list) { if (!initial && index === 0) { memo = value; initial = true; } else { memo = iterator.call(context, memo, value, index, list); } }); if (!initial) throw new TypeError("Reduce of empty array with no initial value"); return memo; }; // The right-associative version of reduce, also known as `foldr`. // Delegates to **ECMAScript 5**'s native `reduceRight` if available. _.reduceRight = _.foldr = function(obj, iterator, memo, context) { if (obj == null) obj = []; if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { if (context) iterator = _.bind(iterator, context); return memo !== void 0 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); } var reversed = (_.isArray(obj) ? obj.slice() : _.toArray(obj)).reverse(); return _.reduce(reversed, iterator, memo, context); }; // Return the first value which passes a truth test. Aliased as `detect`. _.find = _.detect = function(obj, iterator, context) { var result; any(obj, function(value, index, list) { if (iterator.call(context, value, index, list)) { result = value; return true; } }); return result; }; // Return all the elements that pass a truth test. // Delegates to **ECMAScript 5**'s native `filter` if available. // Aliased as `select`. _.filter = _.select = function(obj, iterator, context) { var results = []; if (obj == null) return results; if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); each(obj, function(value, index, list) { if (iterator.call(context, value, index, list)) results[results.length] = value; }); return results; }; // Return all the elements for which a truth test fails. _.reject = function(obj, iterator, context) { var results = []; if (obj == null) return results; each(obj, function(value, index, list) { if (!iterator.call(context, value, index, list)) results[results.length] = value; }); return results; }; // Determine whether all of the elements match a truth test. // Delegates to **ECMAScript 5**'s native `every` if available. // Aliased as `all`. _.every = _.all = function(obj, iterator, context) { iterator || (iterator = _.identity); var result = true; if (obj == null) return result; if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); each(obj, function(value, index, list) { if (!(result = result && iterator.call(context, value, index, list))) return breaker; }); return result; }; // Determine if at least one element in the object matches a truth test. // Delegates to **ECMAScript 5**'s native `some` if available. // Aliased as `any`. var any = _.some = _.any = function(obj, iterator, context) { iterator || (iterator = _.identity); var result = false; if (obj == null) return result; if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); each(obj, function(value, index, list) { if (result = iterator.call(context, value, index, list)) return breaker; }); return result; }; // Determine if a given value is included in the array or object using `===`. // Aliased as `contains`. _.include = _.contains = function(obj, target) { var found = false; if (obj == null) return found; if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; any(obj, function(value) { if (found = value === target) return true; }); return found; }; // Invoke a method (with arguments) on every item in a collection. _.invoke = function(obj, method) { var args = slice.call(arguments, 2); return _.map(obj, function(value) { return (method ? value[method] : value).apply(value, args); }); }; // Convenience version of a common use case of `map`: fetching a property. _.pluck = function(obj, key) { return _.map(obj, function(value){ return value[key]; }); }; // Return the maximum element or (element-based computation). _.max = function(obj, iterator, context) { if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj); var result = {computed : -Infinity}; each(obj, function(value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; computed >= result.computed && (result = {value : value, computed : computed}); }); return result.value; }; // Return the minimum element (or element-based computation). _.min = function(obj, iterator, context) { if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj); var result = {computed : Infinity}; each(obj, function(value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; computed < result.computed && (result = {value : value, computed : computed}); }); return result.value; }; // Sort the object's values by a criterion produced by an iterator. _.sortBy = function(obj, iterator, context) { return _.pluck(_.map(obj, function(value, index, list) { return { value : value, criteria : iterator.call(context, value, index, list) }; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }), 'value'); }; // Use a comparator function to figure out at what index an object should // be inserted so as to maintain order. Uses binary search. _.sortedIndex = function(array, obj, iterator) { iterator || (iterator = _.identity); var low = 0, high = array.length; while (low < high) { var mid = (low + high) >> 1; iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; } return low; }; // Safely convert anything iterable into a real, live array. _.toArray = function(iterable) { if (!iterable) return []; if (iterable.toArray) return iterable.toArray(); if (_.isArray(iterable)) return iterable; if (_.isArguments(iterable)) return slice.call(iterable); return _.values(iterable); }; // Return the number of elements in an object. _.size = function(obj) { return _.toArray(obj).length; }; // Array Functions // --------------- // Get the first element of an array. Passing **n** will return the first N // values in the array. Aliased as `head`. The **guard** check allows it to work // with `_.map`. _.first = _.head = function(array, n, guard) { return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; }; // Returns everything but the first entry of the array. Aliased as `tail`. // Especially useful on the arguments object. Passing an **index** will return // the rest of the values in the array from that index onward. The **guard** // check allows it to work with `_.map`. _.rest = _.tail = function(array, index, guard) { return slice.call(array, (index == null) || guard ? 1 : index); }; // Get the last element of an array. _.last = function(array) { return array[array.length - 1]; }; // Trim out all falsy values from an array. _.compact = function(array) { return _.filter(array, function(value){ return !!value; }); }; // Return a completely flattened version of an array. _.flatten = function(array) { return _.reduce(array, function(memo, value) { if (_.isArray(value)) return memo.concat(_.flatten(value)); memo[memo.length] = value; return memo; }, []); }; // Return a version of the array that does not contain the specified value(s). _.without = function(array) { var values = slice.call(arguments, 1); return _.filter(array, function(value){ return !_.include(values, value); }); }; // Produce a duplicate-free version of the array. If the array has already // been sorted, you have the option of using a faster algorithm. // Aliased as `unique`. _.uniq = _.unique = function(array, isSorted) { return _.reduce(array, function(memo, el, i) { if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el; return memo; }, []); }; // Produce an array that contains every item shared between all the // passed-in arrays. _.intersect = function(array) { var rest = slice.call(arguments, 1); return _.filter(_.uniq(array), function(item) { return _.every(rest, function(other) { return _.indexOf(other, item) >= 0; }); }); }; // Zip together multiple lists into a single array -- elements that share // an index go together. _.zip = function() { var args = slice.call(arguments); var length = _.max(_.pluck(args, 'length')); var results = new Array(length); for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); return results; }; // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), // we need this function. Return the position of the first occurrence of an // item in an array, or -1 if the item is not included in the array. // Delegates to **ECMAScript 5**'s native `indexOf` if available. // If the array is large and already in sort order, pass `true` // for **isSorted** to use binary search. _.indexOf = function(array, item, isSorted) { if (array == null) return -1; var i, l; if (isSorted) { i = _.sortedIndex(array, item); return array[i] === item ? i : -1; } if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i; return -1; }; // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. _.lastIndexOf = function(array, item) { if (array == null) return -1; if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); var i = array.length; while (i--) if (array[i] === item) return i; return -1; }; // Generate an integer Array containing an arithmetic progression. A port of // the native Python `range()` function. See // [the Python documentation](http://docs.python.org/library/functions.html#range). _.range = function(start, stop, step) { if (arguments.length <= 1) { stop = start || 0; start = 0; } step = arguments[2] || 1; var len = Math.max(Math.ceil((stop - start) / step), 0); var idx = 0; var range = new Array(len); while(idx < len) { range[idx++] = start; start += step; } return range; }; // Function (ahem) Functions // ------------------ // Create a function bound to a given object (assigning `this`, and arguments, // optionally). Binding with arguments is also known as `curry`. // Delegates to **ECMAScript 5**'s native `Function.bind` if available. // We check for `func.bind` first, to fail fast when `func` is undefined. _.bind = function(func, obj) { if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); var args = slice.call(arguments, 2); return function() { return func.apply(obj, args.concat(slice.call(arguments))); }; }; // Bind all of an object's methods to that object. Useful for ensuring that // all callbacks defined on an object belong to it. _.bindAll = function(obj) { var funcs = slice.call(arguments, 1); if (funcs.length == 0) funcs = _.functions(obj); each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); return obj; }; // Memoize an expensive function by storing its results. _.memoize = function(func, hasher) { var memo = {}; hasher || (hasher = _.identity); return function() { var key = hasher.apply(this, arguments); return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); }; }; // Delays a function for the given number of milliseconds, and then calls // it with the arguments supplied. _.delay = function(func, wait) { var args = slice.call(arguments, 2); return setTimeout(function(){ return func.apply(func, args); }, wait); }; // Defers a function, scheduling it to run after the current call stack has // cleared. _.defer = function(func) { return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); }; // Internal function used to implement `_.throttle` and `_.debounce`. var limit = function(func, wait, debounce) { var timeout; return function() { var context = this, args = arguments; var throttler = function() { timeout = null; func.apply(context, args); }; if (debounce) clearTimeout(timeout); if (debounce || !timeout) timeout = setTimeout(throttler, wait); }; }; // Returns a function, that, when invoked, will only be triggered at most once // during a given window of time. _.throttle = function(func, wait) { return limit(func, wait, false); }; // Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for // N milliseconds. _.debounce = function(func, wait) { return limit(func, wait, true); }; // Returns a function that will be executed at most one time, no matter how // often you call it. Useful for lazy initialization. _.once = function(func) { var ran = false, memo; return function() { if (ran) return memo; ran = true; return memo = func.apply(this, arguments); }; }; // Returns the first function passed as an argument to the second, // allowing you to adjust arguments, run code before and after, and // conditionally execute the original function. _.wrap = function(func, wrapper) { return function() { var args = [func].concat(slice.call(arguments)); return wrapper.apply(this, args); }; }; // Returns a function that is the composition of a list of functions, each // consuming the return value of the function that follows. _.compose = function() { var funcs = slice.call(arguments); return function() { var args = slice.call(arguments); for (var i=funcs.length-1; i >= 0; i--) { args = [funcs[i].apply(this, args)]; } return args[0]; }; }; // Object Functions // ---------------- // Retrieve the names of an object's properties. // Delegates to **ECMAScript 5**'s native `Object.keys` _.keys = nativeKeys || function(obj) { if (obj !== Object(obj)) throw new TypeError('Invalid object'); var keys = []; for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key; return keys; }; // Retrieve the values of an object's properties. _.values = function(obj) { return _.map(obj, _.identity); }; // Return a sorted list of the function names available on the object. // Aliased as `methods` _.functions = _.methods = function(obj) { return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort(); }; // Extend a given object with all the properties in passed-in object(s). _.extend = function(obj) { each(slice.call(arguments, 1), function(source) { for (var prop in source) obj[prop] = source[prop]; }); return obj; }; // Fill in a given object with default properties. _.defaults = function(obj) { each(slice.call(arguments, 1), function(source) { for (var prop in source) if (obj[prop] == null) obj[prop] = source[prop]; }); return obj; }; // Create a (shallow-cloned) duplicate of an object. _.clone = function(obj) { return _.isArray(obj) ? obj.slice() : _.extend({}, obj); }; // Invokes interceptor with the obj, and then returns obj. // The primary purpose of this method is to "tap into" a method chain, in // order to perform operations on intermediate results within the chain. _.tap = function(obj, interceptor) { interceptor(obj); return obj; }; // Perform a deep comparison to check if two objects are equal. _.isEqual = function(a, b) { // Check object identity. if (a === b) return true; // Different types? var atype = typeof(a), btype = typeof(b); if (atype != btype) return false; // Basic equality test (watch out for coercions). if (a == b) return true; // One is falsy and the other truthy. if ((!a && b) || (a && !b)) return false; // Unwrap any wrapped objects. if (a._chain) a = a._wrapped; if (b._chain) b = b._wrapped; // One of them implements an isEqual()? if (a.isEqual) return a.isEqual(b); // Check dates' integer values. if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime(); // Both are NaN? if (_.isNaN(a) && _.isNaN(b)) return false; // Compare regular expressions. if (_.isRegExp(a) && _.isRegExp(b)) return a.source === b.source && a.global === b.global && a.ignoreCase === b.ignoreCase && a.multiline === b.multiline; // If a is not an object by this point, we can't handle it. if (atype !== 'object') return false; // Check for different array lengths before comparing contents. if (a.length && (a.length !== b.length)) return false; // Nothing else worked, deep compare the contents. var aKeys = _.keys(a), bKeys = _.keys(b); // Different object sizes? if (aKeys.length != bKeys.length) return false; // Recursive comparison of contents. for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false; return true; }; // Is a given array or object empty? _.isEmpty = function(obj) { if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; for (var key in obj) if (hasOwnProperty.call(obj, key)) return false; return true; }; // Is a given value a DOM element? _.isElement = function(obj) { return !!(obj && obj.nodeType == 1); }; // Is a given value an array? // Delegates to ECMA5's native Array.isArray _.isArray = nativeIsArray || function(obj) { return toString.call(obj) === '[object Array]'; }; // Is a given variable an arguments object? _.isArguments = function(obj) { return !!(obj && hasOwnProperty.call(obj, 'callee')); }; // Is a given value a function