backbone-relational-rails 0.8.6 → 0.8.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/backbone-relational-rails/version.rb +1 -1
- data/vendor/assets/javascripts/backbone-relational.js +186 -120
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 383e74d8144f6aa8fde07a6dcfbd2a924559c5b5
|
4
|
+
data.tar.gz: 4971d471d1dc3134765e99980ec3adcd68e6638a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be19e63711b13f668de3b1f0bc4d9308ad3a1570c7c52dd7568bf58c9f874f8ffb6be71b916e034830a07d3882fe3b5e1f7ee9437b06f601521b237edbc40215
|
7
|
+
data.tar.gz: 92937ff96c6069ac98c879176a8983fbef8dfe3cd7fcd3972260c1bed2aeb2872df2ca5a8e4b9d0dcf27483ffe630030bf5f86b36b9996d09fa4a4292405efc8
|
data/README.md
CHANGED
@@ -18,7 +18,7 @@ Add the following directive to your Javascript manifest file (application.js):
|
|
18
18
|
|
19
19
|
## Versioning
|
20
20
|
|
21
|
-
backbone-relational-rails 0.8.
|
21
|
+
backbone-relational-rails 0.8.7 == Backbone-relational 0.8.7
|
22
22
|
|
23
23
|
Every attempt is made to mirror the currently shipping Backbone-relational version number wherever possible.
|
24
24
|
The major, minor, and patch version numbers will always represent the Backbone-relational version. Should a gem
|
@@ -1,11 +1,49 @@
|
|
1
1
|
/* vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab: */
|
2
2
|
/**
|
3
|
-
* Backbone-relational.js 0.8.
|
3
|
+
* Backbone-relational.js 0.8.7
|
4
4
|
* (c) 2011-2013 Paul Uithol and contributors (https://github.com/PaulUithol/Backbone-relational/graphs/contributors)
|
5
|
-
*
|
5
|
+
*
|
6
6
|
* Backbone-relational may be freely distributed under the MIT license; see the accompanying LICENSE.txt.
|
7
7
|
* For details and documentation: https://github.com/PaulUithol/Backbone-relational.
|
8
8
|
* Depends on Backbone (and thus on Underscore as well): https://github.com/documentcloud/backbone.
|
9
|
+
*
|
10
|
+
* Example:
|
11
|
+
*
|
12
|
+
Zoo = Backbone.RelationalModel.extend( {
|
13
|
+
relations: [ {
|
14
|
+
type: Backbone.HasMany,
|
15
|
+
key: 'animals',
|
16
|
+
relatedModel: 'Animal',
|
17
|
+
reverseRelation: {
|
18
|
+
key: 'livesIn',
|
19
|
+
includeInJSON: 'id'
|
20
|
+
// 'relatedModel' is automatically set to 'Zoo'; the 'relationType' to 'HasOne'.
|
21
|
+
}
|
22
|
+
} ],
|
23
|
+
|
24
|
+
toString: function() {
|
25
|
+
return this.get( 'name' );
|
26
|
+
}
|
27
|
+
} );
|
28
|
+
|
29
|
+
Animal = Backbone.RelationalModel.extend( {
|
30
|
+
toString: function() {
|
31
|
+
return this.get( 'species' );
|
32
|
+
}
|
33
|
+
} );
|
34
|
+
|
35
|
+
// Creating the zoo will give it a collection with one animal in it: the monkey.
|
36
|
+
// The animal created after that has a relation `livesIn` that points to the zoo it's currently associated with.
|
37
|
+
// If you instantiate (or fetch) the zebra later, it will automatically be added.
|
38
|
+
|
39
|
+
var zoo = new Zoo( {
|
40
|
+
name: 'Artis',
|
41
|
+
animals: [ { id: 'monkey-1', species: 'Chimp' }, 'lion-1', 'zebra-1' ]
|
42
|
+
} );
|
43
|
+
|
44
|
+
var lion = new Animal( { id: 'lion-1', species: 'Lion' } ),
|
45
|
+
monkey = zoo.get( 'animals' ).first(),
|
46
|
+
sameZoo = lion.get( 'livesIn' );
|
9
47
|
*/
|
10
48
|
( function( undefined ) {
|
11
49
|
"use strict";
|
@@ -224,7 +262,7 @@
|
|
224
262
|
return val === rel[ key ];
|
225
263
|
});
|
226
264
|
});
|
227
|
-
|
265
|
+
|
228
266
|
if ( !exists && relation.model && relation.type ) {
|
229
267
|
this._reverseRelations.push( relation );
|
230
268
|
this._addRelation( relation.model, relation );
|
@@ -305,20 +343,20 @@
|
|
305
343
|
if ( type instanceof Backbone.RelationalModel ) {
|
306
344
|
type = type.constructor;
|
307
345
|
}
|
308
|
-
|
346
|
+
|
309
347
|
var rootModel = type;
|
310
348
|
while ( rootModel._superModel ) {
|
311
349
|
rootModel = rootModel._superModel;
|
312
350
|
}
|
313
|
-
|
351
|
+
|
314
352
|
var coll = _.find( this._collections, function(item) {
|
315
|
-
return item.model === rootModel;
|
353
|
+
return item.model === rootModel;
|
316
354
|
});
|
317
|
-
|
355
|
+
|
318
356
|
if ( !coll && create !== false ) {
|
319
357
|
coll = this._createCollection( rootModel );
|
320
358
|
}
|
321
|
-
|
359
|
+
|
322
360
|
return coll;
|
323
361
|
},
|
324
362
|
|
@@ -346,20 +384,20 @@
|
|
346
384
|
|
347
385
|
_createCollection: function( type ) {
|
348
386
|
var coll;
|
349
|
-
|
387
|
+
|
350
388
|
// If 'type' is an instance, take its constructor
|
351
389
|
if ( type instanceof Backbone.RelationalModel ) {
|
352
390
|
type = type.constructor;
|
353
391
|
}
|
354
|
-
|
392
|
+
|
355
393
|
// Type should inherit from Backbone.RelationalModel.
|
356
394
|
if ( type.prototype instanceof Backbone.RelationalModel ) {
|
357
395
|
coll = new Backbone.Collection();
|
358
396
|
coll.model = type;
|
359
|
-
|
397
|
+
|
360
398
|
this._collections.push( coll );
|
361
399
|
}
|
362
|
-
|
400
|
+
|
363
401
|
return coll;
|
364
402
|
},
|
365
403
|
|
@@ -395,9 +433,9 @@
|
|
395
433
|
* @param {String|Number|Object|Backbone.RelationalModel} item
|
396
434
|
*/
|
397
435
|
find: function( type, item ) {
|
398
|
-
var id = this.resolveIdForItem( type, item )
|
399
|
-
|
400
|
-
|
436
|
+
var id = this.resolveIdForItem( type, item ),
|
437
|
+
coll = this.getCollection( type );
|
438
|
+
|
401
439
|
// Because the found object could be of any of the type's superModel
|
402
440
|
// types, only return it if it's actually of the type asked for.
|
403
441
|
if ( coll ) {
|
@@ -461,9 +499,16 @@
|
|
461
499
|
/**
|
462
500
|
* Remove a 'model' from the store.
|
463
501
|
* @param {Backbone.RelationalModel} model
|
502
|
+
* @param {Backbone.Collection} [collection]
|
503
|
+
* @param {Object} [options]
|
464
504
|
*/
|
465
505
|
unregister: function( model, collection, options ) {
|
466
506
|
this.stopListening( model );
|
507
|
+
|
508
|
+
_.each( model.getRelations(), function( rel ) {
|
509
|
+
rel.stopListening();
|
510
|
+
});
|
511
|
+
|
467
512
|
var coll = this.getCollection( model );
|
468
513
|
coll && coll.remove( model, options );
|
469
514
|
},
|
@@ -673,7 +718,7 @@
|
|
673
718
|
}
|
674
719
|
}, this );
|
675
720
|
}, this );
|
676
|
-
|
721
|
+
|
677
722
|
return reverseRelations;
|
678
723
|
},
|
679
724
|
|
@@ -690,7 +735,7 @@
|
|
690
735
|
else if ( this instanceof Backbone.HasMany ) {
|
691
736
|
this.setRelated( this._prepareCollection() );
|
692
737
|
}
|
693
|
-
|
738
|
+
|
694
739
|
_.each( this.getReverseRelations(), function( relation ) {
|
695
740
|
relation.removeRelated( this.instance );
|
696
741
|
}, this );
|
@@ -733,7 +778,7 @@
|
|
733
778
|
}
|
734
779
|
|
735
780
|
// Nullify `keyId` if we have a related model; in case it was already part of the relation
|
736
|
-
if (
|
781
|
+
if ( related ) {
|
737
782
|
this.keyId = null;
|
738
783
|
}
|
739
784
|
|
@@ -760,19 +805,19 @@
|
|
760
805
|
}
|
761
806
|
this.acquire();
|
762
807
|
options = options ? _.clone( options ) : {};
|
763
|
-
|
808
|
+
|
764
809
|
// 'options.__related' is set by 'addRelated'/'removeRelated'. If it is set, the change
|
765
|
-
// is the result of a call from a relation. If it's not, the change is the result of
|
810
|
+
// is the result of a call from a relation. If it's not, the change is the result of
|
766
811
|
// a 'set' call on this.instance.
|
767
812
|
var changed = _.isUndefined( options.__related ),
|
768
813
|
oldRelated = changed ? this.related : options.__related;
|
769
|
-
|
814
|
+
|
770
815
|
if ( changed ) {
|
771
816
|
this.setKeyContents( attr );
|
772
817
|
var related = this.findRelated( options );
|
773
818
|
this.setRelated( related );
|
774
819
|
}
|
775
|
-
|
820
|
+
|
776
821
|
// Notify old 'related' object of the terminated relation
|
777
822
|
if ( oldRelated && this.related !== oldRelated ) {
|
778
823
|
_.each( this.getReverseRelations( oldRelated ), function( relation ) {
|
@@ -786,7 +831,7 @@
|
|
786
831
|
_.each( this.getReverseRelations(), function( relation ) {
|
787
832
|
relation.addRelated( this.instance, options );
|
788
833
|
}, this );
|
789
|
-
|
834
|
+
|
790
835
|
// Fire the 'change:<key>' event if 'related' was updated
|
791
836
|
if ( !options.silent && this.related !== oldRelated ) {
|
792
837
|
var dit = this;
|
@@ -826,7 +871,7 @@
|
|
826
871
|
if ( !this.related ) {
|
827
872
|
return;
|
828
873
|
}
|
829
|
-
|
874
|
+
|
830
875
|
if ( model === this.related ) {
|
831
876
|
var oldRelated = this.related || null;
|
832
877
|
this.setRelated( null );
|
@@ -847,7 +892,7 @@
|
|
847
892
|
|
848
893
|
initialize: function( opts ) {
|
849
894
|
this.listenTo( this.instance, 'relational:change:' + this.key, this.onChange );
|
850
|
-
|
895
|
+
|
851
896
|
// Handle a custom 'collectionType'
|
852
897
|
this.collectionType = this.options.collectionType;
|
853
898
|
if ( _.isFunction( this.collectionType ) && this.collectionType !== Backbone.Collection && !( this.collectionType.prototype instanceof Backbone.Collection ) ) {
|
@@ -883,10 +928,10 @@
|
|
883
928
|
}
|
884
929
|
|
885
930
|
collection.model = this.relatedModel;
|
886
|
-
|
931
|
+
|
887
932
|
if ( this.options.collectionKey ) {
|
888
933
|
var key = this.options.collectionKey === true ? this.options.reverseRelation.key : this.options.collectionKey;
|
889
|
-
|
934
|
+
|
890
935
|
if ( collection[ key ] && collection[ key ] !== this.instance ) {
|
891
936
|
if ( Backbone.Relational.showWarnings && typeof console !== 'undefined' ) {
|
892
937
|
console.warn( 'Relation=%o; collectionKey=%s already exists on collection=%o', this, key, this.options.collectionKey );
|
@@ -900,7 +945,7 @@
|
|
900
945
|
this.listenTo( collection, 'relational:add', this.handleAddition )
|
901
946
|
.listenTo( collection, 'relational:remove', this.handleRemoval )
|
902
947
|
.listenTo( collection, 'relational:reset', this.handleReset );
|
903
|
-
|
948
|
+
|
904
949
|
return collection;
|
905
950
|
},
|
906
951
|
|
@@ -1009,7 +1054,7 @@
|
|
1009
1054
|
//console.debug('handleAddition called; args=%o', arguments);
|
1010
1055
|
options = options ? _.clone( options ) : {};
|
1011
1056
|
this.changed = true;
|
1012
|
-
|
1057
|
+
|
1013
1058
|
_.each( this.getReverseRelations( model ), function( relation ) {
|
1014
1059
|
relation.addRelated( this.instance, options );
|
1015
1060
|
}, this );
|
@@ -1029,11 +1074,11 @@
|
|
1029
1074
|
//console.debug('handleRemoval called; args=%o', arguments);
|
1030
1075
|
options = options ? _.clone( options ) : {};
|
1031
1076
|
this.changed = true;
|
1032
|
-
|
1077
|
+
|
1033
1078
|
_.each( this.getReverseRelations( model ), function( relation ) {
|
1034
1079
|
relation.removeRelated( this.instance, null, options );
|
1035
1080
|
}, this );
|
1036
|
-
|
1081
|
+
|
1037
1082
|
var dit = this;
|
1038
1083
|
!options.silent && Backbone.Relational.eventQueue.add( function() {
|
1039
1084
|
dit.instance.trigger( 'remove:' + dit.key, model, dit.related, options );
|
@@ -1123,7 +1168,7 @@
|
|
1123
1168
|
}
|
1124
1169
|
|
1125
1170
|
Backbone.Relational.store.processOrphanRelations();
|
1126
|
-
|
1171
|
+
|
1127
1172
|
this._queue = new Backbone.BlockingQueue();
|
1128
1173
|
this._queue.block();
|
1129
1174
|
Backbone.Relational.eventQueue.block();
|
@@ -1202,7 +1247,7 @@
|
|
1202
1247
|
this.acquire(); // Setting up relations often also involve calls to 'set', and we only want to enter this function once
|
1203
1248
|
this._relations = {};
|
1204
1249
|
|
1205
|
-
_.each(
|
1250
|
+
_.each( this.relations || [], function( rel ) {
|
1206
1251
|
Backbone.Relational.store.initializeRelation( this, rel, options );
|
1207
1252
|
}, this );
|
1208
1253
|
|
@@ -1213,20 +1258,28 @@
|
|
1213
1258
|
|
1214
1259
|
/**
|
1215
1260
|
* When new values are set, notify this model's relations (also if options.silent is set).
|
1216
|
-
* (Relation.setRelated locks this model before calling 'set' on it to prevent loops)
|
1261
|
+
* (called from `set`; Relation.setRelated locks this model before calling 'set' on it to prevent loops)
|
1262
|
+
* @param {Object} [changedAttrs]
|
1263
|
+
* @param {Object} [options]
|
1217
1264
|
*/
|
1218
|
-
updateRelations: function( options ) {
|
1265
|
+
updateRelations: function( changedAttrs, options ) {
|
1219
1266
|
if ( this._isInitialized && !this.isLocked() ) {
|
1220
1267
|
_.each( this._relations, function( rel ) {
|
1221
|
-
|
1222
|
-
|
1223
|
-
|
1224
|
-
|
1268
|
+
if ( !changedAttrs || ( rel.keySource in changedAttrs || rel.key in changedAttrs ) ) {
|
1269
|
+
// Fetch data in `rel.keySource` if data got set in there, or `rel.key` otherwise
|
1270
|
+
var value = this.attributes[ rel.keySource ] || this.attributes[ rel.key ],
|
1271
|
+
attr = changedAttrs && ( changedAttrs[ rel.keySource ] || changedAttrs[ rel.key ] );
|
1272
|
+
|
1273
|
+
// Update a relation if its value differs from this model's attributes, or it's been explicitly nullified.
|
1274
|
+
// Which can also happen before the originally intended related model has been found (`val` is null).
|
1275
|
+
if ( rel.related !== value || ( value === null && attr === null ) ) {
|
1276
|
+
this.trigger( 'relational:change:' + rel.key, this, value, options || {} );
|
1277
|
+
}
|
1225
1278
|
}
|
1226
1279
|
|
1227
1280
|
// Explicitly clear 'keySource', to prevent a leaky abstraction if 'keySource' differs from 'key'.
|
1228
1281
|
if ( rel.keySource !== rel.key ) {
|
1229
|
-
delete
|
1282
|
+
delete this.attributes[ rel.keySource ];
|
1230
1283
|
}
|
1231
1284
|
}, this );
|
1232
1285
|
}
|
@@ -1250,7 +1303,7 @@
|
|
1250
1303
|
|
1251
1304
|
/**
|
1252
1305
|
* Get a specific relation.
|
1253
|
-
* @param
|
1306
|
+
* @param {string} key The relation key to look for.
|
1254
1307
|
* @return {Backbone.Relation} An instance of 'Backbone.Relation', if a relation was found for 'key', or null.
|
1255
1308
|
*/
|
1256
1309
|
getRelation: function( key ) {
|
@@ -1267,23 +1320,24 @@
|
|
1267
1320
|
|
1268
1321
|
/**
|
1269
1322
|
* Retrieve related objects.
|
1270
|
-
* @param
|
1271
|
-
* @param [options]
|
1272
|
-
* @param [refresh=false]
|
1323
|
+
* @param {string} key The relation key to fetch models for.
|
1324
|
+
* @param {Object} [options] Options for 'Backbone.Model.fetch' and 'Backbone.sync'.
|
1325
|
+
* @param {Boolean} [refresh=false] Fetch existing models from the server as well (in order to update them).
|
1273
1326
|
* @return {jQuery.when[]} An array of request objects
|
1274
1327
|
*/
|
1275
1328
|
fetchRelated: function( key, options, refresh ) {
|
1276
1329
|
// Set default `options` for fetch
|
1277
1330
|
options = _.extend( { update: true, remove: false }, options );
|
1278
1331
|
|
1279
|
-
var
|
1332
|
+
var models,
|
1333
|
+
setUrl,
|
1280
1334
|
requests = [],
|
1281
1335
|
rel = this.getRelation( key ),
|
1282
1336
|
idsToFetch = rel && ( ( rel.keyIds && rel.keyIds.slice( 0 ) ) || ( ( rel.keyId || rel.keyId === 0 ) ? [ rel.keyId ] : [] ) );
|
1283
1337
|
|
1284
1338
|
// On `refresh`, add the ids for current models in the relation to `idsToFetch`
|
1285
1339
|
if ( refresh ) {
|
1286
|
-
|
1340
|
+
models = rel.related instanceof Backbone.Collection ? rel.related.models : [ rel.related ];
|
1287
1341
|
_.each( models, function( model ) {
|
1288
1342
|
if ( model.id || model.id === 0 ) {
|
1289
1343
|
idsToFetch.push( model.id );
|
@@ -1293,20 +1347,20 @@
|
|
1293
1347
|
|
1294
1348
|
if ( idsToFetch && idsToFetch.length ) {
|
1295
1349
|
// Find (or create) a model for each one that is to be fetched
|
1296
|
-
var created = []
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1350
|
+
var created = [];
|
1351
|
+
models = _.map( idsToFetch, function( id ) {
|
1352
|
+
var model = rel.relatedModel.findModel( id );
|
1353
|
+
|
1354
|
+
if ( !model ) {
|
1355
|
+
var attrs = {};
|
1356
|
+
attrs[ rel.relatedModel.prototype.idAttribute ] = id;
|
1357
|
+
model = rel.relatedModel.findOrCreate( attrs, options );
|
1358
|
+
created.push( model );
|
1359
|
+
}
|
1360
|
+
|
1361
|
+
return model;
|
1362
|
+
}, this );
|
1306
1363
|
|
1307
|
-
return model;
|
1308
|
-
}, this );
|
1309
|
-
|
1310
1364
|
// Try if the 'collection' can provide a url to fetch a set of models in one request.
|
1311
1365
|
if ( rel.related instanceof Backbone.Collection && _.isFunction( rel.related.url ) ) {
|
1312
1366
|
setUrl = rel.related.url( models );
|
@@ -1349,7 +1403,7 @@
|
|
1349
1403
|
}, this );
|
1350
1404
|
}
|
1351
1405
|
}
|
1352
|
-
|
1406
|
+
|
1353
1407
|
return requests;
|
1354
1408
|
},
|
1355
1409
|
|
@@ -1421,14 +1475,14 @@
|
|
1421
1475
|
}
|
1422
1476
|
|
1423
1477
|
if ( attributes ) {
|
1424
|
-
this.updateRelations( options );
|
1478
|
+
this.updateRelations( attributes, options );
|
1425
1479
|
}
|
1426
1480
|
}
|
1427
1481
|
finally {
|
1428
1482
|
// Try to run the global queue holding external events
|
1429
1483
|
Backbone.Relational.eventQueue.unblock();
|
1430
1484
|
}
|
1431
|
-
|
1485
|
+
|
1432
1486
|
return result;
|
1433
1487
|
},
|
1434
1488
|
|
@@ -1486,6 +1540,10 @@
|
|
1486
1540
|
}
|
1487
1541
|
else if ( rel instanceof Backbone.HasOne ) {
|
1488
1542
|
value = value || rel.keyId;
|
1543
|
+
|
1544
|
+
if ( !value && !_.isObject( rel.keyContents ) ) {
|
1545
|
+
value = rel.keyContents || null;
|
1546
|
+
}
|
1489
1547
|
}
|
1490
1548
|
}
|
1491
1549
|
}
|
@@ -1519,7 +1577,7 @@
|
|
1519
1577
|
delete json[ rel.key ];
|
1520
1578
|
}
|
1521
1579
|
});
|
1522
|
-
|
1580
|
+
|
1523
1581
|
this.release();
|
1524
1582
|
return json;
|
1525
1583
|
}
|
@@ -1531,8 +1589,8 @@
|
|
1531
1589
|
* @returns {Backbone.RelationalModel.constructor}
|
1532
1590
|
*/
|
1533
1591
|
setup: function( superModel ) {
|
1534
|
-
// We don't want to share a relations array with a parent, as this will cause problems with
|
1535
|
-
//
|
1592
|
+
// We don't want to share a relations array with a parent, as this will cause problems with reverse
|
1593
|
+
// relations. Since `relations` may also be a property or function, only use slice if we have an array.
|
1536
1594
|
this.prototype.relations = ( this.prototype.relations || [] ).slice( 0 );
|
1537
1595
|
|
1538
1596
|
this._subModels = {};
|
@@ -1552,7 +1610,7 @@
|
|
1552
1610
|
if ( !rel.model ) {
|
1553
1611
|
rel.model = this;
|
1554
1612
|
}
|
1555
|
-
|
1613
|
+
|
1556
1614
|
if ( rel.reverseRelation && rel.model === this ) {
|
1557
1615
|
var preInitialize = true;
|
1558
1616
|
if ( _.isString( rel.relatedModel ) ) {
|
@@ -1577,7 +1635,7 @@
|
|
1577
1635
|
}
|
1578
1636
|
}
|
1579
1637
|
}, this );
|
1580
|
-
|
1638
|
+
|
1581
1639
|
return this;
|
1582
1640
|
},
|
1583
1641
|
|
@@ -1592,8 +1650,8 @@
|
|
1592
1650
|
this.initializeModelHierarchy();
|
1593
1651
|
|
1594
1652
|
// Determine what type of (sub)model should be built if applicable.
|
1595
|
-
var model = this._findSubModelType(this, attributes) || this;
|
1596
|
-
|
1653
|
+
var model = this._findSubModelType( this, attributes ) || this;
|
1654
|
+
|
1597
1655
|
return new model( attributes, options );
|
1598
1656
|
},
|
1599
1657
|
|
@@ -1606,16 +1664,17 @@
|
|
1606
1664
|
* @param {Object} attributes
|
1607
1665
|
* @return {Backbone.Model}
|
1608
1666
|
*/
|
1609
|
-
_findSubModelType: function
|
1667
|
+
_findSubModelType: function( type, attributes ) {
|
1610
1668
|
if ( type._subModels && type.prototype.subModelTypeAttribute in attributes ) {
|
1611
|
-
var subModelTypeAttribute = attributes[type.prototype.subModelTypeAttribute];
|
1612
|
-
var subModelType = type._subModels[subModelTypeAttribute];
|
1669
|
+
var subModelTypeAttribute = attributes[ type.prototype.subModelTypeAttribute ];
|
1670
|
+
var subModelType = type._subModels[ subModelTypeAttribute ];
|
1613
1671
|
if ( subModelType ) {
|
1614
1672
|
return subModelType;
|
1615
|
-
}
|
1673
|
+
}
|
1674
|
+
else {
|
1616
1675
|
// Recurse into subModelTypes to find a match
|
1617
1676
|
for ( subModelTypeAttribute in type._subModels ) {
|
1618
|
-
subModelType = this._findSubModelType(type._subModels[subModelTypeAttribute], attributes);
|
1677
|
+
subModelType = this._findSubModelType( type._subModels[ subModelTypeAttribute ], attributes );
|
1619
1678
|
if ( subModelType ) {
|
1620
1679
|
return subModelType;
|
1621
1680
|
}
|
@@ -1631,46 +1690,46 @@
|
|
1631
1690
|
initializeModelHierarchy: function() {
|
1632
1691
|
// Inherit any relations that have been defined in the parent model.
|
1633
1692
|
this.inheritRelations();
|
1634
|
-
|
1693
|
+
|
1635
1694
|
// If we came here through 'build' for a model that has 'subModelTypes' then try to initialize the ones that
|
1636
1695
|
// haven't been resolved yet.
|
1637
1696
|
if ( this.prototype.subModelTypes ) {
|
1638
|
-
var resolvedSubModels = _.keys(this._subModels);
|
1639
|
-
var unresolvedSubModels = _.omit(this.prototype.subModelTypes, resolvedSubModels);
|
1697
|
+
var resolvedSubModels = _.keys( this._subModels );
|
1698
|
+
var unresolvedSubModels = _.omit( this.prototype.subModelTypes, resolvedSubModels );
|
1640
1699
|
_.each( unresolvedSubModels, function( subModelTypeName ) {
|
1641
1700
|
var subModelType = Backbone.Relational.store.getObjectByName( subModelTypeName );
|
1642
1701
|
subModelType && subModelType.initializeModelHierarchy();
|
1643
1702
|
});
|
1644
1703
|
}
|
1645
1704
|
},
|
1646
|
-
|
1705
|
+
|
1647
1706
|
inheritRelations: function() {
|
1648
1707
|
// Bail out if we've been here before.
|
1649
|
-
if (!_.isUndefined( this._superModel ) && !_.isNull( this._superModel )) {
|
1650
|
-
return;
|
1708
|
+
if (!_.isUndefined( this._superModel ) && !_.isNull( this._superModel )) {
|
1709
|
+
return;
|
1651
1710
|
}
|
1652
1711
|
// Try to initialize the _superModel.
|
1653
1712
|
Backbone.Relational.store.setupSuperModel( this );
|
1654
|
-
|
1655
|
-
// If a superModel has been found, copy relations from the _superModel if they haven't been inherited automatically
|
1713
|
+
|
1714
|
+
// If a superModel has been found, copy relations from the _superModel if they haven't been inherited automatically
|
1656
1715
|
// (due to a redefinition of 'relations').
|
1657
1716
|
if ( this._superModel ) {
|
1658
|
-
// The _superModel needs a chance to initialize its own inherited relations before we attempt to inherit relations
|
1717
|
+
// The _superModel needs a chance to initialize its own inherited relations before we attempt to inherit relations
|
1659
1718
|
// from the _superModel. You don't want to call 'initializeModelHierarchy' because that could cause sub-models of
|
1660
1719
|
// this class to inherit their relations before this class has had chance to inherit it's relations.
|
1661
1720
|
this._superModel.inheritRelations();
|
1662
1721
|
if ( this._superModel.prototype.relations ) {
|
1663
1722
|
// Find relations that exist on the '_superModel', but not yet on this model.
|
1664
|
-
var inheritedRelations = _.
|
1723
|
+
var inheritedRelations = _.filter( this._superModel.prototype.relations || [], function( superRel ) {
|
1665
1724
|
return !_.any( this.prototype.relations || [], function( rel ) {
|
1666
1725
|
return superRel.relatedModel === rel.relatedModel && superRel.key === rel.key;
|
1667
1726
|
}, this );
|
1668
1727
|
}, this );
|
1669
|
-
|
1728
|
+
|
1670
1729
|
this.prototype.relations = inheritedRelations.concat( this.prototype.relations );
|
1671
1730
|
}
|
1672
1731
|
}
|
1673
|
-
// Otherwise, make sure we don't get here again for this type by making '_superModel' false so we fail the
|
1732
|
+
// Otherwise, make sure we don't get here again for this type by making '_superModel' false so we fail the
|
1674
1733
|
// isUndefined/isNull check next time.
|
1675
1734
|
else {
|
1676
1735
|
this._superModel = false;
|
@@ -1679,9 +1738,9 @@
|
|
1679
1738
|
|
1680
1739
|
/**
|
1681
1740
|
* Find an instance of `this` type in 'Backbone.Relational.store'.
|
1682
|
-
*
|
1741
|
+
* A new model is created with `attributes` (unless `options.create` is explicitly set to `false`) if no match is found.
|
1742
|
+
* - If `attributes` is a string or a number, `findOrCreate` will query the `store` and return a model if found.
|
1683
1743
|
* - If `attributes` is an object and is found in the store, the model will be updated with `attributes` unless `options.update` is `false`.
|
1684
|
-
* Otherwise, a new model is created with `attributes` (unless `options.create` is explicitly set to `false`).
|
1685
1744
|
* @param {Object|String|Number} attributes Either a model's id, or the attributes used to create or update a model.
|
1686
1745
|
* @param {Object} [options]
|
1687
1746
|
* @param {Boolean} [options.create=true]
|
@@ -1694,8 +1753,9 @@
|
|
1694
1753
|
var parsedAttributes = ( _.isObject( attributes ) && options.parse && this.prototype.parse ) ?
|
1695
1754
|
this.prototype.parse( _.clone( attributes ) ) : attributes;
|
1696
1755
|
|
1697
|
-
//
|
1698
|
-
|
1756
|
+
// If specified, use a custom `find` function to match up existing models to the given attributes.
|
1757
|
+
// Otherwise, try to find an instance of 'this' model type in the store
|
1758
|
+
var model = this.findModel( parsedAttributes );
|
1699
1759
|
|
1700
1760
|
// If we found an instance, update it with the data in 'item' (unless 'options.merge' is false).
|
1701
1761
|
// If not, create an instance (unless 'options.create' is false).
|
@@ -1717,7 +1777,7 @@
|
|
1717
1777
|
|
1718
1778
|
/**
|
1719
1779
|
* Find an instance of `this` type in 'Backbone.Relational.store'.
|
1720
|
-
* - If `attributes` is a string or a number, `find` will
|
1780
|
+
* - If `attributes` is a string or a number, `find` will query the `store` and return a model if found.
|
1721
1781
|
* - If `attributes` is an object and is found in the store, the model will be updated with `attributes` unless `options.update` is `false`.
|
1722
1782
|
* @param {Object|String|Number} attributes Either a model's id, or the attributes used to create or update a model.
|
1723
1783
|
* @param {Object} [options]
|
@@ -1729,6 +1789,16 @@
|
|
1729
1789
|
options || ( options = {} );
|
1730
1790
|
options.create = false;
|
1731
1791
|
return this.findOrCreate( attributes, options );
|
1792
|
+
},
|
1793
|
+
|
1794
|
+
/**
|
1795
|
+
* A hook to override the matching when updating (or creating) a model.
|
1796
|
+
* The default implementation is to look up the model by id in the store.
|
1797
|
+
* @param {Object} attributes
|
1798
|
+
* @returns {Backbone.RelationalModel}
|
1799
|
+
*/
|
1800
|
+
findModel: function( attributes ) {
|
1801
|
+
return Backbone.Relational.store.find( this, attributes );
|
1732
1802
|
}
|
1733
1803
|
});
|
1734
1804
|
_.extend( Backbone.RelationalModel.prototype, Backbone.Semaphore );
|
@@ -1742,7 +1812,7 @@
|
|
1742
1812
|
Backbone.Collection.prototype.__prepareModel = Backbone.Collection.prototype._prepareModel;
|
1743
1813
|
Backbone.Collection.prototype._prepareModel = function ( attrs, options ) {
|
1744
1814
|
var model;
|
1745
|
-
|
1815
|
+
|
1746
1816
|
if ( attrs instanceof Backbone.Model ) {
|
1747
1817
|
if ( !attrs.collection ) {
|
1748
1818
|
attrs.collection = this;
|
@@ -1750,22 +1820,22 @@
|
|
1750
1820
|
model = attrs;
|
1751
1821
|
}
|
1752
1822
|
else {
|
1753
|
-
options
|
1823
|
+
options = options ? _.clone( options ) : {};
|
1754
1824
|
options.collection = this;
|
1755
|
-
|
1825
|
+
|
1756
1826
|
if ( typeof this.model.findOrCreate !== 'undefined' ) {
|
1757
1827
|
model = this.model.findOrCreate( attrs, options );
|
1758
1828
|
}
|
1759
1829
|
else {
|
1760
1830
|
model = new this.model( attrs, options );
|
1761
1831
|
}
|
1762
|
-
|
1763
|
-
if ( model && model.
|
1832
|
+
|
1833
|
+
if ( model && model.validationError ) {
|
1764
1834
|
this.trigger( 'invalid', this, attrs, options );
|
1765
1835
|
model = false;
|
1766
1836
|
}
|
1767
1837
|
}
|
1768
|
-
|
1838
|
+
|
1769
1839
|
return model;
|
1770
1840
|
};
|
1771
1841
|
|
@@ -1785,9 +1855,7 @@
|
|
1785
1855
|
models = this.parse( models, options );
|
1786
1856
|
}
|
1787
1857
|
|
1788
|
-
|
1789
|
-
models = models ? [ models ] : [];
|
1790
|
-
}
|
1858
|
+
models = _.isArray( models ) ? models.slice() : ( models ? [ models ] : [] );
|
1791
1859
|
|
1792
1860
|
var newModels = [],
|
1793
1861
|
toAdd = [];
|
@@ -1814,7 +1882,7 @@
|
|
1814
1882
|
|
1815
1883
|
// Add 'models' in a single batch, so the original add will only be called once (and thus 'sort', etc).
|
1816
1884
|
// If `parse` was specified, the collection and contained models have been parsed now.
|
1817
|
-
set.call( this, toAdd, _.defaults( { parse: false }, options ) );
|
1885
|
+
var result = set.call( this, toAdd, _.defaults( { parse: false }, options ) );
|
1818
1886
|
|
1819
1887
|
_.each( newModels, function( model ) {
|
1820
1888
|
// Fire a `relational:add` event for any model in `newModels` that has actually been added to the collection.
|
@@ -1822,8 +1890,8 @@
|
|
1822
1890
|
this.trigger( 'relational:add', model, this, options );
|
1823
1891
|
}
|
1824
1892
|
}, this );
|
1825
|
-
|
1826
|
-
return
|
1893
|
+
|
1894
|
+
return result;
|
1827
1895
|
};
|
1828
1896
|
|
1829
1897
|
/**
|
@@ -1836,7 +1904,7 @@
|
|
1836
1904
|
return remove.apply( this, arguments );
|
1837
1905
|
}
|
1838
1906
|
|
1839
|
-
models = _.isArray( models ) ? models.slice(
|
1907
|
+
models = _.isArray( models ) ? models.slice() : [ models ];
|
1840
1908
|
options || ( options = {} );
|
1841
1909
|
|
1842
1910
|
var toRemove = [];
|
@@ -1847,15 +1915,13 @@
|
|
1847
1915
|
model && toRemove.push( model );
|
1848
1916
|
}, this );
|
1849
1917
|
|
1850
|
-
|
1851
|
-
remove.call( this, toRemove, options );
|
1918
|
+
var result = remove.call( this, toRemove, options );
|
1852
1919
|
|
1853
|
-
|
1854
|
-
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1858
|
-
return this;
|
1920
|
+
_.each( toRemove, function( model ) {
|
1921
|
+
this.trigger('relational:remove', model, this, options);
|
1922
|
+
}, this );
|
1923
|
+
|
1924
|
+
return result;
|
1859
1925
|
};
|
1860
1926
|
|
1861
1927
|
/**
|
@@ -1864,13 +1930,13 @@
|
|
1864
1930
|
var reset = Backbone.Collection.prototype.__reset = Backbone.Collection.prototype.reset;
|
1865
1931
|
Backbone.Collection.prototype.reset = function( models, options ) {
|
1866
1932
|
options = _.extend( { merge: true }, options );
|
1867
|
-
reset.call( this, models, options );
|
1933
|
+
var result = reset.call( this, models, options );
|
1868
1934
|
|
1869
1935
|
if ( this.model.prototype instanceof Backbone.RelationalModel ) {
|
1870
1936
|
this.trigger( 'relational:reset', this, options );
|
1871
1937
|
}
|
1872
1938
|
|
1873
|
-
return
|
1939
|
+
return result;
|
1874
1940
|
};
|
1875
1941
|
|
1876
1942
|
/**
|
@@ -1878,13 +1944,13 @@
|
|
1878
1944
|
*/
|
1879
1945
|
var sort = Backbone.Collection.prototype.__sort = Backbone.Collection.prototype.sort;
|
1880
1946
|
Backbone.Collection.prototype.sort = function( options ) {
|
1881
|
-
sort.call( this, options );
|
1947
|
+
var result = sort.call( this, options );
|
1882
1948
|
|
1883
1949
|
if ( this.model.prototype instanceof Backbone.RelationalModel ) {
|
1884
1950
|
this.trigger( 'relational:reset', this, options );
|
1885
1951
|
}
|
1886
1952
|
|
1887
|
-
return
|
1953
|
+
return result;
|
1888
1954
|
};
|
1889
1955
|
|
1890
1956
|
/**
|
@@ -1901,14 +1967,14 @@
|
|
1901
1967
|
if ( eventName === 'add' || eventName === 'remove' || eventName === 'reset' || eventName === 'sort' ) {
|
1902
1968
|
var dit = this,
|
1903
1969
|
args = arguments;
|
1904
|
-
|
1970
|
+
|
1905
1971
|
if ( _.isObject( args[ 3 ] ) ) {
|
1906
1972
|
args = _.toArray( args );
|
1907
1973
|
// the fourth argument is the option object.
|
1908
1974
|
// we need to clone it, as it could be modified while we wait on the eventQueue to be unblocked
|
1909
1975
|
args[ 3 ] = _.clone( args[ 3 ] );
|
1910
1976
|
}
|
1911
|
-
|
1977
|
+
|
1912
1978
|
Backbone.Relational.eventQueue.add( function() {
|
1913
1979
|
trigger.apply( dit, args );
|
1914
1980
|
});
|
@@ -1916,14 +1982,14 @@
|
|
1916
1982
|
else {
|
1917
1983
|
trigger.apply( this, arguments );
|
1918
1984
|
}
|
1919
|
-
|
1985
|
+
|
1920
1986
|
return this;
|
1921
1987
|
};
|
1922
1988
|
|
1923
1989
|
// Override .extend() to automatically call .setup()
|
1924
1990
|
Backbone.RelationalModel.extend = function( protoProps, classProps ) {
|
1925
1991
|
var child = Backbone.Model.extend.apply( this, arguments );
|
1926
|
-
|
1992
|
+
|
1927
1993
|
child.setup( this );
|
1928
1994
|
|
1929
1995
|
return child;
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: backbone-relational-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Marsh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|