1 /* vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab: */ |
1 /* vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab: */ |
2 /** |
2 /** |
3 * Backbone-relational.js 0.9.0 |
3 * Backbone-relational.js 0.10.0 |
4 * (c) 2011-2014 Paul Uithol and contributors (https://github.com/PaulUithol/Backbone-relational/graphs/contributors) |
4 * (c) 2011-2014 Paul Uithol and contributors (https://github.com/PaulUithol/Backbone-relational/graphs/contributors) |
5 * |
5 * |
6 * Backbone-relational may be freely distributed under the MIT license; see the accompanying LICENSE.txt. |
6 * Backbone-relational may be freely distributed under the MIT license; see the accompanying LICENSE.txt. |
7 * For details and documentation: https://github.com/PaulUithol/Backbone-relational. |
7 * For details and documentation: https://github.com/PaulUithol/Backbone-relational. |
8 * Depends on Backbone (and thus on Underscore as well): https://github.com/documentcloud/backbone. |
8 * Depends on Backbone (and thus on Underscore as well): https://github.com/documentcloud/backbone. |
1020 if ( attributes instanceof this.relatedModel ) { |
1020 if ( attributes instanceof this.relatedModel ) { |
1021 model = attributes; |
1021 model = attributes; |
1022 } |
1022 } |
1023 else { |
1023 else { |
1024 // If `merge` is true, update models here, instead of during update. |
1024 // If `merge` is true, update models here, instead of during update. |
1025 model = this.relatedModel.findOrCreate( attributes, |
1025 model = ( _.isObject( attributes ) && options.parse && this.relatedModel.prototype.parse ) ? |
1026 _.extend( { merge: true }, options, { create: this.options.createModels } ) |
1026 this.relatedModel.prototype.parse( _.clone( attributes ), options ) : attributes; |
1027 ); |
|
1028 } |
1027 } |
1029 |
1028 |
1030 model && toAdd.push( model ); |
1029 model && toAdd.push( model ); |
1031 }, this ); |
1030 }, this ); |
1032 |
1031 |
1035 } |
1034 } |
1036 else { |
1035 else { |
1037 related = this._prepareCollection(); |
1036 related = this._prepareCollection(); |
1038 } |
1037 } |
1039 |
1038 |
1040 // By now, both `merge` and `parse` will already have been executed for models if they were specified. |
1039 // By now, `parse` will already have been executed just above for models if specified. |
1041 // Disable them to prevent additional calls. |
1040 // Disable to prevent additional calls. |
1042 related.set( toAdd, _.defaults( { merge: false, parse: false }, options ) ); |
1041 related.set( toAdd, _.defaults( { parse: false }, options ) ); |
1043 } |
1042 } |
1044 |
1043 |
1045 // Remove entries from `keyIds` that were already part of the relation (and are thus 'unchanged') |
1044 // Remove entries from `keyIds` that were already part of the relation (and are thus 'unchanged') |
1046 this.keyIds = _.difference( this.keyIds, _.pluck( related.models, 'id' ) ); |
1045 this.keyIds = _.difference( this.keyIds, _.pluck( related.models, 'id' ) ); |
1047 |
1046 |
1236 trigger: function( eventName ) { |
1235 trigger: function( eventName ) { |
1237 if ( eventName.length > 5 && eventName.indexOf( 'change' ) === 0 ) { |
1236 if ( eventName.length > 5 && eventName.indexOf( 'change' ) === 0 ) { |
1238 var dit = this, |
1237 var dit = this, |
1239 args = arguments; |
1238 args = arguments; |
1240 |
1239 |
1241 if ( !Backbone.Relational.eventQueue.isLocked() ) { |
1240 if ( !Backbone.Relational.eventQueue.isBlocked() ) { |
1242 // If we're not in a more complicated nested scenario, fire the change event right away |
1241 // If we're not in a more complicated nested scenario, fire the change event right away |
1243 Backbone.Model.prototype.trigger.apply( dit, args ); |
1242 Backbone.Model.prototype.trigger.apply( dit, args ); |
1244 } |
1243 } |
1245 else { |
1244 else { |
1246 Backbone.Relational.eventQueue.add( function() { |
1245 Backbone.Relational.eventQueue.add( function() { |
1492 return model.fetch( opts ); |
1491 return model.fetch( opts ); |
1493 }, this ); |
1492 }, this ); |
1494 } |
1493 } |
1495 } |
1494 } |
1496 |
1495 |
1497 return $.when.apply( null, requests ).then( |
1496 return this.deferArray(requests).then( |
1498 function() { |
1497 function() { |
1499 return Backbone.Model.prototype.get.call( dit, attr ); |
1498 return Backbone.Model.prototype.get.call( dit, attr ); |
1500 } |
1499 } |
1501 ); |
1500 ); |
|
1501 }, |
|
1502 |
|
1503 deferArray: function(deferArray) { |
|
1504 return Backbone.$.when.apply(null, deferArray); |
1502 }, |
1505 }, |
1503 |
1506 |
1504 set: function( key, value, options ) { |
1507 set: function( key, value, options ) { |
1505 Backbone.Relational.eventQueue.block(); |
1508 Backbone.Relational.eventQueue.block(); |
1506 |
1509 |
1825 * @return {Backbone.RelationalModel} |
1828 * @return {Backbone.RelationalModel} |
1826 */ |
1829 */ |
1827 findOrCreate: function( attributes, options ) { |
1830 findOrCreate: function( attributes, options ) { |
1828 options || ( options = {} ); |
1831 options || ( options = {} ); |
1829 var parsedAttributes = ( _.isObject( attributes ) && options.parse && this.prototype.parse ) ? |
1832 var parsedAttributes = ( _.isObject( attributes ) && options.parse && this.prototype.parse ) ? |
1830 this.prototype.parse( _.clone( attributes ) ) : attributes; |
1833 this.prototype.parse( _.clone( attributes ), options ) : attributes; |
1831 |
1834 |
1832 // If specified, use a custom `find` function to match up existing models to the given attributes. |
1835 // If specified, use a custom `find` function to match up existing models to the given attributes. |
1833 // Otherwise, try to find an instance of 'this' model type in the store |
1836 // Otherwise, try to find an instance of 'this' model type in the store |
1834 var model = this.findModel( parsedAttributes ); |
1837 var model = this.findModel( parsedAttributes ); |
1835 |
1838 |
1972 |
1975 |
1973 return result; |
1976 return result; |
1974 }; |
1977 }; |
1975 |
1978 |
1976 /** |
1979 /** |
1977 * Override 'Backbone.Collection.remove' to trigger 'relational:remove'. |
1980 * Override 'Backbone.Collection._removeModels' to trigger 'relational:remove'. |
1978 */ |
1981 */ |
1979 var remove = Backbone.Collection.prototype.__remove = Backbone.Collection.prototype.remove; |
1982 var _removeModels = Backbone.Collection.prototype.___removeModels = Backbone.Collection.prototype._removeModels; |
1980 Backbone.Collection.prototype.remove = function( models, options ) { |
1983 Backbone.Collection.prototype._removeModels = function( models, options ) { |
1981 // Short-circuit if this Collection doesn't hold RelationalModels |
1984 // Short-circuit if this Collection doesn't hold RelationalModels |
1982 if ( !( this.model.prototype instanceof Backbone.RelationalModel ) ) { |
1985 if ( !( this.model.prototype instanceof Backbone.RelationalModel ) ) { |
1983 return remove.call( this, models, options ); |
1986 return _removeModels.call( this, models, options ); |
1984 } |
1987 } |
1985 |
1988 |
1986 var singular = !_.isArray( models ), |
1989 var toRemove = []; |
1987 toRemove = []; |
|
1988 |
|
1989 models = singular ? ( models ? [ models ] : [] ) : _.clone( models ); |
|
1990 options || ( options = {} ); |
|
1991 |
1990 |
1992 //console.debug('calling remove on coll=%o; models=%o, options=%o', this, models, options ); |
1991 //console.debug('calling remove on coll=%o; models=%o, options=%o', this, models, options ); |
1993 _.each( models, function( model ) { |
1992 _.each( models, function( model ) { |
1994 model = this.get( model ) || ( model && this.get( model.cid ) ); |
1993 model = this.get( model ) || ( model && this.get( model.cid ) ); |
1995 model && toRemove.push( model ); |
1994 model && toRemove.push( model ); |
1996 }, this ); |
1995 }, this ); |
1997 |
1996 |
1998 var result = remove.call( this, singular ? ( toRemove.length ? toRemove[ 0 ] : null ) : toRemove, options ); |
1997 var result = _removeModels.call( this, toRemove, options ); |
1999 |
1998 |
2000 _.each( toRemove, function( model ) { |
1999 _.each( toRemove, function( model ) { |
2001 this.trigger( 'relational:remove', model, this, options ); |
2000 this.trigger( 'relational:remove', model, this, options ); |
2002 }, this ); |
2001 }, this ); |
2003 |
2002 |