backbone-relational-rails 0.8.6 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|