summaryrefslogtreecommitdiffstats
path: root/module/web/static
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2012-12-17 20:23:18 +0100
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2012-12-17 20:23:18 +0100
commitf2cdd142f3f2d4c593f7004ae68e3f345e658334 (patch)
tree92859f8efc374d4d789d3cd5535c90b15acbf6bf /module/web/static
parentfixes gzip middleware to do nothing when gzip is not available (diff)
downloadpyload-f2cdd142f3f2d4c593f7004ae68e3f345e658334.tar.xz
updated lots of libraries
Diffstat (limited to 'module/web/static')
-rw-r--r--module/web/static/js/default.js65
-rw-r--r--module/web/static/js/libs/backbone-0.9.9.js (renamed from module/web/static/js/libs/backbone-0.9.2.js)986
-rw-r--r--module/web/static/js/libs/jquery-1.8.3.js (renamed from module/web/static/js/libs/jquery-1.8.0.js)3437
-rw-r--r--module/web/static/js/libs/jquery.peity-0.6.js184
-rw-r--r--module/web/static/js/libs/jquery.peity-1.0.js246
-rw-r--r--module/web/static/js/libs/jquery.transit-0.9.9.js (renamed from module/web/static/js/libs/jquery.transit-0.1.3.js)142
-rw-r--r--module/web/static/js/libs/lodash-1.0.rc3.js (renamed from module/web/static/js/libs/lodash-0.7.0.js)2674
-rw-r--r--module/web/static/js/libs/require-2.1.2.js (renamed from module/web/static/js/libs/require-2.0.6.js)788
-rw-r--r--module/web/static/js/views/packageView.js1
9 files changed, 4595 insertions, 3928 deletions
diff --git a/module/web/static/js/default.js b/module/web/static/js/default.js
index 3d02ba49e..8bd54cb25 100644
--- a/module/web/static/js/default.js
+++ b/module/web/static/js/default.js
@@ -3,41 +3,41 @@
require.config({
// XXX: To many dots in file breaks dependencies
- paths:{
+ paths: {
- jquery:"libs/jquery-1.8.0",
- jqueryui:"libs/jqueryui",
- flot:"libs/jquery.flot-1.1",
+ jquery: "libs/jquery-1.8.3",
+ jqueryui: "libs/jqueryui",
+ flot: "libs/jquery.flot-1.1",
flotpie: "libs/jquery.flot.pie",
- peity: "libs/jquery.peity-0.6",
- transit:"libs/jquery.transit-0.1.3",
+ peity: "libs/jquery.peity-1.0",
+ transit: "libs/jquery.transit-0.9.9",
omniwindow: "libs/jquery.omniwindow",
bootstrap: "libs/bootstrap-2.1.1",
- underscore:"libs/lodash-0.7.0",
- backbone:"libs/backbone-0.9.2",
+ underscore: "libs/lodash-1.0.rc3",
+ backbone: "libs/backbone-0.9.9",
// handlebars: "libs/Handlebars-1.0rc1",
// Plugins
// hbs: "plugins/hbs-2.0.1",
- text:"plugins/text-2.0.3",
+ text: "plugins/text-2.0.3",
tpl: "../../templates"
},
// Sets the configuration for your third party scripts that are not AMD compatible
- shim:{
+ shim: {
- "backbone":{
- deps:["underscore", "jquery"],
- exports:"Backbone" //attaches "Backbone" to the window object
+ "backbone": {
+ deps: ["underscore", "jquery"],
+ exports: "Backbone" //attaches "Backbone" to the window object
},
- "flot" : ["jquery"],
- "peity" : ["jquery"],
- "flotpie" : ["flot"],
- "transit" : ["jquery"],
- "omniwindow" : ["jquery"],
- "bootstrap" : ["jquery"]
+ "flot": ["jquery"],
+ "peity": ["jquery"],
+ "flotpie": ["flot"],
+ "transit": ["jquery"],
+ "omniwindow": ["jquery"],
+ "bootstrap": ["jquery"]
} // end Shim Configuration
// Handlebar Configuration
@@ -49,20 +49,19 @@ require.config({
define('default', ['jquery', 'backbone', 'routers/defaultRouter', 'views/headerView', 'views/packageTreeView',
'utils/animations', 'bootstrap'],
- function ($, Backbone, DefaultRouter, HeaderView, TreeView) {
+ function($, Backbone, DefaultRouter, HeaderView, TreeView) {
+ var init = function() {
+ var view = new HeaderView();
+ view.render();
+ };
- var init = function(){
- var view = new HeaderView();
- view.render();
- };
+ var initPackageTree = function() {
+ $(function() {
+ var view = new TreeView();
+ view.init();
+ });
+ };
- var initPackageTree = function() {
- $(function() {
- var view = new TreeView();
- view.init();
- });
- };
-
- return {"init":init, "initPackageTree": initPackageTree};
-}); \ No newline at end of file
+ return {"init": init, "initPackageTree": initPackageTree};
+ }); \ No newline at end of file
diff --git a/module/web/static/js/libs/backbone-0.9.2.js b/module/web/static/js/libs/backbone-0.9.9.js
index d0410b5c8..90e18d4ac 100644
--- a/module/web/static/js/libs/backbone-0.9.2.js
+++ b/module/web/static/js/libs/backbone-0.9.9.js
@@ -1,4 +1,4 @@
-// Backbone.js 0.9.2
+// Backbone.js 0.9.9
// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
// Backbone may be freely distributed under the MIT license.
@@ -10,7 +10,7 @@
// Initial Setup
// -------------
- // Save a reference to the global object (`window` in the browser, `global`
+ // Save a reference to the global object (`window` in the browser, `exports`
// on the server).
var root = this;
@@ -18,9 +18,11 @@
// restored later on, if `noConflict` is used.
var previousBackbone = root.Backbone;
- // Create a local reference to slice/splice.
- var slice = Array.prototype.slice;
- var splice = Array.prototype.splice;
+ // Create a local reference to array methods.
+ var array = [];
+ var push = array.push;
+ var slice = array.slice;
+ var splice = array.splice;
// The top-level namespace. All public Backbone classes and modules will
// be attached to this. Exported for both CommonJS and the browser.
@@ -32,23 +34,14 @@
}
// Current version of the library. Keep in sync with `package.json`.
- Backbone.VERSION = '0.9.2';
+ Backbone.VERSION = '0.9.9';
// Require Underscore, if we're on the server, and it's not already present.
var _ = root._;
if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
// For Backbone's purposes, jQuery, Zepto, or Ender owns the `$` variable.
- var $ = root.jQuery || root.Zepto || root.ender;
-
- // Set the JavaScript library that will be used for DOM manipulation and
- // Ajax calls (a.k.a. the `$` variable). By default Backbone will use: jQuery,
- // Zepto, or Ender; but the `setDomLibrary()` method lets you inject an
- // alternate JavaScript library (or a mock library for testing your views
- // outside of a browser).
- Backbone.setDomLibrary = function(lib) {
- $ = lib;
- };
+ Backbone.$ = root.jQuery || root.Zepto || root.ender;
// Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
// to its previous owner. Returns a reference to this Backbone object.
@@ -69,14 +62,51 @@
Backbone.emulateJSON = false;
// Backbone.Events
- // -----------------
+ // ---------------
- // Regular expression used to split event strings
+ // Regular expression used to split event strings.
var eventSplitter = /\s+/;
+ // Implement fancy features of the Events API such as multiple event
+ // names `"change blur"` and jQuery-style event maps `{change: action}`
+ // in terms of the existing API.
+ var eventsApi = function(obj, action, name, rest) {
+ if (!name) return true;
+ if (typeof name === 'object') {
+ for (var key in name) {
+ obj[action].apply(obj, [key, name[key]].concat(rest));
+ }
+ } else if (eventSplitter.test(name)) {
+ var names = name.split(eventSplitter);
+ for (var i = 0, l = names.length; i < l; i++) {
+ obj[action].apply(obj, [names[i]].concat(rest));
+ }
+ } else {
+ return true;
+ }
+ };
+
+ // Optimized internal dispatch function for triggering events. Tries to
+ // keep the usual cases speedy (most Backbone events have 3 arguments).
+ var triggerEvents = function(obj, events, args) {
+ var ev, i = -1, l = events.length;
+ switch (args.length) {
+ case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx);
+ return;
+ case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0]);
+ return;
+ case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1]);
+ return;
+ case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
+ return;
+ default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
+ }
+ };
+
// A module that can be mixed in to *any object* in order to provide it with
- // custom events. You may bind with `on` or remove with `off` callback functions
- // to an event; trigger`-ing an event fires all callbacks in succession.
+ // custom events. You may bind with `on` or remove with `off` callback
+ // functions to an event; `trigger`-ing an event fires all callbacks in
+ // succession.
//
// var object = {};
// _.extend(object, Backbone.Events);
@@ -85,58 +115,58 @@
//
var Events = Backbone.Events = {
- // Bind one or more space separated events, `events`, to a `callback`
- // function. Passing `"all"` will bind the callback to all events fired.
- on: function(events, callback, context) {
-
- var calls, event, node, tail, list;
- if (!callback) return this;
- events = events.split(eventSplitter);
- calls = this._callbacks || (this._callbacks = {});
-
- // Create an immutable callback list, allowing traversal during
- // modification. The tail is an empty object that will always be used
- // as the next node.
- while (event = events.shift()) {
- list = calls[event];
- node = list ? list.tail : {};
- node.next = tail = {};
- node.context = context;
- node.callback = callback;
- calls[event] = {tail: tail, next: list ? list.next : node};
- }
-
+ // Bind one or more space separated events, or an events map,
+ // to a `callback` function. Passing `"all"` will bind the callback to
+ // all events fired.
+ on: function(name, callback, context) {
+ if (!(eventsApi(this, 'on', name, [callback, context]) && callback)) return this;
+ this._events || (this._events = {});
+ var list = this._events[name] || (this._events[name] = []);
+ list.push({callback: callback, context: context, ctx: context || this});
return this;
},
- // Remove one or many callbacks. If `context` is null, removes all callbacks
- // with that function. If `callback` is null, removes all callbacks for the
- // event. If `events` is null, removes all bound callbacks for all events.
- off: function(events, callback, context) {
- var event, calls, node, tail, cb, ctx;
+ // Bind events to only be triggered a single time. After the first time
+ // the callback is invoked, it will be removed.
+ once: function(name, callback, context) {
+ if (!(eventsApi(this, 'once', name, [callback, context]) && callback)) return this;
+ var self = this;
+ var once = _.once(function() {
+ self.off(name, once);
+ callback.apply(this, arguments);
+ });
+ once._callback = callback;
+ this.on(name, once, context);
+ return this;
+ },
- // No events, or removing *all* events.
- if (!(calls = this._callbacks)) return;
- if (!(events || callback || context)) {
- delete this._callbacks;
+ // Remove one or many callbacks. If `context` is null, removes all
+ // callbacks with that function. If `callback` is null, removes all
+ // callbacks for the event. If `events` is null, removes all bound
+ // callbacks for all events.
+ off: function(name, callback, context) {
+ var list, ev, events, names, i, l, j, k;
+ if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
+ if (!name && !callback && !context) {
+ this._events = {};
return this;
}
- // Loop through the listed events and contexts, splicing them out of the
- // linked list of callbacks if appropriate.
- events = events ? events.split(eventSplitter) : _.keys(calls);
- while (event = events.shift()) {
- node = calls[event];
- delete calls[event];
- if (!node || !(callback || context)) continue;
- // Create a new list, omitting the indicated callbacks.
- tail = node.tail;
- while ((node = node.next) !== tail) {
- cb = node.callback;
- ctx = node.context;
- if ((callback && cb !== callback) || (context && ctx !== context)) {
- this.on(event, cb, ctx);
+ names = name ? [name] : _.keys(this._events);
+ for (i = 0, l = names.length; i < l; i++) {
+ name = names[i];
+ if (list = this._events[name]) {
+ events = [];
+ if (callback || context) {
+ for (j = 0, k = list.length; j < k; j++) {
+ ev = list[j];
+ if ((callback && callback !== (ev.callback._callback || ev.callback)) ||
+ (context && context !== ev.context)) {
+ events.push(ev);
+ }
+ }
}
+ this._events[name] = events;
}
}
@@ -147,40 +177,53 @@
// passed the same arguments as `trigger` is, apart from the event name
// (unless you're listening on `"all"`, which will cause your callback to
// receive the true name of the event as the first argument).
- trigger: function(events) {
- var event, node, calls, tail, args, all, rest;
- if (!(calls = this._callbacks)) return this;
- all = calls.all;
- events = events.split(eventSplitter);
- rest = slice.call(arguments, 1);
-
- // For each event, walk through the linked list of callbacks twice,
- // first to trigger the event, then to trigger any `"all"` callbacks.
- while (event = events.shift()) {
- if (node = calls[event]) {
- tail = node.tail;
- while ((node = node.next) !== tail) {
- node.callback.apply(node.context || this, rest);
- }
- }
- if (node = all) {
- tail = node.tail;
- args = [event].concat(rest);
- while ((node = node.next) !== tail) {
- node.callback.apply(node.context || this, args);
- }
+ trigger: function(name) {
+ if (!this._events) return this;
+ var args = slice.call(arguments, 1);
+ if (!eventsApi(this, 'trigger', name, args)) return this;
+ var events = this._events[name];
+ var allEvents = this._events.all;
+ if (events) triggerEvents(this, events, args);
+ if (allEvents) triggerEvents(this, allEvents, arguments);
+ return this;
+ },
+
+ // An inversion-of-control version of `on`. Tell *this* object to listen to
+ // an event in another object ... keeping track of what it's listening to.
+ listenTo: function(object, events, callback) {
+ var listeners = this._listeners || (this._listeners = {});
+ var id = object._listenerId || (object._listenerId = _.uniqueId('l'));
+ listeners[id] = object;
+ object.on(events, callback || this, this);
+ return this;
+ },
+
+ // Tell this object to stop listening to either specific events ... or
+ // to every object it's currently listening to.
+ stopListening: function(object, events, callback) {
+ var listeners = this._listeners;
+ if (!listeners) return;
+ if (object) {
+ object.off(events, callback, this);
+ if (!events && !callback) delete listeners[object._listenerId];
+ } else {
+ for (var id in listeners) {
+ listeners[id].off(null, null, this);
}
+ this._listeners = {};
}
-
return this;
}
-
};
// Aliases for backwards compatibility.
Events.bind = Events.on;
Events.unbind = Events.off;
+ // Allow the `Backbone` object to serve as a global event bus, for folks who
+ // want global "pubsub" in a convenient place.
+ _.extend(Backbone, Events);
+
// Backbone.Model
// --------------
@@ -188,23 +231,16 @@
// is automatically generated and assigned for you.
var Model = Backbone.Model = function(attributes, options) {
var defaults;
- attributes || (attributes = {});
- if (options && options.parse) attributes = this.parse(attributes);
- if (defaults = getValue(this, 'defaults')) {
- attributes = _.extend({}, defaults, attributes);
- }
- if (options && options.collection) this.collection = options.collection;
- this.attributes = {};
- this._escapedAttributes = {};
+ var attrs = attributes || {};
this.cid = _.uniqueId('c');
this.changed = {};
- this._silent = {};
- this._pending = {};
- this.set(attributes, {silent: true});
- // Reset change tracking.
- this.changed = {};
- this._silent = {};
- this._pending = {};
+ this.attributes = {};
+ this._changes = [];
+ if (options && options.collection) this.collection = options.collection;
+ if (options && options.parse) attrs = this.parse(attrs);
+ if (defaults = _.result(this, 'defaults')) _.defaults(attrs, defaults);
+ this.set(attrs, {silent: true});
+ this._currentAttributes = _.clone(this.attributes);
this._previousAttributes = _.clone(this.attributes);
this.initialize.apply(this, arguments);
};
@@ -215,14 +251,6 @@
// A hash of attributes whose current and previous value differ.
changed: null,
- // A hash of attributes that have silently changed since the last time
- // `change` was called. Will become pending attributes on the next call.
- _silent: null,
-
- // A hash of attributes that have changed since the last `'change'` event
- // began.
- _pending: null,
-
// The default name for the JSON `id` attribute is `"id"`. MongoDB and
// CouchDB users may want to set this to `"_id"`.
idAttribute: 'id',
@@ -236,6 +264,11 @@
return _.clone(this.attributes);
},
+ // Proxy `Backbone.sync` by default.
+ sync: function() {
+ return Backbone.sync.apply(this, arguments);
+ },
+
// Get the value of an attribute.
get: function(attr) {
return this.attributes[attr];
@@ -243,10 +276,7 @@
// Get the HTML-escaped value of an attribute.
escape: function(attr) {
- var html;
- if (html = this._escapedAttributes[attr]) return html;
- var val = this.get(attr);
- return this._escapedAttributes[attr] = _.escape(val == null ? '' : '' + val);
+ return _.escape(this.get(attr));
},
// Returns `true` if the attribute contains a value that is not null
@@ -257,23 +287,21 @@
// Set a hash of model attributes on the object, firing `"change"` unless
// you choose to silence it.
- set: function(key, value, options) {
- var attrs, attr, val;
+ set: function(key, val, options) {
+ var attr, attrs;
+ if (key == null) return this;
// Handle both `"key", value` and `{key: value}` -style arguments.
- if (_.isObject(key) || key == null) {
+ if (_.isObject(key)) {
attrs = key;
- options = value;
+ options = val;
} else {
- attrs = {};
- attrs[key] = value;
+ (attrs = {})[key] = val;
}
// Extract attributes and options.
- options || (options = {});
- if (!attrs) return this;
- if (attrs instanceof Model) attrs = attrs.attributes;
- if (options.unset) for (attr in attrs) attrs[attr] = void 0;
+ var silent = options && options.silent;
+ var unset = options && options.unset;
// Run validation.
if (!this._validate(attrs, options)) return false;
@@ -281,52 +309,38 @@
// Check for changes of `id`.
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
- var changes = options.changes = {};
var now = this.attributes;
- var escaped = this._escapedAttributes;
- var prev = this._previousAttributes || {};
// For each `set` attribute...
for (attr in attrs) {
val = attrs[attr];
- // If the new and current value differ, record the change.
- if (!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) {
- delete escaped[attr];
- (options.silent ? this._silent : changes)[attr] = true;
- }
-
- // Update or delete the current value.
- options.unset ? delete now[attr] : now[attr] = val;
-
- // If the new and previous value differ, record the change. If not,
- // then remove changes for this attribute.
- if (!_.isEqual(prev[attr], val) || (_.has(now, attr) != _.has(prev, attr))) {
- this.changed[attr] = val;
- if (!options.silent) this._pending[attr] = true;
- } else {
- delete this.changed[attr];
- delete this._pending[attr];
- }
+ // Update or delete the current value, and track the change.
+ unset ? delete now[attr] : now[attr] = val;
+ this._changes.push(attr, val);
}
+ // Signal that the model's state has potentially changed, and we need
+ // to recompute the actual changes.
+ this._hasComputed = false;
+
// Fire the `"change"` events.
- if (!options.silent) this.change(options);
+ if (!silent) this.change(options);
return this;
},
// Remove an attribute from the model, firing `"change"` unless you choose
// to silence it. `unset` is a noop if the attribute doesn't exist.
unset: function(attr, options) {
- (options || (options = {})).unset = true;
- return this.set(attr, null, options);
+ return this.set(attr, void 0, _.extend({}, options, {unset: true}));
},
// Clear all attributes on the model, firing `"change"` unless you choose
// to silence it.
clear: function(options) {
- (options || (options = {})).unset = true;
- return this.set(_.clone(this.attributes), options);
+ var attrs = {};
+ for (var key in this.attributes) attrs[key] = void 0;
+ return this.set(attrs, _.extend({}, options, {unset: true}));
},
// Fetch the model from the server. If the server's representation of the
@@ -334,35 +348,34 @@
// triggering a `"change"` event.
fetch: function(options) {
options = options ? _.clone(options) : {};
+ if (options.parse === void 0) options.parse = true;
var model = this;
var success = options.success;
options.success = function(resp, status, xhr) {
- if (!model.set(model.parse(resp, xhr), options)) return false;
- if (success) success(model, resp);
+ if (!model.set(model.parse(resp), options)) return false;
+ if (success) success(model, resp, options);
};
- options.error = Backbone.wrapError(options.error, model, options);
- return (this.sync || Backbone.sync).call(this, 'read', this, options);
+ return this.sync('read', this, options);
},
// Set a hash of model attributes, and sync the model to the server.
// If the server returns an attributes hash that differs, the model's
// state will be `set` again.
- save: function(key, value, options) {
- var attrs, current;
+ save: function(key, val, options) {
+ var attrs, current, done;
- // Handle both `("key", value)` and `({key: value})` -style calls.
- if (_.isObject(key) || key == null) {
+ // Handle both `"key", value` and `{key: value}` -style arguments.
+ if (key == null || _.isObject(key)) {
attrs = key;
- options = value;
- } else {
- attrs = {};
- attrs[key] = value;
+ options = val;
+ } else if (key != null) {
+ (attrs = {})[key] = val;
}
options = options ? _.clone(options) : {};
// If we're "wait"-ing to set changed attributes, validate early.
if (options.wait) {
- if (!this._validate(attrs, options)) return false;
+ if (attrs && !this._validate(attrs, options)) return false;
current = _.clone(this.attributes);
}
@@ -372,29 +385,33 @@
return false;
}
+ // Do not persist invalid models.
+ if (!attrs && !this._validate(null, options)) return false;
+
// After a successful server-side save, the client is (optionally)
// updated with the server-side state.
var model = this;
var success = options.success;
options.success = function(resp, status, xhr) {
- var serverAttrs = model.parse(resp, xhr);
- if (options.wait) {
- delete options.wait;
- serverAttrs = _.extend(attrs || {}, serverAttrs);
- }
+ done = true;
+ var serverAttrs = model.parse(resp);
+ if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
if (!model.set(serverAttrs, options)) return false;
- if (success) {
- success(model, resp);
- } else {
- model.trigger('sync', model, resp, options);
- }
+ if (success) success(model, resp, options);
};
// Finish configuring and sending the Ajax request.
- options.error = Backbone.wrapError(options.error, model, options);
- var method = this.isNew() ? 'create' : 'update';
- var xhr = (this.sync || Backbone.sync).call(this, method, this, options);
- if (options.wait) this.set(current, silentOptions);
+ var method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
+ if (method == 'patch') options.attrs = attrs;
+ var xhr = this.sync(method, this, options);
+
+ // When using `wait`, reset attributes to original values unless
+ // `success` has been called already.
+ if (!done && options.wait) {
+ this.clear(silentOptions);
+ this.set(current, silentOptions);
+ }
+
return xhr;
},
@@ -406,27 +423,22 @@
var model = this;
var success = options.success;
- var triggerDestroy = function() {
+ var destroy = function() {
model.trigger('destroy', model, model.collection, options);
};
+ options.success = function(resp) {
+ if (options.wait || model.isNew()) destroy();
+ if (success) success(model, resp, options);
+ };
+
if (this.isNew()) {
- triggerDestroy();
+ options.success();
return false;
}
- options.success = function(resp) {
- if (options.wait) triggerDestroy();
- if (success) {
- success(model, resp);
- } else {
- model.trigger('sync', model, resp, options);
- }
- };
-
- options.error = Backbone.wrapError(options.error, model, options);
- var xhr = (this.sync || Backbone.sync).call(this, 'delete', this, options);
- if (!options.wait) triggerDestroy();
+ var xhr = this.sync('delete', this, options);
+ if (!options.wait) destroy();
return xhr;
},
@@ -434,14 +446,14 @@
// using Backbone's restful methods, override this to change the endpoint
// that will be called.
url: function() {
- var base = getValue(this, 'urlRoot') || getValue(this.collection, 'url') || urlError();
+ var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
if (this.isNew()) return base;
- return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(this.id);
+ return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
},
// **parse** converts a response into the hash of attributes to be `set` on
// the model. The default implementation is just to pass the response along.
- parse: function(resp, xhr) {
+ parse: function(resp) {
return resp;
},
@@ -459,30 +471,24 @@
// a `"change:attribute"` event for each changed attribute.
// Calling this will cause all objects observing the model to update.
change: function(options) {
- options || (options = {});
var changing = this._changing;
this._changing = true;
- // Silent changes become pending changes.
- for (var attr in this._silent) this._pending[attr] = true;
+ // Generate the changes to be triggered on the model.
+ var triggers = this._computeChanges(true);
- // Silent changes are triggered.
- var changes = _.extend({}, options.changes, this._silent);
- this._silent = {};
- for (var attr in changes) {
- this.trigger('change:' + attr, this, this.get(attr), options);
+ this._pending = !!triggers.length;
+
+ for (var i = triggers.length - 2; i >= 0; i -= 2) {
+ this.trigger('change:' + triggers[i], this, triggers[i + 1], options);
}
+
if (changing) return this;
- // Continue firing `"change"` events while there are pending changes.
- while (!_.isEmpty(this._pending)) {
- this._pending = {};
+ // Trigger a `change` while there have been changes.
+ while (this._pending) {
+ this._pending = false;
this.trigger('change', this, options);
- // Pending and silent changes still remain.
- for (var attr in this.changed) {
- if (this._pending[attr] || this._silent[attr]) continue;
- delete this.changed[attr];
- }
this._previousAttributes = _.clone(this.attributes);
}
@@ -493,7 +499,8 @@
// Determine if the model has changed since the last `"change"` event.
// If you specify an attribute name, determine if that attribute has changed.
hasChanged: function(attr) {
- if (!arguments.length) return !_.isEmpty(this.changed);
+ if (!this._hasComputed) this._computeChanges();
+ if (attr == null) return !_.isEmpty(this.changed);
return _.has(this.changed, attr);
},
@@ -513,10 +520,43 @@
return changed;
},
+ // Looking at the built up list of `set` attribute changes, compute how
+ // many of the attributes have actually changed. If `loud`, return a
+ // boiled-down list of only the real changes.
+ _computeChanges: function(loud) {
+ this.changed = {};
+ var already = {};
+ var triggers = [];
+ var current = this._currentAttributes;
+ var changes = this._changes;
+
+ // Loop through the current queue of potential model changes.
+ for (var i = changes.length - 2; i >= 0; i -= 2) {
+ var key = changes[i], val = changes[i + 1];
+ if (already[key]) continue;
+ already[key] = true;
+
+ // Check if the attribute has been modified since the last change,
+ // and update `this.changed` accordingly. If we're inside of a `change`
+ // call, also add a trigger to the list.
+ if (current[key] !== val) {
+ this.changed[key] = val;
+ if (!loud) continue;
+ triggers.push(key, val);
+ current[key] = val;
+ }
+ }
+ if (loud) this._changes = [];
+
+ // Signals `this.changed` is current to prevent duplicate calls from `this.hasChanged`.
+ this._hasComputed = true;
+ return triggers;
+ },
+
// Get the previous value of an attribute, recorded at the time the last
// `"change"` event was fired.
previous: function(attr) {
- if (!arguments.length || !this._previousAttributes) return null;
+ if (attr == null || !this._previousAttributes) return null;
return this._previousAttributes[attr];
},
@@ -526,25 +566,16 @@
return _.clone(this._previousAttributes);
},
- // Check if the model is currently in a valid state. It's only possible to
- // get into an *invalid* state if you're using silent changes.
- isValid: function() {
- return !this.validate(this.attributes);
- },
-
// Run validation against the next complete set of model attributes,
// returning `true` if all is well. If a specific `error` callback has
// been passed, call that instead of firing the general `"error"` event.
_validate: function(attrs, options) {
- if (options.silent || !this.validate) return true;
+ if (!this.validate) return true;
attrs = _.extend({}, this.attributes, attrs);
var error = this.validate(attrs, options);
if (!error) return true;
- if (options && options.error) {
- options.error(this, error, options);
- } else {
- this.trigger('error', this, error, options);
- }
+ if (options && options.error) options.error(this, error, options);
+ this.trigger('error', this, error, options);
return false;
}
@@ -559,10 +590,10 @@
var Collection = Backbone.Collection = function(models, options) {
options || (options = {});
if (options.model) this.model = options.model;
- if (options.comparator) this.comparator = options.comparator;
+ if (options.comparator !== void 0) this.comparator = options.comparator;
this._reset();
this.initialize.apply(this, arguments);
- if (models) this.reset(models, {silent: true, parse: options.parse});
+ if (models) this.reset(models, _.extend({silent: true}, options));
};
// Define the Collection's inheritable methods.
@@ -582,54 +613,65 @@
return this.map(function(model){ return model.toJSON(options); });
},
+ // Proxy `Backbone.sync` by default.
+ sync: function() {
+ return Backbone.sync.apply(this, arguments);
+ },
+
// Add a model, or list of models to the set. Pass **silent** to avoid
// firing the `add` event for every new model.
add: function(models, options) {
- var i, index, length, model, cid, id, cids = {}, ids = {}, dups = [];
- options || (options = {});
+ var i, args, length, model, existing, needsSort;
+ var at = options && options.at;
+ var sort = ((options && options.sort) == null ? true : options.sort);
models = _.isArray(models) ? models.slice() : [models];
- // Begin by turning bare objects into model references, and preventing
- // invalid models or duplicate models from being added.
- for (i = 0, length = models.length; i < length; i++) {
- if (!(model = models[i] = this._prepareModel(models[i], options))) {
- throw new Error("Can't add an invalid model to a collection");
+ // Turn bare objects into model references, and prevent invalid models
+ // from being added.
+ for (i = models.length - 1; i >= 0; i--) {
+ if(!(model = this._prepareModel(models[i], options))) {
+ this.trigger("error", this, models[i], options);
+ models.splice(i, 1);
+ continue;
}
- cid = model.cid;
- id = model.id;
- if (cids[cid] || this._byCid[cid] || ((id != null) && (ids[id] || this._byId[id]))) {
- dups.push(i);
+ models[i] = model;
+
+ existing = model.id != null && this._byId[model.id];
+ // If a duplicate is found, prevent it from being added and
+ // optionally merge it into the existing model.
+ if (existing || this._byCid[model.cid]) {
+ if (options && options.merge && existing) {
+ existing.set(model.attributes, options);
+ needsSort = sort;
+ }
+ models.splice(i, 1);
continue;
}
- cids[cid] = ids[id] = model;
- }
- // Remove duplicates.
- i = dups.length;
- while (i--) {
- models.splice(dups[i], 1);
- }
-
- // Listen to added models' events, and index models for lookup by
- // `id` and by `cid`.
- for (i = 0, length = models.length; i < length; i++) {
- (model = models[i]).on('all', this._onModelEvent, this);
+ // Listen to added models' events, and index models for lookup by
+ // `id` and by `cid`.
+ model.on('all', this._onModelEvent, this);
this._byCid[model.cid] = model;
if (model.id != null) this._byId[model.id] = model;
}
- // Insert models into the collection, re-sorting if needed, and triggering
- // `add` events unless silenced.
- this.length += length;
- index = options.at != null ? options.at : this.models.length;
- splice.apply(this.models, [index, 0].concat(models));
- if (this.comparator) this.sort({silent: true});
- if (options.silent) return this;
- for (i = 0, length = this.models.length; i < length; i++) {
- if (!cids[(model = this.models[i]).cid]) continue;
- options.index = i;
+ // See if sorting is needed, update `length` and splice in new models.
+ if (models.length) needsSort = sort;
+ this.length += models.length;
+ args = [at != null ? at : this.models.length, 0];
+ push.apply(args, models);
+ splice.apply(this.models, args);
+
+ // Sort the collection if appropriate.
+ if (needsSort && this.comparator && at == null) this.sort({silent: true});
+
+ if (options && options.silent) return this;
+
+ // Trigger `add` events.
+ while (model = models.shift()) {
model.trigger('add', model, this, options);
}
+
return this;
},
@@ -640,7 +682,7 @@
options || (options = {});
models = _.isArray(models) ? models.slice() : [models];
for (i = 0, l = models.length; i < l; i++) {
- model = this.getByCid(models[i]) || this.get(models[i]);
+ model = this.get(models[i]);
if (!model) continue;
delete this._byId[model.id];
delete this._byCid[model.cid];
@@ -659,7 +701,7 @@
// Add a model to the end of the collection.
push: function(model, options) {
model = this._prepareModel(model, options);
- this.add(model, options);
+ this.add(model, _.extend({at: this.length}, options));
return model;
},
@@ -684,15 +726,15 @@
return model;
},
- // Get a model from the set by id.
- get: function(id) {
- if (id == null) return void 0;
- return this._byId[id.id != null ? id.id : id];
+ // Slice out a sub-array of models from the collection.
+ slice: function(begin, end) {
+ return this.models.slice(begin, end);
},
- // Get a model from the set by client id.
- getByCid: function(cid) {
- return cid && this._byCid[cid.cid || cid];
+ // Get a model from the set by id.
+ get: function(obj) {
+ if (obj == null) return void 0;
+ return this._byId[obj.id != null ? obj.id : obj] || this._byCid[obj.cid || obj];
},
// Get the model at the given index.
@@ -715,34 +757,74 @@
// normal circumstances, as the set will maintain sort order as each item
// is added.
sort: function(options) {
- options || (options = {});
- if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
- var boundComparator = _.bind(this.comparator, this);
- if (this.comparator.length == 1) {
- this.models = this.sortBy(boundComparator);
+ if (!this.comparator) {
+ throw new Error('Cannot sort a set without a comparator');
+ }
+
+ if (_.isString(this.comparator) || this.comparator.length === 1) {
+ this.models = this.sortBy(this.comparator, this);
} else {
- this.models.sort(boundComparator);
+ this.models.sort(_.bind(this.comparator, this));
}
- if (!options.silent) this.trigger('reset', this, options);
+
+ if (!options || !options.silent) this.trigger('sort', this, options);
return this;
},
// Pluck an attribute from each model in the collection.
pluck: function(attr) {
- return _.map(this.models, function(model){ return model.get(attr); });
+ return _.invoke(this.models, 'get', attr);
+ },
+
+ // Smartly update a collection with a change set of models, adding,
+ // removing, and merging as necessary.
+ update: function(models, options) {
+ var model, i, l, existing;
+ var add = [], remove = [], modelMap = {};
+ var idAttr = this.model.prototype.idAttribute;
+ options = _.extend({add: true, merge: true, remove: true}, options);
+ if (options.parse) models = this.parse(models);
+
+ // Allow a single model (or no argument) to be passed.
+ if (!_.isArray(models)) models = models ? [models] : [];
+
+ // Proxy to `add` for this case, no need to iterate...
+ if (options.add && !options.remove) return this.add(models, options);
+
+ // Determine which models to add and merge, and which to remove.
+ for (i = 0, l = models.length; i < l; i++) {
+ model = models[i];
+ existing = this.get(model.id || model.cid || model[idAttr]);
+ if (options.remove && existing) modelMap[existing.cid] = true;
+ if ((options.add && !existing) || (options.merge && existing)) {
+ add.push(model);
+ }
+ }
+ if (options.remove) {
+ for (i = 0, l = this.models.length; i < l; i++) {
+ model = this.models[i];
+ if (!modelMap[model.cid]) remove.push(model);
+ }
+ }
+
+ // Remove models (if applicable) before we add and merge the rest.
+ if (remove.length) this.remove(remove, options);
+ if (add.length) this.add(add, options);
+ return this;
},
// When you have more items than you want to add or remove individually,
// you can reset the entire set with a new list of models, without firing
// any `add` or `remove` events. Fires `reset` when finished.
reset: function(models, options) {
- models || (models = []);
options || (options = {});
+ if (options.parse) models = this.parse(models);
for (var i = 0, l = this.models.length; i < l; i++) {
this._removeReference(this.models[i]);
}
+ options.previousModels = this.models;
this._reset();
- this.add(models, _.extend({silent: true}, options));
+ if (models) this.add(models, _.extend({silent: true}, options));
if (!options.silent) this.trigger('reset', this, options);
return this;
},
@@ -752,34 +834,30 @@
// models to the collection instead of resetting.
fetch: function(options) {
options = options ? _.clone(options) : {};
- if (options.parse === undefined) options.parse = true;
+ if (options.parse === void 0) options.parse = true;
var collection = this;
var success = options.success;
options.success = function(resp, status, xhr) {
- collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
- if (success) success(collection, resp);
+ var method = options.update ? 'update' : 'reset';
+ collection[method](resp, options);
+ if (success) success(collection, resp, options);
};
- options.error = Backbone.wrapError(options.error, collection, options);
- return (this.sync || Backbone.sync).call(this, 'read', this, options);
+ return this.sync('read', this, options);
},
// Create a new instance of a model in this collection. Add the model to the
// collection immediately, unless `wait: true` is passed, in which case we
// wait for the server to agree.
create: function(model, options) {
- var coll = this;
+ var collection = this;
options = options ? _.clone(options) : {};
model = this._prepareModel(model, options);
if (!model) return false;
- if (!options.wait) coll.add(model, options);
+ if (!options.wait) collection.add(model, options);
var success = options.success;
- options.success = function(nextModel, resp, xhr) {
- if (options.wait) coll.add(nextModel, options);
- if (success) {
- success(nextModel, resp);
- } else {
- nextModel.trigger('sync', model, resp, options);
- }
+ options.success = function(model, resp, options) {
+ if (options.wait) collection.add(model, options);
+ if (success) success(model, resp, options);
};
model.save(null, options);
return model;
@@ -787,19 +865,24 @@
// **parse** converts a response into a list of models to be added to the
// collection. The default implementation is just to pass it through.
- parse: function(resp, xhr) {
+ parse: function(resp) {
return resp;
},
+ // Create a new collection with an identical list of models as this one.
+ clone: function() {
+ return new this.constructor(this.models);
+ },
+
// Proxy to _'s chain. Can't be proxied the same way the rest of the
// underscore methods are proxied because it relies on the underscore
// constructor.
- chain: function () {
+ chain: function() {
return _(this.models).chain();
},
// Reset all internal state. Called when the collection is reset.
- _reset: function(options) {
+ _reset: function() {
this.length = 0;
this.models = [];
this._byId = {};
@@ -807,24 +890,21 @@
},
// Prepare a model or hash of attributes to be added to this collection.
- _prepareModel: function(model, options) {
- options || (options = {});
- if (!(model instanceof Model)) {
- var attrs = model;
- options.collection = this;
- model = new this.model(attrs, options);
- if (!model._validate(model.attributes, options)) model = false;
- } else if (!model.collection) {
- model.collection = this;
+ _prepareModel: function(attrs, options) {
+ if (attrs instanceof Model) {
+ if (!attrs.collection) attrs.collection = this;
+ return attrs;
}
+ options || (options = {});
+ options.collection = this;
+ var model = new this.model(attrs, options);
+ if (!model._validate(attrs, options)) return false;
return model;
},
// Internal method to remove a model's ties to a collection.
_removeReference: function(model) {
- if (this == model.collection) {
- delete model.collection;
- }
+ if (this === model.collection) delete model.collection;
model.off('all', this._onModelEvent, this);
},
@@ -833,13 +913,11 @@
// events simply proxy through. "add" and "remove" events that originate
// in other collections are ignored.
_onModelEvent: function(event, model, collection, options) {
- if ((event == 'add' || event == 'remove') && collection != this) return;
- if (event == 'destroy') {
- this.remove(model, options);
- }
+ if ((event === 'add' || event === 'remove') && collection !== this) return;
+ if (event === 'destroy') this.remove(model, options);
if (model && event === 'change:' + model.idAttribute) {
delete this._byId[model.previous(model.idAttribute)];
- this._byId[model.id] = model;
+ if (model.id != null) this._byId[model.id] = model;
}
this.trigger.apply(this, arguments);
}
@@ -847,21 +925,37 @@
});
// Underscore methods that we want to implement on the Collection.
- var methods = ['forEach', 'each', 'map', 'reduce', 'reduceRight', 'find',
- 'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any',
- 'include', 'contains', 'invoke', 'max', 'min', 'sortBy', 'sortedIndex',
- 'toArray', 'size', 'first', 'initial', 'rest', 'last', 'without', 'indexOf',
- 'shuffle', 'lastIndexOf', 'isEmpty', 'groupBy'];
+ var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
+ 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
+ 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
+ 'max', 'min', 'sortedIndex', 'toArray', 'size', 'first', 'head', 'take',
+ 'initial', 'rest', 'tail', 'last', 'without', 'indexOf', 'shuffle',
+ 'lastIndexOf', 'isEmpty'];
// Mix in each Underscore method as a proxy to `Collection#models`.
_.each(methods, function(method) {
Collection.prototype[method] = function() {
- return _[method].apply(_, [this.models].concat(_.toArray(arguments)));
+ var args = slice.call(arguments);
+ args.unshift(this.models);
+ return _[method].apply(_, args);
+ };
+ });
+
+ // Underscore methods that take a property name as an argument.
+ var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
+
+ // Use attributes instead of properties.
+ _.each(attributeMethods, function(method) {
+ Collection.prototype[method] = function(value, context) {
+ var iterator = _.isFunction(value) ? value : function(model) {
+ return model.get(value);
+ };
+ return _[method](this.models, iterator, context);
};
});
// Backbone.Router
- // -------------------
+ // ---------------
// Routers map faux-URLs to actions, and fire events when routes are
// matched. Creating a new one sets its `routes` hash, if not set statically.
@@ -874,9 +968,10 @@
// Cached regular expressions for matching named param parts and splatted
// parts of route strings.
+ var optionalParam = /\((.*?)\)/g;
var namedParam = /:\w+/g;
var splatParam = /\*\w+/g;
- var escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g;
+ var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
// Set up all inheritable **Backbone.Router** properties and methods.
_.extend(Router.prototype, Events, {
@@ -892,7 +987,6 @@
// });
//
route: function(route, name, callback) {
- Backbone.history || (Backbone.history = new History);
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
if (!callback) callback = this[name];
Backbone.history.route(route, _.bind(function(fragment) {
@@ -907,6 +1001,7 @@
// Simple proxy to `Backbone.history` to save a fragment into the history.
navigate: function(fragment, options) {
Backbone.history.navigate(fragment, options);
+ return this;
},
// Bind all defined routes to `Backbone.history`. We have to reverse the
@@ -914,12 +1009,9 @@
// routes can be defined at the bottom of the route map.
_bindRoutes: function() {
if (!this.routes) return;
- var routes = [];
- for (var route in this.routes) {
- routes.unshift([route, this.routes[route]]);
- }
- for (var i = 0, l = routes.length; i < l; i++) {
- this.route(routes[i][0], routes[i][1], this[routes[i][1]]);
+ var route, routes = _.keys(this.routes);
+ while ((route = routes.pop()) != null) {
+ this.route(route, this.routes[route]);
}
},
@@ -927,6 +1019,7 @@
// against the current location hash.
_routeToRegExp: function(route) {
route = route.replace(escapeRegExp, '\\$&')
+ .replace(optionalParam, '(?:$1)?')
.replace(namedParam, '([^\/]+)')
.replace(splatParam, '(.*?)');
return new RegExp('^' + route + '$');
@@ -948,14 +1041,26 @@
var History = Backbone.History = function() {
this.handlers = [];
_.bindAll(this, 'checkUrl');
+
+ // Ensure that `History` can be used outside of the browser.
+ if (typeof window !== 'undefined') {
+ this.location = window.location;
+ this.history = window.history;
+ }
};
- // Cached regex for cleaning leading hashes and slashes .
- var routeStripper = /^[#\/]/;
+ // Cached regex for stripping a leading hash/slash and trailing space.
+ var routeStripper = /^[#\/]|\s+$/g;
+
+ // Cached regex for stripping leading and trailing slashes.
+ var rootStripper = /^\/+|\/+$/g;
// Cached regex for detecting MSIE.
var isExplorer = /msie [\w.]+/;
+ // Cached regex for removing a trailing slash.
+ var trailingSlash = /\/$/;
+
// Has the history handling already been started?
History.started = false;
@@ -968,9 +1073,8 @@
// Gets the true hash value. Cannot use location.hash directly due to bug
// in Firefox where location.hash will always be decoded.
- getHash: function(windowOverride) {
- var loc = windowOverride ? windowOverride.location : window.location;
- var match = loc.href.match(/#(.*)$/);
+ getHash: function(window) {
+ var match = (window || this).location.href.match(/#(.*)$/);
return match ? match[1] : '';
},
@@ -978,15 +1082,14 @@
// the hash, or the override.
getFragment: function(fragment, forcePushState) {
if (fragment == null) {
- if (this._hasPushState || forcePushState) {
- fragment = window.location.pathname;
- var search = window.location.search;
- if (search) fragment += search;
+ if (this._hasPushState || !this._wantsHashChange || forcePushState) {
+ fragment = this.location.pathname;
+ var root = this.root.replace(trailingSlash, '');
+ if (!fragment.indexOf(root)) fragment = fragment.substr(root.length);
} else {
fragment = this.getHash();
}
}
- if (!fragment.indexOf(this.options.root)) fragment = fragment.substr(this.options.root.length);
return fragment.replace(routeStripper, '');
},
@@ -999,24 +1102,28 @@
// Figure out the initial configuration. Do we need an iframe?
// Is pushState desired ... is it available?
this.options = _.extend({}, {root: '/'}, this.options, options);
+ this.root = this.options.root;
this._wantsHashChange = this.options.hashChange !== false;
this._wantsPushState = !!this.options.pushState;
- this._hasPushState = !!(this.options.pushState && window.history && window.history.pushState);
+ this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);
var fragment = this.getFragment();
var docMode = document.documentMode;
var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
- if (oldIE) {
- this.iframe = $('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
+ // Normalize root to always include a leading and trailing slash.
+ this.root = ('/' + this.root + '/').replace(rootStripper, '/');
+
+ if (oldIE && this._wantsHashChange) {
+ this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
this.navigate(fragment);
}
// Depending on whether we're using pushState or hashes, and whether
// 'onhashchange' is supported, determine how we check the URL state.
if (this._hasPushState) {
- $(window).bind('popstate', this.checkUrl);
+ Backbone.$(window).bind('popstate', this.checkUrl);
} else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
- $(window).bind('hashchange', this.checkUrl);
+ Backbone.$(window).bind('hashchange', this.checkUrl);
} else if (this._wantsHashChange) {
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
}
@@ -1024,14 +1131,14 @@
// Determine if we need to change the base url, for a pushState link
// opened by a non-pushState browser.
this.fragment = fragment;
- var loc = window.location;
- var atRoot = loc.pathname == this.options.root;
+ var loc = this.location;
+ var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
// If we've started off with a route from a `pushState`-enabled browser,
// but we're currently in a browser that doesn't support it...
if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
this.fragment = this.getFragment(null, true);
- window.location.replace(this.options.root + '#' + this.fragment);
+ this.location.replace(this.root + this.location.search + '#' + this.fragment);
// Return immediately as browser will do redirect to new url
return true;
@@ -1039,18 +1146,16 @@
// in a browser where it could be `pushState`-based instead...
} else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
this.fragment = this.getHash().replace(routeStripper, '');
- window.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root + this.fragment);
+ this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
}
- if (!this.options.silent) {
- return this.loadUrl();
- }
+ if (!this.options.silent) return this.loadUrl();
},
// Disable Backbone.history, perhaps temporarily. Not useful in a real app,
// but possibly useful for unit testing Routers.
stop: function() {
- $(window).unbind('popstate', this.checkUrl).unbind('hashchange', this.checkUrl);
+ Backbone.$(window).unbind('popstate', this.checkUrl).unbind('hashchange', this.checkUrl);
clearInterval(this._checkUrlInterval);
History.started = false;
},
@@ -1065,8 +1170,10 @@
// calls `loadUrl`, normalizing across the hidden iframe.
checkUrl: function(e) {
var current = this.getFragment();
- if (current == this.fragment && this.iframe) current = this.getFragment(this.getHash(this.iframe));
- if (current == this.fragment) return false;
+ if (current === this.fragment && this.iframe) {
+ current = this.getFragment(this.getHash(this.iframe));
+ }
+ if (current === this.fragment) return false;
if (this.iframe) this.navigate(current);
this.loadUrl() || this.loadUrl(this.getHash());
},
@@ -1095,31 +1202,31 @@
navigate: function(fragment, options) {
if (!History.started) return false;
if (!options || options === true) options = {trigger: options};
- var frag = (fragment || '').replace(routeStripper, '');
- if (this.fragment == frag) return;
+ fragment = this.getFragment(fragment || '');
+ if (this.fragment === fragment) return;
+ this.fragment = fragment;
+ var url = this.root + fragment;
// If pushState is available, we use it to set the fragment as a real URL.
if (this._hasPushState) {
- if (frag.indexOf(this.options.root) != 0) frag = this.options.root + frag;
- this.fragment = frag;
- window.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, frag);
+ this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
// If hash changes haven't been explicitly disabled, update the hash
// fragment to store history.
} else if (this._wantsHashChange) {
- this.fragment = frag;
- this._updateHash(window.location, frag, options.replace);
- if (this.iframe && (frag != this.getFragment(this.getHash(this.iframe)))) {
- // Opening and closing the iframe tricks IE7 and earlier to push a history entry on hash-tag change.
- // When replace is true, we don't want this.
+ this._updateHash(this.location, fragment, options.replace);
+ if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
+ // Opening and closing the iframe tricks IE7 and earlier to push a
+ // history entry on hash-tag change. When replace is true, we don't
+ // want this.
if(!options.replace) this.iframe.document.open().close();
- this._updateHash(this.iframe.location, frag, options.replace);
+ this._updateHash(this.iframe.location, fragment, options.replace);
}
// If you've told us that you explicitly don't want fallback hashchange-
// based history, then `navigate` becomes a page refresh.
} else {
- window.location.assign(this.options.root + fragment);
+ return this.location.assign(url);
}
if (options.trigger) this.loadUrl(fragment);
},
@@ -1128,13 +1235,19 @@
// a new one to the browser history.
_updateHash: function(location, fragment, replace) {
if (replace) {
- location.replace(location.toString().replace(/(javascript:|#).*$/, '') + '#' + fragment);
+ var href = location.href.replace(/(javascript:|#).*$/, '');
+ location.replace(href + '#' + fragment);
} else {
- location.hash = fragment;
+ // Some browsers require that `hash` contains a leading #.
+ location.hash = '#' + fragment;
}
}
+
});
+ // Create the default Backbone.history.
+ Backbone.history = new History;
+
// Backbone.View
// -------------
@@ -1152,7 +1265,7 @@
var delegateEventSplitter = /^(\S+)\s*(.*)$/;
// List of view options to be merged as properties.
- var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName'];
+ var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
// Set up all inheritable **Backbone.View** properties and methods.
_.extend(View.prototype, Events, {
@@ -1177,10 +1290,11 @@
return this;
},
- // Remove this view from the DOM. Note that the view isn't present in the
- // DOM by default, so calling this method may be a no-op.
+ // Remove this view by taking the element out of the DOM, and removing any
+ // applicable Backbone.Events listeners.
remove: function() {
this.$el.remove();
+ this.stopListening();
return this;
},
@@ -1191,8 +1305,8 @@
//
make: function(tagName, attributes, content) {
var el = document.createElement(tagName);
- if (attributes) $(el).attr(attributes);
- if (content) $(el).html(content);
+ if (attributes) Backbone.$(el).attr(attributes);
+ if (content != null) Backbone.$(el).html(content);
return el;
},
@@ -1200,7 +1314,7 @@
// re-delegation.
setElement: function(element, delegate) {
if (this.$el) this.undelegateEvents();
- this.$el = (element instanceof $) ? element : $(element);
+ this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
this.el = this.$el[0];
if (delegate !== false) this.delegateEvents();
return this;
@@ -1222,7 +1336,7 @@
// This only works for delegate-able events: not `focus`, `blur`, and
// not `change`, `submit`, and `reset` in Internet Explorer.
delegateEvents: function(events) {
- if (!(events || (events = getValue(this, 'events')))) return;
+ if (!(events || (events = _.result(this, 'events')))) return;
this.undelegateEvents();
for (var key in events) {
var method = events[key];
@@ -1251,11 +1365,8 @@
// Keys with special meaning *(model, collection, id, className)*, are
// attached directly to the view.
_configure: function(options) {
- if (this.options) options = _.extend({}, this.options, options);
- for (var i = 0, l = viewOptions.length; i < l; i++) {
- var attr = viewOptions[i];
- if (options[attr]) this[attr] = options[attr];
- }
+ if (this.options) options = _.extend({}, _.result(this, 'options'), options);
+ _.extend(this, _.pick(options, viewOptions));
this.options = options;
},
@@ -1265,27 +1376,17 @@
// an element from the `id`, `className` and `tagName` properties.
_ensureElement: function() {
if (!this.el) {
- var attrs = getValue(this, 'attributes') || {};
- if (this.id) attrs.id = this.id;
- if (this.className) attrs['class'] = this.className;
- this.setElement(this.make(this.tagName, attrs), false);
+ var attrs = _.extend({}, _.result(this, 'attributes'));
+ if (this.id) attrs.id = _.result(this, 'id');
+ if (this.className) attrs['class'] = _.result(this, 'className');
+ this.setElement(this.make(_.result(this, 'tagName'), attrs), false);
} else {
- this.setElement(this.el, false);
+ this.setElement(_.result(this, 'el'), false);
}
}
});
- // The self-propagating extend function that Backbone classes use.
- var extend = function (protoProps, classProps) {
- var child = inherits(this, protoProps, classProps);
- child.extend = this.extend;
- return child;
- };
-
- // Set up inheritance for the model, collection, and view.
- Model.extend = Collection.extend = Router.extend = View.extend = extend;
-
// Backbone.sync
// -------------
@@ -1293,6 +1394,7 @@
var methodMap = {
'create': 'POST',
'update': 'PUT',
+ 'patch': 'PATCH',
'delete': 'DELETE',
'read': 'GET'
};
@@ -1316,116 +1418,116 @@
var type = methodMap[method];
// Default options, unless specified.
- options || (options = {});
+ _.defaults(options || (options = {}), {
+ emulateHTTP: Backbone.emulateHTTP,
+ emulateJSON: Backbone.emulateJSON
+ });
// Default JSON-request options.
var params = {type: type, dataType: 'json'};
// Ensure that we have a URL.
if (!options.url) {
- params.url = getValue(model, 'url') || urlError();
+ params.url = _.result(model, 'url') || urlError();
}
// Ensure that we have the appropriate request data.
- if (!options.data && model && (method == 'create' || method == 'update')) {
+ if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
params.contentType = 'application/json';
- params.data = JSON.stringify(model.toJSON());
+ params.data = JSON.stringify(options.attrs || model.toJSON(options));
}
// For older servers, emulate JSON by encoding the request into an HTML-form.
- if (Backbone.emulateJSON) {
+ if (options.emulateJSON) {
params.contentType = 'application/x-www-form-urlencoded';
params.data = params.data ? {model: params.data} : {};
}
// For older servers, emulate HTTP by mimicking the HTTP method with `_method`
// And an `X-HTTP-Method-Override` header.
- if (Backbone.emulateHTTP) {
- if (type === 'PUT' || type === 'DELETE') {
- if (Backbone.emulateJSON) params.data._method = type;
- params.type = 'POST';
- params.beforeSend = function(xhr) {
- xhr.setRequestHeader('X-HTTP-Method-Override', type);
- };
- }
+ if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
+ params.type = 'POST';
+ if (options.emulateJSON) params.data._method = type;
+ var beforeSend = options.beforeSend;
+ options.beforeSend = function(xhr) {
+ xhr.setRequestHeader('X-HTTP-Method-Override', type);
+ if (beforeSend) return beforeSend.apply(this, arguments);
+ };
}
// Don't process data on a non-GET request.
- if (params.type !== 'GET' && !Backbone.emulateJSON) {
+ if (params.type !== 'GET' && !options.emulateJSON) {
params.processData = false;
}
+ var success = options.success;
+ options.success = function(resp, status, xhr) {
+ if (success) success(resp, status, xhr);
+ model.trigger('sync', model, resp, options);
+ };
+
+ var error = options.error;
+ options.error = function(xhr, status, thrown) {
+ if (error) error(model, xhr, options);
+ model.trigger('error', model, xhr, options);
+ };
+
// Make the request, allowing the user to override any Ajax options.
- return $.ajax(_.extend(params, options));
+ var xhr = Backbone.ajax(_.extend(params, options));
+ model.trigger('request', model, xhr, options);
+ return xhr;
};
- // Wrap an optional error callback with a fallback error event.
- Backbone.wrapError = function(onError, originalModel, options) {
- return function(model, resp) {
- resp = model === originalModel ? resp : model;
- if (onError) {
- onError(originalModel, resp, options);
- } else {
- originalModel.trigger('error', originalModel, resp, options);
- }
- };
+ // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
+ Backbone.ajax = function() {
+ return Backbone.$.ajax.apply(Backbone.$, arguments);
};
// Helpers
// -------
- // Shared empty constructor function to aid in prototype-chain creation.
- var ctor = function(){};
-
// Helper function to correctly set up the prototype chain, for subclasses.
// Similar to `goog.inherits`, but uses a hash of prototype properties and
// class properties to be extended.
- var inherits = function(parent, protoProps, staticProps) {
+ var extend = function(protoProps, staticProps) {
+ var parent = this;
var child;
// The constructor function for the new subclass is either defined by you
// (the "constructor" property in your `extend` definition), or defaulted
// by us to simply call the parent's constructor.
- if (protoProps && protoProps.hasOwnProperty('constructor')) {
+ if (protoProps && _.has(protoProps, 'constructor')) {
child = protoProps.constructor;
} else {
child = function(){ parent.apply(this, arguments); };
}
- // Inherit class (static) properties from parent.
- _.extend(child, parent);
+ // Add static properties to the constructor function, if supplied.
+ _.extend(child, parent, staticProps);
// Set the prototype chain to inherit from `parent`, without calling
// `parent`'s constructor function.
- ctor.prototype = parent.prototype;
- child.prototype = new ctor();
+ var Surrogate = function(){ this.constructor = child; };
+ Surrogate.prototype = parent.prototype;
+ child.prototype = new Surrogate;
// Add prototype properties (instance properties) to the subclass,
// if supplied.
if (protoProps) _.extend(child.prototype, protoProps);
- // Add static properties to the constructor function, if supplied.
- if (staticProps) _.extend(child, staticProps);
-
- // Correctly set child's `prototype.constructor`.
- child.prototype.constructor = child;
-
- // Set a convenience property in case the parent's prototype is needed later.
+ // Set a convenience property in case the parent's prototype is needed
+ // later.
child.__super__ = parent.prototype;
return child;
};
- // Helper function to get a value from a Backbone object as a property
- // or as a function.
- var getValue = function(object, prop) {
- if (!(object && object[prop])) return null;
- return _.isFunction(object[prop]) ? object[prop]() : object[prop];
- };
+ // Set up inheritance for the model, collection, router, view and history.
+ Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
// Throw an error when a URL is needed, and none is supplied.
var urlError = function() {
throw new Error('A "url" property or function must be specified');
};
-}).call(this); \ No newline at end of file
+}).call(this);
diff --git a/module/web/static/js/libs/jquery-1.8.0.js b/module/web/static/js/libs/jquery-1.8.3.js
index 43991b385..a86bf797a 100644
--- a/module/web/static/js/libs/jquery-1.8.0.js
+++ b/module/web/static/js/libs/jquery-1.8.3.js
@@ -1,5 +1,5 @@
/*!
- * jQuery JavaScript Library v1.8.0
+ * jQuery JavaScript Library v1.8.3
* http://jquery.com/
*
* Includes Sizzle.js
@@ -9,7 +9,7 @@
* Released under the MIT license
* http://jquery.org/license
*
- * Date: Thu Aug 09 2012 16:24:48 GMT-0400 (Eastern Daylight Time)
+ * Date: Tue Nov 13 2012 08:20:33 GMT-0500 (Eastern Standard Time)
*/
(function( window, undefined ) {
var
@@ -51,8 +51,8 @@ var
core_rnotwhite = /\S/,
core_rspace = /\s+/,
- // IE doesn't match non-breaking spaces with \s
- rtrim = core_rnotwhite.test("\xA0") ? (/^[\s\xA0]+|[\s\xA0]+$/g) : /^\s+|\s+$/g,
+ // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
+ rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
// A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
@@ -186,7 +186,7 @@ jQuery.fn = jQuery.prototype = {
selector: "",
// The current version of jQuery being used
- jquery: "1.8.0",
+ jquery: "1.8.3",
// The default length of a jQuery object is 0
length: 0,
@@ -573,7 +573,7 @@ jQuery.extend({
},
nodeName: function( elem, name ) {
- return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
},
// args is for internal usage only
@@ -619,7 +619,7 @@ jQuery.extend({
},
// Use native String.trim function wherever possible
- trim: core_trim ?
+ trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
function( text ) {
return text == null ?
"" :
@@ -630,7 +630,7 @@ jQuery.extend({
function( text ) {
return text == null ?
"" :
- text.toString().replace( rtrim, "" );
+ ( text + "" ).replace( rtrim, "" );
},
// results is for internal usage only
@@ -776,7 +776,7 @@ jQuery.extend({
};
// Set the guid of unique handler to the same of original handler, so it can be removed
- proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
return proxy;
},
@@ -844,9 +844,10 @@ jQuery.ready.promise = function( obj ) {
readyList = jQuery.Deferred();
- // Catch cases where $(document).ready() is called after the
- // browser event has already occurred.
- if ( document.readyState === "complete" || ( document.readyState !== "loading" && document.addEventListener ) ) {
+ // Catch cases where $(document).ready() is called after the browser event has already occurred.
+ // we once tried to use readyState "interactive" here, but it caused issues like the one
+ // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
+ if ( document.readyState === "complete" ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
setTimeout( jQuery.ready, 1 );
@@ -997,9 +998,12 @@ jQuery.Callbacks = function( options ) {
var start = list.length;
(function add( args ) {
jQuery.each( args, function( _, arg ) {
- if ( jQuery.isFunction( arg ) && ( !options.unique || !self.has( arg ) ) ) {
- list.push( arg );
- } else if ( arg && arg.length ) {
+ var type = jQuery.type( arg );
+ if ( type === "function" ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && type !== "string" ) {
// Inspect recursively
add( arg );
}
@@ -1141,7 +1145,7 @@ jQuery.extend({
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
- return typeof obj === "object" ? jQuery.extend( obj, promise ) : promise;
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {};
@@ -1251,24 +1255,23 @@ jQuery.support = (function() {
clickFn,
div = document.createElement("div");
- // Preliminary tests
+ // Setup
div.setAttribute( "className", "t" );
div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
+ // Support tests won't run in some limited or non-browser environments
all = div.getElementsByTagName("*");
a = div.getElementsByTagName("a")[ 0 ];
- a.style.cssText = "top:1px;float:left;opacity:.5";
-
- // Can't get basic test support
- if ( !all || !all.length || !a ) {
+ if ( !all || !a || !all.length ) {
return {};
}
- // First batch of supports tests
+ // First batch of tests
select = document.createElement("select");
opt = select.appendChild( document.createElement("option") );
input = div.getElementsByTagName("input")[ 0 ];
+ a.style.cssText = "top:1px;float:left;opacity:.5";
support = {
// IE strips leading whitespace when .innerHTML is used
leadingWhitespace: ( div.firstChild.nodeType === 3 ),
@@ -1310,7 +1313,7 @@ jQuery.support = (function() {
// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
getSetAttribute: div.className !== "t",
- // Tests for enctype support on a form(#6743)
+ // Tests for enctype support on a form (#6743)
enctype: !!document.createElement("form").enctype,
// Makes sure cloning an html5 element does not cause problems
@@ -1452,10 +1455,8 @@ jQuery.support = (function() {
support.boxSizing = ( div.offsetWidth === 4 );
support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
- // NOTE: To any future maintainer, window.getComputedStyle was used here
- // instead of getComputedStyle because it gave a better gzip size.
- // The difference between window.getComputedStyle and getComputedStyle is
- // 7 bytes
+ // NOTE: To any future maintainer, we've window.getComputedStyle
+ // because jsdom on node.js will break without it.
if ( window.getComputedStyle ) {
support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
@@ -1505,7 +1506,7 @@ jQuery.support = (function() {
return support;
})();
-var rbrace = /^(?:\{.*\}|\[.*\])$/,
+var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
rmultiDash = /([A-Z])/g;
jQuery.extend({
@@ -1513,7 +1514,7 @@ jQuery.extend({
deletedIds: [],
- // Please use with caution
+ // Remove at next major release (1.9/2.0)
uuid: 0,
// Unique for each copy of jQuery on the page
@@ -1565,7 +1566,7 @@ jQuery.extend({
// Only DOM nodes need a new unique ID for each element since their data
// ends up in the global cache
if ( isNode ) {
- elem[ internalKey ] = id = jQuery.deletedIds.pop() || ++jQuery.uuid;
+ elem[ internalKey ] = id = jQuery.deletedIds.pop() || jQuery.guid++;
} else {
id = internalKey;
}
@@ -1739,7 +1740,7 @@ jQuery.fn.extend({
for ( l = attr.length; i < l; i++ ) {
name = attr[i].name;
- if ( name.indexOf( "data-" ) === 0 ) {
+ if ( !name.indexOf( "data-" ) ) {
name = jQuery.camelCase( name.substring(5) );
dataAttr( elem, name, data[ name ] );
@@ -1868,6 +1869,7 @@ jQuery.extend({
type = type || "fx";
var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
fn = queue.shift(),
hooks = jQuery._queueHooks( elem, type ),
next = function() {
@@ -1877,6 +1879,7 @@ jQuery.extend({
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
fn = queue.shift();
+ startLength--;
}
if ( fn ) {
@@ -1891,7 +1894,8 @@ jQuery.extend({
delete hooks.stop;
fn.call( elem, next, hooks );
}
- if ( !queue.length && hooks ) {
+
+ if ( !startLength && hooks ) {
hooks.empty.fire();
}
},
@@ -1977,7 +1981,8 @@ jQuery.fn.extend({
type = type || "fx";
while( i-- ) {
- if ( (tmp = jQuery._data( elements[ i ], type + "queueHooks" )) && tmp.empty ) {
+ tmp = jQuery._data( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
count++;
tmp.empty.add( resolve );
}
@@ -2045,7 +2050,7 @@ jQuery.fn.extend({
setClass = " " + elem.className + " ";
for ( c = 0, cl = classNames.length; c < cl; c++ ) {
- if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
+ if ( setClass.indexOf( " " + classNames[ c ] + " " ) < 0 ) {
setClass += classNames[ c ] + " ";
}
}
@@ -2078,7 +2083,7 @@ jQuery.fn.extend({
// loop over each item in the removal list
for ( c = 0, cl = removes.length; c < cl; c++ ) {
// Remove until there is nothing to remove,
- while ( className.indexOf(" " + removes[ c ] + " ") > -1 ) {
+ while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) {
className = className.replace( " " + removes[ c ] + " " , " " );
}
}
@@ -2132,7 +2137,7 @@ jQuery.fn.extend({
i = 0,
l = this.length;
for ( ; i < l; i++ ) {
- if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
return true;
}
}
@@ -2213,26 +2218,25 @@ jQuery.extend({
},
select: {
get: function( elem ) {
- var value, i, max, option,
- index = elem.selectedIndex,
- values = [],
+ var value, option,
options = elem.options,
- one = elem.type === "select-one";
-
- // Nothing was selected
- if ( index < 0 ) {
- return null;
- }
+ index = elem.selectedIndex,
+ one = elem.type === "select-one" || index < 0,
+ values = one ? null : [],
+ max = one ? index + 1 : options.length,
+ i = index < 0 ?
+ max :
+ one ? index : 0;
// Loop through all the selected options
- i = one ? index : 0;
- max = one ? index + 1 : options.length;
for ( ; i < max; i++ ) {
option = options[ i ];
- // Don't return options that are disabled or in a disabled optgroup
- if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
- (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+ // oldIE doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+ // Don't return options that are disabled or in a disabled optgroup
+ ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
+ ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
// Get the specific value for the option
value = jQuery( option ).val();
@@ -2247,11 +2251,6 @@ jQuery.extend({
}
}
- // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
- if ( one && !values.length && options.length ) {
- return jQuery( options[ index ] ).val();
- }
-
return values;
},
@@ -2310,7 +2309,7 @@ jQuery.extend({
return ret;
} else {
- elem.setAttribute( name, "" + value );
+ elem.setAttribute( name, value + "" );
return value;
}
@@ -2574,7 +2573,7 @@ if ( !jQuery.support.style ) {
return elem.style.cssText.toLowerCase() || undefined;
},
set: function( elem, value ) {
- return ( elem.style.cssText = "" + value );
+ return ( elem.style.cssText = value + "" );
}
};
}
@@ -2707,6 +2706,7 @@ jQuery.event = {
handler: handler,
guid: handler.guid,
selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
namespace: namespaces.join(".")
}, handleObjIn );
@@ -2942,7 +2942,7 @@ jQuery.event = {
}
// Note that this is a bare JS function and not a jQuery handler
handle = ontype && cur[ ontype ];
- if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
+ if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
event.preventDefault();
}
}
@@ -2987,10 +2987,10 @@ jQuery.event = {
// Make a writable jQuery.Event from the native event object
event = jQuery.event.fix( event || window.event );
- var i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related,
+ var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, related,
handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
delegateCount = handlers.delegateCount,
- args = [].slice.call( arguments ),
+ args = core_slice.call( arguments ),
run_all = !event.exclusive && !event.namespace,
special = jQuery.event.special[ event.type ] || {},
handlerQueue = [];
@@ -3008,23 +3008,20 @@ jQuery.event = {
// Avoid non-left-click bubbling in Firefox (#3861)
if ( delegateCount && !(event.button && event.type === "click") ) {
- // Pregenerate a single jQuery object for reuse with .is()
- jqcur = jQuery(this);
- jqcur.context = this;
-
for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
- // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #xxxx)
+ // Don't process clicks (ONLY) on disabled elements (#6911, #8165, #11382, #11764)
if ( cur.disabled !== true || event.type !== "click" ) {
selMatch = {};
matches = [];
- jqcur[0] = cur;
for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ];
sel = handleObj.selector;
if ( selMatch[ sel ] === undefined ) {
- selMatch[ sel ] = jqcur.is( sel );
+ selMatch[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) >= 0 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
}
if ( selMatch[ sel ] ) {
matches.push( handleObj );
@@ -3165,11 +3162,6 @@ jQuery.event = {
},
special: {
- ready: {
- // Make sure the ready event is setup
- setup: jQuery.bindReady
- },
-
load: {
// Prevent triggered image.load events from bubbling to window.load
noBubble: true
@@ -3236,7 +3228,7 @@ jQuery.removeEvent = document.removeEventListener ?
if ( elem.detachEvent ) {
- // #8545, #7054, preventing memory leaks for custom events in IE6-8 –
+ // #8545, #7054, preventing memory leaks for custom events in IE6-8
// detachEvent needed property on element, by name of that event, to properly expose it to GC
if ( typeof elem[ name ] === "undefined" ) {
elem[ name ] = null;
@@ -3458,7 +3450,7 @@ if ( !jQuery.support.changeBubbles ) {
teardown: function() {
jQuery.event.remove( this, "._change" );
- return rformElems.test( this.nodeName );
+ return !rformElems.test( this.nodeName );
}
};
}
@@ -3599,7 +3591,7 @@ jQuery.fn.extend({
},
undelegate: function( selector, types, fn ) {
// ( namespace ) or ( selector, types [, fn] )
- return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
+ return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
},
trigger: function( type, data ) {
@@ -3668,1463 +3660,1685 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
}
});
-/*!
- * Sizzle CSS Selector Engine
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license
- * http://sizzlejs.com/
- */
-(function( window, undefined ) {
-
-var cachedruns,
- dirruns,
- sortOrder,
- siblingCheck,
- assertGetIdNotName,
-
- document = window.document,
- docElem = document.documentElement,
-
- strundefined = "undefined",
- hasDuplicate = false,
- baseHasDuplicate = true,
- done = 0,
- slice = [].slice,
- push = [].push,
-
- expando = ( "sizcache" + Math.random() ).replace( ".", "" ),
-
- // Regex
-
- // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
- whitespace = "[\\x20\\t\\r\\n\\f]",
- // http://www.w3.org/TR/css3-syntax/#characters
- characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",
-
- // Loosely modeled on CSS identifier characters
- // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors)
- // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
- identifier = characterEncoding.replace( "w", "w#" ),
-
- // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
- operators = "([*^$|!~]?=)",
- attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
- "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
- pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|((?:[^,]|\\\\,|(?:,(?=[^\\[]*\\]))|(?:,(?=[^\\(]*\\))))*))\\)|)",
- pos = ":(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\)|)(?=[^-]|$)",
- combinators = whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*",
- groups = "(?=[^\\x20\\t\\r\\n\\f])(?:\\\\.|" + attributes + "|" + pseudos.replace( 2, 7 ) + "|[^\\\\(),])+",
-
- // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
- rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
-
- rcombinators = new RegExp( "^" + combinators ),
-
- // All simple (non-comma) selectors, excluding insignifant trailing whitespace
- rgroups = new RegExp( groups + "?(?=" + whitespace + "*,|$)", "g" ),
-
- // A selector, or everything after leading whitespace
- // Optionally followed in either case by a ")" for terminating sub-selectors
- rselector = new RegExp( "^(?:(?!,)(?:(?:^|,)" + whitespace + "*" + groups + ")*?|" + whitespace + "*(.*?))(\\)|$)" ),
-
- // All combinators and selector components (attribute test, tag, pseudo, etc.), the latter appearing together when consecutive
- rtokens = new RegExp( groups.slice( 19, -6 ) + "\\x20\\t\\r\\n\\f>+~])+|" + combinators, "g" ),
-
- // Easily-parseable/retrievable ID or TAG or CLASS selectors
- rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,
-
- rsibling = /[\x20\t\r\n\f]*[+~]/,
- rendsWithNot = /:not\($/,
-
- rheader = /h\d/i,
- rinputs = /input|select|textarea|button/i,
-
- rbackslash = /\\(?!\\)/g,
-
- matchExpr = {
- "ID": new RegExp( "^#(" + characterEncoding + ")" ),
- "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
- "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
- "TAG": new RegExp( "^(" + characterEncoding.replace( "[-", "[-\\*" ) + ")" ),
- "ATTR": new RegExp( "^" + attributes ),
- "PSEUDO": new RegExp( "^" + pseudos ),
- "CHILD": new RegExp( "^:(only|nth|last|first)-child(?:\\(" + whitespace +
- "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
- "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
- "POS": new RegExp( pos, "ig" ),
- // For use in libraries implementing .is()
- "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" )
- },
-
- classCache = {},
- cachedClasses = [],
- compilerCache = {},
- cachedSelectors = [],
-
- // Mark a function for use in filtering
- markFunction = function( fn ) {
- fn.sizzleFilter = true;
- return fn;
- },
-
- // Returns a function to use in pseudos for input types
- createInputFunction = function( type ) {
- return function( elem ) {
- // Check the input's nodeName and type
- return elem.nodeName.toLowerCase() === "input" && elem.type === type;
- };
- },
-
- // Returns a function to use in pseudos for buttons
- createButtonFunction = function( type ) {
- return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return (name === "input" || name === "button") && elem.type === type;
- };
- },
-
- // Used for testing something on an element
- assert = function( fn ) {
- var pass = false,
- div = document.createElement("div");
- try {
- pass = fn( div );
- } catch (e) {}
- // release memory in IE
- div = null;
- return pass;
- },
-
- // Check if attributes should be retrieved by attribute nodes
- assertAttributes = assert(function( div ) {
- div.innerHTML = "<select></select>";
- var type = typeof div.lastChild.getAttribute("multiple");
- // IE8 returns a string for some attributes even when not present
- return type !== "boolean" && type !== "string";
- }),
-
- // Check if getElementById returns elements by name
- // Check if getElementsByName privileges form controls or returns elements by ID
- assertUsableName = assert(function( div ) {
- // Inject content
- div.id = expando + 0;
- div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
- docElem.insertBefore( div, docElem.firstChild );
-
- // Test
- var pass = document.getElementsByName &&
- // buggy browsers will return fewer than the correct 2
- document.getElementsByName( expando ).length ===
- // buggy browsers will return more than the correct 0
- 2 + document.getElementsByName( expando + 0 ).length;
- assertGetIdNotName = !document.getElementById( expando );
-
- // Cleanup
- docElem.removeChild( div );
-
- return pass;
- }),
-
- // Check if the browser returns only elements
- // when doing getElementsByTagName("*")
- assertTagNameNoComments = assert(function( div ) {
- div.appendChild( document.createComment("") );
- return div.getElementsByTagName("*").length === 0;
- }),
-
- // Check if getAttribute returns normalized href attributes
- assertHrefNotNormalized = assert(function( div ) {
- div.innerHTML = "<a href='#'></a>";
- return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
- div.firstChild.getAttribute("href") === "#";
- }),
-
- // Check if getElementsByClassName can be trusted
- assertUsableClassName = assert(function( div ) {
- // Opera can't find a second classname (in 9.6)
- div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
- if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
- return false;
- }
-
- // Safari caches class attributes, doesn't catch changes (in 3.2)
- div.lastChild.className = "e";
- return div.getElementsByClassName("e").length !== 1;
- });
-
-var Sizzle = function( selector, context, results, seed ) {
- results = results || [];
- context = context || document;
- var match, elem, xml, m,
- nodeType = context.nodeType;
-
- if ( nodeType !== 1 && nodeType !== 9 ) {
- return [];
- }
-
- if ( !selector || typeof selector !== "string" ) {
- return results;
- }
-
- xml = isXML( context );
-
- if ( !xml && !seed ) {
- if ( (match = rquickExpr.exec( selector )) ) {
- // Speed-up: Sizzle("#ID")
- if ( (m = match[1]) ) {
- if ( nodeType === 9 ) {
- elem = context.getElementById( m );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE, Opera, and Webkit return items
- // by name instead of ID
- if ( elem.id === m ) {
- results.push( elem );
- return results;
- }
- } else {
- return results;
- }
- } else {
- // Context is not a document
- if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
- contains( context, elem ) && elem.id === m ) {
- results.push( elem );
- return results;
- }
- }
-
- // Speed-up: Sizzle("TAG")
- } else if ( match[2] ) {
- push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
- return results;
-
- // Speed-up: Sizzle(".CLASS")
- } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) {
- push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
- return results;
- }
- }
- }
-
- // All others
- return select( selector, context, results, seed, xml );
-};
-
-var Expr = Sizzle.selectors = {
-
- // Can be adjusted by the user
- cacheLength: 50,
-
- match: matchExpr,
-
- order: [ "ID", "TAG" ],
-
- attrHandle: {},
-
- createPseudo: markFunction,
-
- find: {
- "ID": assertGetIdNotName ?
- function( id, context, xml ) {
- if ( typeof context.getElementById !== strundefined && !xml ) {
- var m = context.getElementById( id );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- return m && m.parentNode ? [m] : [];
- }
- } :
- function( id, context, xml ) {
- if ( typeof context.getElementById !== strundefined && !xml ) {
- var m = context.getElementById( id );
-
- return m ?
- m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
- [m] :
- undefined :
- [];
- }
- },
-
- "TAG": assertTagNameNoComments ?
- function( tag, context ) {
- if ( typeof context.getElementsByTagName !== strundefined ) {
- return context.getElementsByTagName( tag );
- }
- } :
- function( tag, context ) {
- var results = context.getElementsByTagName( tag );
-
- // Filter out possible comments
- if ( tag === "*" ) {
- var elem,
- tmp = [],
- i = 0;
-
- for ( ; (elem = results[i]); i++ ) {
- if ( elem.nodeType === 1 ) {
- tmp.push( elem );
- }
- }
-
- return tmp;
- }
- return results;
- }
- },
-
- relative: {
- ">": { dir: "parentNode", first: true },
- " ": { dir: "parentNode" },
- "+": { dir: "previousSibling", first: true },
- "~": { dir: "previousSibling" }
- },
-
- preFilter: {
- "ATTR": function( match ) {
- match[1] = match[1].replace( rbackslash, "" );
-
- // Move the given value to match[3] whether quoted or unquoted
- match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" );
-
- if ( match[2] === "~=" ) {
- match[3] = " " + match[3] + " ";
- }
-
- return match.slice( 0, 4 );
- },
-
- "CHILD": function( match ) {
- /* matches from matchExpr.CHILD
- 1 type (only|nth|...)
- 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
- 3 xn-component of xn+y argument ([+-]?\d*n|)
- 4 sign of xn-component
- 5 x of xn-component
- 6 sign of y-component
- 7 y of y-component
- */
- match[1] = match[1].toLowerCase();
-
- if ( match[1] === "nth" ) {
- // nth-child requires argument
- if ( !match[2] ) {
- Sizzle.error( match[0] );
- }
-
- // numeric x and y parameters for Expr.filter.CHILD
- // remember that false/true cast respectively to 0/1
- match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) );
- match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" );
-
- // other types prohibit arguments
- } else if ( match[2] ) {
- Sizzle.error( match[0] );
- }
-
- return match;
- },
-
- "PSEUDO": function( match ) {
- var argument,
- unquoted = match[4];
-
- if ( matchExpr["CHILD"].test( match[0] ) ) {
- return null;
- }
-
- // Relinquish our claim on characters in `unquoted` from a closing parenthesis on
- if ( unquoted && (argument = rselector.exec( unquoted )) && argument.pop() ) {
-
- match[0] = match[0].slice( 0, argument[0].length - unquoted.length - 1 );
- unquoted = argument[0].slice( 0, -1 );
- }
-
- // Quoted or unquoted, we have the full argument
- // Return only captures needed by the pseudo filter method (type and argument)
- match.splice( 2, 3, unquoted || match[3] );
- return match;
- }
- },
-
- filter: {
- "ID": assertGetIdNotName ?
- function( id ) {
- id = id.replace( rbackslash, "" );
- return function( elem ) {
- return elem.getAttribute("id") === id;
- };
- } :
- function( id ) {
- id = id.replace( rbackslash, "" );
- return function( elem ) {
- var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
- return node && node.value === id;
- };
- },
-
- "TAG": function( nodeName ) {
- if ( nodeName === "*" ) {
- return function() { return true; };
- }
- nodeName = nodeName.replace( rbackslash, "" ).toLowerCase();
-
- return function( elem ) {
- return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
- };
- },
-
- "CLASS": function( className ) {
- var pattern = classCache[ className ];
- if ( !pattern ) {
- pattern = classCache[ className ] = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" );
- cachedClasses.push( className );
- // Avoid too large of a cache
- if ( cachedClasses.length > Expr.cacheLength ) {
- delete classCache[ cachedClasses.shift() ];
- }
- }
- return function( elem ) {
- return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
- };
- },
-
- "ATTR": function( name, operator, check ) {
- if ( !operator ) {
- return function( elem ) {
- return Sizzle.attr( elem, name ) != null;
- };
- }
-
- return function( elem ) {
- var result = Sizzle.attr( elem, name ),
- value = result + "";
-
- if ( result == null ) {
- return operator === "!=";
- }
-
- switch ( operator ) {
- case "=":
- return value === check;
- case "!=":
- return value !== check;
- case "^=":
- return check && value.indexOf( check ) === 0;
- case "*=":
- return check && value.indexOf( check ) > -1;
- case "$=":
- return check && value.substr( value.length - check.length ) === check;
- case "~=":
- return ( " " + value + " " ).indexOf( check ) > -1;
- case "|=":
- return value === check || value.substr( 0, check.length + 1 ) === check + "-";
- }
- };
- },
-
- "CHILD": function( type, argument, first, last ) {
-
- if ( type === "nth" ) {
- var doneName = done++;
-
- return function( elem ) {
- var parent, diff,
- count = 0,
- node = elem;
-
- if ( first === 1 && last === 0 ) {
- return true;
- }
-
- parent = elem.parentNode;
-
- if ( parent && (parent[ expando ] !== doneName || !elem.sizset) ) {
- for ( node = parent.firstChild; node; node = node.nextSibling ) {
- if ( node.nodeType === 1 ) {
- node.sizset = ++count;
- if ( node === elem ) {
- break;
- }
- }
- }
-
- parent[ expando ] = doneName;
- }
-
- diff = elem.sizset - last;
-
- if ( first === 0 ) {
- return diff === 0;
-
- } else {
- return ( diff % first === 0 && diff / first >= 0 );
- }
- };
- }
-
- return function( elem ) {
- var node = elem;
-
- switch ( type ) {
- case "only":
- case "first":
- while ( (node = node.previousSibling) ) {
- if ( node.nodeType === 1 ) {
- return false;
- }
- }
-
- if ( type === "first" ) {
- return true;
- }
-
- node = elem;
-
- /* falls through */
- case "last":
- while ( (node = node.nextSibling) ) {
- if ( node.nodeType === 1 ) {
- return false;
- }
- }
-
- return true;
- }
- };
- },
-
- "PSEUDO": function( pseudo, argument, context, xml ) {
- // pseudo-class names are case-insensitive
- // http://www.w3.org/TR/selectors/#pseudo-classes
- // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
- var fn = Expr.pseudos[ pseudo ] || Expr.pseudos[ pseudo.toLowerCase() ];
-
- if ( !fn ) {
- Sizzle.error( "unsupported pseudo: " + pseudo );
- }
-
- // The user may set fn.sizzleFilter to indicate
- // that arguments are needed to create the filter function
- // just as Sizzle does
- if ( !fn.sizzleFilter ) {
- return fn;
- }
-
- return fn( argument, context, xml );
- }
- },
-
- pseudos: {
- "not": markFunction(function( selector, context, xml ) {
- // Trim the selector passed to compile
- // to avoid treating leading and trailing
- // spaces as combinators
- var matcher = compile( selector.replace( rtrim, "$1" ), context, xml );
- return function( elem ) {
- return !matcher( elem );
- };
- }),
-
- "enabled": function( elem ) {
- return elem.disabled === false;
- },
-
- "disabled": function( elem ) {
- return elem.disabled === true;
- },
-
- "checked": function( elem ) {
- // In CSS3, :checked should return both checked and selected elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- var nodeName = elem.nodeName.toLowerCase();
- return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
- },
-
- "selected": function( elem ) {
- // Accessing this property makes selected-by-default
- // options in Safari work properly
- if ( elem.parentNode ) {
- elem.parentNode.selectedIndex;
- }
-
- return elem.selected === true;
- },
-
- "parent": function( elem ) {
- return !Expr.pseudos["empty"]( elem );
- },
-
- "empty": function( elem ) {
- // http://www.w3.org/TR/selectors/#empty-pseudo
- // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
- // not comment, processing instructions, or others
- // Thanks to Diego Perini for the nodeName shortcut
- // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
- var nodeType;
- elem = elem.firstChild;
- while ( elem ) {
- if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) {
- return false;
- }
- elem = elem.nextSibling;
- }
- return true;
- },
-
- "contains": markFunction(function( text ) {
- return function( elem ) {
- return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
- };
- }),
-
- "has": markFunction(function( selector ) {
- return function( elem ) {
- return Sizzle( selector, elem ).length > 0;
- };
- }),
-
- "header": function( elem ) {
- return rheader.test( elem.nodeName );
- },
-
- "text": function( elem ) {
- var type, attr;
- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
- // use getAttribute instead to test this case
- return elem.nodeName.toLowerCase() === "input" &&
- (type = elem.type) === "text" &&
- ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type );
- },
-
- // Input types
- "radio": createInputFunction("radio"),
- "checkbox": createInputFunction("checkbox"),
- "file": createInputFunction("file"),
- "password": createInputFunction("password"),
- "image": createInputFunction("image"),
-
- "submit": createButtonFunction("submit"),
- "reset": createButtonFunction("reset"),
-
- "button": function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === "button" || name === "button";
- },
-
- "input": function( elem ) {
- return rinputs.test( elem.nodeName );
- },
-
- "focus": function( elem ) {
- var doc = elem.ownerDocument;
- return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href);
- },
-
- "active": function( elem ) {
- return elem === elem.ownerDocument.activeElement;
- }
- },
-
- setFilters: {
- "first": function( elements, argument, not ) {
- return not ? elements.slice( 1 ) : [ elements[0] ];
- },
-
- "last": function( elements, argument, not ) {
- var elem = elements.pop();
- return not ? elements : [ elem ];
- },
-
- "even": function( elements, argument, not ) {
- var results = [],
- i = not ? 1 : 0,
- len = elements.length;
- for ( ; i < len; i = i + 2 ) {
- results.push( elements[i] );
- }
- return results;
- },
-
- "odd": function( elements, argument, not ) {
- var results = [],
- i = not ? 0 : 1,
- len = elements.length;
- for ( ; i < len; i = i + 2 ) {
- results.push( elements[i] );
- }
- return results;
- },
-
- "lt": function( elements, argument, not ) {
- return not ? elements.slice( +argument ) : elements.slice( 0, +argument );
- },
-
- "gt": function( elements, argument, not ) {
- return not ? elements.slice( 0, +argument + 1 ) : elements.slice( +argument + 1 );
- },
-
- "eq": function( elements, argument, not ) {
- var elem = elements.splice( +argument, 1 );
- return not ? elements : elem;
- }
- }
-};
-
-// Deprecated
-Expr.setFilters["nth"] = Expr.setFilters["eq"];
-
-// Back-compat
-Expr.filters = Expr.pseudos;
-
-// IE6/7 return a modified href
-if ( !assertHrefNotNormalized ) {
- Expr.attrHandle = {
- "href": function( elem ) {
- return elem.getAttribute( "href", 2 );
- },
- "type": function( elem ) {
- return elem.getAttribute("type");
- }
- };
-}
-
-// Add getElementsByName if usable
-if ( assertUsableName ) {
- Expr.order.push("NAME");
- Expr.find["NAME"] = function( name, context ) {
- if ( typeof context.getElementsByName !== strundefined ) {
- return context.getElementsByName( name );
- }
- };
-}
-
-// Add getElementsByClassName if usable
-if ( assertUsableClassName ) {
- Expr.order.splice( 1, 0, "CLASS" );
- Expr.find["CLASS"] = function( className, context, xml ) {
- if ( typeof context.getElementsByClassName !== strundefined && !xml ) {
- return context.getElementsByClassName( className );
- }
- };
-}
-
-// If slice is not available, provide a backup
-try {
- slice.call( docElem.childNodes, 0 )[0].nodeType;
-} catch ( e ) {
- slice = function( i ) {
- var elem, results = [];
- for ( ; (elem = this[i]); i++ ) {
- results.push( elem );
- }
- return results;
- };
-}
-
-var isXML = Sizzle.isXML = function( elem ) {
- // documentElement is verified for cases where it doesn't yet exist
- // (such as loading iframes in IE - #4833)
- var documentElement = elem && (elem.ownerDocument || elem).documentElement;
- return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-// Element contains another
-var contains = Sizzle.contains = docElem.compareDocumentPosition ?
- function( a, b ) {
- return !!( a.compareDocumentPosition( b ) & 16 );
- } :
- docElem.contains ?
- function( a, b ) {
- var adown = a.nodeType === 9 ? a.documentElement : a,
- bup = b.parentNode;
- return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) );
- } :
- function( a, b ) {
- while ( (b = b.parentNode) ) {
- if ( b === a ) {
- return true;
- }
- }
- return false;
- };
-
-/**
- * Utility function for retrieving the text value of an array of DOM nodes
- * @param {Array|Element} elem
- */
-var getText = Sizzle.getText = function( elem ) {
- var node,
- ret = "",
- i = 0,
- nodeType = elem.nodeType;
-
- if ( nodeType ) {
- if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
- // Use textContent for elements
- // innerText usage removed for consistency of new lines (see #11153)
- if ( typeof elem.textContent === "string" ) {
- return elem.textContent;
- } else {
- // Traverse its children
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- ret += getText( elem );
- }
- }
- } else if ( nodeType === 3 || nodeType === 4 ) {
- return elem.nodeValue;
- }
- // Do not include comment or processing instruction nodes
- } else {
-
- // If no nodeType, this is expected to be an array
- for ( ; (node = elem[i]); i++ ) {
- // Do not traverse comment nodes
- ret += getText( node );
- }
- }
- return ret;
-};
-
-Sizzle.attr = function( elem, name ) {
- var attr,
- xml = isXML( elem );
-
- if ( !xml ) {
- name = name.toLowerCase();
- }
- if ( Expr.attrHandle[ name ] ) {
- return Expr.attrHandle[ name ]( elem );
- }
- if ( assertAttributes || xml ) {
- return elem.getAttribute( name );
- }
- attr = elem.getAttributeNode( name );
- return attr ?
- typeof elem[ name ] === "boolean" ?
- elem[ name ] ? name : null :
- attr.specified ? attr.value : null :
- null;
-};
-
-Sizzle.error = function( msg ) {
- throw new Error( "Syntax error, unrecognized expression: " + msg );
-};
-
-// Check if the JavaScript engine is using some sort of
-// optimization where it does not always call our comparision
-// function. If that is the case, discard the hasDuplicate value.
-// Thus far that includes Google Chrome.
-[0, 0].sort(function() {
- return (baseHasDuplicate = 0);
-});
-
-
-if ( docElem.compareDocumentPosition ) {
- sortOrder = function( a, b ) {
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- return ( !a.compareDocumentPosition || !b.compareDocumentPosition ?
- a.compareDocumentPosition :
- a.compareDocumentPosition(b) & 4
- ) ? -1 : 1;
- };
-
-} else {
- sortOrder = function( a, b ) {
- // The nodes are identical, we can exit early
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
-
- // Fallback to using sourceIndex (in IE) if it's available on both nodes
- } else if ( a.sourceIndex && b.sourceIndex ) {
- return a.sourceIndex - b.sourceIndex;
- }
-
- var al, bl,
- ap = [],
- bp = [],
- aup = a.parentNode,
- bup = b.parentNode,
- cur = aup;
-
- // If the nodes are siblings (or identical) we can do a quick check
- if ( aup === bup ) {
- return siblingCheck( a, b );
-
- // If no parents were found then the nodes are disconnected
- } else if ( !aup ) {
- return -1;
-
- } else if ( !bup ) {
- return 1;
- }
-
- // Otherwise they're somewhere else in the tree so we need
- // to build up a full list of the parentNodes for comparison
- while ( cur ) {
- ap.unshift( cur );
- cur = cur.parentNode;
- }
-
- cur = bup;
-
- while ( cur ) {
- bp.unshift( cur );
- cur = cur.parentNode;
- }
-
- al = ap.length;
- bl = bp.length;
-
- // Start walking down the tree looking for a discrepancy
- for ( var i = 0; i < al && i < bl; i++ ) {
- if ( ap[i] !== bp[i] ) {
- return siblingCheck( ap[i], bp[i] );
- }
- }
-
- // We ended someplace up the tree so do a sibling check
- return i === al ?
- siblingCheck( a, bp[i], -1 ) :
- siblingCheck( ap[i], b, 1 );
- };
-
- siblingCheck = function( a, b, ret ) {
- if ( a === b ) {
- return ret;
- }
-
- var cur = a.nextSibling;
-
- while ( cur ) {
- if ( cur === b ) {
- return -1;
- }
-
- cur = cur.nextSibling;
- }
-
- return 1;
- };
-}
-
-// Document sorting and removing duplicates
-Sizzle.uniqueSort = function( results ) {
- var elem,
- i = 1;
-
- if ( sortOrder ) {
- hasDuplicate = baseHasDuplicate;
- results.sort( sortOrder );
-
- if ( hasDuplicate ) {
- for ( ; (elem = results[i]); i++ ) {
- if ( elem === results[ i - 1 ] ) {
- results.splice( i--, 1 );
- }
- }
- }
- }
-
- return results;
-};
-
-function multipleContexts( selector, contexts, results, seed ) {
- var i = 0,
- len = contexts.length;
- for ( ; i < len; i++ ) {
- Sizzle( selector, contexts[i], results, seed );
- }
-}
-
-function handlePOSGroup( selector, posfilter, argument, contexts, seed, not ) {
- var results,
- fn = Expr.setFilters[ posfilter.toLowerCase() ];
-
- if ( !fn ) {
- Sizzle.error( posfilter );
- }
-
- if ( selector || !(results = seed) ) {
- multipleContexts( selector || "*", contexts, (results = []), seed );
- }
-
- return results.length > 0 ? fn( results, argument, not ) : [];
-}
-
-function handlePOS( selector, context, results, seed, groups ) {
- var match, not, anchor, ret, elements, currentContexts, part, lastIndex,
- i = 0,
- len = groups.length,
- rpos = matchExpr["POS"],
- // This is generated here in case matchExpr["POS"] is extended
- rposgroups = new RegExp( "^" + rpos.source + "(?!" + whitespace + ")", "i" ),
- // This is for making sure non-participating
- // matching groups are represented cross-browser (IE6-8)
- setUndefined = function() {
- var i = 1,
- len = arguments.length - 2;
- for ( ; i < len; i++ ) {
- if ( arguments[i] === undefined ) {
- match[i] = undefined;
- }
- }
- };
-
- for ( ; i < len; i++ ) {
- // Reset regex index to 0
- rpos.exec("");
- selector = groups[i];
- ret = [];
- anchor = 0;
- elements = seed;
- while ( (match = rpos.exec( selector )) ) {
- lastIndex = rpos.lastIndex = match.index + match[0].length;
- if ( lastIndex > anchor ) {
- part = selector.slice( anchor, match.index );
- anchor = lastIndex;
- currentContexts = [ context ];
-
- if ( rcombinators.test(part) ) {
- if ( elements ) {
- currentContexts = elements;
- }
- elements = seed;
- }
-
- if ( (not = rendsWithNot.test( part )) ) {
- part = part.slice( 0, -5 ).replace( rcombinators, "$&*" );
- }
-
- if ( match.length > 1 ) {
- match[0].replace( rposgroups, setUndefined );
- }
- elements = handlePOSGroup( part, match[1], match[2], currentContexts, elements, not );
- }
- }
-
- if ( elements ) {
- ret = ret.concat( elements );
-
- if ( (part = selector.slice( anchor )) && part !== ")" ) {
- if ( rcombinators.test(part) ) {
- multipleContexts( part, ret, results, seed );
- } else {
- Sizzle( part, context, results, seed ? seed.concat(elements) : elements );
- }
- } else {
- push.apply( results, ret );
- }
- } else {
- Sizzle( selector, context, results, seed );
- }
- }
-
- // Do not sort if this is a single filter
- return len === 1 ? results : Sizzle.uniqueSort( results );
-}
-
-function tokenize( selector, context, xml ) {
- var tokens, soFar, type,
- groups = [],
- i = 0,
-
- // Catch obvious selector issues: terminal ")"; nonempty fallback match
- // rselector never fails to match *something*
- match = rselector.exec( selector ),
- matched = !match.pop() && !match.pop(),
- selectorGroups = matched && selector.match( rgroups ) || [""],
-
- preFilters = Expr.preFilter,
- filters = Expr.filter,
- checkContext = !xml && context !== document;
-
- for ( ; (soFar = selectorGroups[i]) != null && matched; i++ ) {
- groups.push( tokens = [] );
-
- // Need to make sure we're within a narrower context if necessary
- // Adding a descendant combinator will generate what is needed
- if ( checkContext ) {
- soFar = " " + soFar;
- }
-
- while ( soFar ) {
- matched = false;
-
- // Combinators
- if ( (match = rcombinators.exec( soFar )) ) {
- soFar = soFar.slice( match[0].length );
-
- // Cast descendant combinators to space
- matched = tokens.push({ part: match.pop().replace( rtrim, " " ), captures: match });
- }
-
- // Filters
- for ( type in filters ) {
- if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
- (match = preFilters[ type ]( match, context, xml )) ) ) {
-
- soFar = soFar.slice( match.shift().length );
- matched = tokens.push({ part: type, captures: match });
- }
- }
-
- if ( !matched ) {
- break;
- }
- }
- }
-
- if ( !matched ) {
- Sizzle.error( selector );
- }
-
- return groups;
-}
-
-function addCombinator( matcher, combinator, context ) {
- var dir = combinator.dir,
- doneName = done++;
-
- if ( !matcher ) {
- // If there is no matcher to check, check against the context
- matcher = function( elem ) {
- return elem === context;
- };
- }
- return combinator.first ?
- function( elem, context ) {
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 ) {
- return matcher( elem, context ) && elem;
- }
- }
- } :
- function( elem, context ) {
- var cache,
- dirkey = doneName + "." + dirruns,
- cachedkey = dirkey + "." + cachedruns;
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 ) {
- if ( (cache = elem[ expando ]) === cachedkey ) {
- return elem.sizset;
- } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) {
- if ( elem.sizset ) {
- return elem;
- }
- } else {
- elem[ expando ] = cachedkey;
- if ( matcher( elem, context ) ) {
- elem.sizset = true;
- return elem;
- }
- elem.sizset = false;
- }
- }
- }
- };
-}
-
-function addMatcher( higher, deeper ) {
- return higher ?
- function( elem, context ) {
- var result = deeper( elem, context );
- return result && higher( result === true ? elem : result, context );
- } :
- deeper;
-}
-
-// ["TAG", ">", "ID", " ", "CLASS"]
-function matcherFromTokens( tokens, context, xml ) {
- var token, matcher,
- i = 0;
-
- for ( ; (token = tokens[i]); i++ ) {
- if ( Expr.relative[ token.part ] ) {
- matcher = addCombinator( matcher, Expr.relative[ token.part ], context );
- } else {
- token.captures.push( context, xml );
- matcher = addMatcher( matcher, Expr.filter[ token.part ].apply( null, token.captures ) );
- }
- }
-
- return matcher;
-}
-
-function matcherFromGroupMatchers( matchers ) {
- return function( elem, context ) {
- var matcher,
- j = 0;
- for ( ; (matcher = matchers[j]); j++ ) {
- if ( matcher(elem, context) ) {
- return true;
- }
- }
- return false;
- };
-}
-
-var compile = Sizzle.compile = function( selector, context, xml ) {
- var tokens, group, i,
- cached = compilerCache[ selector ];
-
- // Return a cached group function if already generated (context dependent)
- if ( cached && cached.context === context ) {
- return cached;
- }
-
- // Generate a function of recursive functions that can be used to check each element
- group = tokenize( selector, context, xml );
- for ( i = 0; (tokens = group[i]); i++ ) {
- group[i] = matcherFromTokens( tokens, context, xml );
- }
-
- // Cache the compiled function
- cached = compilerCache[ selector ] = matcherFromGroupMatchers( group );
- cached.context = context;
- cached.runs = cached.dirruns = 0;
- cachedSelectors.push( selector );
- // Ensure only the most recent are cached
- if ( cachedSelectors.length > Expr.cacheLength ) {
- delete compilerCache[ cachedSelectors.shift() ];
- }
- return cached;
-};
-
-Sizzle.matches = function( expr, elements ) {
- return Sizzle( expr, null, null, elements );
-};
-
-Sizzle.matchesSelector = function( elem, expr ) {
- return Sizzle( expr, null, null, [ elem ] ).length > 0;
-};
-
-var select = function( selector, context, results, seed, xml ) {
- // Remove excessive whitespace
- selector = selector.replace( rtrim, "$1" );
- var elements, matcher, i, len, elem, token,
- type, findContext, notTokens,
- match = selector.match( rgroups ),
- tokens = selector.match( rtokens ),
- contextNodeType = context.nodeType;
-
- // POS handling
- if ( matchExpr["POS"].test(selector) ) {
- return handlePOS( selector, context, results, seed, match );
- }
-
- if ( seed ) {
- elements = slice.call( seed, 0 );
-
- // To maintain document order, only narrow the
- // set if there is one group
- } else if ( match && match.length === 1 ) {
-
- // Take a shortcut and set the context if the root selector is an ID
- if ( tokens.length > 1 && contextNodeType === 9 && !xml &&
- (match = matchExpr["ID"].exec( tokens[0] )) ) {
-
- context = Expr.find["ID"]( match[1], context, xml )[0];
- if ( !context ) {
- return results;
- }
-
- selector = selector.slice( tokens.shift().length );
- }
-
- findContext = ( (match = rsibling.exec( tokens[0] )) && !match.index && context.parentNode ) || context;
-
- // Get the last token, excluding :not
- notTokens = tokens.pop();
- token = notTokens.split(":not")[0];
-
- for ( i = 0, len = Expr.order.length; i < len; i++ ) {
- type = Expr.order[i];
-
- if ( (match = matchExpr[ type ].exec( token )) ) {
- elements = Expr.find[ type ]( (match[1] || "").replace( rbackslash, "" ), findContext, xml );
-
- if ( elements == null ) {
- continue;
- }
-
- if ( token === notTokens ) {
- selector = selector.slice( 0, selector.length - notTokens.length ) +
- token.replace( matchExpr[ type ], "" );
-
- if ( !selector ) {
- push.apply( results, slice.call(elements, 0) );
- }
- }
- break;
- }
- }
- }
-
- // Only loop over the given elements once
- // If selector is empty, we're already done
- if ( selector ) {
- matcher = compile( selector, context, xml );
- dirruns = matcher.dirruns++;
-
- if ( elements == null ) {
- elements = Expr.find["TAG"]( "*", (rsibling.test( selector ) && context.parentNode) || context );
- }
- for ( i = 0; (elem = elements[i]); i++ ) {
- cachedruns = matcher.runs++;
- if ( matcher(elem, context) ) {
- results.push( elem );
- }
- }
- }
-
- return results;
-};
-
-if ( document.querySelectorAll ) {
- (function() {
- var disconnectedMatch,
- oldSelect = select,
- rescape = /'|\\/g,
- rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
- rbuggyQSA = [],
- // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
- // A support test would require too much code (would include document ready)
- // just skip matchesSelector for :active
- rbuggyMatches = [":active"],
- matches = docElem.matchesSelector ||
- docElem.mozMatchesSelector ||
- docElem.webkitMatchesSelector ||
- docElem.oMatchesSelector ||
- docElem.msMatchesSelector;
-
- // Build QSA regex
- // Regex strategy adopted from Diego Perini
- assert(function( div ) {
- div.innerHTML = "<select><option selected></option></select>";
-
- // IE8 - Some boolean attributes are not treated correctly
- if ( !div.querySelectorAll("[selected]").length ) {
- rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
- }
-
- // Webkit/Opera - :checked should return selected option elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- // IE8 throws error here (do not put tests after this one)
- if ( !div.querySelectorAll(":checked").length ) {
- rbuggyQSA.push(":checked");
- }
- });
-
- assert(function( div ) {
-
- // Opera 10-12/IE9 - ^= $= *= and empty values
- // Should not select anything
- div.innerHTML = "<p test=''></p>";
- if ( div.querySelectorAll("[test^='']").length ) {
- rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
- }
-
- // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
- // IE8 throws error here (do not put tests after this one)
- div.innerHTML = "<input type='hidden'>";
- if ( !div.querySelectorAll(":enabled").length ) {
- rbuggyQSA.push(":enabled", ":disabled");
- }
- });
-
- rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
-
- select = function( selector, context, results, seed, xml ) {
- // Only use querySelectorAll when not filtering,
- // when this is not xml,
- // and when no QSA bugs apply
- if ( !seed && !xml && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
- if ( context.nodeType === 9 ) {
- try {
- push.apply( results, slice.call(context.querySelectorAll( selector ), 0) );
- return results;
- } catch(qsaError) {}
- // qSA works strangely on Element-rooted queries
- // We can work around this by specifying an extra ID on the root
- // and working up from there (Thanks to Andrew Dupont for the technique)
- // IE 8 doesn't work on object elements
- } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
- var old = context.getAttribute("id"),
- nid = old || expando,
- newContext = rsibling.test( selector ) && context.parentNode || context;
-
- if ( old ) {
- nid = nid.replace( rescape, "\\$&" );
- } else {
- context.setAttribute( "id", nid );
- }
-
- try {
- push.apply( results, slice.call( newContext.querySelectorAll(
- selector.replace( rgroups, "[id='" + nid + "'] $&" )
- ), 0 ) );
- return results;
- } catch(qsaError) {
- } finally {
- if ( !old ) {
- context.removeAttribute("id");
- }
- }
- }
- }
-
- return oldSelect( selector, context, results, seed, xml );
- };
-
- if ( matches ) {
- assert(function( div ) {
- // Check to see if it's possible to do matchesSelector
- // on a disconnected node (IE 9)
- disconnectedMatch = matches.call( div, "div" );
-
- // This should fail with an exception
- // Gecko does not error, returns false instead
- try {
- matches.call( div, "[test!='']:sizzle" );
- rbuggyMatches.push( Expr.match.PSEUDO );
- } catch ( e ) {}
- });
-
- // rbuggyMatches always contains :active, so no need for a length check
- rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") );
-
- Sizzle.matchesSelector = function( elem, expr ) {
- // Make sure that attribute selectors are quoted
- expr = expr.replace( rattributeQuotes, "='$1']" );
-
- // rbuggyMatches always contains :active, so no need for an existence check
- if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && (!rbuggyQSA || !rbuggyQSA.test( expr )) ) {
- try {
- var ret = matches.call( elem, expr );
-
- // IE 9's matchesSelector returns false on disconnected nodes
- if ( ret || disconnectedMatch ||
- // As well, disconnected nodes are said to be in a document
- // fragment in IE 9
- elem.document && elem.document.nodeType !== 11 ) {
- return ret;
- }
- } catch(e) {}
- }
-
- return Sizzle( expr, null, null, [ elem ] ).length > 0;
- };
- }
- })();
-}
-
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://sizzlejs.com/
+ */
+(function( window, undefined ) {
+
+var cachedruns,
+ assertGetIdNotName,
+ Expr,
+ getText,
+ isXML,
+ contains,
+ compile,
+ sortOrder,
+ hasDuplicate,
+ outermostContext,
+
+ baseHasDuplicate = true,
+ strundefined = "undefined",
+
+ expando = ( "sizcache" + Math.random() ).replace( ".", "" ),
+
+ Token = String,
+ document = window.document,
+ docElem = document.documentElement,
+ dirruns = 0,
+ done = 0,
+ pop = [].pop,
+ push = [].push,
+ slice = [].slice,
+ // Use a stripped-down indexOf if a native one is unavailable
+ indexOf = [].indexOf || function( elem ) {
+ var i = 0,
+ len = this.length;
+ for ( ; i < len; i++ ) {
+ if ( this[i] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ // Augment a function for special use by Sizzle
+ markFunction = function( fn, value ) {
+ fn[ expando ] = value == null || value;
+ return fn;
+ },
+
+ createCache = function() {
+ var cache = {},
+ keys = [];
+
+ return markFunction(function( key, value ) {
+ // Only keep the most recent entries
+ if ( keys.push( key ) > Expr.cacheLength ) {
+ delete cache[ keys.shift() ];
+ }
+
+ // Retrieve with (key + " ") to avoid collision with native Object.prototype properties (see Issue #157)
+ return (cache[ key + " " ] = value);
+ }, cache );
+ },
+
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+
+ // Regex
+
+ // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+ // http://www.w3.org/TR/css3-syntax/#characters
+ characterEncoding = "(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",
+
+ // Loosely modeled on CSS identifier characters
+ // An unquoted value should be a CSS identifier (http://www.w3.org/TR/css3-selectors/#attribute-selectors)
+ // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
+ identifier = characterEncoding.replace( "w", "w#" ),
+
+ // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
+ operators = "([*^$|!~]?=)",
+ attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
+ "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
+
+ // Prefer arguments not in parens/brackets,
+ // then attribute selectors and non-pseudos (denoted by :),
+ // then anything else
+ // These preferences are here to reduce the number of selectors
+ // needing tokenize in the PSEUDO preFilter
+ pseudos = ":(" + characterEncoding + ")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:" + attributes + ")|[^:]|\\\\.)*|.*))\\)|)",
+
+ // For matchExpr.POS and matchExpr.needsContext
+ pos = ":(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
+ "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
+ rpseudo = new RegExp( pseudos ),
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,
+
+ rnot = /^:not/,
+ rsibling = /[\x20\t\r\n\f]*[+~]/,
+ rendsWithNot = /:not\($/,
+
+ rheader = /h\d/i,
+ rinputs = /input|select|textarea|button/i,
+
+ rbackslash = /\\(?!\\)/g,
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + characterEncoding + ")" ),
+ "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
+ "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
+ "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "POS": new RegExp( pos, "i" ),
+ "CHILD": new RegExp( "^:(only|nth|first|last)-child(?:\\(" + whitespace +
+ "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
+ "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ // For use in libraries implementing .is()
+ "needsContext": new RegExp( "^" + whitespace + "*[>+~]|" + pos, "i" )
+ },
+
+ // Support
+
+ // Used for testing something on an element
+ assert = function( fn ) {
+ var div = document.createElement("div");
+
+ try {
+ return fn( div );
+ } catch (e) {
+ return false;
+ } finally {
+ // release memory in IE
+ div = null;
+ }
+ },
+
+ // Check if getElementsByTagName("*") returns only elements
+ assertTagNameNoComments = assert(function( div ) {
+ div.appendChild( document.createComment("") );
+ return !div.getElementsByTagName("*").length;
+ }),
+
+ // Check if getAttribute returns normalized href attributes
+ assertHrefNotNormalized = assert(function( div ) {
+ div.innerHTML = "<a href='#'></a>";
+ return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
+ div.firstChild.getAttribute("href") === "#";
+ }),
+
+ // Check if attributes should be retrieved by attribute nodes
+ assertAttributes = assert(function( div ) {
+ div.innerHTML = "<select></select>";
+ var type = typeof div.lastChild.getAttribute("multiple");
+ // IE8 returns a string for some attributes even when not present
+ return type !== "boolean" && type !== "string";
+ }),
+
+ // Check if getElementsByClassName can be trusted
+ assertUsableClassName = assert(function( div ) {
+ // Opera can't find a second classname (in 9.6)
+ div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
+ if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
+ return false;
+ }
+
+ // Safari 3.2 caches class attributes and doesn't catch changes
+ div.lastChild.className = "e";
+ return div.getElementsByClassName("e").length === 2;
+ }),
+
+ // Check if getElementById returns elements by name
+ // Check if getElementsByName privileges form controls or returns elements by ID
+ assertUsableName = assert(function( div ) {
+ // Inject content
+ div.id = expando + 0;
+ div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
+ docElem.insertBefore( div, docElem.firstChild );
+
+ // Test
+ var pass = document.getElementsByName &&
+ // buggy browsers will return fewer than the correct 2
+ document.getElementsByName( expando ).length === 2 +
+ // buggy browsers will return more than the correct 0
+ document.getElementsByName( expando + 0 ).length;
+ assertGetIdNotName = !document.getElementById( expando );
+
+ // Cleanup
+ docElem.removeChild( div );
+
+ return pass;
+ });
+
+// If slice is not available, provide a backup
+try {
+ slice.call( docElem.childNodes, 0 )[0].nodeType;
+} catch ( e ) {
+ slice = function( i ) {
+ var elem,
+ results = [];
+ for ( ; (elem = this[i]); i++ ) {
+ results.push( elem );
+ }
+ return results;
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ results = results || [];
+ context = context || document;
+ var match, elem, xml, m,
+ nodeType = context.nodeType;
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ if ( nodeType !== 1 && nodeType !== 9 ) {
+ return [];
+ }
+
+ xml = isXML( context );
+
+ if ( !xml && !seed ) {
+ if ( (match = rquickExpr.exec( selector )) ) {
+ // Speed-up: Sizzle("#ID")
+ if ( (m = match[1]) ) {
+ if ( nodeType === 9 ) {
+ elem = context.getElementById( m );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE, Opera, and Webkit return items
+ // by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+ } else {
+ // Context is not a document
+ if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
+ contains( context, elem ) && elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Speed-up: Sizzle("TAG")
+ } else if ( match[2] ) {
+ push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
+ return results;
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( (m = match[3]) && assertUsableClassName && context.getElementsByClassName ) {
+ push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
+ return results;
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed, xml );
+}
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ return Sizzle( expr, null, null, [ elem ] ).length > 0;
+};
+
+// Returns a function to use in pseudos for input types
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+// Returns a function to use in pseudos for buttons
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && elem.type === type;
+ };
+}
+
+// Returns a function to use in pseudos for positionals
+function createPositionalPseudo( fn ) {
+ return markFunction(function( argument ) {
+ argument = +argument;
+ return markFunction(function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ (j = matchIndexes[i]) ] ) {
+ seed[j] = !(matches[j] = seed[j]);
+ }
+ }
+ });
+ });
+}
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( nodeType ) {
+ if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (see #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ // Do not include comment or processing instruction nodes
+ } else {
+
+ // If no nodeType, this is expected to be an array
+ for ( ; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ }
+ return ret;
+};
+
+isXML = Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = elem && (elem.ownerDocument || elem).documentElement;
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+// Element contains another
+contains = Sizzle.contains = docElem.contains ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && adown.contains && adown.contains(bup) );
+ } :
+ docElem.compareDocumentPosition ?
+ function( a, b ) {
+ return b && !!( a.compareDocumentPosition( b ) & 16 );
+ } :
+ function( a, b ) {
+ while ( (b = b.parentNode) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+Sizzle.attr = function( elem, name ) {
+ var val,
+ xml = isXML( elem );
+
+ if ( !xml ) {
+ name = name.toLowerCase();
+ }
+ if ( (val = Expr.attrHandle[ name ]) ) {
+ return val( elem );
+ }
+ if ( xml || assertAttributes ) {
+ return elem.getAttribute( name );
+ }
+ val = elem.getAttributeNode( name );
+ return val ?
+ typeof elem[ name ] === "boolean" ?
+ elem[ name ] ? name : null :
+ val.specified ? val.value : null :
+ null;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ // IE6/7 return a modified href
+ attrHandle: assertHrefNotNormalized ?
+ {} :
+ {
+ "href": function( elem ) {
+ return elem.getAttribute( "href", 2 );
+ },
+ "type": function( elem ) {
+ return elem.getAttribute("type");
+ }
+ },
+
+ find: {
+ "ID": assertGetIdNotName ?
+ function( id, context, xml ) {
+ if ( typeof context.getElementById !== strundefined && !xml ) {
+ var m = context.getElementById( id );
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ } :
+ function( id, context, xml ) {
+ if ( typeof context.getElementById !== strundefined && !xml ) {
+ var m = context.getElementById( id );
+
+ return m ?
+ m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
+ [m] :
+ undefined :
+ [];
+ }
+ },
+
+ "TAG": assertTagNameNoComments ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== strundefined ) {
+ return context.getElementsByTagName( tag );
+ }
+ } :
+ function( tag, context ) {
+ var results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ var elem,
+ tmp = [],
+ i = 0;
+
+ for ( ; (elem = results[i]); i++ ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ },
+
+ "NAME": assertUsableName && function( tag, context ) {
+ if ( typeof context.getElementsByName !== strundefined ) {
+ return context.getElementsByName( name );
+ }
+ },
+
+ "CLASS": assertUsableClassName && function( className, context, xml ) {
+ if ( typeof context.getElementsByClassName !== strundefined && !xml ) {
+ return context.getElementsByClassName( className );
+ }
+ }
+ },
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[1] = match[1].replace( rbackslash, "" );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[3] = ( match[4] || match[5] || "" ).replace( rbackslash, "" );
+
+ if ( match[2] === "~=" ) {
+ match[3] = " " + match[3] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 3 xn-component of xn+y argument ([+-]?\d*n|)
+ 4 sign of xn-component
+ 5 x of xn-component
+ 6 sign of y-component
+ 7 y of y-component
+ */
+ match[1] = match[1].toLowerCase();
+
+ if ( match[1] === "nth" ) {
+ // nth-child requires argument
+ if ( !match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[3] = +( match[3] ? match[4] + (match[5] || 1) : 2 * ( match[2] === "even" || match[2] === "odd" ) );
+ match[4] = +( ( match[6] + match[7] ) || match[2] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var unquoted, excess;
+ if ( matchExpr["CHILD"].test( match[0] ) ) {
+ return null;
+ }
+
+ if ( match[3] ) {
+ match[2] = match[3];
+ } else if ( (unquoted = match[4]) ) {
+ // Only check arguments that contain a pseudo
+ if ( rpseudo.test(unquoted) &&
+ // Get excess from tokenize (recursively)
+ (excess = tokenize( unquoted, true )) &&
+ // advance to the next closing parenthesis
+ (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
+
+ // excess is a negative index
+ unquoted = unquoted.slice( 0, excess );
+ match[0] = match[0].slice( 0, excess );
+ }
+ match[2] = unquoted;
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+ "ID": assertGetIdNotName ?
+ function( id ) {
+ id = id.replace( rbackslash, "" );
+ return function( elem ) {
+ return elem.getAttribute("id") === id;
+ };
+ } :
+ function( id ) {
+ id = id.replace( rbackslash, "" );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
+ return node && node.value === id;
+ };
+ },
+
+ "TAG": function( nodeName ) {
+ if ( nodeName === "*" ) {
+ return function() { return true; };
+ }
+ nodeName = nodeName.replace( rbackslash, "" ).toLowerCase();
+
+ return function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ expando ][ className + " " ];
+
+ return pattern ||
+ (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
+ classCache( className, function( elem ) {
+ return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
+ });
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem, context ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.substr( result.length - check.length ) === check :
+ operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.substr( 0, check.length + 1 ) === check + "-" :
+ false;
+ };
+ },
+
+ "CHILD": function( type, argument, first, last ) {
+
+ if ( type === "nth" ) {
+ return function( elem ) {
+ var node, diff,
+ parent = elem.parentNode;
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ if ( parent ) {
+ diff = 0;
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ diff++;
+ if ( elem === node ) {
+ break;
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset (or cast to NaN), then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ };
+ }
+
+ return function( elem ) {
+ var node = elem;
+
+ switch ( type ) {
+ case "only":
+ case "first":
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ if ( type === "first" ) {
+ return true;
+ }
+
+ node = elem;
+
+ /* falls through */
+ case "last":
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction(function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf.call( seed, matched[i] );
+ seed[ idx ] = !( matches[ idx ] = matched[i] );
+ }
+ }) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+ "not": markFunction(function( selector ) {
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction(function( seed, matches, context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( (elem = unmatched[i]) ) {
+ seed[i] = !(matches[i] = elem);
+ }
+ }
+ }) :
+ function( elem, context, xml ) {
+ input[0] = elem;
+ matcher( input, null, xml, results );
+ return !results.pop();
+ };
+ }),
+
+ "has": markFunction(function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ }),
+
+ "contains": markFunction(function( text ) {
+ return function( elem ) {
+ return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
+ };
+ }),
+
+ "enabled": function( elem ) {
+ return elem.disabled === false;
+ },
+
+ "disabled": function( elem ) {
+ return elem.disabled === true;
+ },
+
+ "checked": function( elem ) {
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
+ },
+
+ "selected": function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos["empty"]( elem );
+ },
+
+ "empty": function( elem ) {
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
+ // not comment, processing instructions, or others
+ // Thanks to Diego Perini for the nodeName shortcut
+ // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
+ var nodeType;
+ elem = elem.firstChild;
+ while ( elem ) {
+ if ( elem.nodeName > "@" || (nodeType = elem.nodeType) === 3 || nodeType === 4 ) {
+ return false;
+ }
+ elem = elem.nextSibling;
+ }
+ return true;
+ },
+
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "text": function( elem ) {
+ var type, attr;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" &&
+ (type = elem.type) === "text" &&
+ ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === type );
+ },
+
+ // Input types
+ "radio": createInputPseudo("radio"),
+ "checkbox": createInputPseudo("checkbox"),
+ "file": createInputPseudo("file"),
+ "password": createInputPseudo("password"),
+ "image": createInputPseudo("image"),
+
+ "submit": createButtonPseudo("submit"),
+ "reset": createButtonPseudo("reset"),
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "focus": function( elem ) {
+ var doc = elem.ownerDocument;
+ return elem === doc.activeElement && (!doc.hasFocus || doc.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
+ },
+
+ "active": function( elem ) {
+ return elem === elem.ownerDocument.activeElement;
+ },
+
+ // Positional types
+ "first": createPositionalPseudo(function() {
+ return [ 0 ];
+ }),
+
+ "last": createPositionalPseudo(function( matchIndexes, length ) {
+ return [ length - 1 ];
+ }),
+
+ "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ }),
+
+ "even": createPositionalPseudo(function( matchIndexes, length ) {
+ for ( var i = 0; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "odd": createPositionalPseudo(function( matchIndexes, length ) {
+ for ( var i = 1; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ for ( var i = argument < 0 ? argument + length : argument; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ }),
+
+ "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
+ for ( var i = argument < 0 ? argument + length : argument; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ })
+ }
+};
+
+function siblingCheck( a, b, ret ) {
+ if ( a === b ) {
+ return ret;
+ }
+
+ var cur = a.nextSibling;
+
+ while ( cur ) {
+ if ( cur === b ) {
+ return -1;
+ }
+
+ cur = cur.nextSibling;
+ }
+
+ return 1;
+}
+
+sortOrder = docElem.compareDocumentPosition ?
+ function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ return ( !a.compareDocumentPosition || !b.compareDocumentPosition ?
+ a.compareDocumentPosition :
+ a.compareDocumentPosition(b) & 4
+ ) ? -1 : 1;
+ } :
+ function( a, b ) {
+ // The nodes are identical, we can exit early
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Fallback to using sourceIndex (in IE) if it's available on both nodes
+ } else if ( a.sourceIndex && b.sourceIndex ) {
+ return a.sourceIndex - b.sourceIndex;
+ }
+
+ var al, bl,
+ ap = [],
+ bp = [],
+ aup = a.parentNode,
+ bup = b.parentNode,
+ cur = aup;
+
+ // If the nodes are siblings (or identical) we can do a quick check
+ if ( aup === bup ) {
+ return siblingCheck( a, b );
+
+ // If no parents were found then the nodes are disconnected
+ } else if ( !aup ) {
+ return -1;
+
+ } else if ( !bup ) {
+ return 1;
+ }
+
+ // Otherwise they're somewhere else in the tree so we need
+ // to build up a full list of the parentNodes for comparison
+ while ( cur ) {
+ ap.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ cur = bup;
+
+ while ( cur ) {
+ bp.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ al = ap.length;
+ bl = bp.length;
+
+ // Start walking down the tree looking for a discrepancy
+ for ( var i = 0; i < al && i < bl; i++ ) {
+ if ( ap[i] !== bp[i] ) {
+ return siblingCheck( ap[i], bp[i] );
+ }
+ }
+
+ // We ended someplace up the tree so do a sibling check
+ return i === al ?
+ siblingCheck( a, bp[i], -1 ) :
+ siblingCheck( ap[i], b, 1 );
+ };
+
+// Always assume the presence of duplicates if sort doesn't
+// pass them to our comparison function (as in Google Chrome).
+[0, 0].sort( sortOrder );
+baseHasDuplicate = !hasDuplicate;
+
+// Document sorting and removing duplicates
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ i = 1,
+ j = 0;
+
+ hasDuplicate = baseHasDuplicate;
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ for ( ; (elem = results[i]); i++ ) {
+ if ( elem === results[ i - 1 ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ return results;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+function tokenize( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ expando ][ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || (match = rcomma.exec( soFar )) ) {
+ if ( match ) {
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[0].length ) || soFar;
+ }
+ groups.push( tokens = [] );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( (match = rcombinators.exec( soFar )) ) {
+ tokens.push( matched = new Token( match.shift() ) );
+ soFar = soFar.slice( matched.length );
+
+ // Cast descendant combinators to space
+ matched.type = match[0].replace( rtrim, " " );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
+ (match = preFilters[ type ]( match ))) ) {
+
+ tokens.push( matched = new Token( match.shift() ) );
+ soFar = soFar.slice( matched.length );
+ matched.type = type;
+ matched.matches = match;
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ checkNonElements = base && combinator.dir === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( (elem = elem[ dir ]) ) {
+ if ( checkNonElements || elem.nodeType === 1 ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
+ if ( !xml ) {
+ var cache,
+ dirkey = dirruns + " " + doneName + " ",
+ cachedkey = dirkey + cachedruns;
+ while ( (elem = elem[ dir ]) ) {
+ if ( checkNonElements || elem.nodeType === 1 ) {
+ if ( (cache = elem[ expando ]) === cachedkey ) {
+ return elem.sizset;
+ } else if ( typeof cache === "string" && cache.indexOf(dirkey) === 0 ) {
+ if ( elem.sizset ) {
+ return elem;
+ }
+ } else {
+ elem[ expando ] = cachedkey;
+ if ( matcher( elem, context, xml ) ) {
+ elem.sizset = true;
+ return elem;
+ }
+ elem.sizset = false;
+ }
+ }
+ }
+ } else {
+ while ( (elem = elem[ dir ]) ) {
+ if ( checkNonElements || elem.nodeType === 1 ) {
+ if ( matcher( elem, context, xml ) ) {
+ return elem;
+ }
+ }
+ }
+ }
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[i]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[0];
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( (elem = unmatched[i]) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction(function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( (elem = temp[i]) ) {
+ matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) ) {
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( (matcherIn[i] = elem) );
+ }
+ }
+ postFinder( null, (matcherOut = []), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( (elem = matcherOut[i]) &&
+ (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
+
+ seed[temp] = !(results[temp] = elem);
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ });
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[0].type ],
+ implicitRelative = leadingRelative || Expr.relative[" "],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf.call( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ (checkContext = context).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
+ matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
+ } else {
+ matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[j].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && tokens.slice( 0, i - 1 ).join("").replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
+ j < len && tokens.join("")
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, expandContext ) {
+ var elem, j, matcher,
+ setMatched = [],
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ outermost = expandContext != null,
+ contextBackup = outermostContext,
+ // We must always have either seed elements or context
+ elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
+ // Nested matchers should use non-integer dirruns
+ dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.E);
+
+ if ( outermost ) {
+ outermostContext = context !== document && context;
+ cachedruns = superMatcher.el;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ for ( ; (elem = elems[i]) != null; i++ ) {
+ if ( byElement && elem ) {
+ for ( j = 0; (matcher = elementMatchers[j]); j++ ) {
+ if ( matcher( elem, context, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ cachedruns = ++superMatcher.el;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+ // They will have gone through all possible matchers
+ if ( (elem = !matcher && elem) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // Apply set filters to unmatched elements
+ matchedCount += i;
+ if ( bySet && i !== matchedCount ) {
+ for ( j = 0; (matcher = setMatchers[j]); j++ ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !(unmatched[i] || setMatched[i]) ) {
+ setMatched[i] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ superMatcher.el = 0;
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ expando ][ selector + " " ];
+
+ if ( !cached ) {
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !group ) {
+ group = tokenize( selector );
+ }
+ i = group.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( group[i] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
+ }
+ return cached;
+};
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[i], results );
+ }
+ return results;
+}
+
+function select( selector, context, results, seed, xml ) {
+ var i, tokens, token, type, find,
+ match = tokenize( selector ),
+ j = match.length;
+
+ if ( !seed ) {
+ // Try to minimize operations if there is only one group
+ if ( match.length === 1 ) {
+
+ // Take a shortcut and set the context if the root selector is an ID
+ tokens = match[0] = match[0].slice( 0 );
+ if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
+ context.nodeType === 9 && !xml &&
+ Expr.relative[ tokens[1].type ] ) {
+
+ context = Expr.find["ID"]( token.matches[0].replace( rbackslash, "" ), context, xml )[0];
+ if ( !context ) {
+ return results;
+ }
+
+ selector = selector.slice( tokens.shift().length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ for ( i = matchExpr["POS"].test( selector ) ? -1 : tokens.length - 1; i >= 0; i-- ) {
+ token = tokens[i];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ (type = token.type) ] ) {
+ break;
+ }
+ if ( (find = Expr.find[ type ]) ) {
+ // Search, expanding context for leading sibling combinators
+ if ( (seed = find(
+ token.matches[0].replace( rbackslash, "" ),
+ rsibling.test( tokens[0].type ) && context.parentNode || context,
+ xml
+ )) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && tokens.join("");
+ if ( !selector ) {
+ push.apply( results, slice.call( seed, 0 ) );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function
+ // Provide `match` to avoid retokenization if we modified the selector above
+ compile( selector, match )(
+ seed,
+ context,
+ xml,
+ results,
+ rsibling.test( selector )
+ );
+ return results;
+}
+
+if ( document.querySelectorAll ) {
+ (function() {
+ var disconnectedMatch,
+ oldSelect = select,
+ rescape = /'|\\/g,
+ rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
+
+ // qSa(:focus) reports false when true (Chrome 21), no need to also add to buggyMatches since matches checks buggyQSA
+ // A support test would require too much code (would include document ready)
+ rbuggyQSA = [ ":focus" ],
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ // A support test would require too much code (would include document ready)
+ // just skip matchesSelector for :active
+ rbuggyMatches = [ ":active" ],
+ matches = docElem.matchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.webkitMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector;
+
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert(function( div ) {
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explictly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // http://bugs.jquery.com/ticket/12359
+ div.innerHTML = "<select><option selected=''></option></select>";
+
+ // IE8 - Some boolean attributes are not treated correctly
+ if ( !div.querySelectorAll("[selected]").length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here (do not put tests after this one)
+ if ( !div.querySelectorAll(":checked").length ) {
+ rbuggyQSA.push(":checked");
+ }
+ });
+
+ assert(function( div ) {
+
+ // Opera 10-12/IE9 - ^= $= *= and empty values
+ // Should not select anything
+ div.innerHTML = "<p test=''></p>";
+ if ( div.querySelectorAll("[test^='']").length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here (do not put tests after this one)
+ div.innerHTML = "<input type='hidden'/>";
+ if ( !div.querySelectorAll(":enabled").length ) {
+ rbuggyQSA.push(":enabled", ":disabled");
+ }
+ });
+
+ // rbuggyQSA always contains :focus, so no need for a length check
+ rbuggyQSA = /* rbuggyQSA.length && */ new RegExp( rbuggyQSA.join("|") );
+
+ select = function( selector, context, results, seed, xml ) {
+ // Only use querySelectorAll when not filtering,
+ // when this is not xml,
+ // and when no QSA bugs apply
+ if ( !seed && !xml && !rbuggyQSA.test( selector ) ) {
+ var groups, i,
+ old = true,
+ nid = expando,
+ newContext = context,
+ newSelector = context.nodeType === 9 && selector;
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ groups = tokenize( selector );
+
+ if ( (old = context.getAttribute("id")) ) {
+ nid = old.replace( rescape, "\\$&" );
+ } else {
+ context.setAttribute( "id", nid );
+ }
+ nid = "[id='" + nid + "'] ";
+
+ i = groups.length;
+ while ( i-- ) {
+ groups[i] = nid + groups[i].join("");
+ }
+ newContext = rsibling.test( selector ) && context.parentNode || context;
+ newSelector = groups.join(",");
+ }
+
+ if ( newSelector ) {
+ try {
+ push.apply( results, slice.call( newContext.querySelectorAll(
+ newSelector
+ ), 0 ) );
+ return results;
+ } catch(qsaError) {
+ } finally {
+ if ( !old ) {
+ context.removeAttribute("id");
+ }
+ }
+ }
+ }
+
+ return oldSelect( selector, context, results, seed, xml );
+ };
+
+ if ( matches ) {
+ assert(function( div ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ disconnectedMatch = matches.call( div, "div" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ try {
+ matches.call( div, "[test!='']:sizzle" );
+ rbuggyMatches.push( "!=", pseudos );
+ } catch ( e ) {}
+ });
+
+ // rbuggyMatches always contains :active and :focus, so no need for a length check
+ rbuggyMatches = /* rbuggyMatches.length && */ new RegExp( rbuggyMatches.join("|") );
+
+ Sizzle.matchesSelector = function( elem, expr ) {
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace( rattributeQuotes, "='$1']" );
+
+ // rbuggyMatches always contains :active, so no need for an existence check
+ if ( !isXML( elem ) && !rbuggyMatches.test( expr ) && !rbuggyQSA.test( expr ) ) {
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle( expr, null, null, [ elem ] ).length > 0;
+ };
+ }
+ })();
+}
+
+// Deprecated
+Expr.pseudos["nth"] = Expr.pseudos["eq"];
+
+// Back-compat
+function setFilters() {}
+Expr.filters = setFilters.prototype = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
// Override sizzle attribute retrieval
Sizzle.attr = jQuery.attr;
jQuery.find = Sizzle;
@@ -5134,9 +5348,9 @@ jQuery.unique = Sizzle.uniqueSort;
jQuery.text = Sizzle.getText;
jQuery.isXMLDoc = Sizzle.isXML;
jQuery.contains = Sizzle.contains;
-
-
-})( window );
+
+
+})( window );
var runtil = /Until$/,
rparentsprev = /^(?:parents|prev(?:Until|All))/,
isSimple = /^.[^:#\[\.,]*$/,
@@ -5923,15 +6137,11 @@ jQuery.buildFragment = function( args, context, scripts ) {
first = args[ 0 ];
// Set context from what may come in as undefined or a jQuery collection or a node
+ // Updated to fix #12266 where accessing context[0] could throw an exception in IE9/10 &
+ // also doubles as fix for #8950 where plain objects caused createDocumentFragment exception
context = context || document;
- context = (context[0] || context).ownerDocument || context[0] || context;
-
- // Ensure that an attr object doesn't incorrectly stand in as a document object
- // Chrome and Firefox seem to allow this to occur and will throw exception
- // Fixes #8950
- if ( typeof context.createDocumentFragment === "undefined" ) {
- context = document;
- }
+ context = !context.nodeType && context[0] || context;
+ context = context.ownerDocument || context;
// Only cache "small" (1/2 KB) HTML strings that are associated with the main document
// Cloning options loses the selected state, so don't cache them
@@ -6076,8 +6286,8 @@ jQuery.extend({
},
clean: function( elems, context, fragment, scripts ) {
- var j, safe, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
- i = 0,
+ var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
+ safe = context === document && safeFragment,
ret = [];
// Ensure that context is a document
@@ -6086,7 +6296,7 @@ jQuery.extend({
}
// Use the already-created safe fragment if context permits
- for ( safe = context === document && safeFragment; (elem = elems[i]) != null; i++ ) {
+ for ( i = 0; (elem = elems[i]) != null; i++ ) {
if ( typeof elem === "number" ) {
elem += "";
}
@@ -6102,7 +6312,8 @@ jQuery.extend({
} else {
// Ensure a safe container in which to render the html
safe = safe || createSafeFragment( context );
- div = div || safe.appendChild( context.createElement("div") );
+ div = context.createElement("div");
+ safe.appendChild( div );
// Fix "XHTML"-style tags in all browsers
elem = elem.replace(rxhtmlTag, "<$1></$2>");
@@ -6145,21 +6356,20 @@ jQuery.extend({
elem = div.childNodes;
- // Remember the top-level container for proper cleanup
- div = safe.lastChild;
+ // Take out of fragment container (we need a fresh div each time)
+ div.parentNode.removeChild( div );
}
}
if ( elem.nodeType ) {
ret.push( elem );
} else {
- ret = jQuery.merge( ret, elem );
+ jQuery.merge( ret, elem );
}
}
// Fix #11356: Clear elements from safeFragment
if ( div ) {
- safe.removeChild( div );
elem = div = safe = null;
}
@@ -6294,9 +6504,10 @@ if ( matched.browser ) {
browser.version = matched.version;
}
-// Deprecated, use jQuery.browser.webkit instead
-// Maintained for back-compat only
-if ( browser.webkit ) {
+// Chrome is Webkit, but Webkit is also Safari.
+if ( browser.chrome ) {
+ browser.webkit = true;
+} else if ( browser.webkit ) {
browser.safari = true;
}
@@ -6322,23 +6533,25 @@ jQuery.sub = function() {
var rootjQuerySub = jQuerySub(document);
return jQuerySub;
};
-
+
})();
var curCSS, iframe, iframeDoc,
ralpha = /alpha\([^)]*\)/i,
ropacity = /opacity=([^)]*)/,
rposition = /^(top|right|bottom|left)$/,
+ // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
+ // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
rmargin = /^margin/,
rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
rrelNum = new RegExp( "^([-+])=(" + core_pnum + ")", "i" ),
- elemdisplay = {},
+ elemdisplay = { BODY: "block" },
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssNormalTransform = {
letterSpacing: 0,
- fontWeight: 400,
- lineHeight: 1
+ fontWeight: 400
},
cssExpand = [ "Top", "Right", "Bottom", "Left" ],
@@ -6604,18 +6817,20 @@ jQuery.extend({
}
});
-// NOTE: To any future maintainer, we've used both window.getComputedStyle
-// and getComputedStyle here to produce a better gzip size
+// NOTE: To any future maintainer, we've window.getComputedStyle
+// because jsdom on node.js will break without it.
if ( window.getComputedStyle ) {
curCSS = function( elem, name ) {
var ret, width, minWidth, maxWidth,
- computed = getComputedStyle( elem, null ),
+ computed = window.getComputedStyle( elem, null ),
style = elem.style;
if ( computed ) {
- ret = computed[ name ];
- if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+ // getPropertyValue is only needed for .css('filter') in IE9, see #12537
+ ret = computed.getPropertyValue( name ) || computed[ name ];
+
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
ret = jQuery.style( elem, name );
}
@@ -6738,7 +6953,10 @@ function getWidthOrHeight( elem, name, extra ) {
valueIsBorderBox = true,
isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing" ) === "border-box";
- if ( val <= 0 ) {
+ // some non-html elements return undefined for offsetWidth, so check for null/undefined
+ // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
+ // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
+ if ( val <= 0 || val == null ) {
// Fall back to computed then uncomputed css if necessary
val = curCSS( elem, name );
if ( val < 0 || val == null ) {
@@ -6817,12 +7035,14 @@ jQuery.each([ "height", "width" ], function( i, name ) {
jQuery.cssHooks[ name ] = {
get: function( elem, computed, extra ) {
if ( computed ) {
- if ( elem.offsetWidth !== 0 || curCSS( elem, "display" ) !== "none" ) {
- return getWidthOrHeight( elem, name, extra );
- } else {
+ // certain elements can have dimension info if we invisibly show them
+ // however, it must have a current display style that would benefit from this
+ if ( elem.offsetWidth === 0 && rdisplayswap.test( curCSS( elem, "display" ) ) ) {
return jQuery.swap( elem, cssShow, function() {
return getWidthOrHeight( elem, name, extra );
});
+ } else {
+ return getWidthOrHeight( elem, name, extra );
}
}
},
@@ -7056,10 +7276,10 @@ function buildParams( prefix, obj, traditional, add ) {
add( prefix, obj );
}
}
-var // Document location
- ajaxLocation,
- // Document location segments
+var
+ // Document location
ajaxLocParts,
+ ajaxLocation,
rhash = /#.*$/,
rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
@@ -7228,7 +7448,7 @@ jQuery.fn.load = function( url, params, callback ) {
params = undefined;
// Otherwise, build a param string
- } else if ( typeof params === "object" ) {
+ } else if ( params && typeof params === "object" ) {
type = "POST";
}
@@ -7576,7 +7796,7 @@ jQuery.extend({
// Set data for the fake xhr object
jqXHR.status = status;
- jqXHR.statusText = "" + ( nativeStatusText || statusText );
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
// Success/Error
if ( isSuccess ) {
@@ -7636,11 +7856,11 @@ jQuery.extend({
// Extract dataTypes list
s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace );
- // Determine if a cross-domain request is in order
+ // A cross-domain request is in order when we have a protocol:host:port mismatch
if ( s.crossDomain == null ) {
parts = rurl.exec( s.url.toLowerCase() );
s.crossDomain = !!( parts &&
- ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
+ ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
);
@@ -8262,7 +8482,7 @@ if ( jQuery.support.ajax ) {
// on any attempt to access responseText (#11426)
try {
responses.text = xhr.responseText;
- } catch( _ ) {
+ } catch( e ) {
}
// Firefox throws an exception when accessing
@@ -8338,12 +8558,13 @@ var fxNow, timerId,
animationPrefilters = [ defaultPrefilter ],
tweeners = {
"*": [function( prop, value ) {
- var end, unit, prevScale,
+ var end, unit,
tween = this.createTween( prop, value ),
parts = rfxnum.exec( value ),
target = tween.cur(),
start = +target || 0,
- scale = 1;
+ scale = 1,
+ maxIterations = 20;
if ( parts ) {
end = +parts[2];
@@ -8359,17 +8580,15 @@ var fxNow, timerId,
do {
// If previous iteration zeroed out, double until we get *something*
// Use a string for doubling factor so we don't accidentally see scale as unchanged below
- prevScale = scale = scale || ".5";
+ scale = scale || ".5";
// Adjust and apply
start = start / scale;
jQuery.style( tween.elem, prop, start + unit );
- // Update scale, tolerating zeroes from tween.cur()
- scale = tween.cur() / target;
-
- // Stop looping if we've hit the mark or scale is unchanged
- } while ( scale !== 1 && scale !== prevScale );
+ // Update scale, tolerating zero or NaN from tween.cur()
+ // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
+ } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
}
tween.unit = unit;
@@ -8416,7 +8635,9 @@ function Animation( elem, properties, options ) {
tick = function() {
var currentTime = fxNow || createFxNow(),
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
- percent = 1 - ( remaining / animation.duration || 0 ),
+ // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
index = 0,
length = animation.tweens.length;
@@ -8568,7 +8789,7 @@ jQuery.Animation = jQuery.extend( Animation, {
});
function defaultPrefilter( elem, props, opts ) {
- var index, prop, value, length, dataShow, tween, hooks, oldfire,
+ var index, prop, value, length, dataShow, toggle, tween, hooks, oldfire,
anim = this,
style = elem.style,
orig = {},
@@ -8642,6 +8863,7 @@ function defaultPrefilter( elem, props, opts ) {
value = props[ index ];
if ( rfxtypes.exec( value ) ) {
delete props[ index ];
+ toggle = toggle || value === "toggle";
if ( value === ( hidden ? "hide" : "show" ) ) {
continue;
}
@@ -8652,6 +8874,14 @@ function defaultPrefilter( elem, props, opts ) {
length = handled.length;
if ( length ) {
dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+
+ // store state if its toggle - enables .stop().toggle() to "reverse"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
if ( hidden ) {
jQuery( elem ).show();
} else {
@@ -8709,7 +8939,13 @@ Tween.prototype = {
var eased,
hooks = Tween.propHooks[ this.prop ];
- this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration );
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
this.now = ( this.end - this.start ) * eased + this.start;
if ( this.options.step ) {
@@ -8867,6 +9103,7 @@ function genFx( type, includeWidth ) {
// if we include width, step value is 1 to do all cssExpand values,
// if we don't include width, step value is 2 to skip over Left and Right
+ includeWidth = includeWidth? 1 : 0;
for( ; i < 4 ; i += 2 - includeWidth ) {
which = cssExpand[ i ];
attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
@@ -8941,6 +9178,8 @@ jQuery.fx.tick = function() {
timers = jQuery.timers,
i = 0;
+ fxNow = jQuery.now();
+
for ( ; i < timers.length; i++ ) {
timer = timers[ i ];
// Checks the timer has not already been removed
@@ -8952,6 +9191,7 @@ jQuery.fx.tick = function() {
if ( !timers.length ) {
jQuery.fx.stop();
}
+ fxNow = undefined;
};
jQuery.fx.timer = function( timer ) {
@@ -8995,7 +9235,8 @@ jQuery.fn.offset = function( options ) {
});
}
- var box, docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft, top, left,
+ var docElem, body, win, clientTop, clientLeft, scrollTop, scrollLeft,
+ box = { top: 0, left: 0 },
elem = this[ 0 ],
doc = elem && elem.ownerDocument;
@@ -9009,21 +9250,25 @@ jQuery.fn.offset = function( options ) {
docElem = doc.documentElement;
- // Make sure we're not dealing with a disconnected DOM node
+ // Make sure it's not a disconnected DOM node
if ( !jQuery.contains( docElem, elem ) ) {
- return { top: 0, left: 0 };
+ return box;
}
- box = elem.getBoundingClientRect();
+ // If we don't have gBCR, just use 0,0 rather than error
+ // BlackBerry 5, iOS 3 (original iPhone)
+ if ( typeof elem.getBoundingClientRect !== "undefined" ) {
+ box = elem.getBoundingClientRect();
+ }
win = getWindow( doc );
clientTop = docElem.clientTop || body.clientTop || 0;
clientLeft = docElem.clientLeft || body.clientLeft || 0;
scrollTop = win.pageYOffset || docElem.scrollTop;
scrollLeft = win.pageXOffset || docElem.scrollLeft;
- top = box.top + scrollTop - clientTop;
- left = box.left + scrollLeft - clientLeft;
-
- return { top: top, left: left };
+ return {
+ top: box.top + scrollTop - clientTop,
+ left: box.left + scrollLeft - clientLeft
+ };
};
jQuery.offset = {
@@ -9201,7 +9446,7 @@ jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
// Set width or height on the element
jQuery.style( elem, type, value, extra );
- }, type, chainable ? margin : undefined, chainable );
+ }, type, chainable ? margin : undefined, chainable, null );
};
});
});
@@ -9224,4 +9469,4 @@ if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
define( "jquery", [], function () { return jQuery; } );
}
-})( window ); \ No newline at end of file
+})( window );
diff --git a/module/web/static/js/libs/jquery.peity-0.6.js b/module/web/static/js/libs/jquery.peity-0.6.js
deleted file mode 100644
index 323ba6fac..000000000
--- a/module/web/static/js/libs/jquery.peity-0.6.js
+++ /dev/null
@@ -1,184 +0,0 @@
-// Peity jQuery plugin version 0.6.0
-// (c) 2011 Ben Pickles
-//
-// http://benpickles.github.com/peity/
-//
-// Released under MIT license.
-(function($, document) {
- var peity = $.fn.peity = function(type, options) {
- if (document.createElement("canvas").getContext) {
- this.each(function() {
- $(this).change(function() {
- var opts = $.extend({}, options)
- var self = this
-
- $.each(opts, function(name, value) {
- if ($.isFunction(value)) opts[name] = value.call(self)
- })
-
- var value = $(this).html();
- peity.graphers[type].call(this, $.extend({}, peity.defaults[type], opts));
- $(this).trigger("chart:changed", value);
- }).trigger("change");
- });
- }
-
- return this;
- };
-
- peity.graphers = {};
- peity.defaults = {};
-
- peity.add = function(type, defaults, grapher){
- peity.graphers[type] = grapher;
- peity.defaults[type] = defaults;
- };
-
- var devicePixelRatio = window.devicePixelRatio || 1
-
- function createCanvas(width, height) {
- var canvas = document.createElement("canvas")
- canvas.setAttribute("width", width * devicePixelRatio)
- canvas.setAttribute("height", height * devicePixelRatio)
-
- if (devicePixelRatio != 1) {
- var style = "width:" + width + "px;height:" + height + "px"
- canvas.setAttribute("style", style)
- }
-
- return canvas
- }
-
- peity.add(
- 'pie',
- {
- colours: ['#FFF4DD', '#FF9900'],
- delimeter: '/',
- diameter: 16
- },
- function(opts) {
- var $this = $(this)
- var values = $this.text().split(opts.delimeter)
- var v1 = parseFloat(values[0]);
- var v2 = parseFloat(values[1]);
- var adjust = -Math.PI / 2;
- var slice = (v1 / v2) * Math.PI * 2;
-
- var canvas = createCanvas(opts.diameter, opts.diameter)
- var context = canvas.getContext("2d");
- var centre = canvas.width / 2;
-
- // Plate.
- context.beginPath();
- context.moveTo(centre, centre);
- context.arc(centre, centre, centre, slice + adjust, (slice == 0) ? Math.PI * 2 : adjust, false);
- context.fillStyle = opts.colours[0];
- context.fill();
-
- // Slice of pie.
- context.beginPath();
- context.moveTo(centre, centre);
- context.arc(centre, centre, centre, adjust, slice + adjust, false);
- context.fillStyle = opts.colours[1];
- context.fill();
-
- $this.wrapInner($("<span>").hide()).append(canvas)
- });
-
- peity.add(
- "line",
- {
- colour: "#c6d9fd",
- strokeColour: "#4d89f9",
- strokeWidth: 1,
- delimeter: ",",
- height: 16,
- max: null,
- min: 0,
- width: 32
- },
- function(opts) {
- var $this = $(this)
- var canvas = createCanvas(opts.width, opts.height)
- var values = $this.text().split(opts.delimeter)
- if (values.length == 1) values.push(values[0])
- var max = Math.max.apply(Math, values.concat([opts.max]));
- var min = Math.min.apply(Math, values.concat([opts.min]))
-
- var context = canvas.getContext("2d");
- var width = canvas.width
- var height = canvas.height
- var xQuotient = width / (values.length - 1)
- var yQuotient = height / (max - min)
-
- var coords = [];
- var i;
-
- context.beginPath();
- context.moveTo(0, height + (min * yQuotient))
-
- for (i = 0; i < values.length; i++) {
- var x = i * xQuotient
- var y = height - (yQuotient * (values[i] - min))
-
- coords.push({ x: x, y: y });
- context.lineTo(x, y);
- }
-
- context.lineTo(width, height + (min * yQuotient))
- context.fillStyle = opts.colour;
- context.fill();
-
- if (opts.strokeWidth) {
- context.beginPath();
- context.moveTo(0, coords[0].y);
- for (i = 0; i < coords.length; i++) {
- context.lineTo(coords[i].x, coords[i].y);
- }
- context.lineWidth = opts.strokeWidth * devicePixelRatio;
- context.strokeStyle = opts.strokeColour;
- context.stroke();
- }
-
- $this.wrapInner($("<span>").hide()).append(canvas)
- }
- );
-
- peity.add(
- 'bar',
- {
- colour: "#4D89F9",
- delimeter: ",",
- height: 16,
- max: null,
- min: 0,
- width: 32
- },
- function(opts) {
- var $this = $(this)
- var values = $this.text().split(opts.delimeter)
- var max = Math.max.apply(Math, values.concat([opts.max]));
- var min = Math.min.apply(Math, values.concat([opts.min]))
-
- var canvas = createCanvas(opts.width, opts.height)
- var context = canvas.getContext("2d");
-
- var width = canvas.width
- var height = canvas.height
- var yQuotient = height / (max - min)
- var space = devicePixelRatio / 2
- var xQuotient = (width + space) / values.length
-
- context.fillStyle = opts.colour;
-
- for (var i = 0; i < values.length; i++) {
- var x = i * xQuotient
- var y = height - (yQuotient * (values[i] - min))
-
- context.fillRect(x, y, xQuotient - space, yQuotient * values[i])
- }
-
- $this.wrapInner($("<span>").hide()).append(canvas)
- }
- );
-})(jQuery, document);
diff --git a/module/web/static/js/libs/jquery.peity-1.0.js b/module/web/static/js/libs/jquery.peity-1.0.js
new file mode 100644
index 000000000..8c2abc236
--- /dev/null
+++ b/module/web/static/js/libs/jquery.peity-1.0.js
@@ -0,0 +1,246 @@
+// Peity jQuery plugin version 1.0.0
+// (c) 2012 Ben Pickles
+//
+// http://benpickles.github.com/peity
+//
+// Released under MIT license.
+(function($, document, Math, devicePixelRatio) {
+ var canvasSupported = document.createElement("canvas").getContext
+
+ var peity = $.fn.peity = function(type, options) {
+ if (canvasSupported) {
+ this.each(function() {
+ var defaults = peity.defaults[type]
+ var data = {}
+ var $this = $(this)
+
+ $.each($this.data(), function(name, value) {
+ if (name in defaults) data[name] = value
+ })
+
+ var opts = $.extend({}, defaults, data, options)
+ var chart = new Peity($this, type, opts)
+ chart.draw()
+
+ $this.change(function() {
+ chart.draw()
+ })
+ });
+ }
+
+ return this;
+ };
+
+ var Peity = function($elem, type, opts) {
+ this.$elem = $elem
+ this.type = type
+ this.opts = opts
+ }
+
+ var PeityPrototype = Peity.prototype
+
+ PeityPrototype.colours = function() {
+ var colours = this.opts.colours
+ var func = colours
+
+ if (!$.isFunction(func)) {
+ func = function(_, i) {
+ return colours[i % colours.length]
+ }
+ }
+
+ return func
+ }
+
+ PeityPrototype.draw = function() {
+ peity.graphers[this.type].call(this, this.opts)
+ }
+
+ PeityPrototype.prepareCanvas = function(width, height) {
+ var canvas = this.canvas
+
+ if (canvas) {
+ this.context.clearRect(0, 0, canvas.width, canvas.height)
+ } else {
+ canvas = $("<canvas>").attr({
+ height: height * devicePixelRatio,
+ width: width * devicePixelRatio
+ })
+
+ if (devicePixelRatio != 1) {
+ canvas.css({
+ height: height,
+ width: width
+ })
+ }
+
+ this.canvas = canvas = canvas[0]
+ this.context = canvas.getContext("2d")
+ this.$elem.hide().before(canvas)
+ }
+
+ return canvas
+ }
+
+ PeityPrototype.values = function() {
+ return $.map(this.$elem.text().split(this.opts.delimiter), function(value) {
+ return parseFloat(value)
+ })
+ }
+
+ peity.defaults = {}
+ peity.graphers = {}
+
+ peity.register = function(type, defaults, grapher) {
+ this.defaults[type] = defaults
+ this.graphers[type] = grapher
+ }
+
+ peity.register(
+ 'pie',
+ {
+ colours: ["#ff9900", "#fff4dd", "#ffc66e"],
+ delimiter: null,
+ diameter: 16
+ },
+ function(opts) {
+ if (!opts.delimiter) {
+ var delimiter = this.$elem.text().match(/[^0-9\.]/)
+ opts.delimiter = delimiter ? delimiter[0] : ","
+ }
+
+ var values = this.values()
+
+ if (opts.delimiter == "/") {
+ var v1 = values[0]
+ var v2 = values[1]
+ values = [v1, v2 - v1]
+ }
+
+ var i = 0
+ var length = values.length
+ var sum = 0
+
+ for (; i < length; i++) {
+ sum += values[i]
+ }
+
+ var canvas = this.prepareCanvas(opts.diameter, opts.diameter)
+ var context = this.context
+ var half = canvas.width / 2
+ var pi = Math.PI
+ var colours = this.colours()
+
+ context.save()
+ context.translate(half, half)
+ context.rotate(-pi / 2)
+
+ for (i = 0; i < length; i++) {
+ var value = values[i]
+ var slice = (value / sum) * pi * 2
+
+ context.beginPath()
+ context.moveTo(0, 0)
+ context.arc(0, 0, half, 0, slice, false)
+ context.fillStyle = colours.call(this, value, i, values)
+ context.fill()
+ context.rotate(slice)
+ }
+
+ context.restore()
+ }
+ )
+
+ peity.register(
+ "line",
+ {
+ colour: "#c6d9fd",
+ strokeColour: "#4d89f9",
+ strokeWidth: 1,
+ delimiter: ",",
+ height: 16,
+ max: null,
+ min: 0,
+ width: 32
+ },
+ function(opts) {
+ var values = this.values()
+ if (values.length == 1) values.push(values[0])
+ var max = Math.max.apply(Math, values.concat([opts.max]));
+ var min = Math.min.apply(Math, values.concat([opts.min]))
+
+ var canvas = this.prepareCanvas(opts.width, opts.height)
+ var context = this.context
+ var width = canvas.width
+ var height = canvas.height
+ var xQuotient = width / (values.length - 1)
+ var yQuotient = height / (max - min)
+
+ var coords = [];
+ var i;
+
+ context.beginPath();
+ context.moveTo(0, height + (min * yQuotient))
+
+ for (i = 0; i < values.length; i++) {
+ var x = i * xQuotient
+ var y = height - (yQuotient * (values[i] - min))
+
+ coords.push({ x: x, y: y });
+ context.lineTo(x, y);
+ }
+
+ context.lineTo(width, height + (min * yQuotient))
+ context.fillStyle = opts.colour;
+ context.fill();
+
+ if (opts.strokeWidth) {
+ context.beginPath();
+ context.moveTo(0, coords[0].y);
+ for (i = 0; i < coords.length; i++) {
+ context.lineTo(coords[i].x, coords[i].y);
+ }
+ context.lineWidth = opts.strokeWidth * devicePixelRatio;
+ context.strokeStyle = opts.strokeColour;
+ context.stroke();
+ }
+ }
+ );
+
+ peity.register(
+ 'bar',
+ {
+ colours: ["#4D89F9"],
+ delimiter: ",",
+ height: 16,
+ max: null,
+ min: 0,
+ spacing: devicePixelRatio,
+ width: 32
+ },
+ function(opts) {
+ var values = this.values()
+ var max = Math.max.apply(Math, values.concat([opts.max]));
+ var min = Math.min.apply(Math, values.concat([opts.min]))
+
+ var canvas = this.prepareCanvas(opts.width, opts.height)
+ var context = this.context
+
+ var width = canvas.width
+ var height = canvas.height
+ var yQuotient = height / (max - min)
+ var space = opts.spacing
+ var xQuotient = (width + space) / values.length
+ var colours = this.colours()
+
+ for (var i = 0; i < values.length; i++) {
+ var value = values[i]
+ var x = i * xQuotient
+ var y = height - (yQuotient * (value - min))
+
+ context.fillStyle = colours.call(this, value, i, values)
+ context.fillRect(x, y, xQuotient - space, yQuotient * values[i])
+ }
+ }
+ );
+})(jQuery, document, Math, window.devicePixelRatio || 1);
diff --git a/module/web/static/js/libs/jquery.transit-0.1.3.js b/module/web/static/js/libs/jquery.transit-0.9.9.js
index 2314f2ca2..f0d9719dd 100644
--- a/module/web/static/js/libs/jquery.transit-0.1.3.js
+++ b/module/web/static/js/libs/jquery.transit-0.9.9.js
@@ -1,6 +1,6 @@
/*!
* jQuery Transit - CSS3 transitions and transformations
- * Copyright(c) 2011 Rico Sta. Cruz <rico@ricostacruz.com>
+ * (c) 2011-2012 Rico Sta. Cruz <rico@ricostacruz.com>
* MIT Licensed.
*
* http://ricostacruz.com/jquery.transit
@@ -8,10 +8,8 @@
*/
(function($) {
- "use strict";
-
$.transit = {
- version: "0.1.3",
+ version: "0.9.9",
// Map of $.css() keys to values for 'transitionProperty'.
// See https://developer.mozilla.org/en/CSS/CSS_transitions#Properties_that_can_be_animated
@@ -39,6 +37,9 @@
// Helper function to get the proper vendor property name.
// (`transition` => `WebkitTransition`)
function getVendorPropertyName(prop) {
+ // Handle unprefixed versions (FF16+, for example)
+ if (prop in div.style) return prop;
+
var prefixes = ['Moz', 'Webkit', 'O', 'ms'];
var prop_ = prop.charAt(0).toUpperCase() + prop.substr(1);
@@ -61,18 +62,14 @@
var isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
// Check for the browser's transitions support.
- // You can access this in jQuery's `$.support.transition`.
- // As per [jQuery's cssHooks documentation](http://api.jquery.com/jQuery.cssHooks/),
- // we set $.support.transition to a string of the actual property name used.
support.transition = getVendorPropertyName('transition');
support.transitionDelay = getVendorPropertyName('transitionDelay');
support.transform = getVendorPropertyName('transform');
support.transformOrigin = getVendorPropertyName('transformOrigin');
support.transform3d = checkTransform3dSupport();
- $.extend($.support, support);
-
var eventNames = {
+ 'transition': 'transitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'WebkitTransition': 'webkitTransitionEnd',
@@ -82,17 +79,50 @@
// Detect the 'transitionend' event needed.
var transitionEnd = support.transitionEnd = eventNames[support.transition] || null;
+ // Populate jQuery's `$.support` with the vendor prefixes we know.
+ // As per [jQuery's cssHooks documentation](http://api.jquery.com/jQuery.cssHooks/),
+ // we set $.support.transition to a string of the actual property name used.
+ for (var key in support) {
+ if (support.hasOwnProperty(key) && typeof $.support[key] === 'undefined') {
+ $.support[key] = support[key];
+ }
+ }
+
// Avoid memory leak in IE.
div = null;
// ## $.cssEase
// List of easing aliases that you can use with `$.fn.transition`.
$.cssEase = {
- '_default': 'ease',
- 'in': 'ease-in',
- 'out': 'ease-out',
- 'in-out': 'ease-in-out',
- 'snap': 'cubic-bezier(0,1,.5,1)'
+ '_default': 'ease',
+ 'in': 'ease-in',
+ 'out': 'ease-out',
+ 'in-out': 'ease-in-out',
+ 'snap': 'cubic-bezier(0,1,.5,1)',
+ // Penner equations
+ 'easeOutCubic': 'cubic-bezier(.215,.61,.355,1)',
+ 'easeInOutCubic': 'cubic-bezier(.645,.045,.355,1)',
+ 'easeInCirc': 'cubic-bezier(.6,.04,.98,.335)',
+ 'easeOutCirc': 'cubic-bezier(.075,.82,.165,1)',
+ 'easeInOutCirc': 'cubic-bezier(.785,.135,.15,.86)',
+ 'easeInExpo': 'cubic-bezier(.95,.05,.795,.035)',
+ 'easeOutExpo': 'cubic-bezier(.19,1,.22,1)',
+ 'easeInOutExpo': 'cubic-bezier(1,0,0,1)',
+ 'easeInQuad': 'cubic-bezier(.55,.085,.68,.53)',
+ 'easeOutQuad': 'cubic-bezier(.25,.46,.45,.94)',
+ 'easeInOutQuad': 'cubic-bezier(.455,.03,.515,.955)',
+ 'easeInQuart': 'cubic-bezier(.895,.03,.685,.22)',
+ 'easeOutQuart': 'cubic-bezier(.165,.84,.44,1)',
+ 'easeInOutQuart': 'cubic-bezier(.77,0,.175,1)',
+ 'easeInQuint': 'cubic-bezier(.755,.05,.855,.06)',
+ 'easeOutQuint': 'cubic-bezier(.23,1,.32,1)',
+ 'easeInOutQuint': 'cubic-bezier(.86,0,.07,1)',
+ 'easeInSine': 'cubic-bezier(.47,0,.745,.715)',
+ 'easeOutSine': 'cubic-bezier(.39,.575,.565,1)',
+ 'easeInOutSine': 'cubic-bezier(.445,.05,.55,.95)',
+ 'easeInBack': 'cubic-bezier(.6,-.28,.735,.045)',
+ 'easeOutBack': 'cubic-bezier(.175, .885,.32,1.275)',
+ 'easeInOutBack': 'cubic-bezier(.68,-.55,.265,1.55)'
};
// ## 'transform' CSS hook
@@ -103,10 +133,10 @@
// $("#hello").css('transform');
// //=> { rotate: '90deg' }
//
- $.cssHooks.transform = {
+ $.cssHooks['transit:transform'] = {
// The getter returns a `Transform` object.
get: function(elem) {
- return $(elem).data('transform');
+ return $(elem).data('transform') || new Transform();
},
// The setter accepts a `Transform` object or a string.
@@ -132,34 +162,45 @@
}
};
- // ## 'transformOrigin' CSS hook
- // Allows the use for `transformOrigin` to define where scaling and rotation
- // is pivoted.
- //
- // $("#hello").css({ transformOrigin: '0 0' });
- //
- $.cssHooks.transformOrigin = {
- get: function(elem) {
- return elem.style[support.transformOrigin];
- },
- set: function(elem, value) {
- elem.style[support.transformOrigin] = value;
- }
+ // Add a CSS hook for `.css({ transform: '...' })`.
+ // In jQuery 1.8+, this will intentionally override the default `transform`
+ // CSS hook so it'll play well with Transit. (see issue #62)
+ $.cssHooks.transform = {
+ set: $.cssHooks['transit:transform'].set
};
- // ## 'transition' CSS hook
- // Allows you to use the `transition` property in CSS.
- //
- // $("#hello").css({ transition: 'all 0 ease 0' });
- //
- $.cssHooks.transition = {
- get: function(elem) {
- return elem.style[support.transition];
- },
- set: function(elem, value) {
- elem.style[support.transition] = value;
- }
- };
+ // jQuery 1.8+ supports prefix-free transitions, so these polyfills will not
+ // be necessary.
+ if ($.fn.jquery < "1.8") {
+ // ## 'transformOrigin' CSS hook
+ // Allows the use for `transformOrigin` to define where scaling and rotation
+ // is pivoted.
+ //
+ // $("#hello").css({ transformOrigin: '0 0' });
+ //
+ $.cssHooks.transformOrigin = {
+ get: function(elem) {
+ return elem.style[support.transformOrigin];
+ },
+ set: function(elem, value) {
+ elem.style[support.transformOrigin] = value;
+ }
+ };
+
+ // ## 'transition' CSS hook
+ // Allows you to use the `transition` property in CSS.
+ //
+ // $("#hello").css({ transition: 'all 0 ease 0' });
+ //
+ $.cssHooks.transition = {
+ get: function(elem) {
+ return elem.style[support.transition];
+ },
+ set: function(elem, value) {
+ elem.style[support.transition] = value;
+ }
+ };
+ }
// ## Other CSS hooks
// Allows you to rotate, scale and translate.
@@ -310,8 +351,8 @@
if (this._translateX === undefined) { this._translateX = 0; }
if (this._translateY === undefined) { this._translateY = 0; }
- if (x !== null) { this._translateX = unit(x, 'px'); }
- if (y !== null) { this._translateY = unit(y, 'px'); }
+ if (x !== null && x !== undefined) { this._translateX = unit(x, 'px'); }
+ if (y !== null && y !== undefined) { this._translateY = unit(y, 'px'); }
this.translate = this._translateX + "," + this._translateY;
}
@@ -405,7 +446,7 @@
$.each(props, function(key) {
key = $.camelCase(key); // Convert "text-align" => "textAlign"
- key = $.transit.propertyMap[key] || key;
+ key = $.transit.propertyMap[key] || $.cssProps[key] || key;
key = uncamel(key); // Convert back to dasherized
if ($.inArray(key, re) === -1) { re.push(key); }
@@ -603,17 +644,18 @@
$.cssHooks[prop] = {
get: function(elem) {
- var t = $(elem).css('transform') || new Transform();
+ var t = $(elem).css('transit:transform');
return t.get(prop);
},
set: function(elem, value) {
- var t = $(elem).css('transform');
- t = (typeof t === 'string' || t === null) ? new Transform() : t;
- t.setFromString(prop, value);
- $(elem).css({ transform: t });
+ var t = $(elem).css('transit:transform');
+ t.setFromString(prop, value);
+
+ $(elem).css({ 'transit:transform': t });
}
};
+
}
// ### uncamel(str)
diff --git a/module/web/static/js/libs/lodash-0.7.0.js b/module/web/static/js/libs/lodash-1.0.rc3.js
index 7843feb80..f4a8bb12d 100644
--- a/module/web/static/js/libs/lodash-0.7.0.js
+++ b/module/web/static/js/libs/lodash-1.0.rc3.js
@@ -1,34 +1,39 @@
/*!
- * Lo-Dash v0.7.0 <http://lodash.com>
+ * Lo-Dash 1.0.0-rc.3 <http://lodash.com>
* (c) 2012 John-David Dalton <http://allyoucanleet.com/>
- * Based on Underscore.js 1.4.0 <http://underscorejs.org>
+ * Based on Underscore.js 1.4.3 <http://underscorejs.org>
* (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
* Available under MIT license <http://lodash.com/license>
*/
;(function(window, undefined) {
- 'use strict';
/** Detect free variable `exports` */
- var freeExports = typeof exports == 'object' && exports &&
- (typeof global == 'object' && global && global == global.global && (window = global), exports);
+ var freeExports = typeof exports == 'object' && exports;
- /** Native prototype shortcuts */
- var ArrayProto = Array.prototype,
- BoolProto = Boolean.prototype,
- ObjectProto = Object.prototype,
- NumberProto = Number.prototype,
- StringProto = String.prototype;
+ /** Detect free variable `global` and use it as `window` */
+ var freeGlobal = typeof global == 'object' && global;
+ if (freeGlobal.global === freeGlobal) {
+ window = freeGlobal;
+ }
+
+ /** Used for array and object method references */
+ var arrayRef = [],
+ // avoid a Closure Compiler bug by creatively creating an object
+ objectRef = new function(){};
/** Used to generate unique IDs */
var idCounter = 0;
+ /** Used internally to indicate various things */
+ var indicatorObject = objectRef;
+
/** Used by `cachedContains` as the default size when optimizations are enabled for large arrays */
var largeArraySize = 30;
/** Used to restore the original `_` reference in `noConflict` */
var oldDash = window._;
- /** Used to detect delimiter values that should be processed by `tokenizeEvaluate` */
+ /** Used to detect template delimiter values that require a with-statement */
var reComplexDelimiter = /[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/;
/** Used to match HTML entities */
@@ -47,12 +52,21 @@
/** Used to detect if a method is native */
var reNative = RegExp('^' +
- (ObjectProto.valueOf + '')
+ (objectRef.valueOf + '')
.replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&')
.replace(/valueOf|for [^\]]+/g, '.+?') + '$'
);
- /** Used to ensure capturing order and avoid matches for undefined delimiters */
+ /**
+ * Used to match ES6 template delimiters
+ * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6
+ */
+ var reEsTemplate = /\$\{((?:(?=\\?)\\?[\s\S])*?)}/g;
+
+ /** Used to match "interpolate" template delimiters */
+ var reInterpolate = /<%=([\s\S]+?)%>/g;
+
+ /** Used to ensure capturing order of template delimiters */
var reNoMatch = /($^)/;
/** Used to match HTML characters */
@@ -71,19 +85,20 @@
var templateCounter = 0;
/** Native method shortcuts */
- var concat = ArrayProto.concat,
- hasOwnProperty = ObjectProto.hasOwnProperty,
- push = ArrayProto.push,
- propertyIsEnumerable = ObjectProto.propertyIsEnumerable,
- slice = ArrayProto.slice,
- toString = ObjectProto.toString;
+ var ceil = Math.ceil,
+ concat = arrayRef.concat,
+ floor = Math.floor,
+ getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
+ hasOwnProperty = objectRef.hasOwnProperty,
+ push = arrayRef.push,
+ propertyIsEnumerable = objectRef.propertyIsEnumerable,
+ toString = objectRef.toString;
/* Native method shortcuts for methods with the same name as other `lodash` methods */
var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind,
- nativeFloor = Math.floor,
- nativeGetPrototypeOf = reNative.test(nativeGetPrototypeOf = Object.getPrototypeOf) && nativeGetPrototypeOf,
nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
nativeIsFinite = window.isFinite,
+ nativeIsNaN = window.isNaN,
nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys,
nativeMax = Math.max,
nativeMin = Math.min,
@@ -100,9 +115,15 @@
regexpClass = '[object RegExp]',
stringClass = '[object String]';
- /** Timer shortcuts */
- var clearTimeout = window.clearTimeout,
- setTimeout = window.setTimeout;
+ /** Detect various environments */
+ var isIeOpera = !!window.attachEvent,
+ isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera);
+
+ /* Detect if `Function#bind` exists and is inferred to be fast (all but V8) */
+ var isBindFast = nativeBind && !isV8;
+
+ /* Detect if `Object.keys` exists and is inferred to be fast (IE, Opera, V8) */
+ var isKeysFast = nativeKeys && (isIeOpera || isV8);
/**
* Detect the JScript [[DontEnum]] bug:
@@ -112,6 +133,9 @@
*/
var hasDontEnumBug;
+ /** Detect if own properties are iterated after inherited properties (IE < 9) */
+ var iteratesOwnLast;
+
/**
* Detect if `Array#shift` and `Array#splice` augment array-like objects
* incorrectly:
@@ -122,33 +146,28 @@
* The `shift()` method is buggy in IE 8 compatibility mode, while `splice()`
* is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9.
*/
- var hasObjectSpliceBug;
-
- /** Detect if own properties are iterated after inherited properties (IE < 9) */
- var iteratesOwnLast;
+ var hasObjectSpliceBug = (hasObjectSpliceBug = { '0': 1, 'length': 1 },
+ arrayRef.splice.call(hasObjectSpliceBug, 0, 1), hasObjectSpliceBug[0]);
/** Detect if an `arguments` object's indexes are non-enumerable (IE < 9) */
- var noArgsEnum = true;
+ var nonEnumArgs = true;
(function() {
- var object = { '0': 1, 'length': 1 },
- props = [];
-
+ var props = [];
function ctor() { this.x = 1; }
ctor.prototype = { 'valueOf': 1, 'y': 1 };
for (var prop in new ctor) { props.push(prop); }
- for (prop in arguments) { noArgsEnum = !prop; }
+ for (prop in arguments) { nonEnumArgs = !prop; }
- hasDontEnumBug = (props + '').length < 4;
+ hasDontEnumBug = !/valueOf/.test(props);
iteratesOwnLast = props[0] != 'x';
- hasObjectSpliceBug = (props.splice.call(object, 0, 1), object[0]);
}(1));
- /** Detect if an `arguments` object's [[Class]] is unresolvable (Firefox < 4, IE < 9) */
- var noArgsClass = !isArguments(arguments);
+ /** Detect if `arguments` objects are `Object` objects (all but Opera < 10.5) */
+ var argsAreObjects = arguments.constructor == Object;
- /** Detect if `Array#slice` cannot be used to convert strings to arrays (Opera < 10.52) */
- var noArraySliceOnStrings = slice.call('x')[0] != 'x';
+ /** Detect if `arguments` objects [[Class]] is unresolvable (Firefox < 4, IE < 9) */
+ var noArgsClass = !isArguments(arguments);
/**
* Detect lack of support for accessing string characters by index:
@@ -164,23 +183,14 @@
* a string without a `toString` property value of `typeof` "function".
*/
try {
- var noNodeClass = ({ 'toString': 0 } + '', toString.call(window.document || 0) == objectClass);
+ var noNodeClass = ({ 'toString': 0 } + '', toString.call(document) == objectClass);
} catch(e) { }
- /* Detect if `Function#bind` exists and is inferred to be fast (all but V8) */
- var isBindFast = nativeBind && /\n|Opera/.test(nativeBind + toString.call(window.opera));
-
- /* Detect if `Object.keys` exists and is inferred to be fast (IE, Opera, V8) */
- var isKeysFast = nativeKeys && /^.+$|true/.test(nativeKeys + !!window.attachEvent);
-
- /* Detect if strict mode, "use strict", is inferred to be fast (V8) */
- var isStrictFast = !isBindFast;
-
/**
* Detect if sourceURL syntax is usable without erroring:
*
- * The JS engine in Adobe products, like InDesign, will throw a syntax error
- * when it encounters a single line comment beginning with the `@` symbol.
+ * The JS engine embedded in Adobe products will throw a syntax error when
+ * it encounters a single line comment beginning with the `@` symbol.
*
* The JS engine in Narwhal will generate the function `function anonymous(){//}`
* and throw a syntax error.
@@ -190,21 +200,26 @@
* http://msdn.microsoft.com/en-us/library/121hztk3(v=vs.94).aspx
*/
try {
- var useSourceURL = (Function('//@')(), !window.attachEvent);
+ var useSourceURL = (Function('//@')(), !isIeOpera);
} catch(e) { }
- /** Used to identify object classifications that are array-like */
- var arrayLikeClasses = {};
- arrayLikeClasses[boolClass] = arrayLikeClasses[dateClass] = arrayLikeClasses[funcClass] =
- arrayLikeClasses[numberClass] = arrayLikeClasses[objectClass] = arrayLikeClasses[regexpClass] = false;
- arrayLikeClasses[argsClass] = arrayLikeClasses[arrayClass] = arrayLikeClasses[stringClass] = true;
-
/** Used to identify object classifications that `_.clone` supports */
var cloneableClasses = {};
- cloneableClasses[argsClass] = cloneableClasses[funcClass] = false;
- cloneableClasses[arrayClass] = cloneableClasses[boolClass] = cloneableClasses[dateClass] =
- cloneableClasses[numberClass] = cloneableClasses[objectClass] = cloneableClasses[regexpClass] =
- cloneableClasses[stringClass] = true;
+ cloneableClasses[funcClass] = false;
+ cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
+ cloneableClasses[boolClass] = cloneableClasses[dateClass] =
+ cloneableClasses[numberClass] = cloneableClasses[objectClass] =
+ cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
+
+ /** Used to lookup a built-in constructor by [[Class]] */
+ var ctorByClass = {};
+ ctorByClass[arrayClass] = Array;
+ ctorByClass[boolClass] = Boolean;
+ ctorByClass[dateClass] = Date;
+ ctorByClass[objectClass] = Object;
+ ctorByClass[numberClass] = Number;
+ ctorByClass[regexpClass] = RegExp;
+ ctorByClass[stringClass] = String;
/** Used to determine if values are of the language type Object */
var objectTypes = {
@@ -213,8 +228,7 @@
'object': true,
'number': false,
'string': false,
- 'undefined': false,
- 'unknown': true
+ 'undefined': false
};
/** Used to escape characters for inclusion in compiled string literals */
@@ -231,16 +245,39 @@
/*--------------------------------------------------------------------------*/
/**
- * The `lodash` function.
+ * Creates a `lodash` object, that wraps the given `value`, to enable
+ * method chaining.
+ *
+ * The chainable wrapper functions are:
+ * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, `compose`,
+ * `concat`, `countBy`, `debounce`, `defaults`, `defer`, `delay`, `difference`,
+ * `filter`, `flatten`, `forEach`, `forIn`, `forOwn`, `functions`, `groupBy`,
+ * `initial`, `intersection`, `invert`, `invoke`, `keys`, `map`, `max`, `memoize`,
+ * `merge`, `min`, `object`, `omit`, `once`, `pairs`, `partial`, `pick`, `pluck`,
+ * `push`, `range`, `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`,
+ * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`,
+ * `unshift`, `values`, `where`, `without`, `wrap`, and `zip`
+ *
+ * The non-chainable wrapper functions are:
+ * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, `identity`,
+ * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`,
+ * `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, `isObject`,
+ * `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, `lastIndexOf`,
+ * `mixin`, `noConflict`, `pop`, `random`, `reduce`, `reduceRight`, `result`,
+ * `shift`, `size`, `some`, `sortedIndex`, `template`, `unescape`, and `uniqueId`
+ *
+ * The wrapper functions `first` and `last` return wrapped values when `n` is
+ * passed, otherwise they return unwrapped values.
*
* @name _
* @constructor
+ * @category Chaining
* @param {Mixed} value The value to wrap in a `lodash` instance.
* @returns {Object} Returns a `lodash` instance.
*/
function lodash(value) {
- // exit early if already wrapped
- if (value && value.__wrapped__) {
+ // exit early if already wrapped, even if wrapped by a different `lodash` constructor
+ if (value && typeof value == 'object' && value.__wrapped__) {
return value;
}
// allow invoking `lodash` without the `new` operator
@@ -286,7 +323,7 @@
* @memberOf _.templateSettings
* @type RegExp
*/
- 'interpolate': /<%=([\s\S]+?)%>/g,
+ 'interpolate': reInterpolate,
/**
* Used to reference the data object in the template text.
@@ -309,46 +346,44 @@
*/
var iteratorTemplate = template(
// conditional strict mode
- '<% if (useStrict) { %>\'use strict\';\n<% } %>' +
+ "<% if (obj.useStrict) { %>'use strict';\n<% } %>" +
// the `iteratee` may be reassigned by the `top` snippet
- 'var index, value, iteratee = <%= firstArg %>, ' +
+ 'var index, iteratee = <%= firstArg %>, ' +
// assign the `result` variable an initial value
- 'result<% if (init) { %> = <%= init %><% } %>;\n' +
+ 'result = <%= firstArg %>;\n' +
+ // exit early if the first argument is falsey
+ 'if (!<%= firstArg %>) return result;\n' +
// add code before the iteration branches
'<%= top %>;\n' +
- // the following branch is for iterating arrays and array-like objects
- '<% if (arrayBranch) { %>' +
- 'var length = iteratee.length; index = -1;' +
- ' <% if (objectBranch) { %>\nif (length === +length) {<% } %>' +
+ // array-like iteration:
+ '<% if (arrayLoop) { %>' +
+ 'var length = iteratee.length; index = -1;\n' +
+ "if (typeof length == 'number') {" +
// add support for accessing string characters by index if needed
' <% if (noCharByIndex) { %>\n' +
- ' if (toString.call(iteratee) == stringClass) {\n' +
- ' iteratee = iteratee.split(\'\')\n' +
+ ' if (isString(iteratee)) {\n' +
+ " iteratee = iteratee.split('')\n" +
' }' +
' <% } %>\n' +
- ' <%= arrayBranch.beforeLoop %>;\n' +
+ // iterate over the array-like value
' while (++index < length) {\n' +
- ' value = iteratee[index];\n' +
- ' <%= arrayBranch.inLoop %>\n' +
- ' }' +
- ' <% if (objectBranch) { %>\n}<% } %>' +
- '<% } %>' +
-
- // the following branch is for iterating an object's own/inherited properties
- '<% if (objectBranch) { %>' +
- ' <% if (arrayBranch) { %>\nelse {' +
+ ' <%= arrayLoop %>\n' +
+ ' }\n' +
+ '}\n' +
+ 'else {' +
+ // object iteration:
// add support for iterating over `arguments` objects if needed
- ' <% } else if (noArgsEnum) { %>\n' +
+ ' <% } else if (nonEnumArgs) { %>\n' +
' var length = iteratee.length; index = -1;\n' +
' if (length && isArguments(iteratee)) {\n' +
' while (++index < length) {\n' +
- ' value = iteratee[index += \'\'];\n' +
- ' <%= objectBranch.inLoop %>\n' +
+ " index += '';\n" +
+ ' <%= objectLoop %>\n' +
' }\n' +
' } else {' +
' <% } %>' +
@@ -360,8 +395,8 @@
// the the `prototype` property of functions regardless of its
// [[Enumerable]] value.
' <% if (!hasDontEnumBug) { %>\n' +
- ' var skipProto = typeof iteratee == \'function\' && \n' +
- ' propertyIsEnumerable.call(iteratee, \'prototype\');\n' +
+ " var skipProto = typeof iteratee == 'function' && \n" +
+ " propertyIsEnumerable.call(iteratee, 'prototype');\n" +
' <% } %>' +
// iterate own properties using `Object.keys` if it's fast
@@ -369,27 +404,23 @@
' var ownIndex = -1,\n' +
' ownProps = objectTypes[typeof iteratee] ? nativeKeys(iteratee) : [],\n' +
' length = ownProps.length;\n\n' +
- ' <%= objectBranch.beforeLoop %>;\n' +
' while (++ownIndex < length) {\n' +
' index = ownProps[ownIndex];\n' +
- ' <% if (!hasDontEnumBug) { %>if (!(skipProto && index == \'prototype\')) {\n <% } %>' +
- ' value = iteratee[index];\n' +
- ' <%= objectBranch.inLoop %>\n' +
+ " <% if (!hasDontEnumBug) { %>if (!(skipProto && index == 'prototype')) {\n <% } %>" +
+ ' <%= objectLoop %>\n' +
' <% if (!hasDontEnumBug) { %>}\n<% } %>' +
' }' +
// else using a for-in loop
' <% } else { %>\n' +
- ' <%= objectBranch.beforeLoop %>;\n' +
' for (index in iteratee) {<%' +
' if (!hasDontEnumBug || useHas) { %>\n if (<%' +
- ' if (!hasDontEnumBug) { %>!(skipProto && index == \'prototype\')<% }' +
+ " if (!hasDontEnumBug) { %>!(skipProto && index == 'prototype')<% }" +
' if (!hasDontEnumBug && useHas) { %> && <% }' +
' if (useHas) { %>hasOwnProperty.call(iteratee, index)<% }' +
' %>) {' +
' <% } %>\n' +
- ' value = iteratee[index];\n' +
- ' <%= objectBranch.inLoop %>;' +
+ ' <%= objectLoop %>;' +
' <% if (!hasDontEnumBug || useHas) { %>\n }<% } %>\n' +
' }' +
' <% } %>' +
@@ -401,18 +432,16 @@
' <% if (hasDontEnumBug) { %>\n\n' +
' var ctor = iteratee.constructor;\n' +
' <% for (var k = 0; k < 7; k++) { %>\n' +
- ' index = \'<%= shadowed[k] %>\';\n' +
+ " index = '<%= shadowed[k] %>';\n" +
' if (<%' +
- ' if (shadowed[k] == \'constructor\') {' +
+ " if (shadowed[k] == 'constructor') {" +
' %>!(ctor && ctor.prototype === iteratee) && <%' +
' } %>hasOwnProperty.call(iteratee, index)) {\n' +
- ' value = iteratee[index];\n' +
- ' <%= objectBranch.inLoop %>\n' +
+ ' <%= objectLoop %>\n' +
' }' +
' <% } %>' +
' <% } %>' +
- ' <% if (arrayBranch || noArgsEnum) { %>\n}<% } %>' +
- '<% } %>\n' +
+ ' <% if (arrayLoop || nonEnumArgs) { %>\n}<% } %>\n' +
// add code to the bottom of the iteration function
'<%= bottom %>;\n' +
@@ -420,103 +449,41 @@
'return result'
);
- /**
- * Reusable iterator options shared by
- * `countBy`, `every`, `filter`, `find`, `forEach`, `forIn`, `forOwn`, `groupBy`,
- * `map`, `reject`, `some`, and `sortBy`.
- */
- var baseIteratorOptions = {
- 'args': 'collection, callback, thisArg',
- 'init': 'collection',
- 'top': 'callback = createCallback(callback, thisArg)',
- 'inLoop': 'if (callback(value, index, collection) === false) return result'
- };
-
- /** Reusable iterator options for `countBy`, `groupBy`, and `sortBy` */
- var countByIteratorOptions = {
- 'init': '{}',
- 'top': 'callback = createCallback(callback, thisArg)',
- 'inLoop':
- 'var prop = callback(value, index, collection);\n' +
- '(hasOwnProperty.call(result, prop) ? result[prop]++ : result[prop] = 1)'
- };
-
- /** Reusable iterator options for `every` and `some` */
- var everyIteratorOptions = {
- 'init': 'true',
- 'inLoop': 'if (!callback(value, index, collection)) return !result'
- };
-
- /** Reusable iterator options for `defaults` and `extend` */
- var extendIteratorOptions = {
- 'useHas': false,
- 'useStrict': false,
- 'args': 'object',
- 'init': 'object',
+ /** Reusable iterator options for `assign` and `defaults` */
+ var assignIteratorOptions = {
+ 'args': 'object, source, guard',
'top':
- 'for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {\n' +
- ' if (iteratee = arguments[argsIndex]) {',
- 'inLoop': 'result[index] = value',
+ "for (var argsIndex = 1, argsLength = typeof guard == 'number' ? 2 : arguments.length; argsIndex < argsLength; argsIndex++) {\n" +
+ ' if ((iteratee = arguments[argsIndex])) {',
+ 'objectLoop': 'result[index] = iteratee[index]',
'bottom': ' }\n}'
};
- /** Reusable iterator options for `filter`, `reject`, and `where` */
- var filterIteratorOptions = {
- 'init': '[]',
- 'inLoop': 'callback(value, index, collection) && result.push(value)'
- };
-
- /** Reusable iterator options for `find`, `forEach`, `forIn`, and `forOwn` */
- var forEachIteratorOptions = {
- 'top': 'callback = createCallback(callback, thisArg)'
+ /**
+ * Reusable iterator options shared by `each`, `forIn`, and `forOwn`.
+ */
+ var eachIteratorOptions = {
+ 'args': 'collection, callback, thisArg',
+ 'top': "callback = callback && typeof thisArg == 'undefined' ? callback : createCallback(callback, thisArg)",
+ 'arrayLoop': 'if (callback(iteratee[index], index, collection) === false) return result',
+ 'objectLoop': 'if (callback(iteratee[index], index, collection) === false) return result'
};
/** Reusable iterator options for `forIn` and `forOwn` */
var forOwnIteratorOptions = {
- 'inLoop': {
- 'object': baseIteratorOptions.inLoop
- }
- };
-
- /** Reusable iterator options for `invoke`, `map`, `pluck`, and `sortBy` */
- var mapIteratorOptions = {
- 'init': '',
- 'beforeLoop': {
- 'array': 'result = Array(length)',
- 'object': 'result = ' + (isKeysFast ? 'Array(length)' : '[]')
- },
- 'inLoop': {
- 'array': 'result[index] = callback(value, index, collection)',
- 'object': 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '(callback(value, index, collection))'
- }
- };
-
- /** Reusable iterator options for `omit` and `pick` */
- var omitIteratorOptions = {
- 'useHas': false,
- 'args': 'object, callback, thisArg',
- 'init': '{}',
- 'top':
- 'var isFunc = typeof callback == \'function\';\n' +
- 'if (isFunc) callback = createCallback(callback, thisArg);\n' +
- 'else var props = concat.apply(ArrayProto, arguments)',
- 'inLoop':
- 'if (isFunc\n' +
- ' ? !callback(value, index, object)\n' +
- ' : indexOf(props, index) < 0\n' +
- ') result[index] = value'
+ 'arrayLoop': null
};
/*--------------------------------------------------------------------------*/
/**
- * Creates a function optimized for searching large arrays for a given `value`,
+ * Creates a function optimized to search large arrays for a given `value`,
* starting at `fromIndex`, using strict equality for comparisons, i.e. `===`.
*
* @private
* @param {Array} array The array to search.
* @param {Mixed} value The value to search for.
- * @param {Number} [fromIndex=0] The index to start searching from.
+ * @param {Number} [fromIndex=0] The index to search from.
* @param {Number} [largeSize=30] The length at which an array is considered large.
* @returns {Boolean} Returns `true` if `value` is found, else `false`.
*/
@@ -524,18 +491,16 @@
fromIndex || (fromIndex = 0);
var length = array.length,
- isLarge = (length - fromIndex) >= (largeSize || largeArraySize),
- cache = isLarge ? {} : array;
+ isLarge = (length - fromIndex) >= (largeSize || largeArraySize);
if (isLarge) {
- // init value cache
- var key,
+ var cache = {},
index = fromIndex - 1;
while (++index < length) {
- // manually coerce `value` to string because `hasOwnProperty`, in some
+ // manually coerce `value` to a string because `hasOwnProperty`, in some
// older versions of Firefox, coerces objects incorrectly
- key = array[index] + '';
+ var key = array[index] + '';
(hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = [])).push(array[index]);
}
}
@@ -544,11 +509,23 @@
var key = value + '';
return hasOwnProperty.call(cache, key) && indexOf(cache[key], value) > -1;
}
- return indexOf(cache, value, fromIndex) > -1;
+ return indexOf(array, value, fromIndex) > -1;
}
}
/**
+ * Used by `_.max` and `_.min` as the default `callback` when a given
+ * `collection` is a string value.
+ *
+ * @private
+ * @param {String} value The character to inspect.
+ * @returns {Number} Returns the code unit of given character.
+ */
+ function charAtCallback(value) {
+ return value.charCodeAt(0);
+ }
+
+ /**
* Used by `sortBy` to compare transformed `collection` values, stable sorting
* them in ascending order.
*
@@ -567,10 +544,10 @@
// ensure a stable sort in V8 and other engines
// http://code.google.com/p/v8/issues/detail?id=90
if (a !== b) {
- if (a > b || a === undefined) {
+ if (a > b || typeof a == 'undefined') {
return 1;
}
- if (a < b || b === undefined) {
+ if (a < b || typeof b == 'undefined') {
return -1;
}
}
@@ -591,12 +568,15 @@
function createBound(func, thisArg, partialArgs) {
var isFunc = isFunction(func),
isPartial = !partialArgs,
- methodName = func;
+ key = thisArg;
// juggle arguments
if (isPartial) {
partialArgs = thisArg;
}
+ if (!isFunc) {
+ thisArg = func;
+ }
function bound() {
// `Function#bind` spec
@@ -605,24 +585,23 @@
thisBinding = isPartial ? this : thisArg;
if (!isFunc) {
- func = thisArg[methodName];
+ func = thisArg[key];
}
if (partialArgs.length) {
args = args.length
- ? partialArgs.concat(slice.call(args))
+ ? partialArgs.concat(slice(args))
: partialArgs;
}
if (this instanceof bound) {
- // get `func` instance if `bound` is invoked in a `new` expression
+ // ensure `new bound` is an instance of `bound` and `func`
noop.prototype = func.prototype;
thisBinding = new noop;
+ noop.prototype = null;
// mimic the constructor's `return` behavior
// http://es5.github.com/#x13.2.2
var result = func.apply(thisBinding, args);
- return result && objectTypes[typeof result]
- ? result
- : thisBinding
+ return isObject(result) ? result : thisBinding;
}
return func.apply(thisBinding, args);
}
@@ -637,9 +616,11 @@
* @param {Function|String} [func=identity|property] The function called per
* iteration or property name to query.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
+ * @param {Object} [accumulating] Used to indicate that the callback should
+ * accept an `accumulator` argument.
* @returns {Function} Returns a callback function.
*/
- function createCallback(func, thisArg) {
+ function createCallback(func, thisArg, accumulating) {
if (!func) {
return identity;
}
@@ -648,7 +629,12 @@
return object[func];
};
}
- if (thisArg !== undefined) {
+ if (typeof thisArg != 'undefined') {
+ if (accumulating) {
+ return function(accumulator, value, index, object) {
+ return func.call(thisArg, accumulator, value, index, object);
+ };
+ }
return function(value, index, object) {
return func.call(thisArg, value, index, object);
};
@@ -657,108 +643,71 @@
}
/**
- * Creates compiled iteration functions. The iteration function will be created
- * to iterate over only objects if the first argument of `options.args` is
- * "object" or `options.inLoop.array` is falsey.
+ * Creates compiled iteration functions.
*
* @private
- * @param {Object} [options1, options2, ...] The compile options objects.
- *
- * useHas - A boolean to specify whether or not to use `hasOwnProperty` checks
- * in the object loop.
- *
- * useStrict - A boolean to specify whether or not to include the ES5
- * "use strict" directive.
- *
- * args - A string of comma separated arguments the iteration function will
- * accept.
- *
- * init - A string to specify the initial value of the `result` variable.
- *
+ * @param {Object} [options1, options2, ...] The compile options object(s).
+ * useHas - A boolean to specify using `hasOwnProperty` checks in the object loop.
+ * args - A string of comma separated arguments the iteration function will accept.
* top - A string of code to execute before the iteration branches.
- *
- * beforeLoop - A string or object containing an "array" or "object" property
- * of code to execute before the array or object loops.
- *
- * inLoop - A string or object containing an "array" or "object" property
- * of code to execute in the array or object loops.
- *
- * bottom - A string of code to execute after the iteration branches but
- * before the `result` is returned.
+ * arrayLoop - A string of code to execute in the array loop.
+ * objectLoop - A string of code to execute in the object loop.
+ * bottom - A string of code to execute after the iteration branches.
*
* @returns {Function} Returns the compiled function.
*/
function createIterator() {
- var object,
- prop,
- value,
- index = -1,
- length = arguments.length;
-
- // merge options into a template data object
var data = {
+ 'arrayLoop': '',
'bottom': '',
+ 'hasDontEnumBug': hasDontEnumBug,
+ 'isKeysFast': isKeysFast,
+ 'objectLoop': '',
+ 'nonEnumArgs': nonEnumArgs,
+ 'noCharByIndex': noCharByIndex,
+ 'shadowed': shadowed,
'top': '',
- 'arrayBranch': { 'beforeLoop': '' },
- 'objectBranch': { 'beforeLoop': '' }
+ 'useHas': true
};
- while (++index < length) {
- object = arguments[index];
- for (prop in object) {
- value = (value = object[prop]) == null ? '' : value;
- // keep this regexp explicit for the build pre-process
- if (/beforeLoop|inLoop/.test(prop)) {
- if (typeof value == 'string') {
- value = { 'array': value, 'object': value };
- }
- data.arrayBranch[prop] = value.array || '';
- data.objectBranch[prop] = value.object || '';
- } else {
- data[prop] = value;
- }
+ // merge options into a template data object
+ for (var object, index = 0; object = arguments[index]; index++) {
+ for (var key in object) {
+ data[key] = object[key];
}
}
- // set additional template `data` values
- var args = data.args,
- firstArg = /^[^,]+/.exec(args)[0],
- init = data.init,
- useStrict = data.useStrict;
-
- data.firstArg = firstArg;
- data.hasDontEnumBug = hasDontEnumBug;
- data.init = init == null ? firstArg : init;
- data.isKeysFast = isKeysFast;
- data.noArgsEnum = noArgsEnum;
- data.shadowed = shadowed;
- data.useHas = data.useHas !== false;
- data.useStrict = useStrict == null ? isStrictFast : useStrict;
-
- if (data.noCharByIndex == null) {
- data.noCharByIndex = noCharByIndex;
- }
- if (firstArg != 'collection' || !data.arrayBranch.inLoop) {
- data.arrayBranch = null;
- }
+ var args = data.args;
+ data.firstArg = /^[^,]+/.exec(args)[0];
+
// create the function factory
var factory = Function(
- 'arrayLikeClasses, ArrayProto, bind, compareAscending, concat, createCallback, ' +
- 'forIn, hasOwnProperty, identity, indexOf, isArguments, isArray, isFunction, ' +
- 'isPlainObject, objectClass, objectTypes, nativeKeys, propertyIsEnumerable, ' +
- 'slice, stringClass, toString, undefined',
- 'var callee = function(' + args + ') {\n' + iteratorTemplate(data) + '\n};\n' +
- 'return callee'
+ 'createCallback, hasOwnProperty, isArguments, isString, objectTypes, ' +
+ 'nativeKeys, propertyIsEnumerable',
+ 'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}'
);
// return the compiled function
return factory(
- arrayLikeClasses, ArrayProto, bind, compareAscending, concat, createCallback,
- forIn, hasOwnProperty, identity, indexOf, isArguments, isArray, isFunction,
- isPlainObject, objectClass, objectTypes, nativeKeys, propertyIsEnumerable,
- slice, stringClass, toString
+ createCallback, hasOwnProperty, isArguments, isString, objectTypes,
+ nativeKeys, propertyIsEnumerable
);
}
/**
+ * A function compiled to iterate `arguments` objects, arrays, objects, and
+ * strings consistenly across environments, executing the `callback` for each
+ * element in the `collection`. The `callback` is bound to `thisArg` and invoked
+ * with three arguments; (value, index|key, collection). Callbacks may exit
+ * iteration early by explicitly returning `false`.
+ *
+ * @private
+ * @param {Array|Object|String} collection The collection to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
+ * @returns {Array|Object|String} Returns `collection`.
+ */
+ var each = createIterator(eachIteratorOptions);
+
+ /**
* Used by `template` to escape characters for inclusion in compiled
* string literals.
*
@@ -782,6 +731,19 @@
}
/**
+ * Checks if `value` is a DOM node in IE < 9.
+ *
+ * @private
+ * @param {Mixed} value The value to check.
+ * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`.
+ */
+ function isNode(value) {
+ // IE < 9 presents DOM nodes as `Object` objects except they have `toString`
+ // methods that are `typeof` "string" and still can coerce nodes to strings
+ return typeof value.toString != 'function' && typeof (value + '') == 'string';
+ }
+
+ /**
* A no-operation function.
*
* @private
@@ -791,6 +753,34 @@
}
/**
+ * Slices the `collection` from the `start` index up to, but not including,
+ * the `end` index.
+ *
+ * Note: This function is used, instead of `Array#slice`, to support node lists
+ * in IE < 9 and to ensure dense arrays are returned.
+ *
+ * @private
+ * @param {Array|Object|String} collection The collection to slice.
+ * @param {Number} start The start index.
+ * @param {Number} end The end index.
+ * @returns {Array} Returns the new array.
+ */
+ function slice(array, start, end) {
+ start || (start = 0);
+ if (typeof end == 'undefined') {
+ end = array ? array.length : 0;
+ }
+ var index = -1,
+ length = end - start || 0,
+ result = Array(length < 0 ? 0 : length);
+
+ while (++index < length) {
+ result[index] = array[start + index];
+ }
+ return result;
+ }
+
+ /**
* Used by `unescape` to convert HTML entities to characters.
*
* @private
@@ -804,23 +794,23 @@
/*--------------------------------------------------------------------------*/
/**
- * Creates an object composed of the inverted keys and values of the given `object`.
+ * Assigns own enumerable properties of source object(s) to the `destination`
+ * object. Subsequent sources will overwrite propery assignments of previous
+ * sources.
*
* @static
* @memberOf _
+ * @alias extend
* @category Objects
- * @param {Object} object The object to invert.
- * @returns {Object} Returns the created inverted object.
+ * @param {Object} object The destination object.
+ * @param {Object} [source1, source2, ...] The source objects.
+ * @returns {Object} Returns the destination object.
* @example
*
- * _.invert({ 'first': 'Moe', 'second': 'Larry', 'third': 'Curly' });
- * // => { 'Moe': 'first', 'Larry': 'second', 'Curly': 'third' } (order is not guaranteed)
+ * _.assign({ 'name': 'moe' }, { 'age': 40 });
+ * // => { 'name': 'moe', 'age': 40 }
*/
- var invert = createIterator({
- 'args': 'object',
- 'init': '{}',
- 'inLoop': 'result[value] = index'
- });
+ var assign = createIterator(assignIteratorOptions);
/**
* Checks if `value` is an `arguments` object.
@@ -844,88 +834,63 @@
// fallback for browsers that can't detect `arguments` objects by [[Class]]
if (noArgsClass) {
isArguments = function(value) {
- return !!(value && hasOwnProperty.call(value, 'callee'));
+ return value ? hasOwnProperty.call(value, 'callee') : false;
};
}
/**
- * Checks if `value` is an array.
+ * Iterates over `object`'s own and inherited enumerable properties, executing
+ * the `callback` for each property. The `callback` is bound to `thisArg` and
+ * invoked with three arguments; (value, key, object). Callbacks may exit iteration
+ * early by explicitly returning `false`.
*
* @static
* @memberOf _
* @category Objects
- * @param {Mixed} value The value to check.
- * @returns {Boolean} Returns `true` if the `value` is an array, else `false`.
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns `object`.
* @example
*
- * (function() { return _.isArray(arguments); })();
- * // => false
- *
- * _.isArray([1, 2, 3]);
- * // => true
- */
- var isArray = nativeIsArray || function(value) {
- return toString.call(value) == arrayClass;
- };
-
- /**
- * Checks if `value` is a function.
+ * function Dog(name) {
+ * this.name = name;
+ * }
*
- * @static
- * @memberOf _
- * @category Objects
- * @param {Mixed} value The value to check.
- * @returns {Boolean} Returns `true` if the `value` is a function, else `false`.
- * @example
+ * Dog.prototype.bark = function() {
+ * alert('Woof, woof!');
+ * };
*
- * _.isFunction(_);
- * // => true
+ * _.forIn(new Dog('Dagny'), function(value, key) {
+ * alert(key);
+ * });
+ * // => alerts 'name' and 'bark' (order is not guaranteed)
*/
- function isFunction(value) {
- return typeof value == 'function';
- }
- // fallback for older versions of Chrome and Safari
- if (isFunction(/x/)) {
- isFunction = function(value) {
- return toString.call(value) == funcClass;
- };
- }
+ var forIn = createIterator(eachIteratorOptions, forOwnIteratorOptions, {
+ 'useHas': false
+ });
/**
- * Checks if a given `value` is an object created by the `Object` constructor.
+ * Iterates over an object's own enumerable properties, executing the `callback`
+ * for each property. The `callback` is bound to `thisArg` and invoked with three
+ * arguments; (value, key, object). Callbacks may exit iteration early by explicitly
+ * returning `false`.
*
* @static
* @memberOf _
* @category Objects
- * @param {Mixed} value The value to check.
- * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @param {Object} object The object to iterate over.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
+ * @returns {Object} Returns `object`.
* @example
*
- * function Stooge(name, age) {
- * this.name = name;
- * this.age = age;
- * }
- *
- * _.isPlainObject(new Stooge('moe', 40));
- * // false
- *
- * _.isPlainObject([1, 2, 3]);
- * // false
- *
- * _.isPlainObject({ 'name': 'moe', 'age': 40 });
- * // => true
+ * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
+ * alert(key);
+ * });
+ * // => alerts '0', '1', and 'length' (order is not guaranteed)
*/
- var isPlainObject = !nativeGetPrototypeOf ? isPlainFallback : function(value) {
- if (!(value && typeof value == 'object')) {
- return false;
- }
- var valueOf = value.valueOf,
- objProto = typeof valueOf == 'function' && (objProto = nativeGetPrototypeOf(valueOf)) && nativeGetPrototypeOf(objProto);
-
- return objProto
- ? value == objProto || (nativeGetPrototypeOf(value) == objProto && !isArguments(value))
- : isPlainFallback(value);
- };
+ var forOwn = createIterator(eachIteratorOptions, forOwnIteratorOptions);
/**
* A fallback implementation of `isPlainObject` that checks if a given `value`
@@ -937,18 +902,15 @@
* @param {Mixed} value The value to check.
* @returns {Boolean} Returns `true` if `value` is a plain object, else `false`.
*/
- function isPlainFallback(value) {
+ function shimIsPlainObject(value) {
// avoid non-objects and false positives for `arguments` objects
var result = false;
if (!(value && typeof value == 'object') || isArguments(value)) {
return result;
}
- // IE < 9 presents DOM nodes as `Object` objects except they have `toString`
- // methods that are `typeof` "string" and still can coerce nodes to strings.
- // Also check that the constructor is `Object` (i.e. `Object instanceof Object`)
+ // check that the constructor is `Object` (i.e. `Object instanceof Object`)
var ctor = value.constructor;
- if ((!noNodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) &&
- (!isFunction(ctor) || ctor instanceof ctor)) {
+ if ((!isFunction(ctor) && (!noNodeClass || !isNode(value))) || ctor instanceof ctor) {
// IE < 9 iterates inherited properties before own properties. If the first
// iterated property is an object's own property then there are no inherited
// enumerable properties.
@@ -971,18 +933,20 @@
}
/**
- * A shim implementation of `Object.keys` that produces an array of the given
- * object's own enumerable property names.
+ * A fallback implementation of `Object.keys` that produces an array of the
+ * given object's own enumerable property names.
*
* @private
* @param {Object} object The object to inspect.
* @returns {Array} Returns a new array of property names.
*/
- var shimKeys = createIterator({
- 'args': 'object',
- 'init': '[]',
- 'inLoop': 'result.push(index)'
- });
+ function shimKeys(object) {
+ var result = [];
+ forOwn(object, function(value, key) {
+ result.push(key);
+ });
+ return result;
+ }
/**
* Used to convert characters to HTML entities:
@@ -1006,10 +970,8 @@
/*--------------------------------------------------------------------------*/
/**
- * Creates a clone of `value`. If `deep` is `true`, all nested objects will
- * also be cloned otherwise they will be assigned by reference. Functions, DOM
- * nodes, `arguments` objects, and objects created by constructors other than
- * `Object` are **not** cloned.
+ * Creates a clone of `value`. If `deep` is `true`, nested objects will also
+ * be cloned, otherwise they will be assigned by reference.
*
* @static
* @memberOf _
@@ -1030,15 +992,12 @@
* { 'name': 'curly', 'age': 60 }
* ];
*
- * _.clone({ 'name': 'moe' });
- * // => { 'name': 'moe' }
- *
* var shallow = _.clone(stooges);
* shallow[0] === stooges[0];
* // => true
*
* var deep = _.clone(stooges, true);
- * shallow[0] === stooges[0];
+ * deep[0] === stooges[0];
* // => false
*/
function clone(value, deep, guard, stackA, stackB) {
@@ -1049,29 +1008,23 @@
deep = false;
}
// inspect [[Class]]
- var isObj = objectTypes[typeof value];
+ var isObj = isObject(value);
if (isObj) {
- // don't clone `arguments` objects, functions, or non-object Objects
var className = toString.call(value);
- if (!cloneableClasses[className] || (noArgsClass && isArguments(value))) {
+ if (!cloneableClasses[className] || (noNodeClass && isNode(value))) {
return value;
}
- var isArr = className == arrayClass;
- isObj = isArr || (className == objectClass ? isPlainObject(value) : isObj);
+ var isArr = isArray(value);
}
// shallow clone
if (!isObj || !deep) {
- // don't clone functions
return isObj
- ? (isArr ? slice.call(value) : extend({}, value))
+ ? (isArr ? slice(value) : assign({}, value))
: value;
}
-
- var ctor = value.constructor;
+ var ctor = ctorByClass[className];
switch (className) {
case boolClass:
- return new ctor(value == true);
-
case dateClass:
return new ctor(+value);
@@ -1082,7 +1035,6 @@
case regexpClass:
return ctor(value.source, reFlags.exec(value));
}
-
// check for circular references and return corresponding clone
stackA || (stackA = []);
stackB || (stackB = []);
@@ -1093,9 +1045,8 @@
return stackB[length];
}
}
-
// init cloned object
- var result = isArr ? ctor(length = value.length) : {};
+ var result = isArr ? ctor(value.length) : {};
// add the source value to the stack of traversed objects
// and associate it with its clone
@@ -1103,154 +1054,159 @@
stackB.push(result);
// recursively populate clone (susceptible to call stack limits)
+ (isArr ? forEach : forOwn)(value, function(objValue, key) {
+ result[key] = clone(objValue, deep, null, stackA, stackB);
+ });
+
+ // add array properties assigned by `RegExp#exec`
if (isArr) {
- var index = -1;
- while (++index < length) {
- result[index] = clone(value[index], deep, null, stackA, stackB);
+ if (hasOwnProperty.call(value, 'index')) {
+ result.index = value.index;
+ }
+ if (hasOwnProperty.call(value, 'input')) {
+ result.input = value.input;
}
- } else {
- forOwn(value, function(objValue, key) {
- result[key] = clone(objValue, deep, null, stackA, stackB);
- });
}
return result;
}
/**
- * Assigns enumerable properties of the default object(s) to the `destination`
- * object for all `destination` properties that resolve to `null`/`undefined`.
- * Once a property is set, additional defaults of the same property will be
- * ignored.
+ * Creates a deep clone of `value`. Functions and DOM nodes are **not** cloned.
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects.
+ *
+ * Note: This function is loosely based on the structured clone algorithm.
+ * See http://www.w3.org/TR/html5/common-dom-interfaces.html#internal-structured-cloning-algorithm.
*
* @static
* @memberOf _
* @category Objects
- * @param {Object} object The destination object.
- * @param {Object} [default1, default2, ...] The default objects.
- * @returns {Object} Returns the destination object.
+ * @param {Mixed} value The value to deep clone.
+ * @returns {Mixed} Returns the deep cloned `value`.
* @example
*
- * var iceCream = { 'flavor': 'chocolate' };
- * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' });
- * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' }
+ * var stooges = [
+ * { 'name': 'moe', 'age': 40 },
+ * { 'name': 'larry', 'age': 50 },
+ * { 'name': 'curly', 'age': 60 }
+ * ];
+ *
+ * var deep = _.cloneDeep(stooges);
+ * deep[0] === stooges[0];
+ * // => false
*/
- var defaults = createIterator(extendIteratorOptions, {
- 'inLoop': 'if (result[index] == null) ' + extendIteratorOptions.inLoop
- });
+ function cloneDeep(value) {
+ return clone(value, true);
+ }
/**
- * Assigns enumerable properties of the source object(s) to the `destination`
- * object. Subsequent sources will overwrite propery assignments of previous
- * sources.
+ * Assigns own enumerable properties of source object(s) to the `destination`
+ * object for all `destination` properties that resolve to `null`/`undefined`.
+ * Once a property is set, additional defaults of the same property will be
+ * ignored.
*
* @static
* @memberOf _
* @category Objects
* @param {Object} object The destination object.
- * @param {Object} [source1, source2, ...] The source objects.
+ * @param {Object} [default1, default2, ...] The default objects.
* @returns {Object} Returns the destination object.
* @example
*
- * _.extend({ 'name': 'moe' }, { 'age': 40 });
- * // => { 'name': 'moe', 'age': 40 }
+ * var iceCream = { 'flavor': 'chocolate' };
+ * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' });
+ * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' }
*/
- var extend = createIterator(extendIteratorOptions);
+ var defaults = createIterator(assignIteratorOptions, {
+ 'objectLoop': 'if (result[index] == null) ' + assignIteratorOptions.objectLoop
+ });
/**
- * Iterates over `object`'s own and inherited enumerable properties, executing
- * the `callback` for each property. The `callback` is bound to `thisArg` and
- * invoked with three arguments; (value, key, object). Callbacks may exit iteration
- * early by explicitly returning `false`.
+ * Creates a sorted array of all enumerable properties, own and inherited,
+ * of `object` that have function values.
*
* @static
* @memberOf _
+ * @alias methods
* @category Objects
- * @param {Object} object The object to iterate over.
- * @param {Function} callback The function called per iteration.
- * @param {Mixed} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns `object`.
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns a new array of property names that have function values.
* @example
*
- * function Dog(name) {
- * this.name = name;
- * }
- *
- * Dog.prototype.bark = function() {
- * alert('Woof, woof!');
- * };
- *
- * _.forIn(new Dog('Dagny'), function(value, key) {
- * alert(key);
- * });
- * // => alerts 'name' and 'bark' (order is not guaranteed)
+ * _.functions(_);
+ * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
*/
- var forIn = createIterator(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions, {
- 'useHas': false
- });
+ function functions(object) {
+ var result = [];
+ forIn(object, function(value, key) {
+ if (isFunction(value)) {
+ result.push(key);
+ }
+ });
+ return result.sort();
+ }
/**
- * Iterates over `object`'s own enumerable properties, executing the `callback`
- * for each property. The `callback` is bound to `thisArg` and invoked with three
- * arguments; (value, key, object). Callbacks may exit iteration early by explicitly
- * returning `false`.
+ * Checks if the specified object `property` exists and is a direct property,
+ * instead of an inherited property.
*
* @static
* @memberOf _
* @category Objects
- * @param {Object} object The object to iterate over.
- * @param {Function} callback The function called per iteration.
- * @param {Mixed} [thisArg] The `this` binding of `callback`.
- * @returns {Object} Returns `object`.
+ * @param {Object} object The object to check.
+ * @param {String} property The property to check for.
+ * @returns {Boolean} Returns `true` if key is a direct property, else `false`.
* @example
*
- * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
- * alert(key);
- * });
- * // => alerts '0', '1', and 'length' (order is not guaranteed)
+ * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
+ * // => true
*/
- var forOwn = createIterator(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions);
+ function has(object, property) {
+ return object ? hasOwnProperty.call(object, property) : false;
+ }
/**
- * Creates a sorted array of all enumerable properties, own and inherited,
- * of `object` that have function values.
+ * Creates an object composed of the inverted keys and values of the given `object`.
*
* @static
* @memberOf _
- * @alias methods
* @category Objects
- * @param {Object} object The object to inspect.
- * @returns {Array} Returns a new array of property names that have function values.
+ * @param {Object} object The object to invert.
+ * @returns {Object} Returns the created inverted object.
* @example
*
- * _.functions(_);
- * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
+ * _.invert({ 'first': 'Moe', 'second': 'Larry', 'third': 'Curly' });
+ * // => { 'Moe': 'first', 'Larry': 'second', 'Curly': 'third' } (order is not guaranteed)
*/
- var functions = createIterator({
- 'useHas': false,
- 'args': 'object',
- 'init': '[]',
- 'inLoop': 'if (isFunction(value)) result.push(index)',
- 'bottom': 'result.sort()'
- });
+ function invert(object) {
+ var result = {};
+ forOwn(object, function(value, key) {
+ result[value] = key;
+ });
+ return result;
+ }
/**
- * Checks if the specified object `property` exists and is a direct property,
- * instead of an inherited property.
+ * Checks if `value` is an array.
*
* @static
* @memberOf _
* @category Objects
- * @param {Object} object The object to check.
- * @param {String} property The property to check for.
- * @returns {Boolean} Returns `true` if key is a direct property, else `false`.
+ * @param {Mixed} value The value to check.
+ * @returns {Boolean} Returns `true` if the `value` is an array, else `false`.
* @example
*
- * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
+ * (function() { return _.isArray(arguments); })();
+ * // => false
+ *
+ * _.isArray([1, 2, 3]);
* // => true
*/
- function has(object, property) {
- return hasOwnProperty.call(object, property);
- }
+ var isArray = nativeIsArray || function(value) {
+ // `instanceof` may cause a memory leak in IE 7 if `value` is a host object
+ // http://ajaxian.com/archives/working-aroung-the-instanceof-memory-leak
+ return (argsAreObjects && value instanceof Array) || toString.call(value) == arrayClass;
+ };
/**
* Checks if `value` is a boolean (`true` or `false`) value.
@@ -1283,7 +1239,7 @@
* // => true
*/
function isDate(value) {
- return toString.call(value) == dateClass;
+ return value instanceof Date || toString.call(value) == dateClass;
}
/**
@@ -1324,22 +1280,24 @@
* _.isEmpty('');
* // => true
*/
- var isEmpty = createIterator({
- 'args': 'value',
- 'init': 'true',
- 'top':
- 'if (!value) return result;\n' +
- 'var className = toString.call(value),\n' +
- ' length = value.length;\n' +
- 'if (arrayLikeClasses[className]' +
- (noArgsClass ? ' || isArguments(value)' : '') + ' ||\n' +
- ' (className == objectClass && length === +length &&\n' +
- ' isFunction(value.splice))' +
- ') return !length',
- 'inLoop': {
- 'object': 'return false'
+ function isEmpty(value) {
+ var result = true;
+ if (!value) {
+ return result;
}
- });
+ var className = toString.call(value),
+ length = value.length;
+
+ if ((className == arrayClass || className == stringClass ||
+ className == argsClass || (noArgsClass && isArguments(value))) ||
+ (className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
+ return !length;
+ }
+ forOwn(value, function() {
+ return (result = false);
+ });
+ return result;
+ }
/**
* Performs a deep comparison between two values to determine if they are
@@ -1365,23 +1323,26 @@
* // => true
*/
function isEqual(a, b, stackA, stackB) {
- // a strict comparison is necessary because `null == undefined`
- if (a == null || b == null) {
- return a === b;
- }
// exit early for identical values
if (a === b) {
// treat `+0` vs. `-0` as not equal
return a !== 0 || (1 / a == 1 / b);
}
- // unwrap any `lodash` wrapped values
- if (objectTypes[typeof a] || objectTypes[typeof b]) {
- a = a.__wrapped__ || a;
- b = b.__wrapped__ || b;
+ // a strict comparison is necessary because `null == undefined`
+ if (a == null || b == null) {
+ return a === b;
}
// compare [[Class]] names
- var className = toString.call(a);
- if (className != toString.call(b)) {
+ var className = toString.call(a),
+ otherName = toString.call(b);
+
+ if (className == argsClass) {
+ className = objectClass;
+ }
+ if (otherName == argsClass) {
+ otherName = objectClass;
+ }
+ if (className != otherName) {
return false;
}
switch (className) {
@@ -1404,18 +1365,28 @@
// treat string primitives and their corresponding object instances as equal
return a == b + '';
}
- // exit early, in older browsers, if `a` is array-like but not `b`
- var isArr = arrayLikeClasses[className];
- if (noArgsClass && !isArr && (isArr = isArguments(a)) && !isArguments(b)) {
- return false;
- }
- // exit for functions and DOM nodes
- if (!isArr && (className != objectClass || (noNodeClass && (
- (typeof a.toString != 'function' && typeof (a + '') == 'string') ||
- (typeof b.toString != 'function' && typeof (b + '') == 'string'))))) {
- return false;
+ var isArr = className == arrayClass;
+ if (!isArr) {
+ // unwrap any `lodash` wrapped values
+ if (a.__wrapped__ || b.__wrapped__) {
+ return isEqual(a.__wrapped__ || a, b.__wrapped__ || b);
+ }
+ // exit for functions and DOM nodes
+ if (className != objectClass || (noNodeClass && (isNode(a) || isNode(b)))) {
+ return false;
+ }
+ // in older versions of Opera, `arguments` objects have `Array` constructors
+ var ctorA = !argsAreObjects && isArguments(a) ? Object : a.constructor,
+ ctorB = !argsAreObjects && isArguments(b) ? Object : b.constructor;
+
+ // non `Object` object instances with different constructors are not equal
+ if (ctorA != ctorB && !(
+ isFunction(ctorA) && ctorA instanceof ctorA &&
+ isFunction(ctorB) && ctorB instanceof ctorB
+ )) {
+ return false;
+ }
}
-
// assume cyclic structures are equal
// the algorithm for detecting cyclic structures is adapted from ES 5.1
// section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3)
@@ -1428,7 +1399,6 @@
return stackB[length] == b;
}
}
-
var index = -1,
result = true,
size = 0;
@@ -1453,58 +1423,35 @@
}
return result;
}
-
- var ctorA = a.constructor,
- ctorB = b.constructor;
-
- // non `Object` object instances with different constructors are not equal
- if (ctorA != ctorB && !(
- isFunction(ctorA) && ctorA instanceof ctorA &&
- isFunction(ctorB) && ctorB instanceof ctorB
- )) {
- return false;
- }
- // deep compare objects
- for (var prop in a) {
- if (hasOwnProperty.call(a, prop)) {
+ // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
+ // which, in this case, is more costly
+ forIn(a, function(value, key, a) {
+ if (hasOwnProperty.call(a, key)) {
// count the number of properties.
size++;
// deep compare each property value.
- if (!(hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stackA, stackB))) {
- return false;
- }
- }
- }
- // ensure both objects have the same number of properties
- for (prop in b) {
- // The JS engine in Adobe products, like InDesign, has a bug that causes
- // `!size--` to throw an error so it must be wrapped in parentheses.
- // https://github.com/documentcloud/underscore/issues/355
- if (hasOwnProperty.call(b, prop) && !(size--)) {
- // `size` will be `-1` if `b` has more properties than `a`
- return false;
+ return (result = hasOwnProperty.call(b, key) && isEqual(value, b[key], stackA, stackB));
}
- }
- // handle JScript [[DontEnum]] bug
- if (hasDontEnumBug) {
- while (++index < 7) {
- prop = shadowed[index];
- if (hasOwnProperty.call(a, prop) &&
- !(hasOwnProperty.call(b, prop) && isEqual(a[prop], b[prop], stackA, stackB))) {
- return false;
+ });
+
+ if (result) {
+ // ensure both objects have the same number of properties
+ forIn(b, function(value, key, b) {
+ if (hasOwnProperty.call(b, key)) {
+ // `size` will be `-1` if `b` has more properties than `a`
+ return (result = --size > -1);
}
- }
+ });
}
- return true;
+ return result;
}
/**
- * Checks if `value` is a finite number.
+ * Checks if `value` is, or can be coerced to, a finite number.
*
* Note: This is not the same as native `isFinite`, which will return true for
- * booleans and other values. See http://es5.github.com/#x15.1.2.5.
+ * booleans and empty strings. See http://es5.github.com/#x15.1.2.5.
*
- * @deprecated
* @static
* @memberOf _
* @category Objects
@@ -1516,13 +1463,42 @@
* // => true
*
* _.isFinite('10');
+ * // => true
+ *
+ * _.isFinite(true);
+ * // => false
+ *
+ * _.isFinite('');
* // => false
*
* _.isFinite(Infinity);
* // => false
*/
function isFinite(value) {
- return nativeIsFinite(value) && toString.call(value) == numberClass;
+ return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
+ }
+
+ /**
+ * Checks if `value` is a function.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Mixed} value The value to check.
+ * @returns {Boolean} Returns `true` if the `value` is a function, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ */
+ function isFunction(value) {
+ return typeof value == 'function';
+ }
+ // fallback for older versions of Chrome and Safari
+ if (isFunction(/x/)) {
+ isFunction = function(value) {
+ return value instanceof Function || toString.call(value) == funcClass;
+ };
}
/**
@@ -1556,10 +1532,9 @@
/**
* Checks if `value` is `NaN`.
*
- * Note: This is not the same as native `isNaN`, which will return true for
+ * Note: This is not the same as native `isNaN`, which will return `true` for
* `undefined` and other values. See http://es5.github.com/#x15.1.2.4.
*
- * @deprecated
* @static
* @memberOf _
* @category Objects
@@ -1582,13 +1557,12 @@
function isNaN(value) {
// `NaN` as a primitive is the only value that is not equal to itself
// (perform the [[Class]] check first to avoid errors with some host objects in IE)
- return toString.call(value) == numberClass && value != +value
+ return isNumber(value) && value != +value
}
/**
* Checks if `value` is `null`.
*
- * @deprecated
* @static
* @memberOf _
* @category Objects
@@ -1620,10 +1594,46 @@
* // => true
*/
function isNumber(value) {
- return toString.call(value) == numberClass;
+ return typeof value == 'number' || toString.call(value) == numberClass;
}
/**
+ * Checks if a given `value` is an object created by the `Object` constructor.
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Mixed} value The value to check.
+ * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @example
+ *
+ * function Stooge(name, age) {
+ * this.name = name;
+ * this.age = age;
+ * }
+ *
+ * _.isPlainObject(new Stooge('moe', 40));
+ * // => false
+ *
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
+ *
+ * _.isPlainObject({ 'name': 'moe', 'age': 40 });
+ * // => true
+ */
+ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
+ if (!(value && typeof value == 'object')) {
+ return false;
+ }
+ var valueOf = value.valueOf,
+ objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
+
+ return objProto
+ ? value == objProto || (getPrototypeOf(value) == objProto && !isArguments(value))
+ : shimIsPlainObject(value);
+ };
+
+ /**
* Checks if `value` is a regular expression.
*
* @static
@@ -1637,7 +1647,7 @@
* // => true
*/
function isRegExp(value) {
- return toString.call(value) == regexpClass;
+ return value instanceof RegExp || toString.call(value) == regexpClass;
}
/**
@@ -1654,13 +1664,12 @@
* // => true
*/
function isString(value) {
- return toString.call(value) == stringClass;
+ return typeof value == 'string' || toString.call(value) == stringClass;
}
/**
* Checks if `value` is `undefined`.
*
- * @deprecated
* @static
* @memberOf _
* @category Objects
@@ -1672,7 +1681,7 @@
* // => true
*/
function isUndefined(value) {
- return value === undefined;
+ return typeof value == 'undefined';
}
/**
@@ -1692,7 +1701,7 @@
// avoid iterating over the `prototype` property
return typeof object == 'function' && propertyIsEnumerable.call(object, 'prototype')
? shimKeys(object)
- : nativeKeys(object);
+ : (isObject(object) ? nativeKeys(object) : []);
};
/**
@@ -1708,7 +1717,7 @@
* @param- {Object} [indicator] Internally used to indicate that the `stack`
* argument is an array of traversed objects instead of another source object.
* @param- {Array} [stackA=[]] Internally used to track traversed source objects.
- * @param- {Array} [stackB=[]] Internally used to associate clones with their
+ * @param- {Array} [stackB=[]] Internally used to associate values with their
* source counterparts.
* @returns {Object} Returns the destination object.
* @example
@@ -1726,37 +1735,54 @@
* _.merge(stooges, ages);
* // => [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }]
*/
- var merge = createIterator(extendIteratorOptions, {
- 'args': 'object, source, indicator',
- 'top':
- 'var isArr, args = arguments, argsIndex = 0;\n' +
- 'if (indicator == compareAscending) {\n' +
- ' var argsLength = 2, stackA = args[3], stackB = args[4]\n' +
- '} else {\n' +
- ' var argsLength = args.length, stackA = [], stackB = []\n' +
- '}\n' +
- 'while (++argsIndex < argsLength) {\n' +
- ' if (iteratee = args[argsIndex]) {',
- 'inLoop':
- 'if ((source = value) && ((isArr = isArray(source)) || isPlainObject(source))) {\n' +
- ' var found = false, stackLength = stackA.length;\n' +
- ' while (stackLength--) {\n' +
- ' if (found = stackA[stackLength] == source) break\n' +
- ' }\n' +
- ' if (found) {\n' +
- ' result[index] = stackB[stackLength]\n' +
- ' } else {\n' +
- ' stackA.push(source);\n' +
- ' stackB.push(value = (value = result[index]) && isArr\n' +
- ' ? (isArray(value) ? value : [])\n' +
- ' : (isPlainObject(value) ? value : {})\n' +
- ' );\n' +
- ' result[index] = callee(value, source, compareAscending, stackA, stackB)\n' +
- ' }\n' +
- '} else if (source != null) {\n' +
- ' result[index] = source\n' +
- '}'
- });
+ function merge(object, source, indicator) {
+ var args = arguments,
+ index = 0,
+ length = 2,
+ stackA = args[3],
+ stackB = args[4];
+
+ if (indicator !== indicatorObject) {
+ stackA = [];
+ stackB = [];
+
+ // work with `_.reduce` by only using its callback `accumulator` and `value` arguments
+ if (typeof indicator != 'number') {
+ length = args.length;
+ }
+ }
+ while (++index < length) {
+ forOwn(args[index], function(source, key) {
+ var found, isArr, value;
+ if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
+ // avoid merging previously merged cyclic sources
+ var stackLength = stackA.length;
+ while (stackLength--) {
+ found = stackA[stackLength] == source;
+ if (found) {
+ break;
+ }
+ }
+ if (found) {
+ object[key] = stackB[stackLength];
+ }
+ else {
+ // add `source` and associated `value` to the stack of traversed objects
+ stackA.push(source);
+ stackB.push(value = (value = object[key], isArr)
+ ? (isArray(value) ? value : [])
+ : (isPlainObject(value) ? value : {})
+ );
+ // recursively merge objects and arrays (susceptible to call stack limits)
+ object[key] = merge(value, source, indicatorObject, stackA, stackB);
+ }
+ } else if (source != null) {
+ object[key] = source;
+ }
+ });
+ }
+ return object;
+ }
/**
* Creates a shallow clone of `object` excluding the specified properties.
@@ -1783,7 +1809,25 @@
* });
* // => { 'name': 'moe' }
*/
- var omit = createIterator(omitIteratorOptions);
+ function omit(object, callback, thisArg) {
+ var isFunc = typeof callback == 'function',
+ result = {};
+
+ if (isFunc) {
+ callback = createCallback(callback, thisArg);
+ } else {
+ var props = concat.apply(arrayRef, arguments);
+ }
+ forIn(object, function(value, key, object) {
+ if (isFunc
+ ? !callback(value, key, object)
+ : indexOf(props, key, 1) < 0
+ ) {
+ result[key] = value;
+ }
+ });
+ return result;
+ }
/**
* Creates a two dimensional array of the given object's key-value pairs,
@@ -1799,11 +1843,13 @@
* _.pairs({ 'moe': 30, 'larry': 40, 'curly': 50 });
* // => [['moe', 30], ['larry', 40], ['curly', 50]] (order is not guaranteed)
*/
- var pairs = createIterator({
- 'args': 'object',
- 'init':'[]',
- 'inLoop': 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '([index, value])'
- });
+ function pairs(object) {
+ var result = [];
+ forOwn(object, function(value, key) {
+ result.push([key, value]);
+ });
+ return result;
+ }
/**
* Creates a shallow clone of `object` composed of the specified properties.
@@ -1830,22 +1876,29 @@
* });
* // => { 'name': 'moe' }
*/
- var pick = createIterator(omitIteratorOptions, {
- 'top':
- 'if (typeof callback != \'function\') {\n' +
- ' var prop,\n' +
- ' props = concat.apply(ArrayProto, arguments),\n' +
- ' length = props.length;\n' +
- ' for (index = 1; index < length; index++) {\n' +
- ' prop = props[index];\n' +
- ' if (prop in object) result[prop] = object[prop]\n' +
- ' }\n' +
- '} else {\n' +
- ' callback = createCallback(callback, thisArg)',
- 'inLoop':
- 'if (callback(value, index, object)) result[index] = value',
- 'bottom': '}'
- });
+ function pick(object, callback, thisArg) {
+ var result = {};
+ if (typeof callback != 'function') {
+ var index = 0,
+ props = concat.apply(arrayRef, arguments),
+ length = props.length;
+
+ while (++index < length) {
+ var key = props[index];
+ if (key in object) {
+ result[key] = object[key];
+ }
+ }
+ } else {
+ callback = createCallback(callback, thisArg);
+ forIn(object, function(value, key, object) {
+ if (callback(value, key, object)) {
+ result[key] = value;
+ }
+ });
+ }
+ return result;
+ }
/**
* Creates an array composed of the own enumerable property values of `object`.
@@ -1860,17 +1913,20 @@
* _.values({ 'one': 1, 'two': 2, 'three': 3 });
* // => [1, 2, 3]
*/
- var values = createIterator({
- 'args': 'object',
- 'init': '[]',
- 'inLoop': 'result.push(value)'
- });
+ function values(object) {
+ var result = [];
+ forOwn(object, function(value) {
+ result.push(value);
+ });
+ return result;
+ }
/*--------------------------------------------------------------------------*/
/**
* Checks if a given `target` element is present in a `collection` using strict
- * equality for comparisons, i.e. `===`.
+ * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
+ * as the offset from the end of the collection.
*
* @static
* @memberOf _
@@ -1878,27 +1934,42 @@
* @category Collections
* @param {Array|Object|String} collection The collection to iterate over.
* @param {Mixed} target The value to check for.
+ * @param {Number} [fromIndex=0] The index to search from.
* @returns {Boolean} Returns `true` if the `target` element is found, else `false`.
* @example
*
- * _.contains([1, 2, 3], 3);
+ * _.contains([1, 2, 3], 1);
* // => true
*
+ * _.contains([1, 2, 3], 1, 2);
+ * // => false
+ *
* _.contains({ 'name': 'moe', 'age': 40 }, 'moe');
* // => true
*
* _.contains('curly', 'ur');
* // => true
*/
- var contains = createIterator({
- 'args': 'collection, target',
- 'init': 'false',
- 'noCharByIndex': false,
- 'beforeLoop': {
- 'array': 'if (toString.call(collection) == stringClass) return collection.indexOf(target) > -1'
- },
- 'inLoop': 'if (value === target) return true'
- });
+ function contains(collection, target, fromIndex) {
+ var index = -1,
+ length = collection ? collection.length : 0,
+ result = false;
+
+ fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
+ if (typeof length == 'number') {
+ result = (isString(collection)
+ ? collection.indexOf(target, fromIndex)
+ : indexOf(collection, target, fromIndex)
+ ) > -1;
+ } else {
+ each(collection, function(value) {
+ if (++index >= fromIndex) {
+ return !(result = value === target);
+ }
+ });
+ }
+ return result;
+ }
/**
* Creates an object composed of keys returned from running each element of
@@ -1926,7 +1997,16 @@
* _.countBy(['one', 'two', 'three'], 'length');
* // => { '3': 2, '5': 1 }
*/
- var countBy = createIterator(baseIteratorOptions, countByIteratorOptions);
+ function countBy(collection, callback, thisArg) {
+ var result = {};
+ callback = createCallback(callback, thisArg);
+
+ forEach(collection, function(value, key, collection) {
+ key = callback(value, key, collection);
+ (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
+ });
+ return result;
+ }
/**
* Checks if the `callback` returns a truthy value for **all** elements of a
@@ -1947,7 +2027,26 @@
* _.every([true, 1, null, 'yes'], Boolean);
* // => false
*/
- var every = createIterator(baseIteratorOptions, everyIteratorOptions);
+ function every(collection, callback, thisArg) {
+ var result = true;
+ callback = createCallback(callback, thisArg);
+
+ if (isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ if (!(result = !!callback(collection[index], index, collection))) {
+ break;
+ }
+ }
+ } else {
+ each(collection, function(value, index, collection) {
+ return (result = !!callback(value, index, collection));
+ });
+ }
+ return result;
+ }
/**
* Examines each element in a `collection`, returning an array of all elements
@@ -1967,7 +2066,29 @@
* var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
* // => [2, 4, 6]
*/
- var filter = createIterator(baseIteratorOptions, filterIteratorOptions);
+ function filter(collection, callback, thisArg) {
+ var result = [];
+ callback = createCallback(callback, thisArg);
+
+ if (isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ var value = collection[index];
+ if (callback(value, index, collection)) {
+ result.push(value);
+ }
+ }
+ } else {
+ each(collection, function(value, index, collection) {
+ if (callback(value, index, collection)) {
+ result.push(value);
+ }
+ });
+ }
+ return result;
+ }
/**
* Examines each element in a `collection`, returning the first one the `callback`
@@ -1980,7 +2101,7 @@
* @alias detect
* @category Collections
* @param {Array|Object|String} collection The collection to iterate over.
- * @param {Function} callback The function called per iteration.
+ * @param {Function} [callback=identity] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Mixed} Returns the element that passed the callback check,
* else `undefined`.
@@ -1989,10 +2110,18 @@
* var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
* // => 2
*/
- var find = createIterator(baseIteratorOptions, forEachIteratorOptions, {
- 'init': '',
- 'inLoop': 'if (callback(value, index, collection)) return value'
- });
+ function find(collection, callback, thisArg) {
+ var result;
+ callback = createCallback(callback, thisArg);
+
+ forEach(collection, function(value, index, collection) {
+ if (callback(value, index, collection)) {
+ result = value;
+ return false;
+ }
+ });
+ return result;
+ }
/**
* Iterates over a `collection`, executing the `callback` for each element in
@@ -2005,7 +2134,7 @@
* @alias each
* @category Collections
* @param {Array|Object|String} collection The collection to iterate over.
- * @param {Function} callback The function called per iteration.
+ * @param {Function} [callback=identity] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Array|Object|String} Returns `collection`.
* @example
@@ -2014,16 +2143,30 @@
* // => alerts each number and returns '1,2,3'
*
* _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert);
- * // => alerts each number (order is not guaranteed)
+ * // => alerts each number value (order is not guaranteed)
*/
- var forEach = createIterator(baseIteratorOptions, forEachIteratorOptions);
+ function forEach(collection, callback, thisArg) {
+ if (callback && typeof thisArg == 'undefined' && isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ if (callback(collection[index], index, collection) === false) {
+ break;
+ }
+ }
+ } else {
+ each(collection, callback, thisArg);
+ }
+ return collection;
+ }
/**
* Creates an object composed of keys returned from running each element of
* `collection` through a `callback`. The corresponding value of each key is an
* array of elements passed to `callback` that returned the key. The `callback`
* is bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
- * The `callback` argument may also be the name of a property to count by (e.g. 'length').
+ * The `callback` argument may also be the name of a property to group by (e.g. 'length').
*
* @static
* @memberOf _
@@ -2044,11 +2187,16 @@
* _.groupBy(['one', 'two', 'three'], 'length');
* // => { '3': ['one', 'two'], '5': ['three'] }
*/
- var groupBy = createIterator(baseIteratorOptions, countByIteratorOptions, {
- 'inLoop':
- 'var prop = callback(value, index, collection);\n' +
- '(hasOwnProperty.call(result, prop) ? result[prop] : result[prop] = []).push(value)'
- });
+ function groupBy(collection, callback, thisArg) {
+ var result = {};
+ callback = createCallback(callback, thisArg);
+
+ forEach(collection, function(value, key, collection) {
+ key = callback(value, key, collection);
+ (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
+ });
+ return result;
+ }
/**
* Invokes the method named by `methodName` on each element in the `collection`,
@@ -2072,19 +2220,16 @@
* _.invoke([123, 456], String.prototype.split, '');
* // => [['1', '2', '3'], ['4', '5', '6']]
*/
- var invoke = createIterator(mapIteratorOptions, {
- 'args': 'collection, methodName',
- 'top':
- 'var args = slice.call(arguments, 2),\n' +
- ' isFunc = typeof methodName == \'function\'',
- 'inLoop': {
- 'array':
- 'result[index] = (isFunc ? methodName : value[methodName]).apply(value, args)',
- 'object':
- 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') +
- '((isFunc ? methodName : value[methodName]).apply(value, args))'
- }
- });
+ function invoke(collection, methodName) {
+ var args = slice(arguments, 2),
+ isFunc = typeof methodName == 'function',
+ result = [];
+
+ forEach(collection, function(value) {
+ result.push((isFunc ? methodName : value[methodName]).apply(value, args));
+ });
+ return result;
+ }
/**
* Creates an array of values by running each element in the `collection`
@@ -2107,7 +2252,121 @@
* _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
* // => [3, 6, 9] (order is not guaranteed)
*/
- var map = createIterator(baseIteratorOptions, mapIteratorOptions);
+ function map(collection, callback, thisArg) {
+ var index = -1,
+ length = collection ? collection.length : 0,
+ result = Array(typeof length == 'number' ? length : 0);
+
+ callback = createCallback(callback, thisArg);
+ if (isArray(collection)) {
+ while (++index < length) {
+ result[index] = callback(collection[index], index, collection);
+ }
+ } else {
+ each(collection, function(value, key, collection) {
+ result[++index] = callback(value, key, collection);
+ });
+ }
+ return result;
+ }
+
+ /**
+ * Retrieves the maximum value of an `array`. If `callback` is passed,
+ * it will be executed for each value in the `array` to generate the
+ * criterion by which the value is ranked. The `callback` is bound to
+ * `thisArg` and invoked with three arguments; (value, index, collection).
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|String} collection The collection to iterate over.
+ * @param {Function} [callback] The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
+ * @returns {Mixed} Returns the maximum value.
+ * @example
+ *
+ * var stooges = [
+ * { 'name': 'moe', 'age': 40 },
+ * { 'name': 'larry', 'age': 50 },
+ * { 'name': 'curly', 'age': 60 }
+ * ];
+ *
+ * _.max(stooges, function(stooge) { return stooge.age; });
+ * // => { 'name': 'curly', 'age': 60 };
+ */
+ function max(collection, callback, thisArg) {
+ var computed = -Infinity,
+ index = -1,
+ length = collection ? collection.length : 0,
+ result = computed;
+
+ if (callback || !isArray(collection)) {
+ callback = !callback && isString(collection)
+ ? charAtCallback
+ : createCallback(callback, thisArg);
+
+ each(collection, function(value, index, collection) {
+ var current = callback(value, index, collection);
+ if (current > computed) {
+ computed = current;
+ result = value;
+ }
+ });
+ } else {
+ while (++index < length) {
+ if (collection[index] > result) {
+ result = collection[index];
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Retrieves the minimum value of an `array`. If `callback` is passed,
+ * it will be executed for each value in the `array` to generate the
+ * criterion by which the value is ranked. The `callback` is bound to `thisArg`
+ * and invoked with three arguments; (value, index, collection).
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|String} collection The collection to iterate over.
+ * @param {Function} [callback] The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
+ * @returns {Mixed} Returns the minimum value.
+ * @example
+ *
+ * _.min([10, 5, 100, 2, 1000]);
+ * // => 2
+ */
+ function min(collection, callback, thisArg) {
+ var computed = Infinity,
+ index = -1,
+ length = collection ? collection.length : 0,
+ result = computed;
+
+ if (callback || !isArray(collection)) {
+ callback = !callback && isString(collection)
+ ? charAtCallback
+ : createCallback(callback, thisArg);
+
+ each(collection, function(value, index, collection) {
+ var current = callback(value, index, collection);
+ if (current < computed) {
+ computed = current;
+ result = value;
+ }
+ });
+ } else {
+ while (++index < length) {
+ if (collection[index] < result) {
+ result = collection[index];
+ }
+ }
+ }
+ return result;
+ }
/**
* Retrieves the value of a specified property from all elements in
@@ -2130,13 +2389,9 @@
* _.pluck(stooges, 'name');
* // => ['moe', 'larry', 'curly']
*/
- var pluck = createIterator(mapIteratorOptions, {
- 'args': 'collection, property',
- 'inLoop': {
- 'array': 'result[index] = value[property]',
- 'object': 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '(value[property])'
- }
- });
+ function pluck(collection, property) {
+ return map(collection, property + '');
+ }
/**
* Boils down a `collection` to a single value. The initial state of the
@@ -2149,7 +2404,7 @@
* @alias foldl, inject
* @category Collections
* @param {Array|Object|String} collection The collection to iterate over.
- * @param {Function} callback The function called per iteration.
+ * @param {Function} [callback=identity] The function called per iteration.
* @param {Mixed} [accumulator] Initial value of the accumulator.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Mixed} Returns the accumulated value.
@@ -2158,24 +2413,29 @@
* var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; });
* // => 6
*/
- var reduce = createIterator({
- 'args': 'collection, callback, accumulator, thisArg',
- 'init': 'accumulator',
- 'top':
- 'var noaccum = arguments.length < 3;\n' +
- 'callback = createCallback(callback, thisArg)',
- 'beforeLoop': {
- 'array': 'if (noaccum) result = iteratee[++index]'
- },
- 'inLoop': {
- 'array':
- 'result = callback(result, value, index, collection)',
- 'object':
- 'result = noaccum\n' +
- ' ? (noaccum = false, value)\n' +
- ' : callback(result, value, index, collection)'
+ function reduce(collection, callback, accumulator, thisArg) {
+ var noaccum = arguments.length < 3;
+ callback = createCallback(callback, thisArg, indicatorObject);
+
+ if (isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ if (noaccum) {
+ accumulator = collection[++index];
+ }
+ while (++index < length) {
+ accumulator = callback(accumulator, collection[index], index, collection);
+ }
+ } else {
+ each(collection, function(value, index, collection) {
+ accumulator = noaccum
+ ? (noaccum = false, value)
+ : callback(accumulator, value, index, collection)
+ });
}
- });
+ return accumulator;
+ }
/**
* The right-associative version of `_.reduce`.
@@ -2185,7 +2445,7 @@
* @alias foldr
* @category Collections
* @param {Array|Object|String} collection The collection to iterate over.
- * @param {Function} callback The function called per iteration.
+ * @param {Function} [callback=identity] The function called per iteration.
* @param {Mixed} [accumulator] Initial value of the accumulator.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Mixed} Returns the accumulated value.
@@ -2197,20 +2457,21 @@
*/
function reduceRight(collection, callback, accumulator, thisArg) {
var iteratee = collection,
- length = collection.length,
+ length = collection ? collection.length : 0,
noaccum = arguments.length < 3;
- if (length !== +length) {
+ if (typeof length != 'number') {
var props = keys(collection);
length = props.length;
- } else if (noCharByIndex && toString.call(collection) == stringClass) {
+ } else if (noCharByIndex && isString(collection)) {
iteratee = collection.split('');
}
- forEach(collection, function(value, index, object) {
+ callback = createCallback(callback, thisArg, indicatorObject);
+ forEach(collection, function(value, index, collection) {
index = props ? props[--length] : --length;
accumulator = noaccum
? (noaccum = false, iteratee[index])
- : callback.call(thisArg, accumulator, iteratee[index], index, object);
+ : callback(accumulator, iteratee[index], index, collection);
});
return accumulator;
}
@@ -2232,9 +2493,38 @@
* var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
* // => [1, 3, 5]
*/
- var reject = createIterator(baseIteratorOptions, filterIteratorOptions, {
- 'inLoop': '!' + filterIteratorOptions.inLoop
- });
+ function reject(collection, callback, thisArg) {
+ callback = createCallback(callback, thisArg);
+ return filter(collection, function(value, index, collection) {
+ return !callback(value, index, collection);
+ });
+ }
+
+ /**
+ * Creates an array of shuffled `array` values, using a version of the
+ * Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
+ *
+ * @static
+ * @memberOf _
+ * @category Collections
+ * @param {Array|Object|String} collection The collection to shuffle.
+ * @returns {Array} Returns a new shuffled collection.
+ * @example
+ *
+ * _.shuffle([1, 2, 3, 4, 5, 6]);
+ * // => [4, 1, 6, 3, 5, 2]
+ */
+ function shuffle(collection) {
+ var index = -1,
+ result = Array(collection ? collection.length : 0);
+
+ forEach(collection, function(value) {
+ var rand = floor(nativeRandom() * (++index + 1));
+ result[index] = result[rand];
+ result[rand] = value;
+ });
+ return result;
+ }
/**
* Gets the size of the `collection` by returning `collection.length` for arrays
@@ -2258,7 +2548,7 @@
*/
function size(collection) {
var length = collection ? collection.length : 0;
- return length === +length ? length : keys(collection).length;
+ return typeof length == 'number' ? length : keys(collection).length;
}
/**
@@ -2278,13 +2568,29 @@
* else `false`.
* @example
*
- * _.some([null, 0, 'yes', false]);
+ * _.some([null, 0, 'yes', false], Boolean);
* // => true
*/
- var some = createIterator(baseIteratorOptions, everyIteratorOptions, {
- 'init': 'false',
- 'inLoop': everyIteratorOptions.inLoop.replace('!', '')
- });
+ function some(collection, callback, thisArg) {
+ var result;
+ callback = createCallback(callback, thisArg);
+
+ if (isArray(collection)) {
+ var index = -1,
+ length = collection.length;
+
+ while (++index < length) {
+ if ((result = callback(collection[index], index, collection))) {
+ break;
+ }
+ }
+ } else {
+ each(collection, function(value, index, collection) {
+ return !(result = callback(value, index, collection));
+ });
+ }
+ return !!result;
+ }
/**
* Creates an array, stable sorted in ascending order by the results of
@@ -2311,31 +2617,28 @@
* _.sortBy(['larry', 'brendan', 'moe'], 'length');
* // => ['moe', 'larry', 'brendan']
*/
- var sortBy = createIterator(baseIteratorOptions, countByIteratorOptions, mapIteratorOptions, {
- 'inLoop': {
- 'array':
- 'result[index] = {\n' +
- ' criteria: callback(value, index, collection),\n' +
- ' index: index,\n' +
- ' value: value\n' +
- '}',
- 'object':
- 'result' + (isKeysFast ? '[ownIndex] = ' : '.push') + '({\n' +
- ' criteria: callback(value, index, collection),\n' +
- ' index: index,\n' +
- ' value: value\n' +
- '})'
- },
- 'bottom':
- 'result.sort(compareAscending);\n' +
- 'length = result.length;\n' +
- 'while (length--) {\n' +
- ' result[length] = result[length].value\n' +
- '}'
- });
+ function sortBy(collection, callback, thisArg) {
+ var result = [];
+ callback = createCallback(callback, thisArg);
+
+ forEach(collection, function(value, index, collection) {
+ result.push({
+ 'criteria': callback(value, index, collection),
+ 'index': index,
+ 'value': value
+ });
+ });
+
+ var length = result.length;
+ result.sort(compareAscending);
+ while (length--) {
+ result[length] = result[length].value;
+ }
+ return result;
+ }
/**
- * Converts the `collection`, to an array.
+ * Converts the `collection` to an array.
*
* @static
* @memberOf _
@@ -2349,10 +2652,10 @@
*/
function toArray(collection) {
var length = collection ? collection.length : 0;
- if (length === +length) {
- return (noArraySliceOnStrings ? toString.call(collection) == stringClass : typeof collection == 'string')
+ if (typeof length == 'number') {
+ return noCharByIndex && isString(collection)
? collection.split('')
- : slice.call(collection);
+ : slice(collection);
}
return values(collection);
}
@@ -2365,7 +2668,7 @@
* @memberOf _
* @category Collections
* @param {Array|Object|String} collection The collection to iterate over.
- * @param {Object} properties The object of properties/values to filter by.
+ * @param {Object} properties The object of property values to filter by.
* @returns {Array} Returns a new array of elements that contain the given `properties`.
* @example
*
@@ -2378,19 +2681,19 @@
* _.where(stooges, { 'age': 40 });
* // => [{ 'name': 'moe', 'age': 40 }]
*/
- var where = createIterator(filterIteratorOptions, {
- 'args': 'collection, properties',
- 'top':
- 'var props = [];\n' +
- 'forIn(properties, function(value, prop) { props.push(prop) });\n' +
- 'var propsLength = props.length',
- 'inLoop':
- 'for (var prop, pass = true, propIndex = 0; propIndex < propsLength; propIndex++) {\n' +
- ' prop = props[propIndex];\n' +
- ' if (!(pass = value[prop] === properties[prop])) break\n' +
- '}\n' +
- 'pass && result.push(value)'
- });
+ function where(collection, properties) {
+ var props = keys(properties);
+ return filter(collection, function(object) {
+ var length = props.length;
+ while (length--) {
+ var result = object[props[length]] === properties[props[length]];
+ if (!result) {
+ break;
+ }
+ }
+ return !!result;
+ });
+ }
/*--------------------------------------------------------------------------*/
@@ -2410,12 +2713,13 @@
*/
function compact(array) {
var index = -1,
- length = array.length,
+ length = array ? array.length : 0,
result = [];
while (++index < length) {
- if (array[index]) {
- result.push(array[index]);
+ var value = array[index];
+ if (value) {
+ result.push(value);
}
}
return result;
@@ -2439,14 +2743,15 @@
*/
function difference(array) {
var index = -1,
- length = array.length,
- flattened = concat.apply(ArrayProto, arguments),
+ length = array ? array.length : 0,
+ flattened = concat.apply(arrayRef, arguments),
contains = cachedContains(flattened, length),
result = [];
while (++index < length) {
- if (!contains(array[index])) {
- result.push(array[index]);
+ var value = array[index];
+ if (!contains(value)) {
+ result.push(value);
}
}
return result;
@@ -2464,15 +2769,20 @@
* @param {Number} [n] The number of elements to return.
* @param- {Object} [guard] Internally used to allow this method to work with
* others like `_.map` without using their callback `index` argument for `n`.
- * @returns {Mixed} Returns the first element or an array of the first `n`
- * elements of `array`.
+ * @returns {Mixed} Returns the first element, or an array of the first `n`
+ * elements, of `array`.
* @example
*
* _.first([5, 4, 3, 2, 1]);
* // => 5
*/
function first(array, n, guard) {
- return (n == null || guard) ? array[0] : slice.call(array, 0, n);
+ if (array) {
+ var length = array.length;
+ return (n == null || guard)
+ ? array[0]
+ : slice(array, 0, nativeMin(nativeMax(0, n), length));
+ }
}
/**
@@ -2494,13 +2804,12 @@
* // => [1, 2, 3, [[4]]];
*/
function flatten(array, shallow) {
- var value,
- index = -1,
- length = array.length,
+ var index = -1,
+ length = array ? array.length : 0,
result = [];
while (++index < length) {
- value = array[index];
+ var value = array[index];
// recursively flatten arrays (susceptible to call stack limits)
if (isArray(value)) {
@@ -2515,15 +2824,15 @@
/**
* Gets the index at which the first occurrence of `value` is found using
* strict equality for comparisons, i.e. `===`. If the `array` is already
- * sorted, passing `true` for `isSorted` will run a faster binary search.
+ * sorted, passing `true` for `fromIndex` will run a faster binary search.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to search.
* @param {Mixed} value The value to search for.
- * @param {Boolean|Number} [fromIndex=0] The index to start searching from or
- * `true` to perform a binary search on a sorted `array`.
+ * @param {Boolean|Number} [fromIndex=0] The index to search from or `true` to
+ * perform a binary search on a sorted `array`.
* @returns {Number} Returns the index of the matched value or `-1`.
* @example
*
@@ -2538,15 +2847,13 @@
*/
function indexOf(array, value, fromIndex) {
var index = -1,
- length = array.length;
+ length = array ? array.length : 0;
- if (fromIndex) {
- if (typeof fromIndex == 'number') {
- index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) - 1;
- } else {
- index = sortedIndex(array, value);
- return array[index] === value ? index : -1;
- }
+ if (typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1;
+ } else if (fromIndex) {
+ index = sortedIndex(array, value);
+ return array[index] === value ? index : -1;
}
while (++index < length) {
if (array[index] === value) {
@@ -2564,17 +2871,22 @@
* @memberOf _
* @category Arrays
* @param {Array} array The array to query.
- * @param {Number} [n] The number of elements to return.
+ * @param {Number} [n=1] The number of elements to exclude.
* @param- {Object} [guard] Internally used to allow this method to work with
* others like `_.map` without using their callback `index` argument for `n`.
- * @returns {Array} Returns all but the last element or `n` elements of `array`.
+ * @returns {Array} Returns all but the last element, or `n` elements, of `array`.
* @example
*
* _.initial([3, 2, 1]);
* // => [3, 2]
*/
function initial(array, n, guard) {
- return slice.call(array, 0, -((n == null || guard) ? 1 : n));
+ if (!array) {
+ return [];
+ }
+ var length = array.length;
+ n = n == null || guard ? 1 : n || 0;
+ return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
}
/**
@@ -2585,27 +2897,40 @@
* @memberOf _
* @category Arrays
* @param {Array} [array1, array2, ...] Arrays to process.
- * @returns {Array} Returns a new array of unique elements, in order, that are
- * present in **all** of the arrays.
+ * @returns {Array} Returns a new array of unique elements that are present
+ * in **all** of the arrays.
* @example
*
* _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
* // => [1, 2]
*/
function intersection(array) {
- var value,
- argsLength = arguments.length,
- cache = [],
+ var args = arguments,
+ argsLength = args.length,
+ cache = { '0': {} },
index = -1,
- length = array.length,
- result = [];
+ length = array ? array.length : 0,
+ isLarge = length >= 100,
+ result = [],
+ seen = result;
- array: while (++index < length) {
- value = array[index];
- if (indexOf(result, value) < 0) {
- for (var argsIndex = 1; argsIndex < argsLength; argsIndex++) {
- if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(arguments[argsIndex])))(value)) {
- continue array;
+ outer:
+ while (++index < length) {
+ var value = array[index];
+ if (isLarge) {
+ var key = value + '';
+ var inited = hasOwnProperty.call(cache[0], key)
+ ? !(seen = cache[0][key])
+ : (seen = cache[0][key] = []);
+ }
+ if (inited || indexOf(seen, value) < 0) {
+ if (isLarge) {
+ seen.push(value);
+ }
+ var argsIndex = argsLength;
+ while (--argsIndex) {
+ if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(args[argsIndex], 0, 100)))(value)) {
+ continue outer;
}
}
result.push(value);
@@ -2625,28 +2950,31 @@
* @param {Number} [n] The number of elements to return.
* @param- {Object} [guard] Internally used to allow this method to work with
* others like `_.map` without using their callback `index` argument for `n`.
- * @returns {Mixed} Returns the last element or an array of the last `n`
- * elements of `array`.
+ * @returns {Mixed} Returns the last element, or an array of the last `n`
+ * elements, of `array`.
* @example
*
* _.last([3, 2, 1]);
* // => 1
*/
function last(array, n, guard) {
- var length = array.length;
- return (n == null || guard) ? array[length - 1] : slice.call(array, -n || length);
+ if (array) {
+ var length = array.length;
+ return (n == null || guard) ? array[length - 1] : slice(array, nativeMax(0, length - n));
+ }
}
/**
- * Gets the index at which the last occurrence of `value` is found using
- * strict equality for comparisons, i.e. `===`.
+ * Gets the index at which the last occurrence of `value` is found using strict
+ * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
+ * as the offset from the end of the collection.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to search.
* @param {Mixed} value The value to search for.
- * @param {Number} [fromIndex=array.length-1] The index to start searching from.
+ * @param {Number} [fromIndex=array.length-1] The index to search from.
* @returns {Number} Returns the index of the matched value or `-1`.
* @example
*
@@ -2657,8 +2985,8 @@
* // => 1
*/
function lastIndexOf(array, value, fromIndex) {
- var index = array.length;
- if (fromIndex && typeof fromIndex == 'number') {
+ var index = array ? array.length : 0;
+ if (typeof fromIndex == 'number') {
index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
}
while (index--) {
@@ -2670,84 +2998,6 @@
}
/**
- * Retrieves the maximum value of an `array`. If `callback` is passed,
- * it will be executed for each value in the `array` to generate the
- * criterion by which the value is ranked. The `callback` is bound to
- * `thisArg` and invoked with three arguments; (value, index, array).
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to iterate over.
- * @param {Function} [callback] The function called per iteration.
- * @param {Mixed} [thisArg] The `this` binding of `callback`.
- * @returns {Mixed} Returns the maximum value.
- * @example
- *
- * var stooges = [
- * { 'name': 'moe', 'age': 40 },
- * { 'name': 'larry', 'age': 50 },
- * { 'name': 'curly', 'age': 60 }
- * ];
- *
- * _.max(stooges, function(stooge) { return stooge.age; });
- * // => { 'name': 'curly', 'age': 60 };
- */
- function max(array, callback, thisArg) {
- var current,
- computed = -Infinity,
- index = -1,
- length = array ? array.length : 0,
- result = computed;
-
- callback = createCallback(callback, thisArg);
- while (++index < length) {
- current = callback(array[index], index, array);
- if (current > computed) {
- computed = current;
- result = array[index];
- }
- }
- return result;
- }
-
- /**
- * Retrieves the minimum value of an `array`. If `callback` is passed,
- * it will be executed for each value in the `array` to generate the
- * criterion by which the value is ranked. The `callback` is bound to `thisArg`
- * and invoked with three arguments; (value, index, array).
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to iterate over.
- * @param {Function} [callback] The function called per iteration.
- * @param {Mixed} [thisArg] The `this` binding of `callback`.
- * @returns {Mixed} Returns the minimum value.
- * @example
- *
- * _.min([10, 5, 100, 2, 1000]);
- * // => 2
- */
- function min(array, callback, thisArg) {
- var current,
- computed = Infinity,
- index = -1,
- length = array ? array.length : 0,
- result = computed;
-
- callback = createCallback(callback, thisArg);
- while (++index < length) {
- current = callback(array[index], index, array);
- if (current < computed) {
- computed = current;
- result = array[index];
- }
- }
- return result;
- }
-
- /**
* Creates an object composed from arrays of `keys` and `values`. Pass either
* a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or
* two arrays, one of `keys` and one of corresponding `values`.
@@ -2766,14 +3016,15 @@
*/
function object(keys, values) {
var index = -1,
- length = keys.length,
+ length = keys ? keys.length : 0,
result = {};
while (++index < length) {
+ var key = keys[index];
if (values) {
- result[keys[index]] = values[index];
+ result[key] = values[index];
} else {
- result[keys[index][0]] = keys[index][1];
+ result[key[0]] = key[1];
}
}
return result;
@@ -2817,9 +3068,9 @@
start = 0;
}
// use `Array(length)` so V8 will avoid the slower "dictionary" mode
- // http://www.youtube.com/watch?v=XAqIpGU8ZZk#t=16m27s
+ // http://youtu.be/XAqIpGU8ZZk#t=17m25s
var index = -1,
- length = nativeMax(0, Math.ceil((end - start) / step)),
+ length = nativeMax(0, ceil((end - start) / step)),
result = Array(length);
while (++index < length) {
@@ -2838,45 +3089,17 @@
* @alias drop, tail
* @category Arrays
* @param {Array} array The array to query.
- * @param {Number} [n] The number of elements to return.
+ * @param {Number} [n=1] The number of elements to exclude.
* @param- {Object} [guard] Internally used to allow this method to work with
* others like `_.map` without using their callback `index` argument for `n`.
- * @returns {Array} Returns all but the first value or `n` values of `array`.
+ * @returns {Array} Returns all but the first element, or `n` elements, of `array`.
* @example
*
* _.rest([3, 2, 1]);
* // => [2, 1]
*/
function rest(array, n, guard) {
- return slice.call(array, (n == null || guard) ? 1 : n);
- }
-
- /**
- * Creates an array of shuffled `array` values, using a version of the
- * Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
- *
- * @static
- * @memberOf _
- * @category Arrays
- * @param {Array} array The array to shuffle.
- * @returns {Array} Returns a new shuffled array.
- * @example
- *
- * _.shuffle([1, 2, 3, 4, 5, 6]);
- * // => [4, 1, 6, 3, 5, 2]
- */
- function shuffle(array) {
- var rand,
- index = -1,
- length = array.length,
- result = Array(length);
-
- while (++index < length) {
- rand = nativeFloor(nativeRandom() * (index + 1));
- result[index] = result[rand];
- result[rand] = array[index];
- }
- return result;
+ return slice(array, (n == null || guard) ? 1 : nativeMax(0, n));
}
/**
@@ -2920,15 +3143,18 @@
* // => 2
*/
function sortedIndex(array, value, callback, thisArg) {
- var mid,
- low = 0,
- high = array.length;
+ var low = 0,
+ high = array ? array.length : low;
- callback = createCallback(callback, thisArg);
+ // explicitly reference `identity` for better inlining in Firefox
+ callback = callback ? createCallback(callback, thisArg) : identity;
value = callback(value);
+
while (low < high) {
- mid = (low + high) >>> 1;
- callback(array[mid]) < value ? low = mid + 1 : high = mid;
+ var mid = (low + high) >>> 1;
+ callback(array[mid]) < value
+ ? low = mid + 1
+ : high = mid;
}
return low;
}
@@ -2949,17 +3175,7 @@
* // => [1, 2, 3, 101, 10]
*/
function union() {
- var index = -1,
- flattened = concat.apply(ArrayProto, arguments),
- length = flattened.length,
- result = [];
-
- while (++index < length) {
- if (indexOf(result, flattened[index]) < 0) {
- result.push(flattened[index]);
- }
- }
- return result;
+ return uniq(concat.apply(arrayRef, arguments));
}
/**
@@ -2993,11 +3209,10 @@
* // => [1, 2, 3]
*/
function uniq(array, isSorted, callback, thisArg) {
- var computed,
- index = -1,
- length = array.length,
+ var index = -1,
+ length = array ? array.length : 0,
result = [],
- seen = [];
+ seen = result;
// juggle arguments
if (typeof isSorted == 'function') {
@@ -3005,15 +3220,33 @@
callback = isSorted;
isSorted = false;
}
- callback = createCallback(callback, thisArg);
+ // init value cache for large arrays
+ var isLarge = !isSorted && length >= 75;
+ if (isLarge) {
+ var cache = {};
+ }
+ if (callback) {
+ seen = [];
+ callback = createCallback(callback, thisArg);
+ }
while (++index < length) {
- computed = callback(array[index], index, array);
+ var value = array[index],
+ computed = callback ? callback(value, index, array) : value;
+
+ if (isLarge) {
+ var key = computed + '';
+ var inited = hasOwnProperty.call(cache, key)
+ ? !(seen = cache[key])
+ : (seen = cache[key] = []);
+ }
if (isSorted
? !index || seen[seen.length - 1] !== computed
- : indexOf(seen, computed) < 0
+ : inited || indexOf(seen, computed) < 0
) {
- seen.push(computed);
- result.push(array[index]);
+ if (callback || isLarge) {
+ seen.push(computed);
+ }
+ result.push(value);
}
}
return result;
@@ -3036,13 +3269,14 @@
*/
function without(array) {
var index = -1,
- length = array.length,
+ length = array ? array.length : 0,
contains = cachedContains(arguments, 1, 20),
result = [];
while (++index < length) {
- if (!contains(array[index])) {
- result.push(array[index]);
+ var value = array[index];
+ if (!contains(value)) {
+ result.push(value);
}
}
return result;
@@ -3066,7 +3300,7 @@
*/
function zip(array) {
var index = -1,
- length = max(pluck(arguments, 'length')),
+ length = array ? max(pluck(arguments, 'length')) : 0,
result = Array(length);
while (++index < length) {
@@ -3078,8 +3312,9 @@
/*--------------------------------------------------------------------------*/
/**
- * Creates a function that is restricted to executing only after it is
- * called `n` times.
+ * Creates a function that is restricted to executing `func` only after it is
+ * called `n` times. The `func` is executed with the `this` binding of the
+ * created function.
*
* @static
* @memberOf _
@@ -3134,7 +3369,7 @@
// (in V8 `Function#bind` is slower except when partially applied)
return isBindFast || (nativeBind && arguments.length > 2)
? nativeBind.call.apply(nativeBind, arguments)
- : createBound(func, thisArg, slice.call(arguments, 2));
+ : createBound(func, thisArg, slice(arguments, 2));
}
/**
@@ -3159,29 +3394,61 @@
* jQuery('#lodash_button').on('click', buttonView.onClick);
* // => When the button is clicked, `this.label` will have the correct value
*/
- var bindAll = createIterator({
- 'useHas': false,
- 'useStrict': false,
- 'args': 'object',
- 'top':
- 'var funcs = arguments,\n' +
- ' length = funcs.length;\n' +
- 'if (length > 1) {\n' +
- ' for (var index = 1; index < length; index++) {\n' +
- ' result[funcs[index]] = bind(result[funcs[index]], result)\n' +
- ' }\n' +
- ' return result\n' +
- '}',
- 'inLoop':
- 'if (isFunction(result[index])) {\n' +
- ' result[index] = bind(result[index], result)\n' +
- '}'
- });
+ function bindAll(object) {
+ var funcs = arguments,
+ index = funcs.length > 1 ? 0 : (funcs = functions(object), -1),
+ length = funcs.length;
+
+ while (++index < length) {
+ var key = funcs[index];
+ object[key] = bind(object[key], object);
+ }
+ return object;
+ }
+
+ /**
+ * Creates a function that, when called, invokes the method at `object[key]`
+ * and prepends any additional `bindKey` arguments to those passed to the bound
+ * function. This method differs from `_.bind` by allowing bound functions to
+ * reference methods that will be redefined or don't yet exist.
+ * See http://michaux.ca/articles/lazy-function-definition-pattern.
+ *
+ * @static
+ * @memberOf _
+ * @category Functions
+ * @param {Object} object The object the method belongs to.
+ * @param {String} key The key of the method.
+ * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
+ * @returns {Function} Returns the new bound function.
+ * @example
+ *
+ * var object = {
+ * 'name': 'moe',
+ * 'greet': function(greeting) {
+ * return greeting + ' ' + this.name;
+ * }
+ * };
+ *
+ * var func = _.bindKey(object, 'greet', 'hi');
+ * func();
+ * // => 'hi moe'
+ *
+ * object.greet = function(greeting) {
+ * return greeting + ', ' + this.name + '!';
+ * };
+ *
+ * func();
+ * // => 'hi, moe!'
+ */
+ function bindKey(object, key) {
+ return createBound(object, key, slice(arguments, 2));
+ }
/**
* Creates a function that is the composition of the passed functions,
* where each function consumes the return value of the function that follows.
* In math terms, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
+ * Each function is executed with the `this` binding of the composed function.
*
* @static
* @memberOf _
@@ -3241,7 +3508,6 @@
result = func.apply(thisArg, args);
}
}
-
return function() {
var isImmediate = immediate && !timeoutId;
args = arguments;
@@ -3275,8 +3541,8 @@
* // => 'logged later' (Appears after one second.)
*/
function delay(func, wait) {
- var args = slice.call(arguments, 2);
- return setTimeout(function() { return func.apply(undefined, args); }, wait);
+ var args = slice(arguments, 2);
+ return setTimeout(function() { func.apply(undefined, args); }, wait);
}
/**
@@ -3295,51 +3561,16 @@
* // returns from the function before `alert` is called
*/
function defer(func) {
- var args = slice.call(arguments, 1);
- return setTimeout(function() { return func.apply(undefined, args); }, 1);
- }
-
- /**
- * Creates a function that, when called, invokes `object[methodName]` and
- * prepends any additional `lateBind` arguments to those passed to the bound
- * function. This method
- *
- * @static
- * @memberOf _
- * @category Functions
- * @param {Object} object The object the method belongs to.
- * @param {String} methodName The method name.
- * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
- * @returns {Function} Returns the new bound function.
- * @example
- *
- * var object = {
- * 'name': 'moe',
- * 'greet': function(greeting) {
- * return greeting + ' ' + this.name;
- * }
- * };
- *
- * var func = _.bind(object, 'greet', 'hi');
- * func();
- * // => 'hi moe'
- *
- * object.greet = function(greeting) {
- * return greeting + ', ' + this.name + '!';
- * };
- *
- * func();
- * // => 'hi, moe!'
- */
- function lateBind(object, methodName) {
- return createBound(methodName, object, slice.call(arguments, 2));
+ var args = slice(arguments, 1);
+ return setTimeout(function() { func.apply(undefined, args); }, 1);
}
/**
* Creates a function that memoizes the result of `func`. If `resolver` is
* passed, it will be used to determine the cache key for storing the result
* based on the arguments passed to the memoized function. By default, the first
- * argument passed to the memoized function is used as the cache key.
+ * argument passed to the memoized function is used as the cache key. The `func`
+ * is executed with the `this` binding of the memoized function.
*
* @static
* @memberOf _
@@ -3356,16 +3587,17 @@
function memoize(func, resolver) {
var cache = {};
return function() {
- var prop = resolver ? resolver.apply(this, arguments) : arguments[0];
- return hasOwnProperty.call(cache, prop)
- ? cache[prop]
- : (cache[prop] = func.apply(this, arguments));
+ var key = resolver ? resolver.apply(this, arguments) : arguments[0];
+ return hasOwnProperty.call(cache, key)
+ ? cache[key]
+ : (cache[key] = func.apply(this, arguments));
};
}
/**
- * Creates a function that is restricted to one execution. Repeat calls to
- * the function will return the value of the first call.
+ * Creates a function that is restricted to execute `func` once. Repeat calls to
+ * the function will return the value of the first call. The `func` is executed
+ * with the `this` binding of the created function.
*
* @static
* @memberOf _
@@ -3398,8 +3630,8 @@
/**
* Creates a function that, when called, invokes `func` with any additional
- * `partial` arguments prepended to those passed to the new function. This method
- * is similar to `bind`, except it does **not** alter the `this` binding.
+ * `partial` arguments prepended to those passed to the new function. This
+ * method is similar to `bind`, except it does **not** alter the `this` binding.
*
* @static
* @memberOf _
@@ -3415,7 +3647,7 @@
* // => 'hi: moe'
*/
function partial(func) {
- return createBound(func, slice.call(arguments, 1));
+ return createBound(func, slice(arguments, 1));
}
/**
@@ -3448,20 +3680,21 @@
timeoutId = null;
result = func.apply(thisArg, args);
}
-
return function() {
var now = new Date,
- remain = wait - (now - lastCalled);
+ remaining = wait - (now - lastCalled);
args = arguments;
thisArg = this;
- if (remain <= 0) {
+ if (remaining <= 0) {
+ clearTimeout(timeoutId);
+ timeoutId = null;
lastCalled = now;
result = func.apply(thisArg, args);
}
else if (!timeoutId) {
- timeoutId = setTimeout(trailingCall, remain);
+ timeoutId = setTimeout(trailingCall, remaining);
}
return result;
};
@@ -3469,8 +3702,9 @@
/**
* Creates a function that passes `value` to the `wrapper` function as its
- * first argument. Additional arguments passed to the new function are appended
- * to those passed to the `wrapper` function.
+ * first argument. Additional arguments passed to the function are appended
+ * to those passed to the `wrapper` function. The `wrapper` is executed with
+ * the `this` binding of the created function.
*
* @static
* @memberOf _
@@ -3480,19 +3714,17 @@
* @returns {Function} Returns the new function.
* @example
*
- * var hello = function(name) { return 'hello: ' + name; };
+ * var hello = function(name) { return 'hello ' + name; };
* hello = _.wrap(hello, function(func) {
* return 'before, ' + func('moe') + ', after';
* });
* hello();
- * // => 'before, hello: moe, after'
+ * // => 'before, hello moe, after'
*/
function wrap(value, wrapper) {
return function() {
var args = [value];
- if (arguments.length) {
- push.apply(args, arguments);
- }
+ push.apply(args, arguments);
return wrapper.apply(this, args);
};
}
@@ -3511,7 +3743,7 @@
* @example
*
* _.escape('Moe, Larry & Curly');
- * // => "Moe, Larry &amp; Curly"
+ * // => 'Moe, Larry &amp; Curly'
*/
function escape(string) {
return string == null ? '' : (string + '').replace(reUnescapedHtml, escapeHtmlChar);
@@ -3520,8 +3752,6 @@
/**
* This function returns the first argument passed to it.
*
- * Note: It is used throughout Lo-Dash as a default callback.
- *
* @static
* @memberOf _
* @category Utilities
@@ -3565,15 +3795,10 @@
lodash.prototype[methodName] = function() {
var args = [this.__wrapped__];
- if (arguments.length) {
- push.apply(args, arguments);
- }
+ push.apply(args, arguments);
+
var result = func.apply(lodash, args);
- if (this.__chain__) {
- result = new lodash(result);
- result.__chain__ = true;
- }
- return result;
+ return new lodash(result);
};
});
}
@@ -3622,7 +3847,7 @@
max = min;
min = 0;
}
- return min + nativeFloor(nativeRandom() * ((+max || 0) - min + 1));
+ return min + floor(nativeRandom() * ((+max || 0) - min + 1));
}
/**
@@ -3630,7 +3855,6 @@
* it will be invoked and its result returned, else the property value is
* returned. If `object` is falsey, then `null` is returned.
*
- * @deprecated
* @static
* @memberOf _
* @category Utilities
@@ -3676,14 +3900,20 @@
* @param {String} text The template text.
* @param {Obect} data The data object used to populate the text.
* @param {Object} options The options object.
+ * escape - The "escape" delimiter regexp.
+ * evaluate - The "evaluate" delimiter regexp.
+ * interpolate - The "interpolate" delimiter regexp.
+ * sourceURL - The sourceURL of the template's compiled source.
+ * variable - The data object variable name.
+ *
* @returns {Function|String} Returns a compiled function when no `data` object
* is given, else it returns the interpolated text.
* @example
*
* // using a compiled template
- * var compiled = _.template('hello: <%= name %>');
+ * var compiled = _.template('hello <%= name %>');
* compiled({ 'name': 'moe' });
- * // => 'hello: moe'
+ * // => 'hello moe'
*
* var list = '<% _.forEach(people, function(name) { %><li><%= name %></li><% }); %>';
* _.template(list, { 'people': ['moe', 'larry', 'curly'] });
@@ -3691,26 +3921,35 @@
*
* // using the "escape" delimiter to escape HTML in data property values
* _.template('<b><%- value %></b>', { 'value': '<script>' });
- * // => '<b>&lt;script></b>'
+ * // => '<b>&lt;script&gt;</b>'
+ *
+ * // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
+ * _.template('hello ${ name }', { 'name': 'curly' });
+ * // => 'hello curly'
*
* // using the internal `print` function in "evaluate" delimiters
- * _.template('<% print("Hello " + epithet); %>.', { 'epithet': 'stooge' });
- * // => 'Hello stooge.'
+ * _.template('<% print("hello " + epithet); %>!', { 'epithet': 'stooge' });
+ * // => 'hello stooge!'
*
- * // using custom template delimiter settings
+ * // using custom template delimiters
* _.templateSettings = {
- * 'interpolate': /\{\{([\s\S]+?)\}\}/g
+ * 'interpolate': /{{([\s\S]+?)}}/g
* };
*
- * _.template('Hello {{ name }}!', { 'name': 'Mustache' });
- * // => 'Hello Mustache!'
+ * _.template('hello {{ name }}!', { 'name': 'mustache' });
+ * // => 'hello mustache!'
+ *
+ * // using the `sourceURL` option to specify a custom sourceURL for the template
+ * var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
+ * compiled(data);
+ * // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
*
* // using the `variable` option to ensure a with-statement isn't used in the compiled template
- * var compiled = _.template('hello: <%= data.name %>', null, { 'variable': 'data' });
+ * var compiled = _.template('hello <%= data.name %>!', null, { 'variable': 'data' });
* compiled.source;
* // => function(data) {
* var __t, __p = '', __e = _.escape;
- * __p += 'hello: ' + ((__t = ( data.name )) == null ? '' : __t);
+ * __p += 'hello ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
* return __p;
* }
*
@@ -3727,12 +3966,14 @@
// http://ejohn.org/blog/javascript-micro-templating/
// and Laura Doktorova's doT.js
// https://github.com/olado/doT
+ text || (text = '');
options || (options = {});
var isEvaluating,
result,
- index = 0,
settings = lodash.templateSettings,
+ index = 0,
+ interpolate = options.interpolate || settings.interpolate || reNoMatch,
source = "__p += '",
variable = options.variable || settings.variable,
hasVariable = variable;
@@ -3740,22 +3981,33 @@
// compile regexp to match each delimiter
var reDelimiters = RegExp(
(options.escape || settings.escape || reNoMatch).source + '|' +
- (options.interpolate || settings.interpolate || reNoMatch).source + '|' +
+ interpolate.source + '|' +
+ (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
(options.evaluate || settings.evaluate || reNoMatch).source + '|$'
, 'g');
- text.replace(reDelimiters, function(match, escapeValue, interpolateValue, evaluateValue, offset) {
+ text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
+ interpolateValue || (interpolateValue = esTemplateValue);
+
// escape characters that cannot be included in string literals
source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
// replace delimiters with snippets
- source +=
- escapeValue ? "' +\n__e(" + escapeValue + ") +\n'" :
- evaluateValue ? "';\n" + evaluateValue + ";\n__p += '" :
- interpolateValue ? "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'" : '';
-
+ if (escapeValue) {
+ source += "' +\n__e(" + escapeValue + ") +\n'";
+ }
+ if (evaluateValue) {
+ source += "';\n" + evaluateValue + ";\n__p += '";
+ }
+ if (interpolateValue) {
+ source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
+ }
isEvaluating || (isEvaluating = evaluateValue || reComplexDelimiter.test(escapeValue || interpolateValue));
index = offset + match.length;
+
+ // the JS engine embedded in Adobe products requires returning the `match`
+ // string in order to produce the correct `offset` value
+ return match;
});
source += "';\n";
@@ -3785,10 +4037,10 @@
// frame code as the function body
source = 'function(' + variable + ') {\n' +
(hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
- 'var __t, __p = \'\', __e = _.escape' +
+ "var __t, __p = '', __e = _.escape" +
(isEvaluating
? ', __j = Array.prototype.join;\n' +
- 'function print() { __p += __j.call(arguments, \'\') }\n'
+ "function print() { __p += __j.call(arguments, '') }\n"
: (hasVariable ? '' : ', __d = ' + variable + '.' + variable + ' || ' + variable) + ';\n'
) +
source +
@@ -3797,7 +4049,7 @@
// use a sourceURL for easier debugging
// http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
var sourceURL = useSourceURL
- ? '\n//@ sourceURL=/lodash/template/source[' + (templateCounter++) + ']'
+ ? '\n//@ sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']')
: '';
try {
@@ -3852,8 +4104,9 @@
}
/**
- * Converts the HTML entities `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#x27;`
- * in `string` to their corresponding characters.
+ * The opposite of `_.escape`, this method converts the HTML entities
+ * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#x27;` in `string` to their
+ * corresponding characters.
*
* @static
* @memberOf _
@@ -3863,63 +4116,35 @@
* @example
*
* _.unescape('Moe, Larry &amp; Curly');
- * // => "Moe, Larry & Curly"
+ * // => 'Moe, Larry & Curly'
*/
function unescape(string) {
return string == null ? '' : (string + '').replace(reEscapedHtml, unescapeHtmlChar);
}
/**
- * Generates a unique id. If `prefix` is passed, the id will be appended to it.
+ * Generates a unique ID. If `prefix` is passed, the ID will be appended to it.
*
* @static
* @memberOf _
* @category Utilities
- * @param {String} [prefix] The value to prefix the id with.
- * @returns {Number|String} Returns a numeric id if no prefix is passed, else
- * a string id may be returned.
+ * @param {String} [prefix] The value to prefix the ID with.
+ * @returns {String} Returns the unique ID.
* @example
*
* _.uniqueId('contact_');
* // => 'contact_104'
+ *
+ * _.uniqueId();
+ * // => '105'
*/
function uniqueId(prefix) {
- var id = idCounter++;
- return prefix ? prefix + id : id;
+ return (prefix == null ? '' : prefix + '') + (++idCounter);
}
/*--------------------------------------------------------------------------*/
/**
- * Wraps the value in a `lodash` wrapper object.
- *
- * @static
- * @memberOf _
- * @category Chaining
- * @param {Mixed} value The value to wrap.
- * @returns {Object} Returns the wrapper object.
- * @example
- *
- * var stooges = [
- * { 'name': 'moe', 'age': 40 },
- * { 'name': 'larry', 'age': 50 },
- * { 'name': 'curly', 'age': 60 }
- * ];
- *
- * var youngest = _.chain(stooges)
- * .sortBy(function(stooge) { return stooge.age; })
- * .map(function(stooge) { return stooge.name + ' is ' + stooge.age; })
- * .first()
- * .value();
- * // => 'moe is 40'
- */
- function chain(value) {
- value = new lodash(value);
- value.__chain__ = true;
- return value;
- }
-
- /**
* Invokes `interceptor` with the `value` as the first argument, and then
* returns `value`. The purpose of this method is to "tap into" a method chain,
* in order to perform operations on intermediate results within the chain.
@@ -3935,7 +4160,7 @@
* _.chain([1, 2, 3, 200])
* .filter(function(num) { return num % 2 == 0; })
* .tap(alert)
- * .map(function(num) { return num * num })
+ * .map(function(num) { return num * num; })
* .value();
* // => // [2, 200] (alerted)
* // => [4, 40000]
@@ -3946,84 +4171,120 @@
}
/**
- * Enables method chaining on the wrapper object.
+ * Produces the `toString` result of the wrapped value.
*
- * @name chain
- * @deprecated
+ * @name toString
* @memberOf _
* @category Chaining
- * @returns {Mixed} Returns the wrapper object.
+ * @returns {String} Returns the string result.
* @example
*
- * _([1, 2, 3]).value();
- * // => [1, 2, 3]
+ * _([1, 2, 3]).toString();
+ * // => '1,2,3'
*/
- function wrapperChain() {
- this.__chain__ = true;
- return this;
+ function wrapperToString() {
+ return this.__wrapped__ + '';
}
/**
* Extracts the wrapped value.
*
- * @name value
+ * @name valueOf
* @memberOf _
+ * @alias value
* @category Chaining
* @returns {Mixed} Returns the wrapped value.
* @example
*
- * _([1, 2, 3]).value();
+ * _([1, 2, 3]).valueOf();
* // => [1, 2, 3]
*/
- function wrapperValue() {
+ function wrapperValueOf() {
return this.__wrapped__;
}
/*--------------------------------------------------------------------------*/
- /**
- * The semantic version number.
- *
- * @static
- * @memberOf _
- * @type String
- */
- lodash.VERSION = '0.7.0';
-
- // assign static methods
+ // add functions that return wrapped values when chaining
lodash.after = after;
+ lodash.assign = assign;
lodash.bind = bind;
lodash.bindAll = bindAll;
- lodash.chain = chain;
- lodash.clone = clone;
+ lodash.bindKey = bindKey;
lodash.compact = compact;
lodash.compose = compose;
- lodash.contains = contains;
lodash.countBy = countBy;
lodash.debounce = debounce;
lodash.defaults = defaults;
lodash.defer = defer;
lodash.delay = delay;
lodash.difference = difference;
- lodash.escape = escape;
- lodash.every = every;
- lodash.extend = extend;
lodash.filter = filter;
- lodash.find = find;
- lodash.first = first;
lodash.flatten = flatten;
lodash.forEach = forEach;
lodash.forIn = forIn;
lodash.forOwn = forOwn;
lodash.functions = functions;
lodash.groupBy = groupBy;
- lodash.has = has;
- lodash.identity = identity;
- lodash.indexOf = indexOf;
lodash.initial = initial;
lodash.intersection = intersection;
lodash.invert = invert;
lodash.invoke = invoke;
+ lodash.keys = keys;
+ lodash.map = map;
+ lodash.max = max;
+ lodash.memoize = memoize;
+ lodash.merge = merge;
+ lodash.min = min;
+ lodash.object = object;
+ lodash.omit = omit;
+ lodash.once = once;
+ lodash.pairs = pairs;
+ lodash.partial = partial;
+ lodash.pick = pick;
+ lodash.pluck = pluck;
+ lodash.range = range;
+ lodash.reject = reject;
+ lodash.rest = rest;
+ lodash.shuffle = shuffle;
+ lodash.sortBy = sortBy;
+ lodash.tap = tap;
+ lodash.throttle = throttle;
+ lodash.times = times;
+ lodash.toArray = toArray;
+ lodash.union = union;
+ lodash.uniq = uniq;
+ lodash.values = values;
+ lodash.where = where;
+ lodash.without = without;
+ lodash.wrap = wrap;
+ lodash.zip = zip;
+
+ // add aliases
+ lodash.collect = map;
+ lodash.drop = rest;
+ lodash.each = forEach;
+ lodash.extend = assign;
+ lodash.methods = functions;
+ lodash.select = filter;
+ lodash.tail = rest;
+ lodash.unique = uniq;
+
+ // add functions to `lodash.prototype`
+ mixin(lodash);
+
+ /*--------------------------------------------------------------------------*/
+
+ // add functions that return unwrapped values when chaining
+ lodash.clone = clone;
+ lodash.cloneDeep = cloneDeep;
+ lodash.contains = contains;
+ lodash.escape = escape;
+ lodash.every = every;
+ lodash.find = find;
+ lodash.has = has;
+ lodash.identity = identity;
+ lodash.indexOf = indexOf;
lodash.isArguments = isArguments;
lodash.isArray = isArray;
lodash.isBoolean = isBoolean;
@@ -4041,120 +4302,123 @@
lodash.isRegExp = isRegExp;
lodash.isString = isString;
lodash.isUndefined = isUndefined;
- lodash.keys = keys;
- lodash.last = last;
lodash.lastIndexOf = lastIndexOf;
- lodash.lateBind = lateBind;
- lodash.map = map;
- lodash.max = max;
- lodash.memoize = memoize;
- lodash.merge = merge;
- lodash.min = min;
lodash.mixin = mixin;
lodash.noConflict = noConflict;
- lodash.object = object;
- lodash.omit = omit;
- lodash.once = once;
- lodash.pairs = pairs;
- lodash.partial = partial;
- lodash.pick = pick;
- lodash.pluck = pluck;
lodash.random = random;
- lodash.range = range;
lodash.reduce = reduce;
lodash.reduceRight = reduceRight;
- lodash.reject = reject;
- lodash.rest = rest;
lodash.result = result;
- lodash.shuffle = shuffle;
lodash.size = size;
lodash.some = some;
- lodash.sortBy = sortBy;
lodash.sortedIndex = sortedIndex;
- lodash.tap = tap;
lodash.template = template;
- lodash.throttle = throttle;
- lodash.times = times;
- lodash.toArray = toArray;
lodash.unescape = unescape;
- lodash.union = union;
- lodash.uniq = uniq;
lodash.uniqueId = uniqueId;
- lodash.values = values;
- lodash.where = where;
- lodash.without = without;
- lodash.wrap = wrap;
- lodash.zip = zip;
- // assign aliases
+ // add aliases
lodash.all = every;
lodash.any = some;
- lodash.collect = map;
lodash.detect = find;
- lodash.drop = rest;
- lodash.each = forEach;
lodash.foldl = reduce;
lodash.foldr = reduceRight;
- lodash.head = first;
lodash.include = contains;
lodash.inject = reduce;
- lodash.methods = functions;
- lodash.select = filter;
- lodash.tail = rest;
- lodash.take = first;
- lodash.unique = uniq;
- // add pseudo private properties used and removed during the build process
- lodash._iteratorTemplate = iteratorTemplate;
- lodash._shimKeys = shimKeys;
+ forOwn(lodash, function(func, methodName) {
+ if (!lodash.prototype[methodName]) {
+ lodash.prototype[methodName] = function() {
+ var args = [this.__wrapped__];
+ push.apply(args, arguments);
+ return func.apply(lodash, args);
+ };
+ }
+ });
/*--------------------------------------------------------------------------*/
- // add all static functions to `lodash.prototype`
- mixin(lodash);
+ // add functions capable of returning wrapped and unwrapped values when chaining
+ lodash.first = first;
+ lodash.last = last;
+
+ // add aliases
+ lodash.take = first;
+ lodash.head = first;
- // add `lodash.prototype.chain` after calling `mixin()` to avoid overwriting
- // it with the wrapped `lodash.chain`
- lodash.prototype.chain = wrapperChain;
- lodash.prototype.value = wrapperValue;
+ forOwn(lodash, function(func, methodName) {
+ if (!lodash.prototype[methodName]) {
+ lodash.prototype[methodName]= function(n, guard) {
+ var result = func(this.__wrapped__, n, guard);
+ return (n == null || guard) ? result : new lodash(result);
+ };
+ }
+ });
- // add all mutator Array functions to the wrapper.
- forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
- var func = ArrayProto[methodName];
+ /*--------------------------------------------------------------------------*/
- lodash.prototype[methodName] = function() {
- var value = this.__wrapped__;
- func.apply(value, arguments);
+ /**
+ * The semantic version number.
+ *
+ * @static
+ * @memberOf _
+ * @type String
+ */
+ lodash.VERSION = '1.0.0-rc.3';
- // avoid array-like object bugs with `Array#shift` and `Array#splice` in
- // Firefox < 10 and IE < 9
- if (hasObjectSpliceBug && value.length === 0) {
- delete value[0];
- }
- if (this.__chain__) {
- value = new lodash(value);
- value.__chain__ = true;
- }
- return value;
+ // add "Chaining" functions to the wrapper
+ lodash.prototype.toString = wrapperToString;
+ lodash.prototype.value = wrapperValueOf;
+ lodash.prototype.valueOf = wrapperValueOf;
+
+ // add `Array` functions that return unwrapped values
+ each(['join', 'pop', 'shift'], function(methodName) {
+ var func = arrayRef[methodName];
+ lodash.prototype[methodName] = function() {
+ return func.apply(this.__wrapped__, arguments);
};
});
- // add all accessor Array functions to the wrapper.
- forEach(['concat', 'join', 'slice'], function(methodName) {
- var func = ArrayProto[methodName];
-
+ // add `Array` functions that return the wrapped value
+ each(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
+ var func = arrayRef[methodName];
lodash.prototype[methodName] = function() {
- var value = this.__wrapped__,
- result = func.apply(value, arguments);
+ func.apply(this.__wrapped__, arguments);
+ return this;
+ };
+ });
- if (this.__chain__) {
- result = new lodash(result);
- result.__chain__ = true;
- }
- return result;
+ // add `Array` functions that return new wrapped values
+ each(['concat', 'slice', 'splice'], function(methodName) {
+ var func = arrayRef[methodName];
+ lodash.prototype[methodName] = function() {
+ var result = func.apply(this.__wrapped__, arguments);
+ return new lodash(result);
};
});
+ // avoid array-like object bugs with `Array#shift` and `Array#splice`
+ // in Firefox < 10 and IE < 9
+ if (hasObjectSpliceBug) {
+ each(['pop', 'shift', 'splice'], function(methodName) {
+ var func = arrayRef[methodName],
+ isSplice = methodName == 'splice';
+
+ lodash.prototype[methodName] = function() {
+ var value = this.__wrapped__,
+ result = func.apply(value, arguments);
+
+ if (value.length === 0) {
+ delete value[0];
+ }
+ return isSplice ? new lodash(result) : result;
+ };
+ });
+ }
+
+ // add pseudo private property to be used and removed during the build process
+ lodash._each = each;
+ lodash._iteratorTemplate = iteratorTemplate;
+
/*--------------------------------------------------------------------------*/
// expose Lo-Dash
diff --git a/module/web/static/js/libs/require-2.0.6.js b/module/web/static/js/libs/require-2.1.2.js
index b592d5f22..0e7b81bc4 100644
--- a/module/web/static/js/libs/require-2.0.6.js
+++ b/module/web/static/js/libs/require-2.1.2.js
@@ -1,5 +1,5 @@
/** vim: et:ts=4:sw=4:sts=4
- * @license RequireJS 2.0.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
+ * @license RequireJS 2.1.2 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details
*/
@@ -12,7 +12,7 @@ var requirejs, require, define;
(function (global) {
var req, s, head, baseElement, dataMain, src,
interactiveScript, currentlyAddingScript, mainScript, subPath,
- version = '2.0.6',
+ version = '2.1.2',
commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
jsSuffixRegExp = /\.js$/,
@@ -81,6 +81,10 @@ var requirejs, require, define;
return hasOwn.call(obj, prop);
}
+ function getOwn(obj, prop) {
+ return hasProp(obj, prop) && obj[prop];
+ }
+
/**
* Cycles over properties in an object and calls a function for each
* property value. If the function returns a truthy value, then the
@@ -89,7 +93,7 @@ var requirejs, require, define;
function eachProp(obj, func) {
var prop;
for (prop in obj) {
- if (obj.hasOwnProperty(prop)) {
+ if (hasProp(obj, prop)) {
if (func(obj[prop], prop)) {
break;
}
@@ -100,9 +104,6 @@ var requirejs, require, define;
/**
* Simple function to mix in properties from source into target,
* but only if target does not already have a property of the same name.
- * This is not robust in IE for transferring methods that match
- * Object.prototype names, but the uses of mixin here seem unlikely to
- * trigger a problem related to that.
*/
function mixin(target, source, force, deepStringMixin) {
if (source) {
@@ -147,41 +148,6 @@ var requirejs, require, define;
return g;
}
- function makeContextModuleFunc(func, relMap, enableBuildCallback) {
- return function () {
- //A version of a require function that passes a moduleName
- //value for items that may need to
- //look up paths relative to the moduleName
- var args = aps.call(arguments, 0), lastArg;
- if (enableBuildCallback &&
- isFunction((lastArg = args[args.length - 1]))) {
- lastArg.__requireJsBuild = true;
- }
- args.push(relMap);
- return func.apply(null, args);
- };
- }
-
- function addRequireMethods(req, context, relMap) {
- each([
- ['toUrl'],
- ['undef'],
- ['defined', 'requireDefined'],
- ['specified', 'requireSpecified']
- ], function (item) {
- var prop = item[1] || item[0];
- req[item[0]] = context ? makeContextModuleFunc(context[prop], relMap) :
- //If no context, then use default context. Reference from
- //contexts instead of early binding to default context, so
- //that during builds, the latest instance of the default
- //context with its config gets used.
- function () {
- var ctx = contexts[defContextName];
- return ctx[prop].apply(ctx, arguments);
- };
- });
- }
-
/**
* Constructs an error with a pointer to an URL with more information.
* @param {String} id the error ID that maps to an ID on a web page.
@@ -230,7 +196,9 @@ var requirejs, require, define;
baseUrl: './',
paths: {},
pkgs: {},
- shim: {}
+ shim: {},
+ map: {},
+ config: {}
},
registry = {},
undefEvents = {},
@@ -238,12 +206,7 @@ var requirejs, require, define;
defined = {},
urlFetched = {},
requireCounter = 1,
- unnormalizedCounter = 1,
- //Used to track the order in which modules
- //should be executed, by the order they
- //load. Important for consistent cycle resolution
- //behavior.
- waitAry = [];
+ unnormalizedCounter = 1;
/**
* Trims the . and .. from an array of path segments.
@@ -302,7 +265,7 @@ var requirejs, require, define;
//otherwise, assume it is a top-level require that will
//be relative to baseUrl in the end.
if (baseName) {
- if (config.pkgs[baseName]) {
+ if (getOwn(config.pkgs, baseName)) {
//If the baseName is a package name, then just treat it as one
//name to concat the name with.
normalizedBaseParts = baseParts = [baseName];
@@ -320,7 +283,7 @@ var requirejs, require, define;
//Some use of packages may use a . path to reference the
//'main' module name, so normalize for that.
- pkgConfig = config.pkgs[(pkgName = name[0])];
+ pkgConfig = getOwn(config.pkgs, (pkgName = name[0]));
name = name.join('/');
if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
name = pkgName;
@@ -343,12 +306,12 @@ var requirejs, require, define;
//Find the longest baseName segment match in the config.
//So, do joins on the biggest to smallest lengths of baseParts.
for (j = baseParts.length; j > 0; j -= 1) {
- mapValue = map[baseParts.slice(0, j).join('/')];
+ mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
//baseName segment has config, find if it has one for
//this name.
if (mapValue) {
- mapValue = mapValue[nameSegment];
+ mapValue = getOwn(mapValue, nameSegment);
if (mapValue) {
//Match, update name to the new value.
foundMap = mapValue;
@@ -366,8 +329,8 @@ var requirejs, require, define;
//Check for a star map match, but just hold on to it,
//if there is a shorter segment match later in a matching
//config, then favor over this star map.
- if (!foundStarMap && starMap && starMap[nameSegment]) {
- foundStarMap = starMap[nameSegment];
+ if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
+ foundStarMap = getOwn(starMap, nameSegment);
starI = i;
}
}
@@ -399,18 +362,31 @@ var requirejs, require, define;
}
function hasPathFallback(id) {
- var pathConfig = config.paths[id];
+ var pathConfig = getOwn(config.paths, id);
if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
removeScript(id);
//Pop off the first array value, since it failed, and
//retry
pathConfig.shift();
- context.undef(id);
+ context.require.undef(id);
context.require([id]);
return true;
}
}
+ //Turns a plugin!resource to [plugin, resource]
+ //with the plugin being undefined if the name
+ //did not have a plugin prefix.
+ function splitPrefix(name) {
+ var prefix,
+ index = name ? name.indexOf('!') : -1;
+ if (index > -1) {
+ prefix = name.substring(0, index);
+ name = name.substring(index + 1, name.length);
+ }
+ return [prefix, name];
+ }
+
/**
* Creates a module mapping that includes plugin prefix, module
* name, and path. If parentModuleMap is provided it will
@@ -427,8 +403,7 @@ var requirejs, require, define;
* @returns {Object}
*/
function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
- var url, pluginModule, suffix,
- index = name ? name.indexOf('!') : -1,
+ var url, pluginModule, suffix, nameParts,
prefix = null,
parentName = parentModuleMap ? parentModuleMap.name : null,
originalName = name,
@@ -442,14 +417,13 @@ var requirejs, require, define;
name = '_@r' + (requireCounter += 1);
}
- if (index !== -1) {
- prefix = name.substring(0, index);
- name = name.substring(index + 1, name.length);
- }
+ nameParts = splitPrefix(name);
+ prefix = nameParts[0];
+ name = nameParts[1];
if (prefix) {
prefix = normalize(prefix, parentName, applyMap);
- pluginModule = defined[prefix];
+ pluginModule = getOwn(defined, prefix);
}
//Account for relative paths if there is a base name.
@@ -466,6 +440,15 @@ var requirejs, require, define;
} else {
//A regular module.
normalizedName = normalize(name, parentName, applyMap);
+
+ //Normalized name may be a plugin ID due to map config
+ //application in normalize. The map config values must
+ //already be normalized, so do not need to redo that part.
+ nameParts = splitPrefix(normalizedName);
+ prefix = nameParts[0];
+ normalizedName = nameParts[1];
+ isNormalized = true;
+
url = context.nameToUrl(normalizedName);
}
}
@@ -493,7 +476,7 @@ var requirejs, require, define;
function getModule(depMap) {
var id = depMap.id,
- mod = registry[id];
+ mod = getOwn(registry, id);
if (!mod) {
mod = registry[id] = new context.Module(depMap);
@@ -504,7 +487,7 @@ var requirejs, require, define;
function on(depMap, name, fn) {
var id = depMap.id,
- mod = registry[id];
+ mod = getOwn(registry, id);
if (hasProp(defined, id) &&
(!mod || mod.defineEmitComplete)) {
@@ -524,7 +507,7 @@ var requirejs, require, define;
errback(err);
} else {
each(ids, function (id) {
- var mod = registry[id];
+ var mod = getOwn(registry, id);
if (mod) {
//Set error on module, so it skips timeout checks.
mod.error = err;
@@ -557,148 +540,71 @@ var requirejs, require, define;
}
}
- /**
- * Helper function that creates a require function object to give to
- * modules that ask for it as a dependency. It needs to be specific
- * per module because of the implication of path mappings that may
- * need to be relative to the module name.
- */
- function makeRequire(mod, enableBuildCallback, altRequire) {
- var relMap = mod && mod.map,
- modRequire = makeContextModuleFunc(altRequire || context.require,
- relMap,
- enableBuildCallback);
-
- addRequireMethods(modRequire, context, relMap);
- modRequire.isBrowser = isBrowser;
-
- return modRequire;
- }
-
handlers = {
'require': function (mod) {
- return makeRequire(mod);
+ if (mod.require) {
+ return mod.require;
+ } else {
+ return (mod.require = context.makeRequire(mod.map));
+ }
},
'exports': function (mod) {
mod.usingExports = true;
if (mod.map.isDefine) {
- return (mod.exports = defined[mod.map.id] = {});
+ if (mod.exports) {
+ return mod.exports;
+ } else {
+ return (mod.exports = defined[mod.map.id] = {});
+ }
}
},
'module': function (mod) {
- return (mod.module = {
- id: mod.map.id,
- uri: mod.map.url,
- config: function () {
- return (config.config && config.config[mod.map.id]) || {};
- },
- exports: defined[mod.map.id]
- });
+ if (mod.module) {
+ return mod.module;
+ } else {
+ return (mod.module = {
+ id: mod.map.id,
+ uri: mod.map.url,
+ config: function () {
+ return (config.config && getOwn(config.config, mod.map.id)) || {};
+ },
+ exports: defined[mod.map.id]
+ });
+ }
}
};
- function removeWaiting(id) {
+ function cleanRegistry(id) {
//Clean up machinery used for waiting modules.
delete registry[id];
-
- each(waitAry, function (mod, i) {
- if (mod.map.id === id) {
- waitAry.splice(i, 1);
- if (!mod.defined) {
- context.waitCount -= 1;
- }
- return true;
- }
- });
}
- function findCycle(mod, traced, processed) {
- var id = mod.map.id,
- depArray = mod.depMaps,
- foundModule;
-
- //Do not bother with unitialized modules or not yet enabled
- //modules.
- if (!mod.inited) {
- return;
- }
-
- //Found the cycle.
- if (traced[id]) {
- return mod;
- }
-
- traced[id] = true;
-
- //Trace through the dependencies.
- each(depArray, function (depMap) {
- var depId = depMap.id,
- depMod = registry[depId];
+ function breakCycle(mod, traced, processed) {
+ var id = mod.map.id;
- if (!depMod || processed[depId] ||
- !depMod.inited || !depMod.enabled) {
- return;
- }
-
- return (foundModule = findCycle(depMod, traced, processed));
- });
-
- processed[id] = true;
-
- return foundModule;
- }
-
- function forceExec(mod, traced, uninited) {
- var id = mod.map.id,
- depArray = mod.depMaps;
-
- if (!mod.inited || !mod.map.isDefine) {
- return;
- }
-
- if (traced[id]) {
- return defined[id];
- }
-
- traced[id] = mod;
-
- each(depArray, function (depMap) {
- var depId = depMap.id,
- depMod = registry[depId],
- value;
-
- if (handlers[depId]) {
- return;
- }
-
- if (depMod) {
- if (!depMod.inited || !depMod.enabled) {
- //Dependency is not inited,
- //so this module cannot be
- //given a forced value yet.
- uninited[id] = true;
- return;
- }
-
- //Get the value for the current dependency
- value = forceExec(depMod, traced, uninited);
-
- //Even with forcing it may not be done,
- //in particular if the module is waiting
- //on a plugin resource.
- if (!uninited[depId]) {
- mod.defineDepById(depId, value);
+ if (mod.error) {
+ mod.emit('error', mod.error);
+ } else {
+ traced[id] = true;
+ each(mod.depMaps, function (depMap, i) {
+ var depId = depMap.id,
+ dep = getOwn(registry, depId);
+
+ //Only force things that have not completed
+ //being defined, so still in the registry,
+ //and only if it has not been matched up
+ //in the module already.
+ if (dep && !mod.depMatched[i] && !processed[depId]) {
+ if (getOwn(traced, depId)) {
+ mod.defineDep(i, defined[depId]);
+ mod.check(); //pass false?
+ } else {
+ breakCycle(dep, traced, processed);
+ }
}
- }
- });
-
- mod.check(true);
-
- return defined[id];
- }
-
- function modCheck(mod) {
- mod.check();
+ });
+ processed[id] = true;
+ }
}
function checkLoaded() {
@@ -707,6 +613,7 @@ var requirejs, require, define;
//It is possible to disable the wait interval by using waitSeconds of 0.
expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
noLoads = [],
+ reqCalls = [],
stillLoading = false,
needCycleCheck = true;
@@ -727,6 +634,10 @@ var requirejs, require, define;
return;
}
+ if (!map.isDefine) {
+ reqCalls.push(mod);
+ }
+
if (!mod.error) {
//If the module should be executed, and it has not
//been inited and time is up, remember it.
@@ -761,31 +672,9 @@ var requirejs, require, define;
//Not expired, check for a cycle.
if (needCycleCheck) {
-
- each(waitAry, function (mod) {
- if (mod.defined) {
- return;
- }
-
- var cycleMod = findCycle(mod, {}, {}),
- traced = {};
-
- if (cycleMod) {
- forceExec(cycleMod, traced, {});
-
- //traced modules may have been
- //removed from the registry, but
- //their listeners still need to
- //be called.
- eachProp(traced, modCheck);
- }
+ each(reqCalls, function (mod) {
+ breakCycle(mod, {}, {});
});
-
- //Now that dependencies have
- //been satisfied, trigger the
- //completion check that then
- //notifies listeners.
- eachProp(registry, modCheck);
}
//If still waiting on loads, and the waiting load is something
@@ -806,9 +695,9 @@ var requirejs, require, define;
}
Module = function (map) {
- this.events = undefEvents[map.id] || {};
+ this.events = getOwn(undefEvents, map.id) || {};
this.map = map;
- this.shim = config.shim[map.id];
+ this.shim = getOwn(config.shim, map.id);
this.depExports = [];
this.depMaps = [];
this.depMatched = [];
@@ -851,7 +740,6 @@ var requirejs, require, define;
//doing a direct modification of the depMaps array
//would affect that config.
this.depMaps = depMaps && depMaps.slice(0);
- this.depMaps.rjsSkipMap = depMaps.rjsSkipMap;
this.errback = errback;
@@ -873,20 +761,6 @@ var requirejs, require, define;
}
},
- defineDepById: function (id, depExports) {
- var i;
-
- //Find the index for this dependency.
- each(this.depMaps, function (map, index) {
- if (map.id === id) {
- i = index;
- return true;
- }
- });
-
- return this.defineDep(i, depExports);
- },
-
defineDep: function (i, depExports) {
//Because of cycles, defined callback for a given
//export can be called more than once.
@@ -910,7 +784,9 @@ var requirejs, require, define;
//If the manager is for a plugin managed resource,
//ask the plugin to load it now.
if (this.shim) {
- makeRequire(this, true)(this.shim.deps || [], bind(this, function () {
+ context.makeRequire(this.map, {
+ enableBuildCallback: true
+ })(this.shim.deps || [], bind(this, function () {
return map.prefix ? this.callPlugin() : this.load();
}));
} else {
@@ -931,11 +807,9 @@ var requirejs, require, define;
/**
* Checks is the module is ready to define itself, and if so,
- * define it. If the silent argument is true, then it will just
- * define, but not notify listeners, and not ask for a context-wide
- * check of all loaded modules. That is useful for cycle breaking.
+ * define it.
*/
- check: function (silent) {
+ check: function () {
if (!this.enabled || this.enabling) {
return;
}
@@ -1013,11 +887,6 @@ var requirejs, require, define;
delete registry[id];
this.defined = true;
- context.waitCount -= 1;
- if (context.waitCount === 0) {
- //Clear the wait array used for cycles.
- waitAry = [];
- }
}
//Finished the define stage. Allow calling check again
@@ -1025,25 +894,33 @@ var requirejs, require, define;
//cycle.
this.defining = false;
- if (!silent) {
- if (this.defined && !this.defineEmitted) {
- this.defineEmitted = true;
- this.emit('defined', this.exports);
- this.defineEmitComplete = true;
- }
+ if (this.defined && !this.defineEmitted) {
+ this.defineEmitted = true;
+ this.emit('defined', this.exports);
+ this.defineEmitComplete = true;
}
+
}
},
callPlugin: function () {
var map = this.map,
id = map.id,
- pluginMap = makeModuleMap(map.prefix, null, false, true);
+ //Map already normalized the prefix.
+ pluginMap = makeModuleMap(map.prefix);
+
+ //Mark this as a dependency for this plugin, so it
+ //can be traced for cycles.
+ this.depMaps.push(pluginMap);
on(pluginMap, 'defined', bind(this, function (plugin) {
var load, normalizedMap, normalizedMod,
name = this.map.name,
- parentName = this.map.parentMap ? this.map.parentMap.name : null;
+ parentName = this.map.parentMap ? this.map.parentMap.name : null,
+ localRequire = context.makeRequire(map.parentMap, {
+ enableBuildCallback: true,
+ skipMap: true
+ });
//If current map is not normalized, wait for that
//normalized name to load instead of continuing.
@@ -1055,10 +932,10 @@ var requirejs, require, define;
}) || '';
}
+ //prefix and name should already be normalized, no need
+ //for applying map config again either.
normalizedMap = makeModuleMap(map.prefix + '!' + name,
- this.map.parentMap,
- false,
- true);
+ this.map.parentMap);
on(normalizedMap,
'defined', bind(this, function (value) {
this.init([], function () { return value; }, null, {
@@ -1066,8 +943,13 @@ var requirejs, require, define;
ignore: true
});
}));
- normalizedMod = registry[normalizedMap.id];
+
+ normalizedMod = getOwn(registry, normalizedMap.id);
if (normalizedMod) {
+ //Mark this as a dependency for this plugin, so it
+ //can be traced for cycles.
+ this.depMaps.push(normalizedMap);
+
if (this.events.error) {
normalizedMod.on('error', bind(this, function (err) {
this.emit('error', err);
@@ -1094,7 +976,7 @@ var requirejs, require, define;
//since they will never be resolved otherwise now.
eachProp(registry, function (mod) {
if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
- removeWaiting(mod.map.id);
+ cleanRegistry(mod.map.id);
}
});
@@ -1103,9 +985,19 @@ var requirejs, require, define;
//Allow plugins to load other code without having to know the
//context or how to 'complete' the load.
- load.fromText = function (moduleName, text) {
+ load.fromText = bind(this, function (text, textAlt) {
/*jslint evil: true */
- var hasInteractive = useInteractive;
+ var moduleName = map.name,
+ moduleMap = makeModuleMap(moduleName),
+ hasInteractive = useInteractive;
+
+ //As of 2.1.0, support just passing the text, to reinforce
+ //fromText only being called once per resource. Still
+ //support old style of passing moduleName but discard
+ //that moduleName in favor of the internal ref.
+ if (textAlt) {
+ text = textAlt;
+ }
//Turn off interactive script matching for IE for any define
//calls in the text, then turn it back on at the end.
@@ -1115,25 +1007,40 @@ var requirejs, require, define;
//Prime the system by creating a module instance for
//it.
- getModule(makeModuleMap(moduleName));
+ getModule(moduleMap);
+
+ //Transfer any config to this other module.
+ if (hasProp(config.config, id)) {
+ config.config[moduleName] = config.config[id];
+ }
- req.exec(text);
+ try {
+ req.exec(text);
+ } catch (e) {
+ throw new Error('fromText eval for ' + moduleName +
+ ' failed: ' + e);
+ }
if (hasInteractive) {
useInteractive = true;
}
+ //Mark this as a dependency for the plugin
+ //resource
+ this.depMaps.push(moduleMap);
+
//Support anonymous modules.
context.completeLoad(moduleName);
- };
+
+ //Bind the value of that module to the value for this
+ //resource ID.
+ localRequire([moduleName], load);
+ });
//Use parentName here since the plugin's name is not reliable,
//could be some weird string with no path that actually wants to
//reference the parentName's path.
- plugin.load(map.name, makeRequire(map.parentMap, true, function (deps, cb, er) {
- deps.rjsSkipMap = true;
- return context.require(deps, cb, er);
- }), load, config);
+ plugin.load(map.name, localRequire, load, config);
}));
context.enable(pluginMap, this);
@@ -1143,12 +1050,6 @@ var requirejs, require, define;
enable: function () {
this.enabled = true;
- if (!this.waitPushed) {
- waitAry.push(this);
- context.waitCount += 1;
- this.waitPushed = true;
- }
-
//Set flag mentioning that the module is enabling,
//so that immediate calls to the defined callbacks
//for dependencies do not trigger inadvertent load
@@ -1165,10 +1066,10 @@ var requirejs, require, define;
depMap = makeModuleMap(depMap,
(this.map.isDefine ? this.map : this.map.parentMap),
false,
- !this.depMaps.rjsSkipMap);
+ !this.skipMap);
this.depMaps[i] = depMap;
- handler = handlers[depMap.id];
+ handler = getOwn(handlers, depMap.id);
if (handler) {
this.depExports[i] = handler(this);
@@ -1193,7 +1094,7 @@ var requirejs, require, define;
//Skip special modules like 'require', 'exports', 'module'
//Also, don't call enable if it is already enabled,
//important in circular dependency cases.
- if (!handlers[id] && mod && !mod.enabled) {
+ if (!hasProp(handlers, id) && mod && !mod.enabled) {
context.enable(depMap, this);
}
}));
@@ -1201,7 +1102,7 @@ var requirejs, require, define;
//Enable each plugin that is used in
//a dependency
eachProp(this.pluginMaps, bind(this, function (pluginMap) {
- var mod = registry[pluginMap.id];
+ var mod = getOwn(registry, pluginMap.id);
if (mod && !mod.enabled) {
context.enable(pluginMap, this);
}
@@ -1227,14 +1128,17 @@ var requirejs, require, define;
if (name === 'error') {
//Now that the error handler was triggered, remove
//the listeners, since this broken Module instance
- //can stay around for a while in the registry/waitAry.
+ //can stay around for a while in the registry.
delete this.events[name];
}
}
};
function callGetModule(args) {
- getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
+ //Skip modules already defined.
+ if (!hasProp(defined, args[0])) {
+ getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
+ }
}
function removeListener(node, func, name, ieName) {
@@ -1274,16 +1178,35 @@ var requirejs, require, define;
};
}
- return (context = {
+ function intakeDefines() {
+ var args;
+
+ //Any defined modules in the global queue, intake them now.
+ takeGlobalQueue();
+
+ //Make sure any remaining defQueue items get properly processed.
+ while (defQueue.length) {
+ args = defQueue.shift();
+ if (args[0] === null) {
+ return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
+ } else {
+ //args are id, deps, factory. Should be normalized by the
+ //define() function.
+ callGetModule(args);
+ }
+ }
+ }
+
+ context = {
config: config,
contextName: contextName,
registry: registry,
defined: defined,
urlFetched: urlFetched,
- waitCount: 0,
defQueue: defQueue,
Module: Module,
makeModuleMap: makeModuleMap,
+ nextTick: req.nextTick,
/**
* Set a configuration for the context.
@@ -1301,20 +1224,23 @@ var requirejs, require, define;
//they are additive.
var pkgs = config.pkgs,
shim = config.shim,
- paths = config.paths,
- map = config.map;
-
- //Mix in the config values, favoring the new values over
- //existing ones in context.config.
- mixin(config, cfg, true);
-
- //Merge paths.
- config.paths = mixin(paths, cfg.paths, true);
+ objs = {
+ paths: true,
+ config: true,
+ map: true
+ };
- //Merge map
- if (cfg.map) {
- config.map = mixin(map || {}, cfg.map, true, true);
- }
+ eachProp(cfg, function (value, prop) {
+ if (objs[prop]) {
+ if (prop === 'map') {
+ mixin(config[prop], value, true, true);
+ } else {
+ mixin(config[prop], value, true);
+ }
+ } else {
+ config[prop] = value;
+ }
+ });
//Merge shim
if (cfg.shim) {
@@ -1325,8 +1251,8 @@ var requirejs, require, define;
deps: value
};
}
- if (value.exports && !value.exports.__buildReady) {
- value.exports = context.makeShimExports(value.exports);
+ if ((value.exports || value.init) && !value.exportsFn) {
+ value.exportsFn = context.makeShimExports(value);
}
shim[id] = value;
});
@@ -1381,125 +1307,144 @@ var requirejs, require, define;
}
},
- makeShimExports: function (exports) {
- var func;
- if (typeof exports === 'string') {
- func = function () {
- return getGlobal(exports);
- };
- //Save the exports for use in nodefine checking.
- func.exports = exports;
- return func;
- } else {
- return function () {
- return exports.apply(global, arguments);
- };
+ makeShimExports: function (value) {
+ function fn() {
+ var ret;
+ if (value.init) {
+ ret = value.init.apply(global, arguments);
+ }
+ return ret || (value.exports && getGlobal(value.exports));
}
+ return fn;
},
- requireDefined: function (id, relMap) {
- return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
- },
+ makeRequire: function (relMap, options) {
+ options = options || {};
- requireSpecified: function (id, relMap) {
- id = makeModuleMap(id, relMap, false, true).id;
- return hasProp(defined, id) || hasProp(registry, id);
- },
+ function localRequire(deps, callback, errback) {
+ var id, map, requireMod;
- require: function (deps, callback, errback, relMap) {
- var moduleName, id, map, requireMod, args;
- if (typeof deps === 'string') {
- if (isFunction(callback)) {
- //Invalid call
- return onError(makeError('requireargs', 'Invalid require call'), errback);
+ if (options.enableBuildCallback && callback && isFunction(callback)) {
+ callback.__requireJsBuild = true;
}
- //Synchronous access to one module. If require.get is
- //available (as in the Node adapter), prefer that.
- //In this case deps is the moduleName and callback is
- //the relMap
- if (req.get) {
- return req.get(context, deps, callback);
- }
+ if (typeof deps === 'string') {
+ if (isFunction(callback)) {
+ //Invalid call
+ return onError(makeError('requireargs', 'Invalid require call'), errback);
+ }
- //Just return the module wanted. In this scenario, the
- //second arg (if passed) is just the relMap.
- moduleName = deps;
- relMap = callback;
+ //If require|exports|module are requested, get the
+ //value for them from the special handlers. Caveat:
+ //this only works while module is being defined.
+ if (relMap && hasProp(handlers, deps)) {
+ return handlers[deps](registry[relMap.id]);
+ }
- //Normalize module name, if it contains . or ..
- map = makeModuleMap(moduleName, relMap, false, true);
- id = map.id;
+ //Synchronous access to one module. If require.get is
+ //available (as in the Node adapter), prefer that.
+ if (req.get) {
+ return req.get(context, deps, relMap);
+ }
+
+ //Normalize module name, if it contains . or ..
+ map = makeModuleMap(deps, relMap, false, true);
+ id = map.id;
- if (!hasProp(defined, id)) {
- return onError(makeError('notloaded', 'Module name "' +
- id +
- '" has not been loaded yet for context: ' +
- contextName));
+ if (!hasProp(defined, id)) {
+ return onError(makeError('notloaded', 'Module name "' +
+ id +
+ '" has not been loaded yet for context: ' +
+ contextName +
+ (relMap ? '' : '. Use require([])')));
+ }
+ return defined[id];
}
- return defined[id];
- }
- //Callback require. Normalize args. if callback or errback is
- //not a function, it means it is a relMap. Test errback first.
- if (errback && !isFunction(errback)) {
- relMap = errback;
- errback = undefined;
- }
- if (callback && !isFunction(callback)) {
- relMap = callback;
- callback = undefined;
- }
+ //Grab defines waiting in the global queue.
+ intakeDefines();
- //Any defined modules in the global queue, intake them now.
- takeGlobalQueue();
+ //Mark all the dependencies as needing to be loaded.
+ context.nextTick(function () {
+ //Some defines could have been added since the
+ //require call, collect them.
+ intakeDefines();
- //Make sure any remaining defQueue items get properly processed.
- while (defQueue.length) {
- args = defQueue.shift();
- if (args[0] === null) {
- return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
- } else {
- //args are id, deps, factory. Should be normalized by the
- //define() function.
- callGetModule(args);
- }
- }
+ requireMod = getModule(makeModuleMap(null, relMap));
- //Mark all the dependencies as needing to be loaded.
- requireMod = getModule(makeModuleMap(null, relMap));
+ //Store if map config should be applied to this require
+ //call for dependencies.
+ requireMod.skipMap = options.skipMap;
- requireMod.init(deps, callback, errback, {
- enabled: true
- });
+ requireMod.init(deps, callback, errback, {
+ enabled: true
+ });
- checkLoaded();
+ checkLoaded();
+ });
- return context.require;
- },
+ return localRequire;
+ }
- undef: function (id) {
- //Bind any waiting define() calls to this context,
- //fix for #408
- takeGlobalQueue();
+ mixin(localRequire, {
+ isBrowser: isBrowser,
+
+ /**
+ * Converts a module name + .extension into an URL path.
+ * *Requires* the use of a module name. It does not support using
+ * plain URLs like nameToUrl.
+ */
+ toUrl: function (moduleNamePlusExt) {
+ var index = moduleNamePlusExt.lastIndexOf('.'),
+ ext = null;
+
+ if (index !== -1) {
+ ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
+ moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
+ }
- var map = makeModuleMap(id, null, true),
- mod = registry[id];
+ return context.nameToUrl(normalize(moduleNamePlusExt,
+ relMap && relMap.id, true), ext);
+ },
- delete defined[id];
- delete urlFetched[map.url];
- delete undefEvents[id];
+ defined: function (id) {
+ return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
+ },
- if (mod) {
- //Hold on to listeners in case the
- //module will be attempted to be reloaded
- //using a different config.
- if (mod.events.defined) {
- undefEvents[id] = mod.events;
+ specified: function (id) {
+ id = makeModuleMap(id, relMap, false, true).id;
+ return hasProp(defined, id) || hasProp(registry, id);
}
+ });
+
+ //Only allow undef on top level require calls
+ if (!relMap) {
+ localRequire.undef = function (id) {
+ //Bind any waiting define() calls to this context,
+ //fix for #408
+ takeGlobalQueue();
+
+ var map = makeModuleMap(id, relMap, true),
+ mod = getOwn(registry, id);
+
+ delete defined[id];
+ delete urlFetched[map.url];
+ delete undefEvents[id];
+
+ if (mod) {
+ //Hold on to listeners in case the
+ //module will be attempted to be reloaded
+ //using a different config.
+ if (mod.events.defined) {
+ undefEvents[id] = mod.events;
+ }
- removeWaiting(id);
+ cleanRegistry(id);
+ }
+ };
}
+
+ return localRequire;
},
/**
@@ -1508,7 +1453,7 @@ var requirejs, require, define;
* used by the optimizer.
*/
enable: function (depMap, parent) {
- var mod = registry[depMap.id];
+ var mod = getOwn(registry, depMap.id);
if (mod) {
getModule(depMap).enable();
}
@@ -1522,8 +1467,8 @@ var requirejs, require, define;
*/
completeLoad: function (moduleName) {
var found, args, mod,
- shim = config.shim[moduleName] || {},
- shExports = shim.exports && shim.exports.exports;
+ shim = getOwn(config.shim, moduleName) || {},
+ shExports = shim.exports;
takeGlobalQueue();
@@ -1548,9 +1493,9 @@ var requirejs, require, define;
//Do this after the cycle of callGetModule in case the result
//of those calls/init calls changes the registry.
- mod = registry[moduleName];
+ mod = getOwn(registry, moduleName);
- if (!found && !defined[moduleName] && mod && !mod.inited) {
+ if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
if (hasPathFallback(moduleName)) {
return;
@@ -1563,7 +1508,7 @@ var requirejs, require, define;
} else {
//A script that does not call define(), so just simulate
//the call for it.
- callGetModule([moduleName, (shim.deps || []), shim.exports]);
+ callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
}
}
@@ -1571,24 +1516,6 @@ var requirejs, require, define;
},
/**
- * Converts a module name + .extension into an URL path.
- * *Requires* the use of a module name. It does not support using
- * plain URLs like nameToUrl.
- */
- toUrl: function (moduleNamePlusExt, relModuleMap) {
- var index = moduleNamePlusExt.lastIndexOf('.'),
- ext = null;
-
- if (index !== -1) {
- ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
- moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
- }
-
- return context.nameToUrl(normalize(moduleNamePlusExt, relModuleMap && relModuleMap.id, true),
- ext);
- },
-
- /**
* Converts a module name to a file path. Supports cases where
* moduleName may actually be just an URL.
* Note that it **does not** call normalize on the moduleName,
@@ -1619,8 +1546,8 @@ var requirejs, require, define;
//and work up from it.
for (i = syms.length; i > 0; i -= 1) {
parentModule = syms.slice(0, i).join('/');
- pkg = pkgs[parentModule];
- parentPath = paths[parentModule];
+ pkg = getOwn(pkgs, parentModule);
+ parentPath = getOwn(paths, parentModule);
if (parentPath) {
//If an array, it means there are a few choices,
//Choose the one that is desired
@@ -1701,7 +1628,10 @@ var requirejs, require, define;
return onError(makeError('scripterror', 'Script error', evt, [data.id]));
}
}
- });
+ };
+
+ context.require = context.makeRequire();
+ return context;
}
/**
@@ -1742,7 +1672,7 @@ var requirejs, require, define;
contextName = config.context;
}
- context = contexts[contextName];
+ context = getOwn(contexts, contextName);
if (!context) {
context = contexts[contextName] = req.s.newContext(contextName);
}
@@ -1763,6 +1693,16 @@ var requirejs, require, define;
};
/**
+ * Execute something after the current tick
+ * of the event loop. Override for other envs
+ * that have a better solution than setTimeout.
+ * @param {Function} fn function to execute later.
+ */
+ req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
+ setTimeout(fn, 4);
+ } : function (fn) { fn(); };
+
+ /**
* Export require as a global, but only if it does not already exist.
*/
if (!require) {
@@ -1782,9 +1722,21 @@ var requirejs, require, define;
//Create default context.
req({});
- //Exports some context-sensitive methods on global require, using
- //default context if no context specified.
- addRequireMethods(req);
+ //Exports some context-sensitive methods on global require.
+ each([
+ 'toUrl',
+ 'undef',
+ 'defined',
+ 'specified'
+ ], function (prop) {
+ //Reference from contexts instead of early binding to default context,
+ //so that during builds, the latest instance of the default context
+ //with its config gets used.
+ req[prop] = function () {
+ var ctx = contexts[defContextName];
+ return ctx.require[prop].apply(ctx, arguments);
+ };
+ });
if (isBrowser) {
head = s.head = document.getElementsByTagName('head')[0];
@@ -1962,7 +1914,7 @@ var requirejs, require, define;
define = function (name, deps, callback) {
var node, context;
- //Allow for anonymous functions
+ //Allow for anonymous modules
if (typeof name !== 'string') {
//Adjust args appropriately
callback = deps;
diff --git a/module/web/static/js/views/packageView.js b/module/web/static/js/views/packageView.js
index a0de18827..5bc23a7b3 100644
--- a/module/web/static/js/views/packageView.js
+++ b/module/web/static/js/views/packageView.js
@@ -38,6 +38,7 @@ define(['jquery', 'views/abstract/itemView', 'underscore', 'views/fileView', 'ut
];
var pie = this.$('.package-graph');
pie.peity('pie');
+ this.$('canvas').addClass('pull-right');
if (this.model.isLoaded()) {
var ul = $('<ul></ul>');