42 |
42 |
43 // Create a local reference to a common array method we'll want to use later. |
43 // Create a local reference to a common array method we'll want to use later. |
44 var slice = Array.prototype.slice; |
44 var slice = Array.prototype.slice; |
45 |
45 |
46 // Current version of the library. Keep in sync with `package.json`. |
46 // Current version of the library. Keep in sync with `package.json`. |
47 Backbone.VERSION = '1.4.1'; |
47 Backbone.VERSION = '1.5.0'; |
48 |
48 |
49 // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns |
49 // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns |
50 // the `$` variable. |
50 // the `$` variable. |
51 Backbone.$ = $; |
51 Backbone.$ = $; |
52 |
52 |
402 this.cid = _.uniqueId(this.cidPrefix); |
402 this.cid = _.uniqueId(this.cidPrefix); |
403 this.attributes = {}; |
403 this.attributes = {}; |
404 if (options.collection) this.collection = options.collection; |
404 if (options.collection) this.collection = options.collection; |
405 if (options.parse) attrs = this.parse(attrs, options) || {}; |
405 if (options.parse) attrs = this.parse(attrs, options) || {}; |
406 var defaults = _.result(this, 'defaults'); |
406 var defaults = _.result(this, 'defaults'); |
|
407 |
|
408 // Just _.defaults would work fine, but the additional _.extends |
|
409 // is in there for historical reasons. See #3843. |
407 attrs = _.defaults(_.extend({}, defaults, attrs), defaults); |
410 attrs = _.defaults(_.extend({}, defaults, attrs), defaults); |
|
411 |
408 this.set(attrs, options); |
412 this.set(attrs, options); |
409 this.changed = {}; |
413 this.changed = {}; |
410 this.initialize.apply(this, arguments); |
414 this.initialize.apply(this, arguments); |
411 }; |
415 }; |
412 |
416 |
1078 if (!model) return false; |
1082 if (!model) return false; |
1079 if (!wait) this.add(model, options); |
1083 if (!wait) this.add(model, options); |
1080 var collection = this; |
1084 var collection = this; |
1081 var success = options.success; |
1085 var success = options.success; |
1082 options.success = function(m, resp, callbackOpts) { |
1086 options.success = function(m, resp, callbackOpts) { |
1083 if (wait) collection.add(m, callbackOpts); |
1087 if (wait) { |
|
1088 m.off('error', this._forwardPristineError, this); |
|
1089 collection.add(m, callbackOpts); |
|
1090 } |
1084 if (success) success.call(callbackOpts.context, m, resp, callbackOpts); |
1091 if (success) success.call(callbackOpts.context, m, resp, callbackOpts); |
1085 }; |
1092 }; |
|
1093 // In case of wait:true, our collection is not listening to any |
|
1094 // of the model's events yet, so it will not forward the error |
|
1095 // event. In this special case, we need to listen for it |
|
1096 // separately and handle the event just once. |
|
1097 // (The reason we don't need to do this for the sync event is |
|
1098 // in the success handler above: we add the model first, which |
|
1099 // causes the collection to listen, and then invoke the callback |
|
1100 // that triggers the event.) |
|
1101 if (wait) { |
|
1102 model.once('error', this._forwardPristineError, this); |
|
1103 } |
1086 model.save(null, options); |
1104 model.save(null, options); |
1087 return model; |
1105 return model; |
1088 }, |
1106 }, |
1089 |
1107 |
1090 // **parse** converts a response into a list of models to be added to the |
1108 // **parse** converts a response into a list of models to be added to the |
1175 } |
1193 } |
1176 |
1194 |
1177 removed.push(model); |
1195 removed.push(model); |
1178 this._removeReference(model, options); |
1196 this._removeReference(model, options); |
1179 } |
1197 } |
|
1198 if (models.length > 0 && !options.silent) delete options.index; |
1180 return removed; |
1199 return removed; |
1181 }, |
1200 }, |
1182 |
1201 |
1183 // Method for checking whether an object should be considered a model for |
1202 // Method for checking whether an object should be considered a model for |
1184 // the purposes of adding to the collection. |
1203 // the purposes of adding to the collection. |
1217 if (prevId != null) delete this._byId[prevId]; |
1236 if (prevId != null) delete this._byId[prevId]; |
1218 if (id != null) this._byId[id] = model; |
1237 if (id != null) this._byId[id] = model; |
1219 } |
1238 } |
1220 } |
1239 } |
1221 this.trigger.apply(this, arguments); |
1240 this.trigger.apply(this, arguments); |
1222 } |
1241 }, |
1223 |
1242 |
|
1243 // Internal callback method used in `create`. It serves as a |
|
1244 // stand-in for the `_onModelEvent` method, which is not yet bound |
|
1245 // during the `wait` period of the `create` call. We still want to |
|
1246 // forward any `'error'` event at the end of the `wait` period, |
|
1247 // hence a customized callback. |
|
1248 _forwardPristineError: function(model, collection, options) { |
|
1249 // Prevent double forward if the model was already in the |
|
1250 // collection before the call to `create`. |
|
1251 if (this.has(model)) return; |
|
1252 this._onModelEvent('error', model, collection, options); |
|
1253 } |
1224 }); |
1254 }); |
1225 |
1255 |
1226 // Defining an @@iterator method implements JavaScript's Iterable protocol. |
1256 // Defining an @@iterator method implements JavaScript's Iterable protocol. |
1227 // In modern ES2015 browsers, this value is found at Symbol.iterator. |
1257 // In modern ES2015 browsers, this value is found at Symbol.iterator. |
1228 /* global Symbol */ |
1258 /* global Symbol */ |
1844 |
1874 |
1845 // Figure out the initial configuration. Do we need an iframe? |
1875 // Figure out the initial configuration. Do we need an iframe? |
1846 // Is pushState desired ... is it available? |
1876 // Is pushState desired ... is it available? |
1847 this.options = _.extend({root: '/'}, this.options, options); |
1877 this.options = _.extend({root: '/'}, this.options, options); |
1848 this.root = this.options.root; |
1878 this.root = this.options.root; |
|
1879 this._trailingSlash = this.options.trailingSlash; |
1849 this._wantsHashChange = this.options.hashChange !== false; |
1880 this._wantsHashChange = this.options.hashChange !== false; |
1850 this._hasHashChange = 'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7); |
1881 this._hasHashChange = 'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7); |
1851 this._useHashChange = this._wantsHashChange && this._hasHashChange; |
1882 this._useHashChange = this._wantsHashChange && this._hasHashChange; |
1852 this._wantsPushState = !!this.options.pushState; |
1883 this._wantsPushState = !!this.options.pushState; |
1853 this._hasPushState = !!(this.history && this.history.pushState); |
1884 this._hasPushState = !!(this.history && this.history.pushState); |
1986 if (!options || options === true) options = {trigger: !!options}; |
2017 if (!options || options === true) options = {trigger: !!options}; |
1987 |
2018 |
1988 // Normalize the fragment. |
2019 // Normalize the fragment. |
1989 fragment = this.getFragment(fragment || ''); |
2020 fragment = this.getFragment(fragment || ''); |
1990 |
2021 |
1991 // Don't include a trailing slash on the root. |
2022 // Strip trailing slash on the root unless _trailingSlash is true |
1992 var rootPath = this.root; |
2023 var rootPath = this.root; |
1993 if (fragment === '' || fragment.charAt(0) === '?') { |
2024 if (!this._trailingSlash && (fragment === '' || fragment.charAt(0) === '?')) { |
1994 rootPath = rootPath.slice(0, -1) || '/'; |
2025 rootPath = rootPath.slice(0, -1) || '/'; |
1995 } |
2026 } |
1996 var url = rootPath + fragment; |
2027 var url = rootPath + fragment; |
1997 |
2028 |
1998 // Strip the fragment of the query and hash for matching. |
2029 // Strip the fragment of the query and hash for matching. |