Make WordPress Core

Ticket #26799: 26799-02.patch

File 26799-02.patch, 126.7 KB (added by gcorne, 11 years ago)
  • new file wp-includes/js/backbone.js

    diff --git wp-includes/js/backbone.js wp-includes/js/backbone.js
    new file mode 100644
    index 0000000..f7783c2
    - +  
     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);
  • deleted file wp-includes/js/backbone.min.js

    diff --git wp-includes/js/backbone.min.js wp-includes/js/backbone.min.js
    deleted file mode 100644
    index 8555eca..0000000
    + -  
    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);
  • wp-includes/js/media-views.js

    diff --git wp-includes/js/media-views.js wp-includes/js/media-views.js
    index 3ac04c5..ba31eb3 100644
     
    26372637                                else
    26382638                                        models = collection.models.slice( modelIndex, singleIndex + 1 );
    26392639
    2640                                 selection.add( models ).single( model );
     2640                                selection.add( models );
     2641                                selection.single( model );
    26412642                                return;
    26422643
    26432644                        // If the `method` is set to `toggle`, just flip the selection
    26442645                        // status, regardless of whether the model is the single model.
    26452646                        } else if ( 'toggle' === method ) {
    2646                                 selection[ this.selected() ? 'remove' : 'add' ]( model ).single( model );
     2647                                selection[ this.selected() ? 'remove' : 'add' ]( model );
     2648                                selection.single( model );
    26472649                                return;
    26482650                        }
    26492651
     
    26592661                                // If the model is not selected, run the `method` on the
    26602662                                // selection. By default, we `reset` the selection, but the
    26612663                                // `method` can be set to `add` the model to the selection.
    2662                                 selection[ method ]( model ).single( model );
     2664                                selection[ method ]( model );
     2665                                selection.single( model );
    26632666                        }
    26642667                },
    26652668
     
    29932996                                        // Silently shift the model to its new index.
    29942997                                        collection.remove( model, {
    29952998                                                silent: true
    2996                                         }).add( model, {
     2999                                        });
     3000                                        collection.add( model, {
    29973001                                                silent: true,
    29983002                                                at:     ui.item.index()
    29993003                                        });
     
    39583962                        this.$('img').attr( 'src', this.model.get('url') );
    39593963                }
    39603964        });
    3961 }(jQuery));
    3962  No newline at end of file
     3965}(jQuery));
  • new file wp-includes/js/underscore.js

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

    diff --git wp-includes/js/wp-backbone.js wp-includes/js/wp-backbone.js
    index 9e0041d..0db9161 100644
    window.wp = window.wp || {}; 
    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
  • wp-includes/script-loader.php

    diff --git wp-includes/script-loader.php wp-includes/script-loader.php
    index 9be72e3..fe147a9 100644
    function wp_default_scripts( &$scripts ) { 
    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.5.2', 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(