WordPress.org

Make WordPress Core

Ticket #26799: 26799-04.diff

File 26799-04.diff, 142.3 KB (added by georgestephanis, 6 years ago)
  • src/wp-includes/js/backbone.js

     
     1//     Backbone.js 1.1.0
     2
     3//     (c) 2010-2011 Jeremy Ashkenas, DocumentCloud Inc.
     4//     (c) 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
     5//     Backbone may be freely distributed under the MIT license.
     6//     For all details and documentation:
     7//     http://backbonejs.org
     8
     9(function(){
     10
     11  // Initial Setup
     12  // -------------
     13
     14  // Save a reference to the global object (`window` in the browser, `exports`
     15  // on the server).
     16  var root = this;
     17
     18  // Save the previous value of the `Backbone` variable, so that it can be
     19  // restored later on, if `noConflict` is used.
     20  var previousBackbone = root.Backbone;
     21
     22  // Create local references to array methods we'll want to use later.
     23  var array = [];
     24  var push = array.push;
     25  var slice = array.slice;
     26  var splice = array.splice;
     27
     28  // The top-level namespace. All public Backbone classes and modules will
     29  // be attached to this. Exported for both the browser and the server.
     30  var Backbone;
     31  if (typeof exports !== 'undefined') {
     32    Backbone = exports;
     33  } else {
     34    Backbone = root.Backbone = {};
     35  }
     36
     37  // Current version of the library. Keep in sync with `package.json`.
     38  Backbone.VERSION = '1.1.0';
     39
     40  // Require Underscore, if we're on the server, and it's not already present.
     41  var _ = root._;
     42  if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
     43
     44  // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
     45  // the `$` variable.
     46  Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
     47
     48  // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
     49  // to its previous owner. Returns a reference to this Backbone object.
     50  Backbone.noConflict = function() {
     51    root.Backbone = previousBackbone;
     52    return this;
     53  };
     54
     55  // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
     56  // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and
     57  // set a `X-Http-Method-Override` header.
     58  Backbone.emulateHTTP = false;
     59
     60  // Turn on `emulateJSON` to support legacy servers that can't deal with direct
     61  // `application/json` requests ... will encode the body as
     62  // `application/x-www-form-urlencoded` instead and will send the model in a
     63  // form param named `model`.
     64  Backbone.emulateJSON = false;
     65
     66  // Backbone.Events
     67  // ---------------
     68
     69  // A module that can be mixed in to *any object* in order to provide it with
     70  // custom events. You may bind with `on` or remove with `off` callback
     71  // functions to an event; `trigger`-ing an event fires all callbacks in
     72  // succession.
     73  //
     74  //     var object = {};
     75  //     _.extend(object, Backbone.Events);
     76  //     object.on('expand', function(){ alert('expanded'); });
     77  //     object.trigger('expand');
     78  //
     79  var Events = Backbone.Events = {
     80
     81    // Bind an event to a `callback` function. Passing `"all"` will bind
     82    // the callback to all events fired.
     83    on: function(name, callback, context) {
     84      if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
     85      this._events || (this._events = {});
     86      var events = this._events[name] || (this._events[name] = []);
     87      events.push({callback: callback, context: context, ctx: context || this});
     88      return this;
     89    },
     90
     91    // Bind an event to only be triggered a single time. After the first time
     92    // the callback is invoked, it will be removed.
     93    once: function(name, callback, context) {
     94      if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
     95      var self = this;
     96      var once = _.once(function() {
     97        self.off(name, once);
     98        callback.apply(this, arguments);
     99      });
     100      once._callback = callback;
     101      return this.on(name, once, context);
     102    },
     103
     104    // Remove one or many callbacks. If `context` is null, removes all
     105    // callbacks with that function. If `callback` is null, removes all
     106    // callbacks for the event. If `name` is null, removes all bound
     107    // callbacks for all events.
     108    off: function(name, callback, context) {
     109      var retain, ev, events, names, i, l, j, k;
     110      if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
     111      if (!name && !callback && !context) {
     112        this._events = {};
     113        return this;
     114      }
     115      names = name ? [name] : _.keys(this._events);
     116      for (i = 0, l = names.length; i < l; i++) {
     117        name = names[i];
     118        if (events = this._events[name]) {
     119          this._events[name] = retain = [];
     120          if (callback || context) {
     121            for (j = 0, k = events.length; j < k; j++) {
     122              ev = events[j];
     123              if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
     124                  (context && context !== ev.context)) {
     125                retain.push(ev);
     126              }
     127            }
     128          }
     129          if (!retain.length) delete this._events[name];
     130        }
     131      }
     132
     133      return this;
     134    },
     135
     136    // Trigger one or many events, firing all bound callbacks. Callbacks are
     137    // passed the same arguments as `trigger` is, apart from the event name
     138    // (unless you're listening on `"all"`, which will cause your callback to
     139    // receive the true name of the event as the first argument).
     140    trigger: function(name) {
     141      if (!this._events) return this;
     142      var args = slice.call(arguments, 1);
     143      if (!eventsApi(this, 'trigger', name, args)) return this;
     144      var events = this._events[name];
     145      var allEvents = this._events.all;
     146      if (events) triggerEvents(events, args);
     147      if (allEvents) triggerEvents(allEvents, arguments);
     148      return this;
     149    },
     150
     151    // Tell this object to stop listening to either specific events ... or
     152    // to every object it's currently listening to.
     153    stopListening: function(obj, name, callback) {
     154      var listeningTo = this._listeningTo;
     155      if (!listeningTo) return this;
     156      var remove = !name && !callback;
     157      if (!callback && typeof name === 'object') callback = this;
     158      if (obj) (listeningTo = {})[obj._listenId] = obj;
     159      for (var id in listeningTo) {
     160        obj = listeningTo[id];
     161        obj.off(name, callback, this);
     162        if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
     163      }
     164      return this;
     165    }
     166
     167  };
     168
     169  // Regular expression used to split event strings.
     170  var eventSplitter = /\s+/;
     171
     172  // Implement fancy features of the Events API such as multiple event
     173  // names `"change blur"` and jQuery-style event maps `{change: action}`
     174  // in terms of the existing API.
     175  var eventsApi = function(obj, action, name, rest) {
     176    if (!name) return true;
     177
     178    // Handle event maps.
     179    if (typeof name === 'object') {
     180      for (var key in name) {
     181        obj[action].apply(obj, [key, name[key]].concat(rest));
     182      }
     183      return false;
     184    }
     185
     186    // Handle space separated event names.
     187    if (eventSplitter.test(name)) {
     188      var names = name.split(eventSplitter);
     189      for (var i = 0, l = names.length; i < l; i++) {
     190        obj[action].apply(obj, [names[i]].concat(rest));
     191      }
     192      return false;
     193    }
     194
     195    return true;
     196  };
     197
     198  // A difficult-to-believe, but optimized internal dispatch function for
     199  // triggering events. Tries to keep the usual cases speedy (most internal
     200  // Backbone events have 3 arguments).
     201  var triggerEvents = function(events, args) {
     202    var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
     203    switch (args.length) {
     204      case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
     205      case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
     206      case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
     207      case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
     208      default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
     209    }
     210  };
     211
     212  var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
     213
     214  // Inversion-of-control versions of `on` and `once`. Tell *this* object to
     215  // listen to an event in another object ... keeping track of what it's
     216  // listening to.
     217  _.each(listenMethods, function(implementation, method) {
     218    Events[method] = function(obj, name, callback) {
     219      var listeningTo = this._listeningTo || (this._listeningTo = {});
     220      var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
     221      listeningTo[id] = obj;
     222      if (!callback && typeof name === 'object') callback = this;
     223      obj[implementation](name, callback, this);
     224      return this;
     225    };
     226  });
     227
     228  // Aliases for backwards compatibility.
     229  Events.bind   = Events.on;
     230  Events.unbind = Events.off;
     231
     232  // Allow the `Backbone` object to serve as a global event bus, for folks who
     233  // want global "pubsub" in a convenient place.
     234  _.extend(Backbone, Events);
     235
     236  // Backbone.Model
     237  // --------------
     238
     239  // Backbone **Models** are the basic data object in the framework --
     240  // frequently representing a row in a table in a database on your server.
     241  // A discrete chunk of data and a bunch of useful, related methods for
     242  // performing computations and transformations on that data.
     243
     244  // Create a new model with the specified attributes. A client id (`cid`)
     245  // is automatically generated and assigned for you.
     246  var Model = Backbone.Model = function(attributes, options) {
     247    var attrs = attributes || {};
     248    options || (options = {});
     249    this.cid = _.uniqueId('c');
     250    this.attributes = {};
     251    if (options.collection) this.collection = options.collection;
     252    if (options.parse) attrs = this.parse(attrs, options) || {};
     253    attrs = _.defaults({}, attrs, _.result(this, 'defaults'));
     254    this.set(attrs, options);
     255    this.changed = {};
     256    this.initialize.apply(this, arguments);
     257  };
     258
     259  // Attach all inheritable methods to the Model prototype.
     260  _.extend(Model.prototype, Events, {
     261
     262    // A hash of attributes whose current and previous value differ.
     263    changed: null,
     264
     265    // The value returned during the last failed validation.
     266    validationError: null,
     267
     268    // The default name for the JSON `id` attribute is `"id"`. MongoDB and
     269    // CouchDB users may want to set this to `"_id"`.
     270    idAttribute: 'id',
     271
     272    // Initialize is an empty function by default. Override it with your own
     273    // initialization logic.
     274    initialize: function(){},
     275
     276    // Return a copy of the model's `attributes` object.
     277    toJSON: function(options) {
     278      return _.clone(this.attributes);
     279    },
     280
     281    // Proxy `Backbone.sync` by default -- but override this if you need
     282    // custom syncing semantics for *this* particular model.
     283    sync: function() {
     284      return Backbone.sync.apply(this, arguments);
     285    },
     286
     287    // Get the value of an attribute.
     288    get: function(attr) {
     289      return this.attributes[attr];
     290    },
     291
     292    // Get the HTML-escaped value of an attribute.
     293    escape: function(attr) {
     294      return _.escape(this.get(attr));
     295    },
     296
     297    // Returns `true` if the attribute contains a value that is not null
     298    // or undefined.
     299    has: function(attr) {
     300      return this.get(attr) != null;
     301    },
     302
     303    // Set a hash of model attributes on the object, firing `"change"`. This is
     304    // the core primitive operation of a model, updating the data and notifying
     305    // anyone who needs to know about the change in state. The heart of the beast.
     306    set: function(key, val, options) {
     307      var attr, attrs, unset, changes, silent, changing, prev, current;
     308      if (key == null) return this;
     309
     310      // Handle both `"key", value` and `{key: value}` -style arguments.
     311      if (typeof key === 'object') {
     312        attrs = key;
     313        options = val;
     314      } else {
     315        (attrs = {})[key] = val;
     316      }
     317
     318      options || (options = {});
     319
     320      // Run validation.
     321      if (!this._validate(attrs, options)) return false;
     322
     323      // Extract attributes and options.
     324      unset           = options.unset;
     325      silent          = options.silent;
     326      changes         = [];
     327      changing        = this._changing;
     328      this._changing  = true;
     329
     330      if (!changing) {
     331        this._previousAttributes = _.clone(this.attributes);
     332        this.changed = {};
     333      }
     334      current = this.attributes, prev = this._previousAttributes;
     335
     336      // Check for changes of `id`.
     337      if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
     338
     339      // For each `set` attribute, update or delete the current value.
     340      for (attr in attrs) {
     341        val = attrs[attr];
     342        if (!_.isEqual(current[attr], val)) changes.push(attr);
     343        if (!_.isEqual(prev[attr], val)) {
     344          this.changed[attr] = val;
     345        } else {
     346          delete this.changed[attr];
     347        }
     348        unset ? delete current[attr] : current[attr] = val;
     349      }
     350
     351      // Trigger all relevant attribute changes.
     352      if (!silent) {
     353        if (changes.length) this._pending = true;
     354        for (var i = 0, l = changes.length; i < l; i++) {
     355          this.trigger('change:' + changes[i], this, current[changes[i]], options);
     356        }
     357      }
     358
     359      // You might be wondering why there's a `while` loop here. Changes can
     360      // be recursively nested within `"change"` events.
     361      if (changing) return this;
     362      if (!silent) {
     363        while (this._pending) {
     364          this._pending = false;
     365          this.trigger('change', this, options);
     366        }
     367      }
     368      this._pending = false;
     369      this._changing = false;
     370      return this;
     371    },
     372
     373    // Remove an attribute from the model, firing `"change"`. `unset` is a noop
     374    // if the attribute doesn't exist.
     375    unset: function(attr, options) {
     376      return this.set(attr, void 0, _.extend({}, options, {unset: true}));
     377    },
     378
     379    // Clear all attributes on the model, firing `"change"`.
     380    clear: function(options) {
     381      var attrs = {};
     382      for (var key in this.attributes) attrs[key] = void 0;
     383      return this.set(attrs, _.extend({}, options, {unset: true}));
     384    },
     385
     386    // Determine if the model has changed since the last `"change"` event.
     387    // If you specify an attribute name, determine if that attribute has changed.
     388    hasChanged: function(attr) {
     389      if (attr == null) return !_.isEmpty(this.changed);
     390      return _.has(this.changed, attr);
     391    },
     392
     393    // Return an object containing all the attributes that have changed, or
     394    // false if there are no changed attributes. Useful for determining what
     395    // parts of a view need to be updated and/or what attributes need to be
     396    // persisted to the server. Unset attributes will be set to undefined.
     397    // You can also pass an attributes object to diff against the model,
     398    // determining if there *would be* a change.
     399    changedAttributes: function(diff) {
     400      if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
     401      var val, changed = false;
     402      var old = this._changing ? this._previousAttributes : this.attributes;
     403      for (var attr in diff) {
     404        if (_.isEqual(old[attr], (val = diff[attr]))) continue;
     405        (changed || (changed = {}))[attr] = val;
     406      }
     407      return changed;
     408    },
     409
     410    // Get the previous value of an attribute, recorded at the time the last
     411    // `"change"` event was fired.
     412    previous: function(attr) {
     413      if (attr == null || !this._previousAttributes) return null;
     414      return this._previousAttributes[attr];
     415    },
     416
     417    // Get all of the attributes of the model at the time of the previous
     418    // `"change"` event.
     419    previousAttributes: function() {
     420      return _.clone(this._previousAttributes);
     421    },
     422
     423    // Fetch the model from the server. If the server's representation of the
     424    // model differs from its current attributes, they will be overridden,
     425    // triggering a `"change"` event.
     426    fetch: function(options) {
     427      options = options ? _.clone(options) : {};
     428      if (options.parse === void 0) options.parse = true;
     429      var model = this;
     430      var success = options.success;
     431      options.success = function(resp) {
     432        if (!model.set(model.parse(resp, options), options)) return false;
     433        if (success) success(model, resp, options);
     434        model.trigger('sync', model, resp, options);
     435      };
     436      wrapError(this, options);
     437      return this.sync('read', this, options);
     438    },
     439
     440    // Set a hash of model attributes, and sync the model to the server.
     441    // If the server returns an attributes hash that differs, the model's
     442    // state will be `set` again.
     443    save: function(key, val, options) {
     444      var attrs, method, xhr, attributes = this.attributes;
     445
     446      // Handle both `"key", value` and `{key: value}` -style arguments.
     447      if (key == null || typeof key === 'object') {
     448        attrs = key;
     449        options = val;
     450      } else {
     451        (attrs = {})[key] = val;
     452      }
     453
     454      options = _.extend({validate: true}, options);
     455
     456      // If we're not waiting and attributes exist, save acts as
     457      // `set(attr).save(null, opts)` with validation. Otherwise, check if
     458      // the model will be valid when the attributes, if any, are set.
     459      if (attrs && !options.wait) {
     460        if (!this.set(attrs, options)) return false;
     461      } else {
     462        if (!this._validate(attrs, options)) return false;
     463      }
     464
     465      // Set temporary attributes if `{wait: true}`.
     466      if (attrs && options.wait) {
     467        this.attributes = _.extend({}, attributes, attrs);
     468      }
     469
     470      // After a successful server-side save, the client is (optionally)
     471      // updated with the server-side state.
     472      if (options.parse === void 0) options.parse = true;
     473      var model = this;
     474      var success = options.success;
     475      options.success = function(resp) {
     476        // Ensure attributes are restored during synchronous saves.
     477        model.attributes = attributes;
     478        var serverAttrs = model.parse(resp, options);
     479        if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
     480        if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
     481          return false;
     482        }
     483        if (success) success(model, resp, options);
     484        model.trigger('sync', model, resp, options);
     485      };
     486      wrapError(this, options);
     487
     488      method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
     489      if (method === 'patch') options.attrs = attrs;
     490      xhr = this.sync(method, this, options);
     491
     492      // Restore attributes.
     493      if (attrs && options.wait) this.attributes = attributes;
     494
     495      return xhr;
     496    },
     497
     498    // Destroy this model on the server if it was already persisted.
     499    // Optimistically removes the model from its collection, if it has one.
     500    // If `wait: true` is passed, waits for the server to respond before removal.
     501    destroy: function(options) {
     502      options = options ? _.clone(options) : {};
     503      var model = this;
     504      var success = options.success;
     505
     506      var destroy = function() {
     507        model.trigger('destroy', model, model.collection, options);
     508      };
     509
     510      options.success = function(resp) {
     511        if (options.wait || model.isNew()) destroy();
     512        if (success) success(model, resp, options);
     513        if (!model.isNew()) model.trigger('sync', model, resp, options);
     514      };
     515
     516      if (this.isNew()) {
     517        options.success();
     518        return false;
     519      }
     520      wrapError(this, options);
     521
     522      var xhr = this.sync('delete', this, options);
     523      if (!options.wait) destroy();
     524      return xhr;
     525    },
     526
     527    // Default URL for the model's representation on the server -- if you're
     528    // using Backbone's restful methods, override this to change the endpoint
     529    // that will be called.
     530    url: function() {
     531      var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
     532      if (this.isNew()) return base;
     533      return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
     534    },
     535
     536    // **parse** converts a response into the hash of attributes to be `set` on
     537    // the model. The default implementation is just to pass the response along.
     538    parse: function(resp, options) {
     539      return resp;
     540    },
     541
     542    // Create a new model with identical attributes to this one.
     543    clone: function() {
     544      return new this.constructor(this.attributes);
     545    },
     546
     547    // A model is new if it has never been saved to the server, and lacks an id.
     548    isNew: function() {
     549      return this.id == null;
     550    },
     551
     552    // Check if the model is currently in a valid state.
     553    isValid: function(options) {
     554      return this._validate({}, _.extend(options || {}, { validate: true }));
     555    },
     556
     557    // Run validation against the next complete set of model attributes,
     558    // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
     559    _validate: function(attrs, options) {
     560      if (!options.validate || !this.validate) return true;
     561      attrs = _.extend({}, this.attributes, attrs);
     562      var error = this.validationError = this.validate(attrs, options) || null;
     563      if (!error) return true;
     564      this.trigger('invalid', this, error, _.extend(options, {validationError: error}));
     565      return false;
     566    }
     567
     568  });
     569
     570  // Underscore methods that we want to implement on the Model.
     571  var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
     572
     573  // Mix in each Underscore method as a proxy to `Model#attributes`.
     574  _.each(modelMethods, function(method) {
     575    Model.prototype[method] = function() {
     576      var args = slice.call(arguments);
     577      args.unshift(this.attributes);
     578      return _[method].apply(_, args);
     579    };
     580  });
     581
     582  // Backbone.Collection
     583  // -------------------
     584
     585  // If models tend to represent a single row of data, a Backbone Collection is
     586  // more analagous to a table full of data ... or a small slice or page of that
     587  // table, or a collection of rows that belong together for a particular reason
     588  // -- all of the messages in this particular folder, all of the documents
     589  // belonging to this particular author, and so on. Collections maintain
     590  // indexes of their models, both in order, and for lookup by `id`.
     591
     592  // Create a new **Collection**, perhaps to contain a specific type of `model`.
     593  // If a `comparator` is specified, the Collection will maintain
     594  // its models in sort order, as they're added and removed.
     595  var Collection = Backbone.Collection = function(models, options) {
     596    options || (options = {});
     597    if (options.model) this.model = options.model;
     598    if (options.comparator !== void 0) this.comparator = options.comparator;
     599    this._reset();
     600    this.initialize.apply(this, arguments);
     601    if (models) this.reset(models, _.extend({silent: true}, options));
     602  };
     603
     604  // Default options for `Collection#set`.
     605  var setOptions = {add: true, remove: true, merge: true};
     606  var addOptions = {add: true, remove: false};
     607
     608  // Define the Collection's inheritable methods.
     609  _.extend(Collection.prototype, Events, {
     610
     611    // The default model for a collection is just a **Backbone.Model**.
     612    // This should be overridden in most cases.
     613    model: Model,
     614
     615    // Initialize is an empty function by default. Override it with your own
     616    // initialization logic.
     617    initialize: function(){},
     618
     619    // The JSON representation of a Collection is an array of the
     620    // models' attributes.
     621    toJSON: function(options) {
     622      return this.map(function(model){ return model.toJSON(options); });
     623    },
     624
     625    // Proxy `Backbone.sync` by default.
     626    sync: function() {
     627      return Backbone.sync.apply(this, arguments);
     628    },
     629
     630    // Add a model, or list of models to the set.
     631    add: function(models, options) {
     632      return this.set(models, _.extend({merge: false}, options, addOptions));
     633    },
     634
     635    // Remove a model, or a list of models from the set.
     636    remove: function(models, options) {
     637      var singular = !_.isArray(models);
     638      models = singular ? [models] : _.clone(models);
     639      options || (options = {});
     640      var i, l, index, model;
     641      for (i = 0, l = models.length; i < l; i++) {
     642        model = models[i] = this.get(models[i]);
     643        if (!model) continue;
     644        delete this._byId[model.id];
     645        delete this._byId[model.cid];
     646        index = this.indexOf(model);
     647        this.models.splice(index, 1);
     648        this.length--;
     649        if (!options.silent) {
     650          options.index = index;
     651          model.trigger('remove', model, this, options);
     652        }
     653        this._removeReference(model);
     654      }
     655      return singular ? models[0] : models;
     656    },
     657
     658    // Update a collection by `set`-ing a new list of models, adding new ones,
     659    // removing models that are no longer present, and merging models that
     660    // already exist in the collection, as necessary. Similar to **Model#set**,
     661    // the core operation for updating the data contained by the collection.
     662    set: function(models, options) {
     663      options = _.defaults({}, options, setOptions);
     664      if (options.parse) models = this.parse(models, options);
     665      var singular = !_.isArray(models);
     666      models = singular ? (models ? [models] : []) : _.clone(models);
     667      var i, l, id, model, attrs, existing, sort;
     668      var at = options.at;
     669      var targetModel = this.model;
     670      var sortable = this.comparator && (at == null) && options.sort !== false;
     671      var sortAttr = _.isString(this.comparator) ? this.comparator : null;
     672      var toAdd = [], toRemove = [], modelMap = {};
     673      var add = options.add, merge = options.merge, remove = options.remove;
     674      var order = !sortable && add && remove ? [] : false;
     675
     676      // Turn bare objects into model references, and prevent invalid models
     677      // from being added.
     678      for (i = 0, l = models.length; i < l; i++) {
     679        attrs = models[i];
     680        if (attrs instanceof Model) {
     681          id = model = attrs;
     682        } else {
     683          id = attrs[targetModel.prototype.idAttribute];
     684        }
     685
     686        // If a duplicate is found, prevent it from being added and
     687        // optionally merge it into the existing model.
     688        if (existing = this.get(id)) {
     689          if (remove) modelMap[existing.cid] = true;
     690          if (merge) {
     691            attrs = attrs === model ? model.attributes : attrs;
     692            if (options.parse) attrs = existing.parse(attrs, options);
     693            existing.set(attrs, options);
     694            if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
     695          }
     696          models[i] = existing;
     697
     698        // If this is a new, valid model, push it to the `toAdd` list.
     699        } else if (add) {
     700          model = models[i] = this._prepareModel(attrs, options);
     701          if (!model) continue;
     702          toAdd.push(model);
     703
     704          // Listen to added models' events, and index models for lookup by
     705          // `id` and by `cid`.
     706          model.on('all', this._onModelEvent, this);
     707          this._byId[model.cid] = model;
     708          if (model.id != null) this._byId[model.id] = model;
     709        }
     710        if (order) order.push(existing || model);
     711      }
     712
     713      // Remove nonexistent models if appropriate.
     714      if (remove) {
     715        for (i = 0, l = this.length; i < l; ++i) {
     716          if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
     717        }
     718        if (toRemove.length) this.remove(toRemove, options);
     719      }
     720
     721      // See if sorting is needed, update `length` and splice in new models.
     722      if (toAdd.length || (order && order.length)) {
     723        if (sortable) sort = true;
     724        this.length += toAdd.length;
     725        if (at != null) {
     726          for (i = 0, l = toAdd.length; i < l; i++) {
     727            this.models.splice(at + i, 0, toAdd[i]);
     728          }
     729        } else {
     730          if (order) this.models.length = 0;
     731          var orderedModels = order || toAdd;
     732          for (i = 0, l = orderedModels.length; i < l; i++) {
     733            this.models.push(orderedModels[i]);
     734          }
     735        }
     736      }
     737
     738      // Silently sort the collection if appropriate.
     739      if (sort) this.sort({silent: true});
     740
     741      // Unless silenced, it's time to fire all appropriate add/sort events.
     742      if (!options.silent) {
     743        for (i = 0, l = toAdd.length; i < l; i++) {
     744          (model = toAdd[i]).trigger('add', model, this, options);
     745        }
     746        if (sort || (order && order.length)) this.trigger('sort', this, options);
     747      }
     748     
     749      // Return the added (or merged) model (or models).
     750      return singular ? models[0] : models;
     751    },
     752
     753    // When you have more items than you want to add or remove individually,
     754    // you can reset the entire set with a new list of models, without firing
     755    // any granular `add` or `remove` events. Fires `reset` when finished.
     756    // Useful for bulk operations and optimizations.
     757    reset: function(models, options) {
     758      options || (options = {});
     759      for (var i = 0, l = this.models.length; i < l; i++) {
     760        this._removeReference(this.models[i]);
     761      }
     762      options.previousModels = this.models;
     763      this._reset();
     764      models = this.add(models, _.extend({silent: true}, options));
     765      if (!options.silent) this.trigger('reset', this, options);
     766      return models;
     767    },
     768
     769    // Add a model to the end of the collection.
     770    push: function(model, options) {
     771      return this.add(model, _.extend({at: this.length}, options));
     772    },
     773
     774    // Remove a model from the end of the collection.
     775    pop: function(options) {
     776      var model = this.at(this.length - 1);
     777      this.remove(model, options);
     778      return model;
     779    },
     780
     781    // Add a model to the beginning of the collection.
     782    unshift: function(model, options) {
     783      return this.add(model, _.extend({at: 0}, options));
     784    },
     785
     786    // Remove a model from the beginning of the collection.
     787    shift: function(options) {
     788      var model = this.at(0);
     789      this.remove(model, options);
     790      return model;
     791    },
     792
     793    // Slice out a sub-array of models from the collection.
     794    slice: function() {
     795      return slice.apply(this.models, arguments);
     796    },
     797
     798    // Get a model from the set by id.
     799    get: function(obj) {
     800      if (obj == null) return void 0;
     801      return this._byId[obj.id] || this._byId[obj.cid] || this._byId[obj];
     802    },
     803
     804    // Get the model at the given index.
     805    at: function(index) {
     806      return this.models[index];
     807    },
     808
     809    // Return models with matching attributes. Useful for simple cases of
     810    // `filter`.
     811    where: function(attrs, first) {
     812      if (_.isEmpty(attrs)) return first ? void 0 : [];
     813      return this[first ? 'find' : 'filter'](function(model) {
     814        for (var key in attrs) {
     815          if (attrs[key] !== model.get(key)) return false;
     816        }
     817        return true;
     818      });
     819    },
     820
     821    // Return the first model with matching attributes. Useful for simple cases
     822    // of `find`.
     823    findWhere: function(attrs) {
     824      return this.where(attrs, true);
     825    },
     826
     827    // Force the collection to re-sort itself. You don't need to call this under
     828    // normal circumstances, as the set will maintain sort order as each item
     829    // is added.
     830    sort: function(options) {
     831      if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
     832      options || (options = {});
     833
     834      // Run sort based on type of `comparator`.
     835      if (_.isString(this.comparator) || this.comparator.length === 1) {
     836        this.models = this.sortBy(this.comparator, this);
     837      } else {
     838        this.models.sort(_.bind(this.comparator, this));
     839      }
     840
     841      if (!options.silent) this.trigger('sort', this, options);
     842      return this;
     843    },
     844
     845    // Pluck an attribute from each model in the collection.
     846    pluck: function(attr) {
     847      return _.invoke(this.models, 'get', attr);
     848    },
     849
     850    // Fetch the default set of models for this collection, resetting the
     851    // collection when they arrive. If `reset: true` is passed, the response
     852    // data will be passed through the `reset` method instead of `set`.
     853    fetch: function(options) {
     854      options = options ? _.clone(options) : {};
     855      if (options.parse === void 0) options.parse = true;
     856      var success = options.success;
     857      var collection = this;
     858      options.success = function(resp) {
     859        var method = options.reset ? 'reset' : 'set';
     860        collection[method](resp, options);
     861        if (success) success(collection, resp, options);
     862        collection.trigger('sync', collection, resp, options);
     863      };
     864      wrapError(this, options);
     865      return this.sync('read', this, options);
     866    },
     867
     868    // Create a new instance of a model in this collection. Add the model to the
     869    // collection immediately, unless `wait: true` is passed, in which case we
     870    // wait for the server to agree.
     871    create: function(model, options) {
     872      options = options ? _.clone(options) : {};
     873      if (!(model = this._prepareModel(model, options))) return false;
     874      if (!options.wait) this.add(model, options);
     875      var collection = this;
     876      var success = options.success;
     877      options.success = function(model, resp, options) {
     878        if (options.wait) collection.add(model, options);
     879        if (success) success(model, resp, options);
     880      };
     881      model.save(null, options);
     882      return model;
     883    },
     884
     885    // **parse** converts a response into a list of models to be added to the
     886    // collection. The default implementation is just to pass it through.
     887    parse: function(resp, options) {
     888      return resp;
     889    },
     890
     891    // Create a new collection with an identical list of models as this one.
     892    clone: function() {
     893      return new this.constructor(this.models);
     894    },
     895
     896    // Private method to reset all internal state. Called when the collection
     897    // is first initialized or reset.
     898    _reset: function() {
     899      this.length = 0;
     900      this.models = [];
     901      this._byId  = {};
     902    },
     903
     904    // Prepare a hash of attributes (or other model) to be added to this
     905    // collection.
     906    _prepareModel: function(attrs, options) {
     907      if (attrs instanceof Model) {
     908        if (!attrs.collection) attrs.collection = this;
     909        return attrs;
     910      }
     911      options = options ? _.clone(options) : {};
     912      options.collection = this;
     913      var model = new this.model(attrs, options);
     914      if (!model.validationError) return model;
     915      this.trigger('invalid', this, model.validationError, options);
     916      return false;
     917    },
     918
     919    // Internal method to sever a model's ties to a collection.
     920    _removeReference: function(model) {
     921      if (this === model.collection) delete model.collection;
     922      model.off('all', this._onModelEvent, this);
     923    },
     924
     925    // Internal method called every time a model in the set fires an event.
     926    // Sets need to update their indexes when models change ids. All other
     927    // events simply proxy through. "add" and "remove" events that originate
     928    // in other collections are ignored.
     929    _onModelEvent: function(event, model, collection, options) {
     930      if ((event === 'add' || event === 'remove') && collection !== this) return;
     931      if (event === 'destroy') this.remove(model, options);
     932      if (model && event === 'change:' + model.idAttribute) {
     933        delete this._byId[model.previous(model.idAttribute)];
     934        if (model.id != null) this._byId[model.id] = model;
     935      }
     936      this.trigger.apply(this, arguments);
     937    }
     938
     939  });
     940
     941  // Underscore methods that we want to implement on the Collection.
     942  // 90% of the core usefulness of Backbone Collections is actually implemented
     943  // right here:
     944  var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
     945    'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
     946    'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
     947    'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
     948    'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
     949    'lastIndexOf', 'isEmpty', 'chain'];
     950
     951  // Mix in each Underscore method as a proxy to `Collection#models`.
     952  _.each(methods, function(method) {
     953    Collection.prototype[method] = function() {
     954      var args = slice.call(arguments);
     955      args.unshift(this.models);
     956      return _[method].apply(_, args);
     957    };
     958  });
     959
     960  // Underscore methods that take a property name as an argument.
     961  var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
     962
     963  // Use attributes instead of properties.
     964  _.each(attributeMethods, function(method) {
     965    Collection.prototype[method] = function(value, context) {
     966      var iterator = _.isFunction(value) ? value : function(model) {
     967        return model.get(value);
     968      };
     969      return _[method](this.models, iterator, context);
     970    };
     971  });
     972
     973  // Backbone.View
     974  // -------------
     975
     976  // Backbone Views are almost more convention than they are actual code. A View
     977  // is simply a JavaScript object that represents a logical chunk of UI in the
     978  // DOM. This might be a single item, an entire list, a sidebar or panel, or
     979  // even the surrounding frame which wraps your whole app. Defining a chunk of
     980  // UI as a **View** allows you to define your DOM events declaratively, without
     981  // having to worry about render order ... and makes it easy for the view to
     982  // react to specific changes in the state of your models.
     983
     984  // Creating a Backbone.View creates its initial element outside of the DOM,
     985  // if an existing element is not provided...
     986  var View = Backbone.View = function(options) {
     987    this.cid = _.uniqueId('view');
     988    options || (options = {});
     989    _.extend(this, _.pick(options, viewOptions));
     990    this._ensureElement();
     991    this.initialize.apply(this, arguments);
     992    this.delegateEvents();
     993  };
     994
     995  // Cached regex to split keys for `delegate`.
     996  var delegateEventSplitter = /^(\S+)\s*(.*)$/;
     997
     998  // List of view options to be merged as properties.
     999  var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
     1000
     1001  // Set up all inheritable **Backbone.View** properties and methods.
     1002  _.extend(View.prototype, Events, {
     1003
     1004    // The default `tagName` of a View's element is `"div"`.
     1005    tagName: 'div',
     1006
     1007    // jQuery delegate for element lookup, scoped to DOM elements within the
     1008    // current view. This should be preferred to global lookups where possible.
     1009    $: function(selector) {
     1010      return this.$el.find(selector);
     1011    },
     1012
     1013    // Initialize is an empty function by default. Override it with your own
     1014    // initialization logic.
     1015    initialize: function(){},
     1016
     1017    // **render** is the core function that your view should override, in order
     1018    // to populate its element (`this.el`), with the appropriate HTML. The
     1019    // convention is for **render** to always return `this`.
     1020    render: function() {
     1021      return this;
     1022    },
     1023
     1024    // Remove this view by taking the element out of the DOM, and removing any
     1025    // applicable Backbone.Events listeners.
     1026    remove: function() {
     1027      this.$el.remove();
     1028      this.stopListening();
     1029      return this;
     1030    },
     1031
     1032    // Change the view's element (`this.el` property), including event
     1033    // re-delegation.
     1034    setElement: function(element, delegate) {
     1035      if (this.$el) this.undelegateEvents();
     1036      this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
     1037      this.el = this.$el[0];
     1038      if (delegate !== false) this.delegateEvents();
     1039      return this;
     1040    },
     1041
     1042    // Set callbacks, where `this.events` is a hash of
     1043    //
     1044    // *{"event selector": "callback"}*
     1045    //
     1046    //     {
     1047    //       'mousedown .title':  'edit',
     1048    //       'click .button':     'save',
     1049    //       'click .open':       function(e) { ... }
     1050    //     }
     1051    //
     1052    // pairs. Callbacks will be bound to the view, with `this` set properly.
     1053    // Uses event delegation for efficiency.
     1054    // Omitting the selector binds the event to `this.el`.
     1055    // This only works for delegate-able events: not `focus`, `blur`, and
     1056    // not `change`, `submit`, and `reset` in Internet Explorer.
     1057    delegateEvents: function(events) {
     1058      if (!(events || (events = _.result(this, 'events')))) return this;
     1059      this.undelegateEvents();
     1060      for (var key in events) {
     1061        var method = events[key];
     1062        if (!_.isFunction(method)) method = this[events[key]];
     1063        if (!method) continue;
     1064
     1065        var match = key.match(delegateEventSplitter);
     1066        var eventName = match[1], selector = match[2];
     1067        method = _.bind(method, this);
     1068        eventName += '.delegateEvents' + this.cid;
     1069        if (selector === '') {
     1070          this.$el.on(eventName, method);
     1071        } else {
     1072          this.$el.on(eventName, selector, method);
     1073        }
     1074      }
     1075      return this;
     1076    },
     1077
     1078    // Clears all callbacks previously bound to the view with `delegateEvents`.
     1079    // You usually don't need to use this, but may wish to if you have multiple
     1080    // Backbone views attached to the same DOM element.
     1081    undelegateEvents: function() {
     1082      this.$el.off('.delegateEvents' + this.cid);
     1083      return this;
     1084    },
     1085
     1086    // Ensure that the View has a DOM element to render into.
     1087    // If `this.el` is a string, pass it through `$()`, take the first
     1088    // matching element, and re-assign it to `el`. Otherwise, create
     1089    // an element from the `id`, `className` and `tagName` properties.
     1090    _ensureElement: function() {
     1091      if (!this.el) {
     1092        var attrs = _.extend({}, _.result(this, 'attributes'));
     1093        if (this.id) attrs.id = _.result(this, 'id');
     1094        if (this.className) attrs['class'] = _.result(this, 'className');
     1095        var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
     1096        this.setElement($el, false);
     1097      } else {
     1098        this.setElement(_.result(this, 'el'), false);
     1099      }
     1100    }
     1101
     1102  });
     1103
     1104  // Backbone.sync
     1105  // -------------
     1106
     1107  // Override this function to change the manner in which Backbone persists
     1108  // models to the server. You will be passed the type of request, and the
     1109  // model in question. By default, makes a RESTful Ajax request
     1110  // to the model's `url()`. Some possible customizations could be:
     1111  //
     1112  // * Use `setTimeout` to batch rapid-fire updates into a single request.
     1113  // * Send up the models as XML instead of JSON.
     1114  // * Persist models via WebSockets instead of Ajax.
     1115  //
     1116  // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
     1117  // as `POST`, with a `_method` parameter containing the true HTTP method,
     1118  // as well as all requests with the body as `application/x-www-form-urlencoded`
     1119  // instead of `application/json` with the model in a param named `model`.
     1120  // Useful when interfacing with server-side languages like **PHP** that make
     1121  // it difficult to read the body of `PUT` requests.
     1122  Backbone.sync = function(method, model, options) {
     1123    var type = methodMap[method];
     1124
     1125    // Default options, unless specified.
     1126    _.defaults(options || (options = {}), {
     1127      emulateHTTP: Backbone.emulateHTTP,
     1128      emulateJSON: Backbone.emulateJSON
     1129    });
     1130
     1131    // Default JSON-request options.
     1132    var params = {type: type, dataType: 'json'};
     1133
     1134    // Ensure that we have a URL.
     1135    if (!options.url) {
     1136      params.url = _.result(model, 'url') || urlError();
     1137    }
     1138
     1139    // Ensure that we have the appropriate request data.
     1140    if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
     1141      params.contentType = 'application/json';
     1142      params.data = JSON.stringify(options.attrs || model.toJSON(options));
     1143    }
     1144
     1145    // For older servers, emulate JSON by encoding the request into an HTML-form.
     1146    if (options.emulateJSON) {
     1147      params.contentType = 'application/x-www-form-urlencoded';
     1148      params.data = params.data ? {model: params.data} : {};
     1149    }
     1150
     1151    // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
     1152    // And an `X-HTTP-Method-Override` header.
     1153    if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
     1154      params.type = 'POST';
     1155      if (options.emulateJSON) params.data._method = type;
     1156      var beforeSend = options.beforeSend;
     1157      options.beforeSend = function(xhr) {
     1158        xhr.setRequestHeader('X-HTTP-Method-Override', type);
     1159        if (beforeSend) return beforeSend.apply(this, arguments);
     1160      };
     1161    }
     1162
     1163    // Don't process data on a non-GET request.
     1164    if (params.type !== 'GET' && !options.emulateJSON) {
     1165      params.processData = false;
     1166    }
     1167
     1168    // If we're sending a `PATCH` request, and we're in an old Internet Explorer
     1169    // that still has ActiveX enabled by default, override jQuery to use that
     1170    // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
     1171    if (params.type === 'PATCH' && noXhrPatch) {
     1172      params.xhr = function() {
     1173        return new ActiveXObject("Microsoft.XMLHTTP");
     1174      };
     1175    }
     1176
     1177    // Make the request, allowing the user to override any Ajax options.
     1178    var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
     1179    model.trigger('request', model, xhr, options);
     1180    return xhr;
     1181  };
     1182
     1183  var noXhrPatch = typeof window !== 'undefined' && !!window.ActiveXObject && !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);
     1184
     1185  // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
     1186  var methodMap = {
     1187    'create': 'POST',
     1188    'update': 'PUT',
     1189    'patch':  'PATCH',
     1190    'delete': 'DELETE',
     1191    'read':   'GET'
     1192  };
     1193
     1194  // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
     1195  // Override this if you'd like to use a different library.
     1196  Backbone.ajax = function() {
     1197    return Backbone.$.ajax.apply(Backbone.$, arguments);
     1198  };
     1199
     1200  // Backbone.Router
     1201  // ---------------
     1202
     1203  // Routers map faux-URLs to actions, and fire events when routes are
     1204  // matched. Creating a new one sets its `routes` hash, if not set statically.
     1205  var Router = Backbone.Router = function(options) {
     1206    options || (options = {});
     1207    if (options.routes) this.routes = options.routes;
     1208    this._bindRoutes();
     1209    this.initialize.apply(this, arguments);
     1210  };
     1211
     1212  // Cached regular expressions for matching named param parts and splatted
     1213  // parts of route strings.
     1214  var optionalParam = /\((.*?)\)/g;
     1215  var namedParam    = /(\(\?)?:\w+/g;
     1216  var splatParam    = /\*\w+/g;
     1217  var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;
     1218
     1219  // Set up all inheritable **Backbone.Router** properties and methods.
     1220  _.extend(Router.prototype, Events, {
     1221
     1222    // Initialize is an empty function by default. Override it with your own
     1223    // initialization logic.
     1224    initialize: function(){},
     1225
     1226    // Manually bind a single named route to a callback. For example:
     1227    //
     1228    //     this.route('search/:query/p:num', 'search', function(query, num) {
     1229    //       ...
     1230    //     });
     1231    //
     1232    route: function(route, name, callback) {
     1233      if (!_.isRegExp(route)) route = this._routeToRegExp(route);
     1234      if (_.isFunction(name)) {
     1235        callback = name;
     1236        name = '';
     1237      }
     1238      if (!callback) callback = this[name];
     1239      var router = this;
     1240      Backbone.history.route(route, function(fragment) {
     1241        var args = router._extractParameters(route, fragment);
     1242        callback && callback.apply(router, args);
     1243        router.trigger.apply(router, ['route:' + name].concat(args));
     1244        router.trigger('route', name, args);
     1245        Backbone.history.trigger('route', router, name, args);
     1246      });
     1247      return this;
     1248    },
     1249
     1250    // Simple proxy to `Backbone.history` to save a fragment into the history.
     1251    navigate: function(fragment, options) {
     1252      Backbone.history.navigate(fragment, options);
     1253      return this;
     1254    },
     1255
     1256    // Bind all defined routes to `Backbone.history`. We have to reverse the
     1257    // order of the routes here to support behavior where the most general
     1258    // routes can be defined at the bottom of the route map.
     1259    _bindRoutes: function() {
     1260      if (!this.routes) return;
     1261      this.routes = _.result(this, 'routes');
     1262      var route, routes = _.keys(this.routes);
     1263      while ((route = routes.pop()) != null) {
     1264        this.route(route, this.routes[route]);
     1265      }
     1266    },
     1267
     1268    // Convert a route string into a regular expression, suitable for matching
     1269    // against the current location hash.
     1270    _routeToRegExp: function(route) {
     1271      route = route.replace(escapeRegExp, '\\$&')
     1272                   .replace(optionalParam, '(?:$1)?')
     1273                   .replace(namedParam, function(match, optional) {
     1274                     return optional ? match : '([^\/]+)';
     1275                   })
     1276                   .replace(splatParam, '(.*?)');
     1277      return new RegExp('^' + route + '$');
     1278    },
     1279
     1280    // Given a route, and a URL fragment that it matches, return the array of
     1281    // extracted decoded parameters. Empty or unmatched parameters will be
     1282    // treated as `null` to normalize cross-browser behavior.
     1283    _extractParameters: function(route, fragment) {
     1284      var params = route.exec(fragment).slice(1);
     1285      return _.map(params, function(param) {
     1286        return param ? decodeURIComponent(param) : null;
     1287      });
     1288    }
     1289
     1290  });
     1291
     1292  // Backbone.History
     1293  // ----------------
     1294
     1295  // Handles cross-browser history management, based on either
     1296  // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
     1297  // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
     1298  // and URL fragments. If the browser supports neither (old IE, natch),
     1299  // falls back to polling.
     1300  var History = Backbone.History = function() {
     1301    this.handlers = [];
     1302    _.bindAll(this, 'checkUrl');
     1303
     1304    // Ensure that `History` can be used outside of the browser.
     1305    if (typeof window !== 'undefined') {
     1306      this.location = window.location;
     1307      this.history = window.history;
     1308    }
     1309  };
     1310
     1311  // Cached regex for stripping a leading hash/slash and trailing space.
     1312  var routeStripper = /^[#\/]|\s+$/g;
     1313
     1314  // Cached regex for stripping leading and trailing slashes.
     1315  var rootStripper = /^\/+|\/+$/g;
     1316
     1317  // Cached regex for detecting MSIE.
     1318  var isExplorer = /msie [\w.]+/;
     1319
     1320  // Cached regex for removing a trailing slash.
     1321  var trailingSlash = /\/$/;
     1322
     1323  // Cached regex for stripping urls of hash and query.
     1324  var pathStripper = /[?#].*$/;
     1325
     1326  // Has the history handling already been started?
     1327  History.started = false;
     1328
     1329  // Set up all inheritable **Backbone.History** properties and methods.
     1330  _.extend(History.prototype, Events, {
     1331
     1332    // The default interval to poll for hash changes, if necessary, is
     1333    // twenty times a second.
     1334    interval: 50,
     1335
     1336    // Gets the true hash value. Cannot use location.hash directly due to bug
     1337    // in Firefox where location.hash will always be decoded.
     1338    getHash: function(window) {
     1339      var match = (window || this).location.href.match(/#(.*)$/);
     1340      return match ? match[1] : '';
     1341    },
     1342
     1343    // Get the cross-browser normalized URL fragment, either from the URL,
     1344    // the hash, or the override.
     1345    getFragment: function(fragment, forcePushState) {
     1346      if (fragment == null) {
     1347        if (this._hasPushState || !this._wantsHashChange || forcePushState) {
     1348          fragment = this.location.pathname;
     1349          var root = this.root.replace(trailingSlash, '');
     1350          if (!fragment.indexOf(root)) fragment = fragment.slice(root.length);
     1351        } else {
     1352          fragment = this.getHash();
     1353        }
     1354      }
     1355      return fragment.replace(routeStripper, '');
     1356    },
     1357
     1358    // Start the hash change handling, returning `true` if the current URL matches
     1359    // an existing route, and `false` otherwise.
     1360    start: function(options) {
     1361      if (History.started) throw new Error("Backbone.history has already been started");
     1362      History.started = true;
     1363
     1364      // Figure out the initial configuration. Do we need an iframe?
     1365      // Is pushState desired ... is it available?
     1366      this.options          = _.extend({root: '/'}, this.options, options);
     1367      this.root             = this.options.root;
     1368      this._wantsHashChange = this.options.hashChange !== false;
     1369      this._wantsPushState  = !!this.options.pushState;
     1370      this._hasPushState    = !!(this.options.pushState && this.history && this.history.pushState);
     1371      var fragment          = this.getFragment();
     1372      var docMode           = document.documentMode;
     1373      var oldIE             = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
     1374
     1375      // Normalize root to always include a leading and trailing slash.
     1376      this.root = ('/' + this.root + '/').replace(rootStripper, '/');
     1377
     1378      if (oldIE && this._wantsHashChange) {
     1379        this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
     1380        this.navigate(fragment);
     1381      }
     1382
     1383      // Depending on whether we're using pushState or hashes, and whether
     1384      // 'onhashchange' is supported, determine how we check the URL state.
     1385      if (this._hasPushState) {
     1386        Backbone.$(window).on('popstate', this.checkUrl);
     1387      } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
     1388        Backbone.$(window).on('hashchange', this.checkUrl);
     1389      } else if (this._wantsHashChange) {
     1390        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
     1391      }
     1392
     1393      // Determine if we need to change the base url, for a pushState link
     1394      // opened by a non-pushState browser.
     1395      this.fragment = fragment;
     1396      var loc = this.location;
     1397      var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
     1398
     1399      // Transition from hashChange to pushState or vice versa if both are
     1400      // requested.
     1401      if (this._wantsHashChange && this._wantsPushState) {
     1402
     1403        // If we've started off with a route from a `pushState`-enabled
     1404        // browser, but we're currently in a browser that doesn't support it...
     1405        if (!this._hasPushState && !atRoot) {
     1406          this.fragment = this.getFragment(null, true);
     1407          this.location.replace(this.root + this.location.search + '#' + this.fragment);
     1408          // Return immediately as browser will do redirect to new url
     1409          return true;
     1410
     1411        // Or if we've started out with a hash-based route, but we're currently
     1412        // in a browser where it could be `pushState`-based instead...
     1413        } else if (this._hasPushState && atRoot && loc.hash) {
     1414          this.fragment = this.getHash().replace(routeStripper, '');
     1415          this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
     1416        }
     1417
     1418      }
     1419
     1420      if (!this.options.silent) return this.loadUrl();
     1421    },
     1422
     1423    // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
     1424    // but possibly useful for unit testing Routers.
     1425    stop: function() {
     1426      Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
     1427      clearInterval(this._checkUrlInterval);
     1428      History.started = false;
     1429    },
     1430
     1431    // Add a route to be tested when the fragment changes. Routes added later
     1432    // may override previous routes.
     1433    route: function(route, callback) {
     1434      this.handlers.unshift({route: route, callback: callback});
     1435    },
     1436
     1437    // Checks the current URL to see if it has changed, and if it has,
     1438    // calls `loadUrl`, normalizing across the hidden iframe.
     1439    checkUrl: function(e) {
     1440      var current = this.getFragment();
     1441      if (current === this.fragment && this.iframe) {
     1442        current = this.getFragment(this.getHash(this.iframe));
     1443      }
     1444      if (current === this.fragment) return false;
     1445      if (this.iframe) this.navigate(current);
     1446      this.loadUrl();
     1447    },
     1448
     1449    // Attempt to load the current URL fragment. If a route succeeds with a
     1450    // match, returns `true`. If no defined routes matches the fragment,
     1451    // returns `false`.
     1452    loadUrl: function(fragment) {
     1453      fragment = this.fragment = this.getFragment(fragment);
     1454      return _.any(this.handlers, function(handler) {
     1455        if (handler.route.test(fragment)) {
     1456          handler.callback(fragment);
     1457          return true;
     1458        }
     1459      });
     1460    },
     1461
     1462    // Save a fragment into the hash history, or replace the URL state if the
     1463    // 'replace' option is passed. You are responsible for properly URL-encoding
     1464    // the fragment in advance.
     1465    //
     1466    // The options object can contain `trigger: true` if you wish to have the
     1467    // route callback be fired (not usually desirable), or `replace: true`, if
     1468    // you wish to modify the current URL without adding an entry to the history.
     1469    navigate: function(fragment, options) {
     1470      if (!History.started) return false;
     1471      if (!options || options === true) options = {trigger: !!options};
     1472
     1473      var url = this.root + (fragment = this.getFragment(fragment || ''));
     1474
     1475      // Strip the fragment of the query and hash for matching.
     1476      fragment = fragment.replace(pathStripper, '');
     1477
     1478      if (this.fragment === fragment) return;
     1479      this.fragment = fragment;
     1480
     1481      // Don't include a trailing slash on the root.
     1482      if (fragment === '' && url !== '/') url = url.slice(0, -1);
     1483
     1484      // If pushState is available, we use it to set the fragment as a real URL.
     1485      if (this._hasPushState) {
     1486        this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
     1487
     1488      // If hash changes haven't been explicitly disabled, update the hash
     1489      // fragment to store history.
     1490      } else if (this._wantsHashChange) {
     1491        this._updateHash(this.location, fragment, options.replace);
     1492        if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
     1493          // Opening and closing the iframe tricks IE7 and earlier to push a
     1494          // history entry on hash-tag change.  When replace is true, we don't
     1495          // want this.
     1496          if(!options.replace) this.iframe.document.open().close();
     1497          this._updateHash(this.iframe.location, fragment, options.replace);
     1498        }
     1499
     1500      // If you've told us that you explicitly don't want fallback hashchange-
     1501      // based history, then `navigate` becomes a page refresh.
     1502      } else {
     1503        return this.location.assign(url);
     1504      }
     1505      if (options.trigger) return this.loadUrl(fragment);
     1506    },
     1507
     1508    // Update the hash location, either replacing the current entry, or adding
     1509    // a new one to the browser history.
     1510    _updateHash: function(location, fragment, replace) {
     1511      if (replace) {
     1512        var href = location.href.replace(/(javascript:|#).*$/, '');
     1513        location.replace(href + '#' + fragment);
     1514      } else {
     1515        // Some browsers require that `hash` contains a leading #.
     1516        location.hash = '#' + fragment;
     1517      }
     1518    }
     1519
     1520  });
     1521
     1522  // Create the default Backbone.history.
     1523  Backbone.history = new History;
     1524
     1525  // Helpers
     1526  // -------
     1527
     1528  // Helper function to correctly set up the prototype chain, for subclasses.
     1529  // Similar to `goog.inherits`, but uses a hash of prototype properties and
     1530  // class properties to be extended.
     1531  var extend = function(protoProps, staticProps) {
     1532    var parent = this;
     1533    var child;
     1534
     1535    // The constructor function for the new subclass is either defined by you
     1536    // (the "constructor" property in your `extend` definition), or defaulted
     1537    // by us to simply call the parent's constructor.
     1538    if (protoProps && _.has(protoProps, 'constructor')) {
     1539      child = protoProps.constructor;
     1540    } else {
     1541      child = function(){ return parent.apply(this, arguments); };
     1542    }
     1543
     1544    // Add static properties to the constructor function, if supplied.
     1545    _.extend(child, parent, staticProps);
     1546
     1547    // Set the prototype chain to inherit from `parent`, without calling
     1548    // `parent`'s constructor function.
     1549    var Surrogate = function(){ this.constructor = child; };
     1550    Surrogate.prototype = parent.prototype;
     1551    child.prototype = new Surrogate;
     1552
     1553    // Add prototype properties (instance properties) to the subclass,
     1554    // if supplied.
     1555    if (protoProps) _.extend(child.prototype, protoProps);
     1556
     1557    // Set a convenience property in case the parent's prototype is needed
     1558    // later.
     1559    child.__super__ = parent.prototype;
     1560
     1561    return child;
     1562  };
     1563
     1564  // Set up inheritance for the model, collection, router, view and history.
     1565  Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
     1566
     1567  // Throw an error when a URL is needed, and none is supplied.
     1568  var urlError = function() {
     1569    throw new Error('A "url" property or function must be specified');
     1570  };
     1571
     1572  // Wrap an optional error callback with a fallback error event.
     1573  var wrapError = function(model, options) {
     1574    var error = options.error;
     1575    options.error = function(resp) {
     1576      if (error) error(model, resp, options);
     1577      model.trigger('error', model, resp, options);
     1578    };
     1579  };
     1580
     1581}).call(this);
  • src/wp-includes/js/backbone.min.js

     
    1 // Backbone.js 1.0.0
    2 
    3 // (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc.
    4 // Backbone may be freely distributed under the MIT license.
    5 // For all details and documentation:
    6 // http://backbonejs.org
    7 (function(){var t=this;var e=t.Backbone;var i=[];var r=i.push;var s=i.slice;var n=i.splice;var a;if(typeof exports!=="undefined"){a=exports}else{a=t.Backbone={}}a.VERSION="1.0.0";var h=t._;if(!h&&typeof require!=="undefined")h=require("underscore");a.$=t.jQuery||t.Zepto||t.ender||t.$;a.noConflict=function(){t.Backbone=e;return this};a.emulateHTTP=false;a.emulateJSON=false;var o=a.Events={on:function(t,e,i){if(!l(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,i){if(!l(this,"once",t,[e,i])||!e)return this;var r=this;var s=h.once(function(){r.off(t,s);e.apply(this,arguments)});s._callback=e;return this.on(t,s,i)},off:function(t,e,i){var r,s,n,a,o,u,c,f;if(!this._events||!l(this,"off",t,[e,i]))return this;if(!t&&!e&&!i){this._events={};return this}a=t?[t]:h.keys(this._events);for(o=0,u=a.length;o<u;o++){t=a[o];if(n=this._events[t]){this._events[t]=r=[];if(e||i){for(c=0,f=n.length;c<f;c++){s=n[c];if(e&&e!==s.callback&&e!==s.callback._callback||i&&i!==s.context){r.push(s)}}}if(!r.length)delete this._events[t]}}return this},trigger:function(t){if(!this._events)return this;var e=s.call(arguments,1);if(!l(this,"trigger",t,e))return this;var i=this._events[t];var r=this._events.all;if(i)c(i,e);if(r)c(r,arguments);return this},stopListening:function(t,e,i){var r=this._listeners;if(!r)return this;var s=!e&&!i;if(typeof e==="object")i=this;if(t)(r={})[t._listenerId]=t;for(var n in r){r[n].off(e,i,this);if(s)delete this._listeners[n]}return this}};var u=/\s+/;var l=function(t,e,i,r){if(!i)return true;if(typeof i==="object"){for(var s in i){t[e].apply(t,[s,i[s]].concat(r))}return false}if(u.test(i)){var n=i.split(u);for(var a=0,h=n.length;a<h;a++){t[e].apply(t,[n[a]].concat(r))}return false}return true};var c=function(t,e){var i,r=-1,s=t.length,n=e[0],a=e[1],h=e[2];switch(e.length){case 0:while(++r<s)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<s)(i=t[r]).callback.call(i.ctx,n);return;case 2:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a);return;case 3:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a,h);return;default:while(++r<s)(i=t[r]).callback.apply(i.ctx,e)}};var f={listenTo:"on",listenToOnce:"once"};h.each(f,function(t,e){o[e]=function(e,i,r){var s=this._listeners||(this._listeners={});var n=e._listenerId||(e._listenerId=h.uniqueId("l"));s[n]=e;if(typeof i==="object")r=this;e[t](i,r,this);return this}});o.bind=o.on;o.unbind=o.off;h.extend(a,o);var d=a.Model=function(t,e){var i;var r=t||{};e||(e={});this.cid=h.uniqueId("c");this.attributes={};h.extend(this,h.pick(e,p));if(e.parse)r=this.parse(r,e)||{};if(i=h.result(this,"defaults")){r=h.defaults({},r,i)}this.set(r,e);this.changed={};this.initialize.apply(this,arguments)};var p=["url","urlRoot","collection"];h.extend(d.prototype,o,{changed:null,validationError:null,idAttribute:"id",initialize:function(){},toJSON:function(t){return h.clone(this.attributes)},sync:function(){return a.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return h.escape(this.get(t))},has:function(t){return this.get(t)!=null},set:function(t,e,i){var r,s,n,a,o,u,l,c;if(t==null)return this;if(typeof t==="object"){s=t;i=e}else{(s={})[t]=e}i||(i={});if(!this._validate(s,i))return false;n=i.unset;o=i.silent;a=[];u=this._changing;this._changing=true;if(!u){this._previousAttributes=h.clone(this.attributes);this.changed={}}c=this.attributes,l=this._previousAttributes;if(this.idAttribute in s)this.id=s[this.idAttribute];for(r in s){e=s[r];if(!h.isEqual(c[r],e))a.push(r);if(!h.isEqual(l[r],e)){this.changed[r]=e}else{delete this.changed[r]}n?delete c[r]:c[r]=e}if(!o){if(a.length)this._pending=true;for(var f=0,d=a.length;f<d;f++){this.trigger("change:"+a[f],this,c[a[f]],i)}}if(u)return this;if(!o){while(this._pending){this._pending=false;this.trigger("change",this,i)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,h.extend({},e,{unset:true}))},clear:function(t){var e={};for(var i in this.attributes)e[i]=void 0;return this.set(e,h.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!h.isEmpty(this.changed);return h.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?h.clone(this.changed):false;var e,i=false;var r=this._changing?this._previousAttributes:this.attributes;for(var s in t){if(h.isEqual(r[s],e=t[s]))continue;(i||(i={}))[s]=e}return i},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return h.clone(this._previousAttributes)},fetch:function(t){t=t?h.clone(t):{};if(t.parse===void 0)t.parse=true;var e=this;var i=t.success;t.success=function(r){if(!e.set(e.parse(r,t),t))return false;if(i)i(e,r,t);e.trigger("sync",e,r,t)};R(this,t);return this.sync("read",this,t)},save:function(t,e,i){var r,s,n,a=this.attributes;if(t==null||typeof t==="object"){r=t;i=e}else{(r={})[t]=e}if(r&&(!i||!i.wait)&&!this.set(r,i))return false;i=h.extend({validate:true},i);if(!this._validate(r,i))return false;if(r&&i.wait){this.attributes=h.extend({},a,r)}if(i.parse===void 0)i.parse=true;var o=this;var u=i.success;i.success=function(t){o.attributes=a;var e=o.parse(t,i);if(i.wait)e=h.extend(r||{},e);if(h.isObject(e)&&!o.set(e,i)){return false}if(u)u(o,t,i);o.trigger("sync",o,t,i)};R(this,i);s=this.isNew()?"create":i.patch?"patch":"update";if(s==="patch")i.attrs=r;n=this.sync(s,this,i);if(r&&i.wait)this.attributes=a;return n},destroy:function(t){t=t?h.clone(t):{};var e=this;var i=t.success;var r=function(){e.trigger("destroy",e,e.collection,t)};t.success=function(s){if(t.wait||e.isNew())r();if(i)i(e,s,t);if(!e.isNew())e.trigger("sync",e,s,t)};if(this.isNew()){t.success();return false}R(this,t);var s=this.sync("delete",this,t);if(!t.wait)r();return s},url:function(){var t=h.result(this,"urlRoot")||h.result(this.collection,"url")||U();if(this.isNew())return t;return t+(t.charAt(t.length-1)==="/"?"":"/")+encodeURIComponent(this.id)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return this.id==null},isValid:function(t){return this._validate({},h.extend(t||{},{validate:true}))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=h.extend({},this.attributes,t);var i=this.validationError=this.validate(t,e)||null;if(!i)return true;this.trigger("invalid",this,i,h.extend(e||{},{validationError:i}));return false}});var v=["keys","values","pairs","invert","pick","omit"];h.each(v,function(t){d.prototype[t]=function(){var e=s.call(arguments);e.unshift(this.attributes);return h[t].apply(h,e)}});var g=a.Collection=function(t,e){e||(e={});if(e.url)this.url=e.url;if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,h.extend({silent:true},e))};var m={add:true,remove:true,merge:true};var y={add:true,merge:false,remove:false};h.extend(g.prototype,o,{model:d,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return a.sync.apply(this,arguments)},add:function(t,e){return this.set(t,h.defaults(e||{},y))},remove:function(t,e){t=h.isArray(t)?t.slice():[t];e||(e={});var i,r,s,n;for(i=0,r=t.length;i<r;i++){n=this.get(t[i]);if(!n)continue;delete this._byId[n.id];delete this._byId[n.cid];s=this.indexOf(n);this.models.splice(s,1);this.length--;if(!e.silent){e.index=s;n.trigger("remove",n,this,e)}this._removeReference(n)}return this},set:function(t,e){e=h.defaults(e||{},m);if(e.parse)t=this.parse(t,e);if(!h.isArray(t))t=t?[t]:[];var i,s,a,o,u,l;var c=e.at;var f=this.comparator&&c==null&&e.sort!==false;var d=h.isString(this.comparator)?this.comparator:null;var p=[],v=[],g={};for(i=0,s=t.length;i<s;i++){if(!(a=this._prepareModel(t[i],e)))continue;if(u=this.get(a)){if(e.remove)g[u.cid]=true;if(e.merge){u.set(a.attributes,e);if(f&&!l&&u.hasChanged(d))l=true}}else if(e.add){p.push(a);a.on("all",this._onModelEvent,this);this._byId[a.cid]=a;if(a.id!=null)this._byId[a.id]=a}}if(e.remove){for(i=0,s=this.length;i<s;++i){if(!g[(a=this.models[i]).cid])v.push(a)}if(v.length)this.remove(v,e)}if(p.length){if(f)l=true;this.length+=p.length;if(c!=null){n.apply(this.models,[c,0].concat(p))}else{r.apply(this.models,p)}}if(l)this.sort({silent:true});if(e.silent)return this;for(i=0,s=p.length;i<s;i++){(a=p[i]).trigger("add",a,this,e)}if(l)this.trigger("sort",this,e);return this},reset:function(t,e){e||(e={});for(var i=0,r=this.models.length;i<r;i++){this._removeReference(this.models[i])}e.previousModels=this.models;this._reset();this.add(t,h.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return this},push:function(t,e){t=this._prepareModel(t,e);this.add(t,h.extend({at:this.length},e));return t},pop:function(t){var e=this.at(this.length-1);this.remove(e,t);return e},unshift:function(t,e){t=this._prepareModel(t,e);this.add(t,h.extend({at:0},e));return t},shift:function(t){var e=this.at(0);this.remove(e,t);return e},slice:function(t,e){return this.models.slice(t,e)},get:function(t){if(t==null)return void 0;return this._byId[t.id!=null?t.id:t.cid||t]},at:function(t){return this.models[t]},where:function(t,e){if(h.isEmpty(t))return e?void 0:[];return this[e?"find":"filter"](function(e){for(var i in t){if(t[i]!==e.get(i))return false}return true})},findWhere:function(t){return this.where(t,true)},sort:function(t){if(!this.comparator)throw new Error("Cannot sort a set without a comparator");t||(t={});if(h.isString(this.comparator)||this.comparator.length===1){this.models=this.sortBy(this.comparator,this)}else{this.models.sort(h.bind(this.comparator,this))}if(!t.silent)this.trigger("sort",this,t);return this},sortedIndex:function(t,e,i){e||(e=this.comparator);var r=h.isFunction(e)?e:function(t){return t.get(e)};return h.sortedIndex(this.models,t,r,i)},pluck:function(t){return h.invoke(this.models,"get",t)},fetch:function(t){t=t?h.clone(t):{};if(t.parse===void 0)t.parse=true;var e=t.success;var i=this;t.success=function(r){var s=t.reset?"reset":"set";i[s](r,t);if(e)e(i,r,t);i.trigger("sync",i,r,t)};R(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?h.clone(e):{};if(!(t=this._prepareModel(t,e)))return false;if(!e.wait)this.add(t,e);var i=this;var r=e.success;e.success=function(s){if(e.wait)i.add(t,e);if(r)r(t,s,e)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models)},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(t instanceof d){if(!t.collection)t.collection=this;return t}e||(e={});e.collection=this;var i=new this.model(t,e);if(!i._validate(t,e)){this.trigger("invalid",this,t,e);return false}return i},_removeReference:function(t){if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(e&&t==="change:"+e.idAttribute){delete this._byId[e.previous(e.idAttribute)];if(e.id!=null)this._byId[e.id]=e}this.trigger.apply(this,arguments)}});var _=["forEach","each","map","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","max","min","toArray","size","first","head","take","initial","rest","tail","drop","last","without","indexOf","shuffle","lastIndexOf","isEmpty","chain"];h.each(_,function(t){g.prototype[t]=function(){var e=s.call(arguments);e.unshift(this.models);return h[t].apply(h,e)}});var w=["groupBy","countBy","sortBy"];h.each(w,function(t){g.prototype[t]=function(e,i){var r=h.isFunction(e)?e:function(t){return t.get(e)};return h[t](this.models,r,i)}});var b=a.View=function(t){this.cid=h.uniqueId("view");this._configure(t||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var x=/^(\S+)\s*(.*)$/;var E=["model","collection","el","id","attributes","className","tagName","events"];h.extend(b.prototype,o,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();this.stopListening();return this},setElement:function(t,e){if(this.$el)this.undelegateEvents();this.$el=t instanceof a.$?t:a.$(t);this.el=this.$el[0];if(e!==false)this.delegateEvents();return this},delegateEvents:function(t){if(!(t||(t=h.result(this,"events"))))return this;this.undelegateEvents();for(var e in t){var i=t[e];if(!h.isFunction(i))i=this[t[e]];if(!i)continue;var r=e.match(x);var s=r[1],n=r[2];i=h.bind(i,this);s+=".delegateEvents"+this.cid;if(n===""){this.$el.on(s,i)}else{this.$el.on(s,n,i)}}return this},undelegateEvents:function(){this.$el.off(".delegateEvents"+this.cid);return this},_configure:function(t){if(this.options)t=h.extend({},h.result(this,"options"),t);h.extend(this,h.pick(t,E));this.options=t},_ensureElement:function(){if(!this.el){var t=h.extend({},h.result(this,"attributes"));if(this.id)t.id=h.result(this,"id");if(this.className)t["class"]=h.result(this,"className");var e=a.$("<"+h.result(this,"tagName")+">").attr(t);this.setElement(e,false)}else{this.setElement(h.result(this,"el"),false)}}});a.sync=function(t,e,i){var r=k[t];h.defaults(i||(i={}),{emulateHTTP:a.emulateHTTP,emulateJSON:a.emulateJSON});var s={type:r,dataType:"json"};if(!i.url){s.url=h.result(e,"url")||U()}if(i.data==null&&e&&(t==="create"||t==="update"||t==="patch")){s.contentType="application/json";s.data=JSON.stringify(i.attrs||e.toJSON(i))}if(i.emulateJSON){s.contentType="application/x-www-form-urlencoded";s.data=s.data?{model:s.data}:{}}if(i.emulateHTTP&&(r==="PUT"||r==="DELETE"||r==="PATCH")){s.type="POST";if(i.emulateJSON)s.data._method=r;var n=i.beforeSend;i.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",r);if(n)return n.apply(this,arguments)}}if(s.type!=="GET"&&!i.emulateJSON){s.processData=false}if(s.type==="PATCH"&&window.ActiveXObject&&!(window.external&&window.external.msActiveXFilteringEnabled)){s.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var o=i.xhr=a.ajax(h.extend(s,i));e.trigger("request",e,o,i);return o};var k={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};a.ajax=function(){return a.$.ajax.apply(a.$,arguments)};var S=a.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var $=/\((.*?)\)/g;var T=/(\(\?)?:\w+/g;var H=/\*\w+/g;var A=/[\-{}\[\]+?.,\\\^$|#\s]/g;h.extend(S.prototype,o,{initialize:function(){},route:function(t,e,i){if(!h.isRegExp(t))t=this._routeToRegExp(t);if(h.isFunction(e)){i=e;e=""}if(!i)i=this[e];var r=this;a.history.route(t,function(s){var n=r._extractParameters(t,s);i&&i.apply(r,n);r.trigger.apply(r,["route:"+e].concat(n));r.trigger("route",e,n);a.history.trigger("route",r,e,n)});return this},navigate:function(t,e){a.history.navigate(t,e);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=h.result(this,"routes");var t,e=h.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(A,"\\$&").replace($,"(?:$1)?").replace(T,function(t,e){return e?t:"([^/]+)"}).replace(H,"(.*?)");return new RegExp("^"+t+"$")},_extractParameters:function(t,e){var i=t.exec(e).slice(1);return h.map(i,function(t){return t?decodeURIComponent(t):null})}});var I=a.History=function(){this.handlers=[];h.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var N=/^[#\/]|\s+$/g;var P=/^\/+|\/+$/g;var O=/msie [\w.]+/;var C=/\/$/;I.started=false;h.extend(I.prototype,o,{interval:50,getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=this.location.pathname;var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.substr(i.length)}else{t=this.getHash()}}return t.replace(N,"")},start:function(t){if(I.started)throw new Error("Backbone.history has already been started");I.started=true;this.options=h.extend({},{root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var e=this.getFragment();var i=document.documentMode;var r=O.exec(navigator.userAgent.toLowerCase())&&(!i||i<=7);this.root=("/"+this.root+"/").replace(P,"/");if(r&&this._wantsHashChange){this.iframe=a.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow;this.navigate(e)}if(this._hasPushState){a.$(window).on("popstate",this.checkUrl)}else if(this._wantsHashChange&&"onhashchange"in window&&!r){a.$(window).on("hashchange",this.checkUrl)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}this.fragment=e;var s=this.location;var n=s.pathname.replace(/[^\/]$/,"$&/")===this.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!n){this.fragment=this.getFragment(null,true);this.location.replace(this.root+this.location.search+"#"+this.fragment);return true}else if(this._wantsPushState&&this._hasPushState&&n&&s.hash){this.fragment=this.getHash().replace(N,"");this.history.replaceState({},document.title,this.root+this.fragment+s.search)}if(!this.options.silent)return this.loadUrl()},stop:function(){a.$(window).off("popstate",this.checkUrl).off("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);I.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getFragment(this.getHash(this.iframe))}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()||this.loadUrl(this.getHash())},loadUrl:function(t){var e=this.fragment=this.getFragment(t);var i=h.any(this.handlers,function(t){if(t.route.test(e)){t.callback(e);return true}});return i},navigate:function(t,e){if(!I.started)return false;if(!e||e===true)e={trigger:e};t=this.getFragment(t||"");if(this.fragment===t)return;this.fragment=t;var i=this.root+t;if(this._hasPushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,i)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getFragment(this.getHash(this.iframe))){if(!e.replace)this.iframe.document.open().close();this._updateHash(this.iframe.location,t,e.replace)}}else{return this.location.assign(i)}if(e.trigger)this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});a.history=new I;var j=function(t,e){var i=this;var r;if(t&&h.has(t,"constructor")){r=t.constructor}else{r=function(){return i.apply(this,arguments)}}h.extend(r,i,e);var s=function(){this.constructor=r};s.prototype=i.prototype;r.prototype=new s;if(t)h.extend(r.prototype,t);r.__super__=i.prototype;return r};d.extend=g.extend=S.extend=b.extend=I.extend=j;var U=function(){throw new Error('A "url" property or function must be specified')};var R=function(t,e){var i=e.error;e.error=function(r){if(i)i(t,r,e);t.trigger("error",t,r,e)}}}).call(this);
  • src/wp-includes/js/media-views.js

     
    35663566                                        models = collection.models.slice( modelIndex, singleIndex + 1 );
    35673567                                }
    35683568
    3569                                 selection.add( models ).single( model );
     3569                                selection.add( models );
     3570                                selection.single( model );
    35703571                                return;
    35713572
    35723573                        // If the `method` is set to `toggle`, just flip the selection
    35733574                        // status, regardless of whether the model is the single model.
    35743575                        } else if ( 'toggle' === method ) {
    3575                                 selection[ this.selected() ? 'remove' : 'add' ]( model ).single( model );
     3576                                selection[ this.selected() ? 'remove' : 'add' ]( model );
     3577                                selection.single( model );
    35763578                                return;
    35773579                        }
    35783580
     
    35893591                                // If the model is not selected, run the `method` on the
    35903592                                // selection. By default, we `reset` the selection, but the
    35913593                                // `method` can be set to `add` the model to the selection.
    3592                                 selection[ method ]( model ).single( model );
     3594                                selection[ method ]( model );
     3595                                selection.single( model );
    35933596                        }
    35943597                },
    35953598
     
    39943997                                        // Silently shift the model to its new index.
    39953998                                        collection.remove( model, {
    39963999                                                silent: true
    3997                                         }).add( model, {
     4000                                        });
     4001                                        collection.add( model, {
    39984002                                                silent: true,
    39994003                                                at:     ui.item.index()
    40004004                                        });
  • src/wp-includes/js/underscore.js

     
     1//     Underscore.js 1.6.0
     2//     http://underscorejs.org
     3//     (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
     4//     Underscore may be freely distributed under the MIT license.
     5
     6(function() {
     7
     8  // Baseline setup
     9  // --------------
     10
     11  // Establish the root object, `window` in the browser, or `exports` on the server.
     12  var root = this;
     13
     14  // Save the previous value of the `_` variable.
     15  var previousUnderscore = root._;
     16
     17  // Establish the object that gets returned to break out of a loop iteration.
     18  var breaker = {};
     19
     20  // Save bytes in the minified (but not gzipped) version:
     21  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
     22
     23  // Create quick reference variables for speed access to core prototypes.
     24  var
     25    push             = ArrayProto.push,
     26    slice            = ArrayProto.slice,
     27    concat           = ArrayProto.concat,
     28    toString         = ObjProto.toString,
     29    hasOwnProperty   = ObjProto.hasOwnProperty;
     30
     31  // All **ECMAScript 5** native function implementations that we hope to use
     32  // are declared here.
     33  var
     34    nativeForEach      = ArrayProto.forEach,
     35    nativeMap          = ArrayProto.map,
     36    nativeReduce       = ArrayProto.reduce,
     37    nativeReduceRight  = ArrayProto.reduceRight,
     38    nativeFilter       = ArrayProto.filter,
     39    nativeEvery        = ArrayProto.every,
     40    nativeSome         = ArrayProto.some,
     41    nativeIndexOf      = ArrayProto.indexOf,
     42    nativeLastIndexOf  = ArrayProto.lastIndexOf,
     43    nativeIsArray      = Array.isArray,
     44    nativeKeys         = Object.keys,
     45    nativeBind         = FuncProto.bind;
     46
     47  // Create a safe reference to the Underscore object for use below.
     48  var _ = function(obj) {
     49    if (obj instanceof _) return obj;
     50    if (!(this instanceof _)) return new _(obj);
     51    this._wrapped = obj;
     52  };
     53
     54  // Export the Underscore object for **Node.js**, with
     55  // backwards-compatibility for the old `require()` API. If we're in
     56  // the browser, add `_` as a global object via a string identifier,
     57  // for Closure Compiler "advanced" mode.
     58  if (typeof exports !== 'undefined') {
     59    if (typeof module !== 'undefined' && module.exports) {
     60      exports = module.exports = _;
     61    }
     62    exports._ = _;
     63  } else {
     64    root._ = _;
     65  }
     66
     67  // Current version.
     68  _.VERSION = '1.6.0';
     69
     70  // Collection Functions
     71  // --------------------
     72
     73  // The cornerstone, an `each` implementation, aka `forEach`.
     74  // Handles objects with the built-in `forEach`, arrays, and raw objects.
     75  // Delegates to **ECMAScript 5**'s native `forEach` if available.
     76  var each = _.each = _.forEach = function(obj, iterator, context) {
     77    if (obj == null) return obj;
     78    if (nativeForEach && obj.forEach === nativeForEach) {
     79      obj.forEach(iterator, context);
     80    } else if (obj.length === +obj.length) {
     81      for (var i = 0, length = obj.length; i < length; i++) {
     82        if (iterator.call(context, obj[i], i, obj) === breaker) return;
     83      }
     84    } else {
     85      var keys = _.keys(obj);
     86      for (var i = 0, length = keys.length; i < length; i++) {
     87        if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
     88      }
     89    }
     90    return obj;
     91  };
     92
     93  // Return the results of applying the iterator to each element.
     94  // Delegates to **ECMAScript 5**'s native `map` if available.
     95  _.map = _.collect = function(obj, iterator, context) {
     96    var results = [];
     97    if (obj == null) return results;
     98    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
     99    each(obj, function(value, index, list) {
     100      results.push(iterator.call(context, value, index, list));
     101    });
     102    return results;
     103  };
     104
     105  var reduceError = 'Reduce of empty array with no initial value';
     106
     107  // **Reduce** builds up a single result from a list of values, aka `inject`,
     108  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
     109  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
     110    var initial = arguments.length > 2;
     111    if (obj == null) obj = [];
     112    if (nativeReduce && obj.reduce === nativeReduce) {
     113      if (context) iterator = _.bind(iterator, context);
     114      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
     115    }
     116    each(obj, function(value, index, list) {
     117      if (!initial) {
     118        memo = value;
     119        initial = true;
     120      } else {
     121        memo = iterator.call(context, memo, value, index, list);
     122      }
     123    });
     124    if (!initial) throw new TypeError(reduceError);
     125    return memo;
     126  };
     127
     128  // The right-associative version of reduce, also known as `foldr`.
     129  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
     130  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
     131    var initial = arguments.length > 2;
     132    if (obj == null) obj = [];
     133    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
     134      if (context) iterator = _.bind(iterator, context);
     135      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
     136    }
     137    var length = obj.length;
     138    if (length !== +length) {
     139      var keys = _.keys(obj);
     140      length = keys.length;
     141    }
     142    each(obj, function(value, index, list) {
     143      index = keys ? keys[--length] : --length;
     144      if (!initial) {
     145        memo = obj[index];
     146        initial = true;
     147      } else {
     148        memo = iterator.call(context, memo, obj[index], index, list);
     149      }
     150    });
     151    if (!initial) throw new TypeError(reduceError);
     152    return memo;
     153  };
     154
     155  // Return the first value which passes a truth test. Aliased as `detect`.
     156  _.find = _.detect = function(obj, predicate, context) {
     157    var result;
     158    any(obj, function(value, index, list) {
     159      if (predicate.call(context, value, index, list)) {
     160        result = value;
     161        return true;
     162      }
     163    });
     164    return result;
     165  };
     166
     167  // Return all the elements that pass a truth test.
     168  // Delegates to **ECMAScript 5**'s native `filter` if available.
     169  // Aliased as `select`.
     170  _.filter = _.select = function(obj, predicate, context) {
     171    var results = [];
     172    if (obj == null) return results;
     173    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
     174    each(obj, function(value, index, list) {
     175      if (predicate.call(context, value, index, list)) results.push(value);
     176    });
     177    return results;
     178  };
     179
     180  // Return all the elements for which a truth test fails.
     181  _.reject = function(obj, predicate, context) {
     182    return _.filter(obj, function(value, index, list) {
     183      return !predicate.call(context, value, index, list);
     184    }, context);
     185  };
     186
     187  // Determine whether all of the elements match a truth test.
     188  // Delegates to **ECMAScript 5**'s native `every` if available.
     189  // Aliased as `all`.
     190  _.every = _.all = function(obj, predicate, context) {
     191    predicate || (predicate = _.identity);
     192    var result = true;
     193    if (obj == null) return result;
     194    if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context);
     195    each(obj, function(value, index, list) {
     196      if (!(result = result && predicate.call(context, value, index, list))) return breaker;
     197    });
     198    return !!result;
     199  };
     200
     201  // Determine if at least one element in the object matches a truth test.
     202  // Delegates to **ECMAScript 5**'s native `some` if available.
     203  // Aliased as `any`.
     204  var any = _.some = _.any = function(obj, predicate, context) {
     205    predicate || (predicate = _.identity);
     206    var result = false;
     207    if (obj == null) return result;
     208    if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
     209    each(obj, function(value, index, list) {
     210      if (result || (result = predicate.call(context, value, index, list))) return breaker;
     211    });
     212    return !!result;
     213  };
     214
     215  // Determine if the array or object contains a given value (using `===`).
     216  // Aliased as `include`.
     217  _.contains = _.include = function(obj, target) {
     218    if (obj == null) return false;
     219    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
     220    return any(obj, function(value) {
     221      return value === target;
     222    });
     223  };
     224
     225  // Invoke a method (with arguments) on every item in a collection.
     226  _.invoke = function(obj, method) {
     227    var args = slice.call(arguments, 2);
     228    var isFunc = _.isFunction(method);
     229    return _.map(obj, function(value) {
     230      return (isFunc ? method : value[method]).apply(value, args);
     231    });
     232  };
     233
     234  // Convenience version of a common use case of `map`: fetching a property.
     235  _.pluck = function(obj, key) {
     236    return _.map(obj, _.property(key));
     237  };
     238
     239  // Convenience version of a common use case of `filter`: selecting only objects
     240  // containing specific `key:value` pairs.
     241  _.where = function(obj, attrs) {
     242    return _.filter(obj, _.matches(attrs));
     243  };
     244
     245  // Convenience version of a common use case of `find`: getting the first object
     246  // containing specific `key:value` pairs.
     247  _.findWhere = function(obj, attrs) {
     248    return _.find(obj, _.matches(attrs));
     249  };
     250
     251  // Return the maximum element or (element-based computation).
     252  // Can't optimize arrays of integers longer than 65,535 elements.
     253  // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
     254  _.max = function(obj, iterator, context) {
     255    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
     256      return Math.max.apply(Math, obj);
     257    }
     258    var result = -Infinity, lastComputed = -Infinity;
     259    each(obj, function(value, index, list) {
     260      var computed = iterator ? iterator.call(context, value, index, list) : value;
     261      if (computed > lastComputed) {
     262        result = value;
     263        lastComputed = computed;
     264      }
     265    });
     266    return result;
     267  };
     268
     269  // Return the minimum element (or element-based computation).
     270  _.min = function(obj, iterator, context) {
     271    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
     272      return Math.min.apply(Math, obj);
     273    }
     274    var result = Infinity, lastComputed = Infinity;
     275    each(obj, function(value, index, list) {
     276      var computed = iterator ? iterator.call(context, value, index, list) : value;
     277      if (computed < lastComputed) {
     278        result = value;
     279        lastComputed = computed;
     280      }
     281    });
     282    return result;
     283  };
     284
     285  // Shuffle an array, using the modern version of the
     286  // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
     287  _.shuffle = function(obj) {
     288    var rand;
     289    var index = 0;
     290    var shuffled = [];
     291    each(obj, function(value) {
     292      rand = _.random(index++);
     293      shuffled[index - 1] = shuffled[rand];
     294      shuffled[rand] = value;
     295    });
     296    return shuffled;
     297  };
     298
     299  // Sample **n** random values from a collection.
     300  // If **n** is not specified, returns a single random element.
     301  // The internal `guard` argument allows it to work with `map`.
     302  _.sample = function(obj, n, guard) {
     303    if (n == null || guard) {
     304      if (obj.length !== +obj.length) obj = _.values(obj);
     305      return obj[_.random(obj.length - 1)];
     306    }
     307    return _.shuffle(obj).slice(0, Math.max(0, n));
     308  };
     309
     310  // An internal function to generate lookup iterators.
     311  var lookupIterator = function(value) {
     312    if (value == null) return _.identity;
     313    if (_.isFunction(value)) return value;
     314    return _.property(value);
     315  };
     316
     317  // Sort the object's values by a criterion produced by an iterator.
     318  _.sortBy = function(obj, iterator, context) {
     319    iterator = lookupIterator(iterator);
     320    return _.pluck(_.map(obj, function(value, index, list) {
     321      return {
     322        value: value,
     323        index: index,
     324        criteria: iterator.call(context, value, index, list)
     325      };
     326    }).sort(function(left, right) {
     327      var a = left.criteria;
     328      var b = right.criteria;
     329      if (a !== b) {
     330        if (a > b || a === void 0) return 1;
     331        if (a < b || b === void 0) return -1;
     332      }
     333      return left.index - right.index;
     334    }), 'value');
     335  };
     336
     337  // An internal function used for aggregate "group by" operations.
     338  var group = function(behavior) {
     339    return function(obj, iterator, context) {
     340      var result = {};
     341      iterator = lookupIterator(iterator);
     342      each(obj, function(value, index) {
     343        var key = iterator.call(context, value, index, obj);
     344        behavior(result, key, value);
     345      });
     346      return result;
     347    };
     348  };
     349
     350  // Groups the object's values by a criterion. Pass either a string attribute
     351  // to group by, or a function that returns the criterion.
     352  _.groupBy = group(function(result, key, value) {
     353    _.has(result, key) ? result[key].push(value) : result[key] = [value];
     354  });
     355
     356  // Indexes the object's values by a criterion, similar to `groupBy`, but for
     357  // when you know that your index values will be unique.
     358  _.indexBy = group(function(result, key, value) {
     359    result[key] = value;
     360  });
     361
     362  // Counts instances of an object that group by a certain criterion. Pass
     363  // either a string attribute to count by, or a function that returns the
     364  // criterion.
     365  _.countBy = group(function(result, key) {
     366    _.has(result, key) ? result[key]++ : result[key] = 1;
     367  });
     368
     369  // Use a comparator function to figure out the smallest index at which
     370  // an object should be inserted so as to maintain order. Uses binary search.
     371  _.sortedIndex = function(array, obj, iterator, context) {
     372    iterator = lookupIterator(iterator);
     373    var value = iterator.call(context, obj);
     374    var low = 0, high = array.length;
     375    while (low < high) {
     376      var mid = (low + high) >>> 1;
     377      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
     378    }
     379    return low;
     380  };
     381
     382  // Safely create a real, live array from anything iterable.
     383  _.toArray = function(obj) {
     384    if (!obj) return [];
     385    if (_.isArray(obj)) return slice.call(obj);
     386    if (obj.length === +obj.length) return _.map(obj, _.identity);
     387    return _.values(obj);
     388  };
     389
     390  // Return the number of elements in an object.
     391  _.size = function(obj) {
     392    if (obj == null) return 0;
     393    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
     394  };
     395
     396  // Array Functions
     397  // ---------------
     398
     399  // Get the first element of an array. Passing **n** will return the first N
     400  // values in the array. Aliased as `head` and `take`. The **guard** check
     401  // allows it to work with `_.map`.
     402  _.first = _.head = _.take = function(array, n, guard) {
     403    if (array == null) return void 0;
     404    if ((n == null) || guard) return array[0];
     405    if (n < 0) return [];
     406    return slice.call(array, 0, n);
     407  };
     408
     409  // Returns everything but the last entry of the array. Especially useful on
     410  // the arguments object. Passing **n** will return all the values in
     411  // the array, excluding the last N. The **guard** check allows it to work with
     412  // `_.map`.
     413  _.initial = function(array, n, guard) {
     414    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
     415  };
     416
     417  // Get the last element of an array. Passing **n** will return the last N
     418  // values in the array. The **guard** check allows it to work with `_.map`.
     419  _.last = function(array, n, guard) {
     420    if (array == null) return void 0;
     421    if ((n == null) || guard) return array[array.length - 1];
     422    return slice.call(array, Math.max(array.length - n, 0));
     423  };
     424
     425  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
     426  // Especially useful on the arguments object. Passing an **n** will return
     427  // the rest N values in the array. The **guard**
     428  // check allows it to work with `_.map`.
     429  _.rest = _.tail = _.drop = function(array, n, guard) {
     430    return slice.call(array, (n == null) || guard ? 1 : n);
     431  };
     432
     433  // Trim out all falsy values from an array.
     434  _.compact = function(array) {
     435    return _.filter(array, _.identity);
     436  };
     437
     438  // Internal implementation of a recursive `flatten` function.
     439  var flatten = function(input, shallow, output) {
     440    if (shallow && _.every(input, _.isArray)) {
     441      return concat.apply(output, input);
     442    }
     443    each(input, function(value) {
     444      if (_.isArray(value) || _.isArguments(value)) {
     445        shallow ? push.apply(output, value) : flatten(value, shallow, output);
     446      } else {
     447        output.push(value);
     448      }
     449    });
     450    return output;
     451  };
     452
     453  // Flatten out an array, either recursively (by default), or just one level.
     454  _.flatten = function(array, shallow) {
     455    return flatten(array, shallow, []);
     456  };
     457
     458  // Return a version of the array that does not contain the specified value(s).
     459  _.without = function(array) {
     460    return _.difference(array, slice.call(arguments, 1));
     461  };
     462
     463  // Split an array into two arrays: one whose elements all satisfy the given
     464  // predicate, and one whose elements all do not satisfy the predicate.
     465  _.partition = function(array, predicate) {
     466    var pass = [], fail = [];
     467    each(array, function(elem) {
     468      (predicate(elem) ? pass : fail).push(elem);
     469    });
     470    return [pass, fail];
     471  };
     472
     473  // Produce a duplicate-free version of the array. If the array has already
     474  // been sorted, you have the option of using a faster algorithm.
     475  // Aliased as `unique`.
     476  _.uniq = _.unique = function(array, isSorted, iterator, context) {
     477    if (_.isFunction(isSorted)) {
     478      context = iterator;
     479      iterator = isSorted;
     480      isSorted = false;
     481    }
     482    var initial = iterator ? _.map(array, iterator, context) : array;
     483    var results = [];
     484    var seen = [];
     485    each(initial, function(value, index) {
     486      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
     487        seen.push(value);
     488        results.push(array[index]);
     489      }
     490    });
     491    return results;
     492  };
     493
     494  // Produce an array that contains the union: each distinct element from all of
     495  // the passed-in arrays.
     496  _.union = function() {
     497    return _.uniq(_.flatten(arguments, true));
     498  };
     499
     500  // Produce an array that contains every item shared between all the
     501  // passed-in arrays.
     502  _.intersection = function(array) {
     503    var rest = slice.call(arguments, 1);
     504    return _.filter(_.uniq(array), function(item) {
     505      return _.every(rest, function(other) {
     506        return _.contains(other, item);
     507      });
     508    });
     509  };
     510
     511  // Take the difference between one array and a number of other arrays.
     512  // Only the elements present in just the first array will remain.
     513  _.difference = function(array) {
     514    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
     515    return _.filter(array, function(value){ return !_.contains(rest, value); });
     516  };
     517
     518  // Zip together multiple lists into a single array -- elements that share
     519  // an index go together.
     520  _.zip = function() {
     521    var length = _.max(_.pluck(arguments, 'length').concat(0));
     522    var results = new Array(length);
     523    for (var i = 0; i < length; i++) {
     524      results[i] = _.pluck(arguments, '' + i);
     525    }
     526    return results;
     527  };
     528
     529  // Converts lists into objects. Pass either a single array of `[key, value]`
     530  // pairs, or two parallel arrays of the same length -- one of keys, and one of
     531  // the corresponding values.
     532  _.object = function(list, values) {
     533    if (list == null) return {};
     534    var result = {};
     535    for (var i = 0, length = list.length; i < length; i++) {
     536      if (values) {
     537        result[list[i]] = values[i];
     538      } else {
     539        result[list[i][0]] = list[i][1];
     540      }
     541    }
     542    return result;
     543  };
     544
     545  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
     546  // we need this function. Return the position of the first occurrence of an
     547  // item in an array, or -1 if the item is not included in the array.
     548  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
     549  // If the array is large and already in sort order, pass `true`
     550  // for **isSorted** to use binary search.
     551  _.indexOf = function(array, item, isSorted) {
     552    if (array == null) return -1;
     553    var i = 0, length = array.length;
     554    if (isSorted) {
     555      if (typeof isSorted == 'number') {
     556        i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
     557      } else {
     558        i = _.sortedIndex(array, item);
     559        return array[i] === item ? i : -1;
     560      }
     561    }
     562    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
     563    for (; i < length; i++) if (array[i] === item) return i;
     564    return -1;
     565  };
     566
     567  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
     568  _.lastIndexOf = function(array, item, from) {
     569    if (array == null) return -1;
     570    var hasIndex = from != null;
     571    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
     572      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
     573    }
     574    var i = (hasIndex ? from : array.length);
     575    while (i--) if (array[i] === item) return i;
     576    return -1;
     577  };
     578
     579  // Generate an integer Array containing an arithmetic progression. A port of
     580  // the native Python `range()` function. See
     581  // [the Python documentation](http://docs.python.org/library/functions.html#range).
     582  _.range = function(start, stop, step) {
     583    if (arguments.length <= 1) {
     584      stop = start || 0;
     585      start = 0;
     586    }
     587    step = arguments[2] || 1;
     588
     589    var length = Math.max(Math.ceil((stop - start) / step), 0);
     590    var idx = 0;
     591    var range = new Array(length);
     592
     593    while(idx < length) {
     594      range[idx++] = start;
     595      start += step;
     596    }
     597
     598    return range;
     599  };
     600
     601  // Function (ahem) Functions
     602  // ------------------
     603
     604  // Reusable constructor function for prototype setting.
     605  var ctor = function(){};
     606
     607  // Create a function bound to a given object (assigning `this`, and arguments,
     608  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
     609  // available.
     610  _.bind = function(func, context) {
     611    var args, bound;
     612    if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
     613    if (!_.isFunction(func)) throw new TypeError;
     614    args = slice.call(arguments, 2);
     615    return bound = function() {
     616      if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
     617      ctor.prototype = func.prototype;
     618      var self = new ctor;
     619      ctor.prototype = null;
     620      var result = func.apply(self, args.concat(slice.call(arguments)));
     621      if (Object(result) === result) return result;
     622      return self;
     623    };
     624  };
     625
     626  // Partially apply a function by creating a version that has had some of its
     627  // arguments pre-filled, without changing its dynamic `this` context. _ acts
     628  // as a placeholder, allowing any combination of arguments to be pre-filled.
     629  _.partial = function(func) {
     630    var boundArgs = slice.call(arguments, 1);
     631    return function() {
     632      var position = 0;
     633      var args = boundArgs.slice();
     634      for (var i = 0, length = args.length; i < length; i++) {
     635        if (args[i] === _) args[i] = arguments[position++];
     636      }
     637      while (position < arguments.length) args.push(arguments[position++]);
     638      return func.apply(this, args);
     639    };
     640  };
     641
     642  // Bind a number of an object's methods to that object. Remaining arguments
     643  // are the method names to be bound. Useful for ensuring that all callbacks
     644  // defined on an object belong to it.
     645  _.bindAll = function(obj) {
     646    var funcs = slice.call(arguments, 1);
     647    if (funcs.length === 0) throw new Error('bindAll must be passed function names');
     648    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
     649    return obj;
     650  };
     651
     652  // Memoize an expensive function by storing its results.
     653  _.memoize = function(func, hasher) {
     654    var memo = {};
     655    hasher || (hasher = _.identity);
     656    return function() {
     657      var key = hasher.apply(this, arguments);
     658      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
     659    };
     660  };
     661
     662  // Delays a function for the given number of milliseconds, and then calls
     663  // it with the arguments supplied.
     664  _.delay = function(func, wait) {
     665    var args = slice.call(arguments, 2);
     666    return setTimeout(function(){ return func.apply(null, args); }, wait);
     667  };
     668
     669  // Defers a function, scheduling it to run after the current call stack has
     670  // cleared.
     671  _.defer = function(func) {
     672    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
     673  };
     674
     675  // Returns a function, that, when invoked, will only be triggered at most once
     676  // during a given window of time. Normally, the throttled function will run
     677  // as much as it can, without ever going more than once per `wait` duration;
     678  // but if you'd like to disable the execution on the leading edge, pass
     679  // `{leading: false}`. To disable execution on the trailing edge, ditto.
     680  _.throttle = function(func, wait, options) {
     681    var context, args, result;
     682    var timeout = null;
     683    var previous = 0;
     684    options || (options = {});
     685    var later = function() {
     686      previous = options.leading === false ? 0 : _.now();
     687      timeout = null;
     688      result = func.apply(context, args);
     689      context = args = null;
     690    };
     691    return function() {
     692      var now = _.now();
     693      if (!previous && options.leading === false) previous = now;
     694      var remaining = wait - (now - previous);
     695      context = this;
     696      args = arguments;
     697      if (remaining <= 0) {
     698        clearTimeout(timeout);
     699        timeout = null;
     700        previous = now;
     701        result = func.apply(context, args);
     702        context = args = null;
     703      } else if (!timeout && options.trailing !== false) {
     704        timeout = setTimeout(later, remaining);
     705      }
     706      return result;
     707    };
     708  };
     709
     710  // Returns a function, that, as long as it continues to be invoked, will not
     711  // be triggered. The function will be called after it stops being called for
     712  // N milliseconds. If `immediate` is passed, trigger the function on the
     713  // leading edge, instead of the trailing.
     714  _.debounce = function(func, wait, immediate) {
     715    var timeout, args, context, timestamp, result;
     716
     717    var later = function() {
     718      var last = _.now() - timestamp;
     719      if (last < wait) {
     720        timeout = setTimeout(later, wait - last);
     721      } else {
     722        timeout = null;
     723        if (!immediate) {
     724          result = func.apply(context, args);
     725          context = args = null;
     726        }
     727      }
     728    };
     729
     730    return function() {
     731      context = this;
     732      args = arguments;
     733      timestamp = _.now();
     734      var callNow = immediate && !timeout;
     735      if (!timeout) {
     736        timeout = setTimeout(later, wait);
     737      }
     738      if (callNow) {
     739        result = func.apply(context, args);
     740        context = args = null;
     741      }
     742
     743      return result;
     744    };
     745  };
     746
     747  // Returns a function that will be executed at most one time, no matter how
     748  // often you call it. Useful for lazy initialization.
     749  _.once = function(func) {
     750    var ran = false, memo;
     751    return function() {
     752      if (ran) return memo;
     753      ran = true;
     754      memo = func.apply(this, arguments);
     755      func = null;
     756      return memo;
     757    };
     758  };
     759
     760  // Returns the first function passed as an argument to the second,
     761  // allowing you to adjust arguments, run code before and after, and
     762  // conditionally execute the original function.
     763  _.wrap = function(func, wrapper) {
     764    return _.partial(wrapper, func);
     765  };
     766
     767  // Returns a function that is the composition of a list of functions, each
     768  // consuming the return value of the function that follows.
     769  _.compose = function() {
     770    var funcs = arguments;
     771    return function() {
     772      var args = arguments;
     773      for (var i = funcs.length - 1; i >= 0; i--) {
     774        args = [funcs[i].apply(this, args)];
     775      }
     776      return args[0];
     777    };
     778  };
     779
     780  // Returns a function that will only be executed after being called N times.
     781  _.after = function(times, func) {
     782    return function() {
     783      if (--times < 1) {
     784        return func.apply(this, arguments);
     785      }
     786    };
     787  };
     788
     789  // Object Functions
     790  // ----------------
     791
     792  // Retrieve the names of an object's properties.
     793  // Delegates to **ECMAScript 5**'s native `Object.keys`
     794  _.keys = function(obj) {
     795    if (!_.isObject(obj)) return [];
     796    if (nativeKeys) return nativeKeys(obj);
     797    var keys = [];
     798    for (var key in obj) if (_.has(obj, key)) keys.push(key);
     799    return keys;
     800  };
     801
     802  // Retrieve the values of an object's properties.
     803  _.values = function(obj) {
     804    var keys = _.keys(obj);
     805    var length = keys.length;
     806    var values = new Array(length);
     807    for (var i = 0; i < length; i++) {
     808      values[i] = obj[keys[i]];
     809    }
     810    return values;
     811  };
     812
     813  // Convert an object into a list of `[key, value]` pairs.
     814  _.pairs = function(obj) {
     815    var keys = _.keys(obj);
     816    var length = keys.length;
     817    var pairs = new Array(length);
     818    for (var i = 0; i < length; i++) {
     819      pairs[i] = [keys[i], obj[keys[i]]];
     820    }
     821    return pairs;
     822  };
     823
     824  // Invert the keys and values of an object. The values must be serializable.
     825  _.invert = function(obj) {
     826    var result = {};
     827    var keys = _.keys(obj);
     828    for (var i = 0, length = keys.length; i < length; i++) {
     829      result[obj[keys[i]]] = keys[i];
     830    }
     831    return result;
     832  };
     833
     834  // Return a sorted list of the function names available on the object.
     835  // Aliased as `methods`
     836  _.functions = _.methods = function(obj) {
     837    var names = [];
     838    for (var key in obj) {
     839      if (_.isFunction(obj[key])) names.push(key);
     840    }
     841    return names.sort();
     842  };
     843
     844  // Extend a given object with all the properties in passed-in object(s).
     845  _.extend = function(obj) {
     846    each(slice.call(arguments, 1), function(source) {
     847      if (source) {
     848        for (var prop in source) {
     849          obj[prop] = source[prop];
     850        }
     851      }
     852    });
     853    return obj;
     854  };
     855
     856  // Return a copy of the object only containing the whitelisted properties.
     857  _.pick = function(obj) {
     858    var copy = {};
     859    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
     860    each(keys, function(key) {
     861      if (key in obj) copy[key] = obj[key];
     862    });
     863    return copy;
     864  };
     865
     866   // Return a copy of the object without the blacklisted properties.
     867  _.omit = function(obj) {
     868    var copy = {};
     869    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
     870    for (var key in obj) {
     871      if (!_.contains(keys, key)) copy[key] = obj[key];
     872    }
     873    return copy;
     874  };
     875
     876  // Fill in a given object with default properties.
     877  _.defaults = function(obj) {
     878    each(slice.call(arguments, 1), function(source) {
     879      if (source) {
     880        for (var prop in source) {
     881          if (obj[prop] === void 0) obj[prop] = source[prop];
     882        }
     883      }
     884    });
     885    return obj;
     886  };
     887
     888  // Create a (shallow-cloned) duplicate of an object.
     889  _.clone = function(obj) {
     890    if (!_.isObject(obj)) return obj;
     891    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
     892  };
     893
     894  // Invokes interceptor with the obj, and then returns obj.
     895  // The primary purpose of this method is to "tap into" a method chain, in
     896  // order to perform operations on intermediate results within the chain.
     897  _.tap = function(obj, interceptor) {
     898    interceptor(obj);
     899    return obj;
     900  };
     901
     902  // Internal recursive comparison function for `isEqual`.
     903  var eq = function(a, b, aStack, bStack) {
     904    // Identical objects are equal. `0 === -0`, but they aren't identical.
     905    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
     906    if (a === b) return a !== 0 || 1 / a == 1 / b;
     907    // A strict comparison is necessary because `null == undefined`.
     908    if (a == null || b == null) return a === b;
     909    // Unwrap any wrapped objects.
     910    if (a instanceof _) a = a._wrapped;
     911    if (b instanceof _) b = b._wrapped;
     912    // Compare `[[Class]]` names.
     913    var className = toString.call(a);
     914    if (className != toString.call(b)) return false;
     915    switch (className) {
     916      // Strings, numbers, dates, and booleans are compared by value.
     917      case '[object String]':
     918        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
     919        // equivalent to `new String("5")`.
     920        return a == String(b);
     921      case '[object Number]':
     922        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
     923        // other numeric values.
     924        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
     925      case '[object Date]':
     926      case '[object Boolean]':
     927        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
     928        // millisecond representations. Note that invalid dates with millisecond representations
     929        // of `NaN` are not equivalent.
     930        return +a == +b;
     931      // RegExps are compared by their source patterns and flags.
     932      case '[object RegExp]':
     933        return a.source == b.source &&
     934               a.global == b.global &&
     935               a.multiline == b.multiline &&
     936               a.ignoreCase == b.ignoreCase;
     937    }
     938    if (typeof a != 'object' || typeof b != 'object') return false;
     939    // Assume equality for cyclic structures. The algorithm for detecting cyclic
     940    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
     941    var length = aStack.length;
     942    while (length--) {
     943      // Linear search. Performance is inversely proportional to the number of
     944      // unique nested structures.
     945      if (aStack[length] == a) return bStack[length] == b;
     946    }
     947    // Objects with different constructors are not equivalent, but `Object`s
     948    // from different frames are.
     949    var aCtor = a.constructor, bCtor = b.constructor;
     950    if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
     951                             _.isFunction(bCtor) && (bCtor instanceof bCtor))
     952                        && ('constructor' in a && 'constructor' in b)) {
     953      return false;
     954    }
     955    // Add the first object to the stack of traversed objects.
     956    aStack.push(a);
     957    bStack.push(b);
     958    var size = 0, result = true;
     959    // Recursively compare objects and arrays.
     960    if (className == '[object Array]') {
     961      // Compare array lengths to determine if a deep comparison is necessary.
     962      size = a.length;
     963      result = size == b.length;
     964      if (result) {
     965        // Deep compare the contents, ignoring non-numeric properties.
     966        while (size--) {
     967          if (!(result = eq(a[size], b[size], aStack, bStack))) break;
     968        }
     969      }
     970    } else {
     971      // Deep compare objects.
     972      for (var key in a) {
     973        if (_.has(a, key)) {
     974          // Count the expected number of properties.
     975          size++;
     976          // Deep compare each member.
     977          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
     978        }
     979      }
     980      // Ensure that both objects contain the same number of properties.
     981      if (result) {
     982        for (key in b) {
     983          if (_.has(b, key) && !(size--)) break;
     984        }
     985        result = !size;
     986      }
     987    }
     988    // Remove the first object from the stack of traversed objects.
     989    aStack.pop();
     990    bStack.pop();
     991    return result;
     992  };
     993
     994  // Perform a deep comparison to check if two objects are equal.
     995  _.isEqual = function(a, b) {
     996    return eq(a, b, [], []);
     997  };
     998
     999  // Is a given array, string, or object empty?
     1000  // An "empty" object has no enumerable own-properties.
     1001  _.isEmpty = function(obj) {
     1002    if (obj == null) return true;
     1003    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
     1004    for (var key in obj) if (_.has(obj, key)) return false;
     1005    return true;
     1006  };
     1007
     1008  // Is a given value a DOM element?
     1009  _.isElement = function(obj) {
     1010    return !!(obj && obj.nodeType === 1);
     1011  };
     1012
     1013  // Is a given value an array?
     1014  // Delegates to ECMA5's native Array.isArray
     1015  _.isArray = nativeIsArray || function(obj) {
     1016    return toString.call(obj) == '[object Array]';
     1017  };
     1018
     1019  // Is a given variable an object?
     1020  _.isObject = function(obj) {
     1021    return obj === Object(obj);
     1022  };
     1023
     1024  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
     1025  each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
     1026    _['is' + name] = function(obj) {
     1027      return toString.call(obj) == '[object ' + name + ']';
     1028    };
     1029  });
     1030
     1031  // Define a fallback version of the method in browsers (ahem, IE), where
     1032  // there isn't any inspectable "Arguments" type.
     1033  if (!_.isArguments(arguments)) {
     1034    _.isArguments = function(obj) {
     1035      return !!(obj && _.has(obj, 'callee'));
     1036    };
     1037  }
     1038
     1039  // Optimize `isFunction` if appropriate.
     1040  if (typeof (/./) !== 'function') {
     1041    _.isFunction = function(obj) {
     1042      return typeof obj === 'function';
     1043    };
     1044  }
     1045
     1046  // Is a given object a finite number?
     1047  _.isFinite = function(obj) {
     1048    return isFinite(obj) && !isNaN(parseFloat(obj));
     1049  };
     1050
     1051  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
     1052  _.isNaN = function(obj) {
     1053    return _.isNumber(obj) && obj != +obj;
     1054  };
     1055
     1056  // Is a given value a boolean?
     1057  _.isBoolean = function(obj) {
     1058    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
     1059  };
     1060
     1061  // Is a given value equal to null?
     1062  _.isNull = function(obj) {
     1063    return obj === null;
     1064  };
     1065
     1066  // Is a given variable undefined?
     1067  _.isUndefined = function(obj) {
     1068    return obj === void 0;
     1069  };
     1070
     1071  // Shortcut function for checking if an object has a given property directly
     1072  // on itself (in other words, not on a prototype).
     1073  _.has = function(obj, key) {
     1074    return hasOwnProperty.call(obj, key);
     1075  };
     1076
     1077  // Utility Functions
     1078  // -----------------
     1079
     1080  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
     1081  // previous owner. Returns a reference to the Underscore object.
     1082  _.noConflict = function() {
     1083    root._ = previousUnderscore;
     1084    return this;
     1085  };
     1086
     1087  // Keep the identity function around for default iterators.
     1088  _.identity = function(value) {
     1089    return value;
     1090  };
     1091
     1092  _.constant = function(value) {
     1093    return function () {
     1094      return value;
     1095    };
     1096  };
     1097
     1098  _.property = function(key) {
     1099    return function(obj) {
     1100      return obj[key];
     1101    };
     1102  };
     1103
     1104  // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
     1105  _.matches = function(attrs) {
     1106    return function(obj) {
     1107      if (obj === attrs) return true; //avoid comparing an object to itself.
     1108      for (var key in attrs) {
     1109        if (attrs[key] !== obj[key])
     1110          return false;
     1111      }
     1112      return true;
     1113    }
     1114  };
     1115
     1116  // Run a function **n** times.
     1117  _.times = function(n, iterator, context) {
     1118    var accum = Array(Math.max(0, n));
     1119    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
     1120    return accum;
     1121  };
     1122
     1123  // Return a random integer between min and max (inclusive).
     1124  _.random = function(min, max) {
     1125    if (max == null) {
     1126      max = min;
     1127      min = 0;
     1128    }
     1129    return min + Math.floor(Math.random() * (max - min + 1));
     1130  };
     1131
     1132  // A (possibly faster) way to get the current timestamp as an integer.
     1133  _.now = Date.now || function() { return new Date().getTime(); };
     1134
     1135  // List of HTML entities for escaping.
     1136  var entityMap = {
     1137    escape: {
     1138      '&': '&amp;',
     1139      '<': '&lt;',
     1140      '>': '&gt;',
     1141      '"': '&quot;',
     1142      "'": '&#x27;'
     1143    }
     1144  };
     1145  entityMap.unescape = _.invert(entityMap.escape);
     1146
     1147  // Regexes containing the keys and values listed immediately above.
     1148  var entityRegexes = {
     1149    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
     1150    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
     1151  };
     1152
     1153  // Functions for escaping and unescaping strings to/from HTML interpolation.
     1154  _.each(['escape', 'unescape'], function(method) {
     1155    _[method] = function(string) {
     1156      if (string == null) return '';
     1157      return ('' + string).replace(entityRegexes[method], function(match) {
     1158        return entityMap[method][match];
     1159      });
     1160    };
     1161  });
     1162
     1163  // If the value of the named `property` is a function then invoke it with the
     1164  // `object` as context; otherwise, return it.
     1165  _.result = function(object, property) {
     1166    if (object == null) return void 0;
     1167    var value = object[property];
     1168    return _.isFunction(value) ? value.call(object) : value;
     1169  };
     1170
     1171  // Add your own custom functions to the Underscore object.
     1172  _.mixin = function(obj) {
     1173    each(_.functions(obj), function(name) {
     1174      var func = _[name] = obj[name];
     1175      _.prototype[name] = function() {
     1176        var args = [this._wrapped];
     1177        push.apply(args, arguments);
     1178        return result.call(this, func.apply(_, args));
     1179      };
     1180    });
     1181  };
     1182
     1183  // Generate a unique integer id (unique within the entire client session).
     1184  // Useful for temporary DOM ids.
     1185  var idCounter = 0;
     1186  _.uniqueId = function(prefix) {
     1187    var id = ++idCounter + '';
     1188    return prefix ? prefix + id : id;
     1189  };
     1190
     1191  // By default, Underscore uses ERB-style template delimiters, change the
     1192  // following template settings to use alternative delimiters.
     1193  _.templateSettings = {
     1194    evaluate    : /<%([\s\S]+?)%>/g,
     1195    interpolate : /<%=([\s\S]+?)%>/g,
     1196    escape      : /<%-([\s\S]+?)%>/g
     1197  };
     1198
     1199  // When customizing `templateSettings`, if you don't want to define an
     1200  // interpolation, evaluation or escaping regex, we need one that is
     1201  // guaranteed not to match.
     1202  var noMatch = /(.)^/;
     1203
     1204  // Certain characters need to be escaped so that they can be put into a
     1205  // string literal.
     1206  var escapes = {
     1207    "'":      "'",
     1208    '\\':     '\\',
     1209    '\r':     'r',
     1210    '\n':     'n',
     1211    '\t':     't',
     1212    '\u2028': 'u2028',
     1213    '\u2029': 'u2029'
     1214  };
     1215
     1216  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
     1217
     1218  // JavaScript micro-templating, similar to John Resig's implementation.
     1219  // Underscore templating handles arbitrary delimiters, preserves whitespace,
     1220  // and correctly escapes quotes within interpolated code.
     1221  _.template = function(text, data, settings) {
     1222    var render;
     1223    settings = _.defaults({}, settings, _.templateSettings);
     1224
     1225    // Combine delimiters into one regular expression via alternation.
     1226    var matcher = new RegExp([
     1227      (settings.escape || noMatch).source,
     1228      (settings.interpolate || noMatch).source,
     1229      (settings.evaluate || noMatch).source
     1230    ].join('|') + '|$', 'g');
     1231
     1232    // Compile the template source, escaping string literals appropriately.
     1233    var index = 0;
     1234    var source = "__p+='";
     1235    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
     1236      source += text.slice(index, offset)
     1237        .replace(escaper, function(match) { return '\\' + escapes[match]; });
     1238
     1239      if (escape) {
     1240        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
     1241      }
     1242      if (interpolate) {
     1243        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
     1244      }
     1245      if (evaluate) {
     1246        source += "';\n" + evaluate + "\n__p+='";
     1247      }
     1248      index = offset + match.length;
     1249      return match;
     1250    });
     1251    source += "';\n";
     1252
     1253    // If a variable is not specified, place data values in local scope.
     1254    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
     1255
     1256    source = "var __t,__p='',__j=Array.prototype.join," +
     1257      "print=function(){__p+=__j.call(arguments,'');};\n" +
     1258      source + "return __p;\n";
     1259
     1260    try {
     1261      render = new Function(settings.variable || 'obj', '_', source);
     1262    } catch (e) {
     1263      e.source = source;
     1264      throw e;
     1265    }
     1266
     1267    if (data) return render(data, _);
     1268    var template = function(data) {
     1269      return render.call(this, data, _);
     1270    };
     1271
     1272    // Provide the compiled function source as a convenience for precompilation.
     1273    template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
     1274
     1275    return template;
     1276  };
     1277
     1278  // Add a "chain" function, which will delegate to the wrapper.
     1279  _.chain = function(obj) {
     1280    return _(obj).chain();
     1281  };
     1282
     1283  // OOP
     1284  // ---------------
     1285  // If Underscore is called as a function, it returns a wrapped object that
     1286  // can be used OO-style. This wrapper holds altered versions of all the
     1287  // underscore functions. Wrapped objects may be chained.
     1288
     1289  // Helper function to continue chaining intermediate results.
     1290  var result = function(obj) {
     1291    return this._chain ? _(obj).chain() : obj;
     1292  };
     1293
     1294  // Add all of the Underscore functions to the wrapper object.
     1295  _.mixin(_);
     1296
     1297  // Add all mutator Array functions to the wrapper.
     1298  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
     1299    var method = ArrayProto[name];
     1300    _.prototype[name] = function() {
     1301      var obj = this._wrapped;
     1302      method.apply(obj, arguments);
     1303      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
     1304      return result.call(this, obj);
     1305    };
     1306  });
     1307
     1308  // Add all accessor Array functions to the wrapper.
     1309  each(['concat', 'join', 'slice'], function(name) {
     1310    var method = ArrayProto[name];
     1311    _.prototype[name] = function() {
     1312      return result.call(this, method.apply(this._wrapped, arguments));
     1313    };
     1314  });
     1315
     1316  _.extend(_.prototype, {
     1317
     1318    // Start chaining a wrapped Underscore object.
     1319    chain: function() {
     1320      this._chain = true;
     1321      return this;
     1322    },
     1323
     1324    // Extracts the result from a wrapped and chained object.
     1325    value: function() {
     1326      return this._wrapped;
     1327    }
     1328
     1329  });
     1330
     1331  // AMD registration happens at the end for compatibility with AMD loaders
     1332  // that may not enforce next-turn semantics on modules. Even though general
     1333  // practice for AMD registration is to be anonymous, underscore registers
     1334  // as a named module because, like jQuery, it is a base library that is
     1335  // popular enough to be bundled in a third party lib, but not be part of
     1336  // an AMD load request. Those cases could generate an error when an
     1337  // anonymous define() is called outside of a loader request.
     1338  if (typeof define === 'function' && define.amd) {
     1339    define('underscore', [], function() {
     1340      return _;
     1341    });
     1342  }
     1343}).call(this);
  • src/wp-includes/js/underscore.min.js

     
    1 //     Underscore.js 1.4.4
    2 //     http://underscorejs.org
    3 //     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
    4 //     Underscore may be freely distributed under the MIT license.
    5 (function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,j=i.bind,w=function(n){return n instanceof w?n:this instanceof w?(this._wrapped=n,void 0):new w(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=w),exports._=w):n._=w,w.VERSION="1.4.4";var A=w.each=w.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(w.has(n,a)&&t.call(e,n[a],a,n)===r)return};w.map=w.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e[e.length]=t.call(r,n,u,i)}),e)};var O="Reduce of empty array with no initial value";w.reduce=w.foldl=w.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=w.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},w.reduceRight=w.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=w.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=w.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},w.find=w.detect=function(n,t,r){var e;return E(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},w.filter=w.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&(e[e.length]=n)}),e)},w.reject=function(n,t,r){return w.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},w.every=w.all=function(n,t,e){t||(t=w.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var E=w.some=w.any=function(n,t,e){t||(t=w.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};w.contains=w.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:E(n,function(n){return n===t})},w.invoke=function(n,t){var r=o.call(arguments,2),e=w.isFunction(t);return w.map(n,function(n){return(e?t:n[t]).apply(n,r)})},w.pluck=function(n,t){return w.map(n,function(n){return n[t]})},w.where=function(n,t,r){return w.isEmpty(t)?r?null:[]:w[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},w.findWhere=function(n,t){return w.where(n,t,!0)},w.max=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.max.apply(Math,n);if(!t&&w.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>=e.computed&&(e={value:n,computed:a})}),e.value},w.min=function(n,t,r){if(!t&&w.isArray(n)&&n[0]===+n[0]&&65535>n.length)return Math.min.apply(Math,n);if(!t&&w.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;e.computed>a&&(e={value:n,computed:a})}),e.value},w.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=w.random(r++),e[r-1]=e[t],e[t]=n}),e};var k=function(n){return w.isFunction(n)?n:function(t){return t[n]}};w.sortBy=function(n,t,r){var e=k(t);return w.pluck(w.map(n,function(n,t,u){return{value:n,index:t,criteria:e.call(r,n,t,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index<t.index?-1:1}),"value")};var F=function(n,t,r,e){var u={},i=k(t||w.identity);return A(n,function(t,a){var o=i.call(r,t,a,n);e(u,o,t)}),u};w.groupBy=function(n,t,r){return F(n,t,r,function(n,t,r){(w.has(n,t)?n[t]:n[t]=[]).push(r)})},w.countBy=function(n,t,r){return F(n,t,r,function(n,t){w.has(n,t)||(n[t]=0),n[t]++})},w.sortedIndex=function(n,t,r,e){r=null==r?w.identity:k(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;u>r.call(e,n[o])?i=o+1:a=o}return i},w.toArray=function(n){return n?w.isArray(n)?o.call(n):n.length===+n.length?w.map(n,w.identity):w.values(n):[]},w.size=function(n){return null==n?0:n.length===+n.length?n.length:w.keys(n).length},w.first=w.head=w.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:o.call(n,0,t)},w.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},w.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},w.rest=w.tail=w.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},w.compact=function(n){return w.filter(n,w.identity)};var R=function(n,t,r){return A(n,function(n){w.isArray(n)?t?a.apply(r,n):R(n,t,r):r.push(n)}),r};w.flatten=function(n,t){return R(n,t,[])},w.without=function(n){return w.difference(n,o.call(arguments,1))},w.uniq=w.unique=function(n,t,r,e){w.isFunction(t)&&(e=r,r=t,t=!1);var u=r?w.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:w.contains(a,r))||(a.push(r),i.push(n[e]))}),i},w.union=function(){return w.uniq(c.apply(e,arguments))},w.intersection=function(n){var t=o.call(arguments,1);return w.filter(w.uniq(n),function(n){return w.every(t,function(t){return w.indexOf(t,n)>=0})})},w.difference=function(n){var t=c.apply(e,o.call(arguments,1));return w.filter(n,function(n){return!w.contains(t,n)})},w.zip=function(){for(var n=o.call(arguments),t=w.max(w.pluck(n,"length")),r=Array(t),e=0;t>e;e++)r[e]=w.pluck(n,""+e);return r},w.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},w.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=w.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},w.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},w.range=function(n,t,r){1>=arguments.length&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=Array(e);e>u;)i[u++]=n,n+=r;return i},w.bind=function(n,t){if(n.bind===j&&j)return j.apply(n,o.call(arguments,1));var r=o.call(arguments,2);return function(){return n.apply(t,r.concat(o.call(arguments)))}},w.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},w.bindAll=function(n){var t=o.call(arguments,1);return 0===t.length&&(t=w.functions(n)),A(t,function(t){n[t]=w.bind(n[t],n)}),n},w.memoize=function(n,t){var r={};return t||(t=w.identity),function(){var e=t.apply(this,arguments);return w.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},w.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},w.defer=function(n){return w.delay.apply(w,[n,1].concat(o.call(arguments,1)))},w.throttle=function(n,t){var r,e,u,i,a=0,o=function(){a=new Date,u=null,i=n.apply(r,e)};return function(){var c=new Date,l=t-(c-a);return r=this,e=arguments,0>=l?(clearTimeout(u),u=null,a=c,i=n.apply(r,e)):u||(u=setTimeout(o,l)),i}},w.debounce=function(n,t,r){var e,u;return function(){var i=this,a=arguments,o=function(){e=null,r||(u=n.apply(i,a))},c=r&&!e;return clearTimeout(e),e=setTimeout(o,t),c&&(u=n.apply(i,a)),u}},w.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},w.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},w.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},w.after=function(n,t){return 0>=n?t():function(){return 1>--n?t.apply(this,arguments):void 0}},w.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)w.has(n,r)&&(t[t.length]=r);return t},w.values=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push(n[r]);return t},w.pairs=function(n){var t=[];for(var r in n)w.has(n,r)&&t.push([r,n[r]]);return t},w.invert=function(n){var t={};for(var r in n)w.has(n,r)&&(t[n[r]]=r);return t},w.functions=w.methods=function(n){var t=[];for(var r in n)w.isFunction(n[r])&&t.push(r);return t.sort()},w.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},w.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},w.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)w.contains(r,u)||(t[u]=n[u]);return t},w.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)null==n[r]&&(n[r]=t[r])}),n},w.clone=function(n){return w.isObject(n)?w.isArray(n)?n.slice():w.extend({},n):n},w.tap=function(n,t){return t(n),n};var I=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof w&&(n=n._wrapped),t instanceof w&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==t+"";case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;r.push(n),e.push(t);var a=0,o=!0;if("[object Array]"==u){if(a=n.length,o=a==t.length)for(;a--&&(o=I(n[a],t[a],r,e)););}else{var c=n.constructor,f=t.constructor;if(c!==f&&!(w.isFunction(c)&&c instanceof c&&w.isFunction(f)&&f instanceof f))return!1;for(var s in n)if(w.has(n,s)&&(a++,!(o=w.has(t,s)&&I(n[s],t[s],r,e))))break;if(o){for(s in t)if(w.has(t,s)&&!a--)break;o=!a}}return r.pop(),e.pop(),o};w.isEqual=function(n,t){return I(n,t,[],[])},w.isEmpty=function(n){if(null==n)return!0;if(w.isArray(n)||w.isString(n))return 0===n.length;for(var t in n)if(w.has(n,t))return!1;return!0},w.isElement=function(n){return!(!n||1!==n.nodeType)},w.isArray=x||function(n){return"[object Array]"==l.call(n)},w.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){w["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),w.isArguments(arguments)||(w.isArguments=function(n){return!(!n||!w.has(n,"callee"))}),"function"!=typeof/./&&(w.isFunction=function(n){return"function"==typeof n}),w.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},w.isNaN=function(n){return w.isNumber(n)&&n!=+n},w.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},w.isNull=function(n){return null===n},w.isUndefined=function(n){return n===void 0},w.has=function(n,t){return f.call(n,t)},w.noConflict=function(){return n._=t,this},w.identity=function(n){return n},w.times=function(n,t,r){for(var e=Array(n),u=0;n>u;u++)e[u]=t.call(r,u);return e},w.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var M={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"}};M.unescape=w.invert(M.escape);var S={escape:RegExp("["+w.keys(M.escape).join("")+"]","g"),unescape:RegExp("("+w.keys(M.unescape).join("|")+")","g")};w.each(["escape","unescape"],function(n){w[n]=function(t){return null==t?"":(""+t).replace(S[n],function(t){return M[n][t]})}}),w.result=function(n,t){if(null==n)return null;var r=n[t];return w.isFunction(r)?r.call(n):r},w.mixin=function(n){A(w.functions(n),function(t){var r=w[t]=n[t];w.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(w,n))}})};var N=0;w.uniqueId=function(n){var t=++N+"";return n?n+t:t},w.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var T=/(.)^/,q={"'":"'","\\":"\\","\r":"r","\n":"n","        ":"t","\u2028":"u2028","\u2029":"u2029"},B=/\\|'|\r|\n|\t|\u2028|\u2029/g;w.template=function(n,t,r){var e;r=w.defaults({},r,w.templateSettings);var u=RegExp([(r.escape||T).source,(r.interpolate||T).source,(r.evaluate||T).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(B,function(n){return"\\"+q[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,w);var c=function(n){return e.call(this,n,w)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},w.chain=function(n){return w(n).chain()};var D=function(n){return this._chain?w(n).chain():n};w.mixin(w),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];w.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];w.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),w.extend(w.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}).call(this);
    6  No newline at end of file
  • src/wp-includes/js/wp-backbone.js

     
    340340                // The constructor for the `Views` manager.
    341341                Subviews: wp.Backbone.Subviews,
    342342
    343                 constructor: function() {
     343                constructor: function( options ) {
    344344                        this.views = new this.Subviews( this, this.views );
    345345                        this.on( 'ready', this.ready, this );
    346346
     347                        this.options = options || {};
     348
    347349                        Backbone.View.apply( this, arguments );
    348350                },
    349351
  • src/wp-includes/script-loader.php

     
    270270
    271271        $scripts->add( 'json2', "/wp-includes/js/json2$suffix.js", array(), '2011-02-23');
    272272
    273         $scripts->add( 'underscore', '/wp-includes/js/underscore.min.js', array(), '1.4.4', 1 );
    274         $scripts->add( 'backbone', '/wp-includes/js/backbone.min.js', array('underscore','jquery'), '1.0.0', 1 );
     273        $scripts->add( 'underscore', "/wp-includes/js/underscore$suffix.js", array(), '1.6.0', 1 );
     274        $scripts->add( 'backbone', "/wp-includes/js/backbone$suffix.js", array('underscore','jquery'), '1.1.0', 1 );
    275275
    276276        $scripts->add( 'wp-util', "/wp-includes/js/wp-util$suffix.js", array('underscore', 'jquery'), false, 1 );
    277277        did_action( 'init' ) && $scripts->localize( 'wp-util', '_wpUtilSettings', array(