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