~ubuntu-branches/debian/sid/wordpress/sid

« back to all changes in this revision

Viewing changes to debian/missing-sources/backbone-1.0.js

  • Committer: Package Import Robot
  • Author(s): Craig Small
  • Date: 2014-04-16 22:48:26 UTC
  • mfrom: (1.2.34)
  • Revision ID: package-import@ubuntu.com-20140416224826-087tu71aw8bjhvmd
Tags: 3.8.3+dfsg-1
New upstream release - fixes Quick Draft tool that broke in 3.8.2

Show diffs side-by-side

added added

removed removed

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