Skip to content
This repository
Browse code

Removed Backbone v0.5.3 specific stuff from tests

  • Loading branch information...
commit a67f5583dea7a6754595896427877d75f482ff6b 1 parent b31df8a
Thomas Pedersen authored
1,158 lib/backbone-0.5.3.js
... ... @@ -1,1158 +0,0 @@
1   -// Backbone.js 0.5.3
2   -// (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
3   -// Backbone may be freely distributed under the MIT license.
4   -// For all details and documentation:
5   -// http://documentcloud.github.com/backbone
6   -
7   -(function(){
8   -
9   - // Initial Setup
10   - // -------------
11   -
12   - // Save a reference to the global object.
13   - var root = this;
14   -
15   - // Save the previous value of the `Backbone` variable.
16   - var previousBackbone = root.Backbone;
17   -
18   - // The top-level namespace. All public Backbone classes and modules will
19   - // be attached to this. Exported for both CommonJS and the browser.
20   - var Backbone;
21   - if (typeof exports !== 'undefined') {
22   - Backbone = exports;
23   - } else {
24   - Backbone = root.Backbone = {};
25   - }
26   -
27   - // Current version of the library. Keep in sync with `package.json`.
28   - Backbone.VERSION = '0.5.3';
29   -
30   - // Require Underscore, if we're on the server, and it's not already present.
31   - var _ = root._;
32   - if (!_ && (typeof require !== 'undefined')) _ = require('underscore')._;
33   -
34   - // For Backbone's purposes, jQuery or Zepto owns the `$` variable.
35   - var $ = root.jQuery || root.Zepto;
36   -
37   - // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
38   - // to its previous owner. Returns a reference to this Backbone object.
39   - Backbone.noConflict = function() {
40   - root.Backbone = previousBackbone;
41   - return this;
42   - };
43   -
44   - // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option will
45   - // fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and set a
46   - // `X-Http-Method-Override` header.
47   - Backbone.emulateHTTP = false;
48   -
49   - // Turn on `emulateJSON` to support legacy servers that can't deal with direct
50   - // `application/json` requests ... will encode the body as
51   - // `application/x-www-form-urlencoded` instead and will send the model in a
52   - // form param named `model`.
53   - Backbone.emulateJSON = false;
54   -
55   - // Backbone.Events
56   - // -----------------
57   -
58   - // A module that can be mixed in to *any object* in order to provide it with
59   - // custom events. You may `bind` or `unbind` a callback function to an event;
60   - // `trigger`-ing an event fires all callbacks in succession.
61   - //
62   - // var object = {};
63   - // _.extend(object, Backbone.Events);
64   - // object.bind('expand', function(){ alert('expanded'); });
65   - // object.trigger('expand');
66   - //
67   - Backbone.Events = {
68   -
69   - // Bind an event, specified by a string name, `ev`, to a `callback` function.
70   - // Passing `"all"` will bind the callback to all events fired.
71   - bind : function(ev, callback, context) {
72   - var calls = this._callbacks || (this._callbacks = {});
73   - var list = calls[ev] || (calls[ev] = []);
74   - list.push([callback, context]);
75   - return this;
76   - },
77   -
78   - // Remove one or many callbacks. If `callback` is null, removes all
79   - // callbacks for the event. If `ev` is null, removes all bound callbacks
80   - // for all events.
81   - unbind : function(ev, callback) {
82   - var calls;
83   - if (!ev) {
84   - this._callbacks = {};
85   - } else if (calls = this._callbacks) {
86   - if (!callback) {
87   - calls[ev] = [];
88   - } else {
89   - var list = calls[ev];
90   - if (!list) return this;
91   - for (var i = 0, l = list.length; i < l; i++) {
92   - if (list[i] && callback === list[i][0]) {
93   - list[i] = null;
94   - break;
95   - }
96   - }
97   - }
98   - }
99   - return this;
100   - },
101   -
102   - // Trigger an event, firing all bound callbacks. Callbacks are passed the
103   - // same arguments as `trigger` is, apart from the event name.
104   - // Listening for `"all"` passes the true event name as the first argument.
105   - trigger : function(eventName) {
106   - var list, calls, ev, callback, args;
107   - var both = 2;
108   - if (!(calls = this._callbacks)) return this;
109   - while (both--) {
110   - ev = both ? eventName : 'all';
111   - if (list = calls[ev]) {
112   - for (var i = 0, l = list.length; i < l; i++) {
113   - if (!(callback = list[i])) {
114   - list.splice(i, 1); i--; l--;
115   - } else {
116   - args = both ? Array.prototype.slice.call(arguments, 1) : arguments;
117   - callback[0].apply(callback[1] || this, args);
118   - }
119   - }
120   - }
121   - }
122   - return this;
123   - }
124   -
125   - };
126   -
127   - // Backbone.Model
128   - // --------------
129   -
130   - // Create a new model, with defined attributes. A client id (`cid`)
131   - // is automatically generated and assigned for you.
132   - Backbone.Model = function(attributes, options) {
133   - var defaults;
134   - attributes || (attributes = {});
135   - if (defaults = this.defaults) {
136   - if (_.isFunction(defaults)) defaults = defaults.call(this);
137   - attributes = _.extend({}, defaults, attributes);
138   - }
139   - this.attributes = {};
140   - this._escapedAttributes = {};
141   - this.cid = _.uniqueId('c');
142   - this.set(attributes, {silent : true});
143   - this._changed = false;
144   - this._previousAttributes = _.clone(this.attributes);
145   - if (options && options.collection) this.collection = options.collection;
146   - this.initialize(attributes, options);
147   - };
148   -
149   - // Attach all inheritable methods to the Model prototype.
150   - _.extend(Backbone.Model.prototype, Backbone.Events, {
151   -
152   - // A snapshot of the model's previous attributes, taken immediately
153   - // after the last `"change"` event was fired.
154   - _previousAttributes : null,
155   -
156   - // Has the item been changed since the last `"change"` event?
157   - _changed : false,
158   -
159   - // The default name for the JSON `id` attribute is `"id"`. MongoDB and
160   - // CouchDB users may want to set this to `"_id"`.
161   - idAttribute : 'id',
162   -
163   - // Initialize is an empty function by default. Override it with your own
164   - // initialization logic.
165   - initialize : function(){},
166   -
167   - // Return a copy of the model's `attributes` object.
168   - toJSON : function() {
169   - return _.clone(this.attributes);
170   - },
171   -
172   - // Get the value of an attribute.
173   - get : function(attr) {
174   - return this.attributes[attr];
175   - },
176   -
177   - // Get the HTML-escaped value of an attribute.
178   - escape : function(attr) {
179   - var html;
180   - if (html = this._escapedAttributes[attr]) return html;
181   - var val = this.attributes[attr];
182   - return this._escapedAttributes[attr] = escapeHTML(val == null ? '' : '' + val);
183   - },
184   -
185   - // Returns `true` if the attribute contains a value that is not null
186   - // or undefined.
187   - has : function(attr) {
188   - return this.attributes[attr] != null;
189   - },
190   -
191   - // Set a hash of model attributes on the object, firing `"change"` unless you
192   - // choose to silence it.
193   - set : function(attrs, options) {
194   -
195   - // Extract attributes and options.
196   - options || (options = {});
197   - if (!attrs) return this;
198   - if (attrs.attributes) attrs = attrs.attributes;
199   - var now = this.attributes, escaped = this._escapedAttributes;
200   -
201   - // Run validation.
202   - if (!options.silent && this.validate && !this._performValidation(attrs, options)) return false;
203   -
204   - // Check for changes of `id`.
205   - if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
206   -
207   - // We're about to start triggering change events.
208   - var alreadyChanging = this._changing;
209   - this._changing = true;
210   -
211   - // Update attributes.
212   - for (var attr in attrs) {
213   - var val = attrs[attr];
214   - if (!_.isEqual(now[attr], val)) {
215   - now[attr] = val;
216   - delete escaped[attr];
217   - this._changed = true;
218   - if (!options.silent) this.trigger('change:' + attr, this, val, options);
219   - }
220   - }
221   -
222   - // Fire the `"change"` event, if the model has been changed.
223   - if (!alreadyChanging && !options.silent && this._changed) this.change(options);
224   - this._changing = false;
225   - return this;
226   - },
227   -
228   - // Remove an attribute from the model, firing `"change"` unless you choose
229   - // to silence it. `unset` is a noop if the attribute doesn't exist.
230   - unset : function(attr, options) {
231   - if (!(attr in this.attributes)) return this;
232   - options || (options = {});
233   - var value = this.attributes[attr];
234   -
235   - // Run validation.
236   - var validObj = {};
237   - validObj[attr] = void 0;
238   - if (!options.silent && this.validate && !this._performValidation(validObj, options)) return false;
239   -
240   - // Remove the attribute.
241   - delete this.attributes[attr];
242   - delete this._escapedAttributes[attr];
243   - if (attr == this.idAttribute) delete this.id;
244   - this._changed = true;
245   - if (!options.silent) {
246   - this.trigger('change:' + attr, this, void 0, options);
247   - this.change(options);
248   - }
249   - return this;
250   - },
251   -
252   - // Clear all attributes on the model, firing `"change"` unless you choose
253   - // to silence it.
254   - clear : function(options) {
255   - options || (options = {});
256   - var attr;
257   - var old = this.attributes;
258   -
259   - // Run validation.
260   - var validObj = {};
261   - for (attr in old) validObj[attr] = void 0;
262   - if (!options.silent && this.validate && !this._performValidation(validObj, options)) return false;
263   -
264   - this.attributes = {};
265   - this._escapedAttributes = {};
266   - this._changed = true;
267   - if (!options.silent) {
268   - for (attr in old) {
269   - this.trigger('change:' + attr, this, void 0, options);
270   - }
271   - this.change(options);
272   - }
273   - return this;
274   - },
275   -
276   - // Fetch the model from the server. If the server's representation of the
277   - // model differs from its current attributes, they will be overriden,
278   - // triggering a `"change"` event.
279   - fetch : function(options) {
280   - options || (options = {});
281   - var model = this;
282   - var success = options.success;
283   - options.success = function(resp, status, xhr) {
284   - if (!model.set(model.parse(resp, xhr), options)) return false;
285   - if (success) success(model, resp);
286   - };
287   - options.error = wrapError(options.error, model, options);
288   - return (this.sync || Backbone.sync).call(this, 'read', this, options);
289   - },
290   -
291   - // Set a hash of model attributes, and sync the model to the server.
292   - // If the server returns an attributes hash that differs, the model's
293   - // state will be `set` again.
294   - save : function(attrs, options) {
295   - options || (options = {});
296   - if (attrs && !this.set(attrs, options)) return false;
297   - var model = this;
298   - var success = options.success;
299   - options.success = function(resp, status, xhr) {
300   - if (!model.set(model.parse(resp, xhr), options)) return false;
301   - if (success) success(model, resp, xhr);
302   - };
303   - options.error = wrapError(options.error, model, options);
304   - var method = this.isNew() ? 'create' : 'update';
305   - return (this.sync || Backbone.sync).call(this, method, this, options);
306   - },
307   -
308   - // Destroy this model on the server if it was already persisted. Upon success, the model is removed
309   - // from its collection, if it has one.
310   - destroy : function(options) {
311   - options || (options = {});
312   - if (this.isNew()) return this.trigger('destroy', this, this.collection, options);
313   - var model = this;
314   - var success = options.success;
315   - options.success = function(resp) {
316   - model.trigger('destroy', model, model.collection, options);
317   - if (success) success(model, resp);
318   - };
319   - options.error = wrapError(options.error, model, options);
320   - return (this.sync || Backbone.sync).call(this, 'delete', this, options);
321   - },
322   -
323   - // Default URL for the model's representation on the server -- if you're
324   - // using Backbone's restful methods, override this to change the endpoint
325   - // that will be called.
326   - url : function() {
327   - var base = getUrl(this.collection) || this.urlRoot || urlError();
328   - if (this.isNew()) return base;
329   - return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(this.id);
330   - },
331   -
332   - // **parse** converts a response into the hash of attributes to be `set` on
333   - // the model. The default implementation is just to pass the response along.
334   - parse : function(resp, xhr) {
335   - return resp;
336   - },
337   -
338   - // Create a new model with identical attributes to this one.
339   - clone : function() {
340   - return new this.constructor(this);
341   - },
342   -
343   - // A model is new if it has never been saved to the server, and lacks an id.
344   - isNew : function() {
345   - return this.id == null;
346   - },
347   -
348   - // Call this method to manually fire a `change` event for this model.
349   - // Calling this will cause all objects observing the model to update.
350   - change : function(options) {
351   - this.trigger('change', this, options);
352   - this._previousAttributes = _.clone(this.attributes);
353   - this._changed = false;
354   - },
355   -
356   - // Determine if the model has changed since the last `"change"` event.
357   - // If you specify an attribute name, determine if that attribute has changed.
358   - hasChanged : function(attr) {
359   - if (attr) return this._previousAttributes[attr] != this.attributes[attr];
360   - return this._changed;
361   - },
362   -
363   - // Return an object containing all the attributes that have changed, or false
364   - // if there are no changed attributes. Useful for determining what parts of a
365   - // view need to be updated and/or what attributes need to be persisted to
366   - // the server.
367   - changedAttributes : function(now) {
368   - now || (now = this.attributes);
369   - var old = this._previousAttributes;
370   - var changed = false;
371   - for (var attr in now) {
372   - if (!_.isEqual(old[attr], now[attr])) {
373   - changed = changed || {};
374   - changed[attr] = now[attr];
375   - }
376   - }
377   - return changed;
378   - },
379   -
380   - // Get the previous value of an attribute, recorded at the time the last
381   - // `"change"` event was fired.
382   - previous : function(attr) {
383   - if (!attr || !this._previousAttributes) return null;
384   - return this._previousAttributes[attr];
385   - },
386   -
387   - // Get all of the attributes of the model at the time of the previous
388   - // `"change"` event.
389   - previousAttributes : function() {
390   - return _.clone(this._previousAttributes);
391   - },
392   -
393   - // Run validation against a set of incoming attributes, returning `true`
394   - // if all is well. If a specific `error` callback has been passed,
395   - // call that instead of firing the general `"error"` event.
396   - _performValidation : function(attrs, options) {
397   - var error = this.validate(attrs);
398   - if (error) {
399   - if (options.error) {
400   - options.error(this, error, options);
401   - } else {
402   - this.trigger('error', this, error, options);
403   - }
404   - return false;
405   - }
406   - return true;
407   - }
408   -
409   - });
410   -
411   - // Backbone.Collection
412   - // -------------------
413   -
414   - // Provides a standard collection class for our sets of models, ordered
415   - // or unordered. If a `comparator` is specified, the Collection will maintain
416   - // its models in sort order, as they're added and removed.
417   - Backbone.Collection = function(models, options) {
418   - options || (options = {});
419   - if (options.comparator) this.comparator = options.comparator;
420   - _.bindAll(this, '_onModelEvent', '_removeReference');
421   - this._reset();
422   - if (models) this.reset(models, {silent: true});
423   - this.initialize.apply(this, arguments);
424   - };
425   -
426   - // Define the Collection's inheritable methods.
427   - _.extend(Backbone.Collection.prototype, Backbone.Events, {
428   -
429   - // The default model for a collection is just a **Backbone.Model**.
430   - // This should be overridden in most cases.
431   - model : Backbone.Model,
432   -
433   - // Initialize is an empty function by default. Override it with your own
434   - // initialization logic.
435   - initialize : function(){},
436   -
437   - // The JSON representation of a Collection is an array of the
438   - // models' attributes.
439   - toJSON : function() {
440   - return this.map(function(model){ return model.toJSON(); });
441   - },
442   -
443   - // Add a model, or list of models to the set. Pass **silent** to avoid
444   - // firing the `added` event for every new model.
445   - add : function(models, options) {
446   - if (_.isArray(models)) {
447   - for (var i = 0, l = models.length; i < l; i++) {
448   - this._add(models[i], options);
449   - }
450   - } else {
451   - this._add(models, options);
452   - }
453   - return this;
454   - },
455   -
456   - // Remove a model, or a list of models from the set. Pass silent to avoid
457   - // firing the `removed` event for every model removed.
458   - remove : function(models, options) {
459   - if (_.isArray(models)) {
460   - for (var i = 0, l = models.length; i < l; i++) {
461   - this._remove(models[i], options);
462   - }
463   - } else {
464   - this._remove(models, options);
465   - }
466   - return this;
467   - },
468   -
469   - // Get a model from the set by id.
470   - get : function(id) {
471   - if (id == null) return null;
472   - return this._byId[id.id != null ? id.id : id];
473   - },
474   -
475   - // Get a model from the set by client id.
476   - getByCid : function(cid) {
477   - return cid && this._byCid[cid.cid || cid];
478   - },
479   -
480   - // Get the model at the given index.
481   - at: function(index) {
482   - return this.models[index];
483   - },
484   -
485   - // Force the collection to re-sort itself. You don't need to call this under normal
486   - // circumstances, as the set will maintain sort order as each item is added.
487   - sort : function(options) {
488   - options || (options = {});
489   - if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
490   - this.models = this.sortBy(this.comparator);
491   - if (!options.silent) this.trigger('reset', this, options);
492   - return this;
493   - },
494   -
495   - // Pluck an attribute from each model in the collection.
496   - pluck : function(attr) {
497   - return _.map(this.models, function(model){ return model.get(attr); });
498   - },
499   -
500   - // When you have more items than you want to add or remove individually,
501   - // you can reset the entire set with a new list of models, without firing
502   - // any `added` or `removed` events. Fires `reset` when finished.
503   - reset : function(models, options) {
504   - models || (models = []);
505   - options || (options = {});
506   - this.each(this._removeReference);
507   - this._reset();
508   - this.add(models, {silent: true});
509   - if (!options.silent) this.trigger('reset', this, options);
510   - return this;
511   - },
512   -
513   - // Fetch the default set of models for this collection, resetting the
514   - // collection when they arrive. If `add: true` is passed, appends the
515   - // models to the collection instead of resetting.
516   - fetch : function(options) {
517   - options || (options = {});
518   - var collection = this;
519   - var success = options.success;
520   - options.success = function(resp, status, xhr) {
521   - collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
522   - if (success) success(collection, resp);
523   - };
524   - options.error = wrapError(options.error, collection, options);
525   - return (this.sync || Backbone.sync).call(this, 'read', this, options);
526   - },
527   -
528   - // Create a new instance of a model in this collection. After the model
529   - // has been created on the server, it will be added to the collection.
530   - // Returns the model, or 'false' if validation on a new model fails.
531   - create : function(model, options) {
532   - var coll = this;
533   - options || (options = {});
534   - model = this._prepareModel(model, options);
535   - if (!model) return false;
536   - var success = options.success;
537   - options.success = function(nextModel, resp, xhr) {
538   - coll.add(nextModel, options);
539   - if (success) success(nextModel, resp, xhr);
540   - };
541   - model.save(null, options);
542   - return model;
543   - },
544   -
545   - // **parse** converts a response into a list of models to be added to the
546   - // collection. The default implementation is just to pass it through.
547   - parse : function(resp, xhr) {
548   - return resp;
549   - },
550   -
551   - // Proxy to _'s chain. Can't be proxied the same way the rest of the
552   - // underscore methods are proxied because it relies on the underscore
553   - // constructor.
554   - chain: function () {
555   - return _(this.models).chain();
556   - },
557   -
558   - // Reset all internal state. Called when the collection is reset.
559   - _reset : function(options) {
560   - this.length = 0;
561   - this.models = [];
562   - this._byId = {};
563   - this._byCid = {};
564   - },
565   -
566   - // Prepare a model to be added to this collection
567   - _prepareModel: function(model, options) {
568   - if (!(model instanceof Backbone.Model)) {
569   - var attrs = model;
570   - model = new this.model(attrs, {collection: this});
571   - if (model.validate && !model._performValidation(attrs, options)) model = false;
572   - } else if (!model.collection) {
573   - model.collection = this;
574   - }
575   - return model;
576   - },
577   -
578   - // Internal implementation of adding a single model to the set, updating
579   - // hash indexes for `id` and `cid` lookups.
580   - // Returns the model, or 'false' if validation on a new model fails.
581   - _add : function(model, options) {
582   - options || (options = {});
583   - model = this._prepareModel(model, options);
584   - if (!model) return false;
585   - var already = this.getByCid(model);
586   - if (already) throw new Error(["Can't add the same model to a set twice", already.id]);
587   - this._byId[model.id] = model;
588   - this._byCid[model.cid] = model;
589   - var index = options.at != null ? options.at :
590   - this.comparator ? this.sortedIndex(model, this.comparator) :
591   - this.length;
592   - this.models.splice(index, 0, model);
593   - model.bind('all', this._onModelEvent);
594   - this.length++;
595   - if (!options.silent) model.trigger('add', model, this, options);
596   - return model;
597   - },
598   -
599   - // Internal implementation of removing a single model from the set, updating
600   - // hash indexes for `id` and `cid` lookups.
601   - _remove : function(model, options) {
602   - options || (options = {});
603   - model = this.getByCid(model) || this.get(model);
604   - if (!model) return null;
605   - delete this._byId[model.id];
606   - delete this._byCid[model.cid];
607   - this.models.splice(this.indexOf(model), 1);
608   - this.length--;
609   - if (!options.silent) model.trigger('remove', model, this, options);
610   - this._removeReference(model);
611   - return model;
612   - },
613   -
614   - // Internal method to remove a model's ties to a collection.
615   - _removeReference : function(model) {
616   - if (this == model.collection) {
617   - delete model.collection;
618   - }
619   - model.unbind('all', this._onModelEvent);
620   - },
621   -
622   - // Internal method called every time a model in the set fires an event.
623   - // Sets need to update their indexes when models change ids. All other
624   - // events simply proxy through. "add" and "remove" events that originate
625   - // in other collections are ignored.
626   - _onModelEvent : function(ev, model, collection, options) {
627   - if ((ev == 'add' || ev == 'remove') && collection != this) return;
628   - if (ev == 'destroy') {
629   - this._remove(model, options);
630   - }
631   - if (model && ev === 'change:' + model.idAttribute) {
632   - delete this._byId[model.previous(model.idAttribute)];
633   - this._byId[model.id] = model;
634   - }
635   - this.trigger.apply(this, arguments);
636   - }
637   -
638   - });
639   -
640   - // Underscore methods that we want to implement on the Collection.
641   - var methods = ['forEach', 'each', 'map', 'reduce', 'reduceRight', 'find', 'detect',
642   - 'filter', 'select', 'reject', 'every', 'all', 'some', 'any', 'include',
643   - 'contains', 'invoke', 'max', 'min', 'sortBy', 'sortedIndex', 'toArray', 'size',
644   - 'first', 'rest', 'last', 'without', 'indexOf', 'lastIndexOf', 'isEmpty', 'groupBy'];
645   -
646   - // Mix in each Underscore method as a proxy to `Collection#models`.
647   - _.each(methods, function(method) {
648   - Backbone.Collection.prototype[method] = function() {
649   - return _[method].apply(_, [this.models].concat(_.toArray(arguments)));
650   - };
651   - });
652   -
653   - // Backbone.Router
654   - // -------------------
655   -
656   - // Routers map faux-URLs to actions, and fire events when routes are
657   - // matched. Creating a new one sets its `routes` hash, if not set statically.
658   - Backbone.Router = function(options) {
659   - options || (options = {});
660   - if (options.routes) this.routes = options.routes;
661   - this._bindRoutes();
662   - this.initialize.apply(this, arguments);
663   - };
664   -
665   - // Cached regular expressions for matching named param parts and splatted
666   - // parts of route strings.
667   - var namedParam = /:([\w\d]+)/g;
668   - var splatParam = /\*([\w\d]+)/g;
669   - var escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g;
670   -
671   - // Set up all inheritable **Backbone.Router** properties and methods.
672   - _.extend(Backbone.Router.prototype, Backbone.Events, {
673   -
674   - // Initialize is an empty function by default. Override it with your own
675   - // initialization logic.
676   - initialize : function(){},
677   -
678   - // Manually bind a single named route to a callback. For example:
679   - //
680   - // this.route('search/:query/p:num', 'search', function(query, num) {
681   - // ...
682   - // });
683   - //
684   - route : function(route, name, callback) {
685   - Backbone.history || (Backbone.history = new Backbone.History);
686   - if (!_.isRegExp(route)) route = this._routeToRegExp(route);
687   - Backbone.history.route(route, _.bind(function(fragment) {
688   - var args = this._extractParameters(route, fragment);
689   - callback.apply(this, args);
690   - this.trigger.apply(this, ['route:' + name].concat(args));
691   - }, this));
692   - },
693   -
694   - // Simple proxy to `Backbone.history` to save a fragment into the history.
695   - navigate : function(fragment, triggerRoute) {
696   - Backbone.history.navigate(fragment, triggerRoute);
697   - },
698   -
699   - // Bind all defined routes to `Backbone.history`. We have to reverse the
700   - // order of the routes here to support behavior where the most general
701   - // routes can be defined at the bottom of the route map.
702   - _bindRoutes : function() {
703   - if (!this.routes) return;
704   - var routes = [];
705   - for (var route in this.routes) {
706   - routes.unshift([route, this.routes[route]]);
707   - }
708   - for (var i = 0, l = routes.length; i < l; i++) {
709   - this.route(routes[i][0], routes[i][1], this[routes[i][1]]);
710   - }
711   - },
712   -
713   - // Convert a route string into a regular expression, suitable for matching
714   - // against the current location hash.
715   - _routeToRegExp : function(route) {
716   - route = route.replace(escapeRegExp, "\\$&")
717   - .replace(namedParam, "([^\/]*)")
718   - .replace(splatParam, "(.*?)");
719   - return new RegExp('^' + route + '$');
720   - },
721   -
722   - // Given a route, and a URL fragment that it matches, return the array of
723   - // extracted parameters.
724   - _extractParameters : function(route, fragment) {
725   - return route.exec(fragment).slice(1);
726   - }
727   -
728   - });
729   -
730   - // Backbone.History
731   - // ----------------
732   -
733   - // Handles cross-browser history management, based on URL fragments. If the
734   - // browser does not support `onhashchange`, falls back to polling.
735   - Backbone.History = function() {
736   - this.handlers = [];
737   - _.bindAll(this, 'checkUrl');
738   - };
739   -
740   - // Cached regex for cleaning hashes.
741   - var hashStrip = /^#*/;
742   -
743   - // Cached regex for detecting MSIE.
744   - var isExplorer = /msie [\w.]+/;
745   -
746   - // Has the history handling already been started?
747   - var historyStarted = false;
748   -
749   - // Set up all inheritable **Backbone.History** properties and methods.
750   - _.extend(Backbone.History.prototype, {
751   -
752   - // The default interval to poll for hash changes, if necessary, is
753   - // twenty times a second.
754   - interval: 50,
755   -
756   - // Get the cross-browser normalized URL fragment, either from the URL,
757   - // the hash, or the override.
758   - getFragment : function(fragment, forcePushState) {
759   - if (fragment == null) {
760   - if (this._hasPushState || forcePushState) {
761   - fragment = window.location.pathname;
762   - var search = window.location.search;
763   - if (search) fragment += search;
764   - if (fragment.indexOf(this.options.root) == 0) fragment = fragment.substr(this.options.root.length);
765   - } else {
766   - fragment = window.location.hash;
767   - }
768   - }
769   - return decodeURIComponent(fragment.replace(hashStrip, ''));
770   - },
771   -
772   - // Start the hash change handling, returning `true` if the current URL matches
773   - // an existing route, and `false` otherwise.
774   - start : function(options) {
775   -
776   - // Figure out the initial configuration. Do we need an iframe?
777   - // Is pushState desired ... is it available?
778   - if (historyStarted) throw new Error("Backbone.history has already been started");
779   - this.options = _.extend({}, {root: '/'}, this.options, options);
780   - this._wantsPushState = !!this.options.pushState;
781   - this._hasPushState = !!(this.options.pushState && window.history && window.history.pushState);
782   - var fragment = this.getFragment();
783   - var docMode = document.documentMode;
784   - var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
785   - if (oldIE) {
786   - this.iframe = $('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
787   - this.navigate(fragment);
788   - }
789   -
790   - // Depending on whether we're using pushState or hashes, and whether
791   - // 'onhashchange' is supported, determine how we check the URL state.
792   - if (this._hasPushState) {
793   - $(window).bind('popstate', this.checkUrl);
794   - } else if ('onhashchange' in window && !oldIE) {
795   - $(window).bind('hashchange', this.checkUrl);
796   - } else {
797   - setInterval(this.checkUrl, this.interval);
798   - }
799   -
800   - // Determine if we need to change the base url, for a pushState link
801   - // opened by a non-pushState browser.
802   - this.fragment = fragment;
803   - historyStarted = true;
804   - var loc = window.location;
805   - var atRoot = loc.pathname == this.options.root;
806   - if (this._wantsPushState && !this._hasPushState && !atRoot) {
807   - this.fragment = this.getFragment(null, true);
808   - window.location.replace(this.options.root + '#' + this.fragment);
809   - // Return immediately as browser will do redirect to new url
810   - return true;
811   - } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
812   - this.fragment = loc.hash.replace(hashStrip, '');
813   - window.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root + this.fragment);
814   - }
815   -
816   - if (!this.options.silent) {
817   - return this.loadUrl();
818   - }
819   - },
820   -
821   - // Add a route to be tested when the fragment changes. Routes added later may
822   - // override previous routes.
823   - route : function(route, callback) {
824   - this.handlers.unshift({route : route, callback : callback});
825   - },
826   -
827   - // Checks the current URL to see if it has changed, and if it has,
828   - // calls `loadUrl`, normalizing across the hidden iframe.
829   - checkUrl : function(e) {
830   - var current = this.getFragment();
831   - if (current == this.fragment && this.iframe) current = this.getFragment(this.iframe.location.hash);
832   - if (current == this.fragment || current == decodeURIComponent(this.fragment)) return false;
833   - if (this.iframe) this.navigate(current);
834   - this.loadUrl() || this.loadUrl(window.location.hash);
835   - },
836   -
837   - // Attempt to load the current URL fragment. If a route succeeds with a
838   - // match, returns `true`. If no defined routes matches the fragment,
839   - // returns `false`.
840   - loadUrl : function(fragmentOverride) {
841   - var fragment = this.fragment = this.getFragment(fragmentOverride);
842   - var matched = _.any(this.handlers, function(handler) {
843   - if (handler.route.test(fragment)) {
844   - handler.callback(fragment);
845   - return true;
846   - }
847   - });
848   - return matched;
849   - },
850   -
851   - // Save a fragment into the hash history. You are responsible for properly
852   - // URL-encoding the fragment in advance. This does not trigger
853   - // a `hashchange` event.
854   - navigate : function(fragment, triggerRoute) {
855   - var frag = (fragment || '').replace(hashStrip, '');
856   - if (this.fragment == frag || this.fragment == decodeURIComponent(frag)) return;
857   - if (this._hasPushState) {
858   - var loc = window.location;
859   - if (frag.indexOf(this.options.root) != 0) frag = this.options.root + frag;
860   - this.fragment = frag;
861   - window.history.pushState({}, document.title, loc.protocol + '//' + loc.host + frag);
862   - } else {
863   - window.location.hash = this.fragment = frag;
864   - if (this.iframe && (frag != this.getFragment(this.iframe.location.hash))) {
865   - this.iframe.document.open().close();
866   - this.iframe.location.hash = frag;
867   - }
868   - }
869   - if (triggerRoute) this.loadUrl(fragment);
870   - }
871   -
872   - });
873   -
874   - // Backbone.View
875   - // -------------
876   -
877   - // Creating a Backbone.View creates its initial element outside of the DOM,
878   - // if an existing element is not provided...
879   - Backbone.View = function(options) {
880   - this.cid = _.uniqueId('view');
881   - this._configure(options || {});
882   - this._ensureElement();
883   - this.delegateEvents();
884   - this.initialize.apply(this, arguments);
885   - };
886   -
887   - // Element lookup, scoped to DOM elements within the current view.
888   - // This should be prefered to global lookups, if you're dealing with
889   - // a specific view.
890   - var selectorDelegate = function(selector) {
891   - return $(selector, this.el);
892   - };
893   -
894   - // Cached regex to split keys for `delegate`.
895   - var eventSplitter = /^(\S+)\s*(.*)$/;
896   -
897   - // List of view options to be merged as properties.
898   - var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName'];
899   -
900   - // Set up all inheritable **Backbone.View** properties and methods.
901   - _.extend(Backbone.View.prototype, Backbone.Events, {
902   -
903   - // The default `tagName` of a View's element is `"div"`.
904   - tagName : 'div',
905   -
906   - // Attach the `selectorDelegate` function as the `$` property.
907   - $ : selectorDelegate,
908   -
909   - // Initialize is an empty function by default. Override it with your own
910   - // initialization logic.
911   - initialize : function(){},
912   -
913   - // **render** is the core function that your view should override, in order
914   - // to populate its element (`this.el`), with the appropriate HTML. The
915   - // convention is for **render** to always return `this`.
916   - render : function() {
917   - return this;
918   - },
919   -
920   - // Remove this view from the DOM. Note that the view isn't present in the
921   - // DOM by default, so calling this method may be a no-op.
922   - remove : function() {
923   - $(this.el).remove();
924   - return this;
925   - },
926   -
927   - // For small amounts of DOM Elements, where a full-blown template isn't
928   - // needed, use **make** to manufacture elements, one at a time.
929   - //
930   - // var el = this.make('li', {'class': 'row'}, this.model.escape('title'));
931   - //
932   - make : function(tagName, attributes, content) {
933   - var el = document.createElement(tagName);
934   - if (attributes) $(el).attr(attributes);
935   - if (content) $(el).html(content);
936   - return el;
937   - },
938   -
939   - // Set callbacks, where `this.callbacks` is a hash of
940   - //
941   - // *{"event selector": "callback"}*
942   - //
943   - // {
944   - // 'mousedown .title': 'edit',
945   - // 'click .button': 'save'
946   - // }
947   - //
948   - // pairs. Callbacks will be bound to the view, with `this` set properly.
949   - // Uses event delegation for efficiency.
950   - // Omitting the selector binds the event to `this.el`.
951   - // This only works for delegate-able events: not `focus`, `blur`, and
952   - // not `change`, `submit`, and `reset` in Internet Explorer.
953   - delegateEvents : function(events) {
954   - if (!(events || (events = this.events))) return;
955   - if (_.isFunction(events)) events = events.call(this);
956   - $(this.el).unbind('.delegateEvents' + this.cid);
957   - for (var key in events) {
958   - var method = this[events[key]];
959   - if (!method) throw new Error('Event "' + events[key] + '" does not exist');
960   - var match = key.match(eventSplitter);
961   - var eventName = match[1], selector = match[2];
962   - method = _.bind(method, this);
963   - eventName += '.delegateEvents' + this.cid;
964   - if (selector === '') {
965   - $(this.el).bind(eventName, method);
966   - } else {
967   - $(this.el).delegate(selector, eventName, method);
968   - }
969   - }
970   - },
971   -
972   - // Performs the initial configuration of a View with a set of options.
973   - // Keys with special meaning *(model, collection, id, className)*, are
974   - // attached directly to the view.
975   - _configure : function(options) {
976   - if (this.options) options = _.extend({}, this.options, options);
977   - for (var i = 0, l = viewOptions.length; i < l; i++) {
978   - var attr = viewOptions[i];
979   - if (options[attr]) this[attr] = options[attr];
980   - }
981   - this.options = options;
982   - },
983   -
984   - // Ensure that the View has a DOM element to render into.
985   - // If `this.el` is a string, pass it through `$()`, take the first
986   - // matching element, and re-assign it to `el`. Otherwise, create
987   - // an element from the `id`, `className` and `tagName` proeprties.
988   - _ensureElement : function() {
989   - if (!this.el) {
990   - var attrs = this.attributes || {};
991   - if (this.id) attrs.id = this.id;
992   - if (this.className) attrs['class'] = this.className;
993   - this.el = this.make(this.tagName, attrs);
994   - } else if (_.isString(this.el)) {
995   - this.el = $(this.el).get(0);
996   - }
997   - }
998   -
999   - });
1000   -
1001   - // The self-propagating extend function that Backbone classes use.
1002   - var extend = function (protoProps, classProps) {
1003   - var child = inherits(this, protoProps, classProps);
1004   - child.extend = this.extend;
1005   - return child;
1006   - };
1007   -
1008   - // Set up inheritance for the model, collection, and view.
1009   - Backbone.Model.extend = Backbone.Collection.extend =
1010   - Backbone.Router.extend = Backbone.View.extend = extend;
1011   -
1012   - // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
1013   - var methodMap = {
1014   - 'create': 'POST',
1015   - 'update': 'PUT',
1016   - 'delete': 'DELETE',
1017   - 'read' : 'GET'
1018   - };
1019   -
1020   - // Backbone.sync
1021   - // -------------
1022   -
1023   - // Override this function to change the manner in which Backbone persists
1024   - // models to the server. You will be passed the type of request, and the
1025   - // model in question. By default, uses makes a RESTful Ajax request
1026   - // to the model's `url()`. Some possible customizations could be:
1027   - //
1028   - // * Use `setTimeout` to batch rapid-fire updates into a single request.
1029   - // * Send up the models as XML instead of JSON.
1030   - // * Persist models via WebSockets instead of Ajax.
1031   - //
1032   - // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
1033   - // as `POST`, with a `_method` parameter containing the true HTTP method,
1034   - // as well as all requests with the body as `application/x-www-form-urlencoded` instead of
1035   - // `application/json` with the model in a param named `model`.
1036   - // Useful when interfacing with server-side languages like **PHP** that make
1037   - // it difficult to read the body of `PUT` requests.
1038   - Backbone.sync = function(method, model, options) {
1039   - var type = methodMap[method];
1040   -
1041   - // Default JSON-request options.
1042   - var params = _.extend({
1043   - type: type,
1044   - dataType: 'json'
1045   - }, options);
1046   -
1047   - // Ensure that we have a URL.
1048   - if (!params.url) {
1049   - params.url = getUrl(model) || urlError();
1050   - }
1051   -
1052   - // Ensure that we have the appropriate request data.
1053   - if (!params.data && model && (method == 'create' || method == 'update')) {
1054   - params.contentType = 'application/json';
1055   - params.data = JSON.stringify(model.toJSON());
1056   - }
1057   -
1058   - // For older servers, emulate JSON by encoding the request into an HTML-form.
1059   - if (Backbone.emulateJSON) {
1060   - params.contentType = 'application/x-www-form-urlencoded';
1061   - params.data = params.data ? {model : params.data} : {};
1062   - }
1063   -
1064   - // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
1065   - // And an `X-HTTP-Method-Override` header.
1066   - if (Backbone.emulateHTTP) {
1067   - if (type === 'PUT' || type === 'DELETE') {
1068   - if (Backbone.emulateJSON) params.data._method = type;
1069   - params.type = 'POST';
1070   - params.beforeSend = function(xhr) {
1071   - xhr.setRequestHeader('X-HTTP-Method-Override', type);
1072   - };
1073   - }
1074   - }
1075   -
1076   - // Don't process data on a non-GET request.
1077   - if (params.type !== 'GET' && !Backbone.emulateJSON) {
1078   - params.processData = false;
1079   - }
1080   -
1081   - // Make the request.
1082   - return $.ajax(params);
1083   - };
1084   -
1085   - // Helpers
1086   - // -------
1087   -
1088   - // Shared empty constructor function to aid in prototype-chain creation.
1089   - var ctor = function(){};
1090   -
1091   - // Helper function to correctly set up the prototype chain, for subclasses.
1092   - // Similar to `goog.inherits`, but uses a hash of prototype properties and
1093   - // class properties to be extended.
1094   - var inherits = function(parent, protoProps, staticProps) {
1095   - var child;
1096   -
1097   - // The constructor function for the new subclass is either defined by you
1098   - // (the "constructor" property in your `extend` definition), or defaulted
1099   - // by us to simply call `super()`.
1100   - if (protoProps && protoProps.hasOwnProperty('constructor')) {
1101   - child = protoProps.constructor;
1102   - } else {
1103   - child = function(){ return parent.apply(this, arguments); };
1104   - }
1105   -
1106   - // Inherit class (static) properties from parent.
1107   - _.extend(child, parent);
1108   -
1109   - // Set the prototype chain to inherit from `parent`, without calling
1110   - // `parent`'s constructor function.
1111   - ctor.prototype = parent.prototype;
1112   - child.prototype = new ctor();
1113   -
1114   - // Add prototype properties (instance properties) to the subclass,
1115   - // if supplied.
1116   - if (protoProps) _.extend(child.prototype, protoProps);
1117   -
1118   - // Add static properties to the constructor function, if supplied.
1119   - if (staticProps) _.extend(child, staticProps);
1120   -
1121   - // Correctly set child's `prototype.constructor`.
1122   - child.prototype.constructor = child;
1123   -
1124   - // Set a convenience property in case the parent's prototype is needed later.
1125   - child.__super__ = parent.prototype;
1126   -
1127   - return child;
1128   - };
1129   -
1130   - // Helper function to get a URL from a Model or Collection as a property
1131   - // or as a function.
1132   - var getUrl = function(object) {
1133   - if (!(object && object.url)) return null;
1134   - return _.isFunction(object.url) ? object.url() : object.url;
1135   - };
1136   -
1137   - // Throw an error when a URL is needed, and none is supplied.
1138   - var urlError = function() {
1139   - throw new Error('A "url" property or function must be specified');
1140   - };
1141   -
1142   - // Wrap an optional error callback with a fallback error event.
1143   - var wrapError = function(onError, model, options) {
1144   - return function(resp) {
1145   - if (onError) {
1146   - onError(model, resp, options);
1147   - } else {
1148   - model.trigger('error', model, resp, options);
1149   - }
1150   - };
1151   - };
1152   -
1153   - // Helper function to escape a string for HTML rendering.
1154   - var escapeHTML = function(string) {
1155   - return string.replace(/&(?!\w+;|#\d+;|#x[\da-f]+;)/gi, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#x27;').replace(/\//g,'&#x2F;');
1156   - };
1157   -
1158   -}).call(this);
6 tests/customSelectors.js
@@ -3,11 +3,7 @@ buster.testCase("Overriding default id selector with class", {
3 3 var View = Backbone.View.extend({
4 4 render: function() {
5 5 var html = $('<input type="text" class="name" />');
6   - if(!this.$el) { // Backbone 0.5.3
7   - this.$(this.el).append(html);
8   - } else { // Backbone 0.9.0
9   - this.$el.append(html);
10   - }
  6 + this.$el.append(html);
11 7 }
12 8 });
13 9
6 tests/forceUpdate.js
@@ -39,11 +39,7 @@ buster.testCase("forceUpdate", {
39 39 },
40 40
41 41 "invalid values are set on model": function() {
42   - if(Backbone.VERSION === '0.5.3') {
43   - refute(this.model.set({name:''}, {forceUpdate: true}));
44   - } else {
45   - assert(this.model.set({name:''}, {forceUpdate: true}));
46   - }
  42 + assert(this.model.set({name:''}, {forceUpdate: true}));
47 43 }
48 44 },
49 45
19 tests/general.js
@@ -3,11 +3,7 @@ buster.testCase("Backbone.Validation", {
3 3 var View = Backbone.View.extend({