Ticket #26799: 26799-01.patch
File 26799-01.patch, 126.6 KB (added by , 11 years ago) |
---|
-
wp-admin/js/revisions.js
diff --git wp-admin/js/revisions.js wp-admin/js/revisions.js index 26b22cf..f4a4c76 100644
window.wp = window.wp || {}; 1042 1042 className: 'revisions-diff', 1043 1043 template: wp.template('revisions-diff'), 1044 1044 1045 initialize: function( options ) { 1046 this.options = options || {}; 1047 } 1048 1045 1049 // Generate the options to be passed to the template. 1046 1050 prepare: function() { 1047 1051 return _.extend({ fields: this.model.fields.toJSON() }, this.options ); -
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.02 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.org7 (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..06d3395 100644
877 877 if ( options && options.controller ) 878 878 this.controller = options.controller; 879 879 880 this.options = options || {}; 881 880 882 wp.Backbone.View.apply( this, arguments ); 881 883 }, 882 884 … … 2637 2639 else 2638 2640 models = collection.models.slice( modelIndex, singleIndex + 1 ); 2639 2641 2640 selection.add( models ).single( model ); 2642 selection.add( models ); 2643 selection.single( model ); 2641 2644 return; 2642 2645 2643 2646 // If the `method` is set to `toggle`, just flip the selection 2644 2647 // status, regardless of whether the model is the single model. 2645 2648 } else if ( 'toggle' === method ) { 2646 selection[ this.selected() ? 'remove' : 'add' ]( model ).single( model ); 2649 selection[ this.selected() ? 'remove' : 'add' ]( model ); 2650 selection.single( model ); 2647 2651 return; 2648 2652 } 2649 2653 … … 2659 2663 // If the model is not selected, run the `method` on the 2660 2664 // selection. By default, we `reset` the selection, but the 2661 2665 // `method` can be set to `add` the model to the selection. 2662 selection[ method ]( model ).single( model ); 2666 selection[ method ]( model ); 2667 selection.single( model ); 2663 2668 } 2664 2669 }, 2665 2670 … … 3958 3963 this.$('img').attr( 'src', this.model.get('url') ); 3959 3964 } 3960 3965 }); 3961 }(jQuery)); 3962 No newline at end of file 3966 }(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 '&': '&', 1084 '<': '<', 1085 '>': '>', 1086 '"': '"', 1087 "'": ''' 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/script-loader.php
diff --git wp-includes/script-loader.php wp-includes/script-loader.php index 9be72e3..fe147a9 100644
function wp_default_scripts( &$scripts ) { 270 270 271 271 $scripts->add( 'json2', "/wp-includes/js/json2$suffix.js", array(), '2011-02-23'); 272 272 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 ); 275 275 276 276 $scripts->add( 'wp-util', "/wp-includes/js/wp-util$suffix.js", array('underscore', 'jquery'), false, 1 ); 277 277 did_action( 'init' ) && $scripts->localize( 'wp-util', '_wpUtilSettings', array(