rightnow_oms 0.1.2 → 0.1.3
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.
- data/CHANGELOG +8 -1
- data/README.md +10 -0
- data/app/assets/javascripts/rightnow_oms/app/app.js.coffee +2 -0
- data/app/assets/javascripts/rightnow_oms/app/controllers/cart.js.coffee +3 -3
- data/app/assets/javascripts/rightnow_oms/app/models/cart.js.coffee +14 -4
- data/app/assets/javascripts/rightnow_oms/app/models/cart_item.js.coffee +25 -15
- data/app/assets/javascripts/rightnow_oms/app/templates/cart_items/show.hjs +23 -9
- data/app/assets/javascripts/rightnow_oms/app/templates/cart_items/show_in_detail.hjs +45 -18
- data/app/assets/javascripts/rightnow_oms/app/templates/carts/show.hjs +0 -2
- data/app/assets/javascripts/rightnow_oms/app/templates/carts/show_in_detail.hjs +15 -23
- data/app/assets/javascripts/rightnow_oms/app/views/cart_items/show.js.coffee +5 -1
- data/app/assets/javascripts/rightnow_oms/app/views/cart_items/show_in_detail.js.coffee +9 -6
- data/app/assets/javascripts/rightnow_oms/app/views/carts/show_in_detail.js.coffee +1 -0
- data/app/assets/javascripts/rightnow_oms/vendor/ember-data.js +640 -236
- data/app/assets/javascripts/rightnow_oms/vendor/ember-data.min.js +1 -1
- data/app/assets/javascripts/rightnow_oms/vendor/ember.js +61 -37
- data/app/assets/javascripts/rightnow_oms/vendor/ember.min.js +2 -2
- data/app/assets/stylesheets/rightnow_oms/application.css.scss +17 -0
- data/app/assets/stylesheets/rightnow_oms/carts.css.scss +99 -72
- data/app/assets/stylesheets/rightnow_oms/orders.css.scss +50 -0
- data/app/controllers/rightnow_oms/cart_items_controller.rb +5 -5
- data/app/controllers/rightnow_oms/orders_controller.rb +30 -0
- data/app/models/rightnow_oms/cart.rb +22 -13
- data/app/models/rightnow_oms/cart_item.rb +20 -2
- data/app/models/rightnow_oms/order.rb +43 -0
- data/app/models/rightnow_oms/order_item.rb +16 -0
- data/app/views/rightnow_oms/carts/show.html.haml +2 -0
- data/app/views/rightnow_oms/orders/show.html.haml +45 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20120214074943_create_rightnow_oms_orders.rb +20 -0
- data/db/migrate/20120214081113_create_rightnow_oms_order_items.rb +15 -0
- data/db/migrate/20120215064659_add_user_id_to_rightnow_oms_orders.rb +7 -0
- data/db/migrate/20120217081138_add_base_quantity_to_rightnow_oms_cart_items.rb +6 -0
- data/lib/rightnow_oms/order_no_generator.rb +13 -0
- data/lib/rightnow_oms/version.rb +1 -1
- data/lib/rightnow_oms.rb +19 -5
- metadata +41 -20
- data/app/assets/stylesheets/rightnow_oms/application.css +0 -7
@@ -71,7 +71,7 @@ DS.fixtureAdapter = DS.Adapter.create({
|
|
71
71
|
|
72
72
|
ember_assert("Unable to find fixtures for model type "+type.toString(), !!fixtures);
|
73
73
|
|
74
|
-
var ids = fixtures.map(function(item, index, self){ return item.id });
|
74
|
+
var ids = fixtures.map(function(item, index, self){ return item.id; });
|
75
75
|
store.loadMany(type, ids, fixtures);
|
76
76
|
}
|
77
77
|
|
@@ -81,6 +81,7 @@ DS.fixtureAdapter = DS.Adapter.create({
|
|
81
81
|
|
82
82
|
|
83
83
|
(function(exports) {
|
84
|
+
/*global jQuery*/
|
84
85
|
var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
|
85
86
|
|
86
87
|
DS.RESTAdapter = DS.Adapter.extend({
|
@@ -120,8 +121,7 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
120
121
|
},
|
121
122
|
|
122
123
|
updateRecord: function(store, type, model) {
|
123
|
-
var
|
124
|
-
id = get(model, primaryKey);
|
124
|
+
var id = get(model, 'id');
|
125
125
|
var root = this.rootForType(type);
|
126
126
|
|
127
127
|
var data = {};
|
@@ -159,8 +159,7 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
159
159
|
},
|
160
160
|
|
161
161
|
deleteRecord: function(store, type, model) {
|
162
|
-
var
|
163
|
-
id = get(model, primaryKey);
|
162
|
+
var id = get(model, 'id');
|
164
163
|
var root = this.rootForType(type);
|
165
164
|
|
166
165
|
var url = ["", this.pluralize(root), id].join("/");
|
@@ -178,12 +177,11 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
178
177
|
}
|
179
178
|
|
180
179
|
var root = this.rootForType(type),
|
181
|
-
plural = this.pluralize(root)
|
182
|
-
primaryKey = getPath(type, 'proto.primaryKey');
|
180
|
+
plural = this.pluralize(root);
|
183
181
|
|
184
182
|
var data = {};
|
185
183
|
data[plural] = models.map(function(model) {
|
186
|
-
return get(model,
|
184
|
+
return get(model, 'id');
|
187
185
|
});
|
188
186
|
|
189
187
|
this.ajax("/" + this.pluralize(root) + "/delete", "POST", {
|
@@ -215,7 +213,6 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
215
213
|
store.loadMany(type, ids, json[plural]);
|
216
214
|
}
|
217
215
|
});
|
218
|
-
var url = "/" + plural;
|
219
216
|
},
|
220
217
|
|
221
218
|
findAll: function(store, type) {
|
@@ -274,19 +271,58 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
274
271
|
(function(exports) {
|
275
272
|
var get = Ember.get, set = Ember.set;
|
276
273
|
|
274
|
+
/**
|
275
|
+
A model array is an array that contains records of a certain type. The model
|
276
|
+
array materializes records as needed when they are retrieved for the first
|
277
|
+
time. You should not create model arrays yourself. Instead, an instance of
|
278
|
+
DS.ModelArray or its subclasses will be returned by your application's store
|
279
|
+
in response to queries.
|
280
|
+
*/
|
281
|
+
|
277
282
|
DS.ModelArray = Ember.ArrayProxy.extend({
|
283
|
+
|
284
|
+
/**
|
285
|
+
The model type contained by this model array.
|
286
|
+
|
287
|
+
@type DS.Model
|
288
|
+
*/
|
278
289
|
type: null,
|
290
|
+
|
291
|
+
// The array of client ids backing the model array. When a
|
292
|
+
// record is requested from the model array, the record
|
293
|
+
// for the client id at the same index is materialized, if
|
294
|
+
// necessary, by the store.
|
279
295
|
content: null,
|
296
|
+
|
297
|
+
// The store that created this model array.
|
280
298
|
store: null,
|
281
299
|
|
300
|
+
// for associations, the model that this association belongs to.
|
301
|
+
parentModel: null,
|
302
|
+
|
282
303
|
init: function() {
|
283
304
|
set(this, 'modelCache', Ember.A([]));
|
284
305
|
this._super();
|
285
306
|
},
|
286
307
|
|
308
|
+
// Overrides Ember.Array's replace method to implement
|
309
|
+
replace: function(index, removed, added) {
|
310
|
+
var parentRecord = get(this, 'parentRecord');
|
311
|
+
var pendingParent = parentRecord && !get(parentRecord, 'id');
|
312
|
+
|
313
|
+
added = added.map(function(item) {
|
314
|
+
ember_assert("You can only add items of " + (get(this, 'type') && get(this, 'type').toString()) + " to this association.", !get(this, 'type') || (get(this, 'type') === item.constructor));
|
315
|
+
|
316
|
+
if (pendingParent) { item.send('waitingOn', parentRecord); }
|
317
|
+
return item.get('clientId');
|
318
|
+
});
|
319
|
+
|
320
|
+
this._super(index, removed, added);
|
321
|
+
},
|
322
|
+
|
287
323
|
arrayDidChange: function(array, index, removed, added) {
|
288
324
|
var modelCache = get(this, 'modelCache');
|
289
|
-
modelCache.replace(index, 0, Array(added));
|
325
|
+
modelCache.replace(index, 0, new Array(added));
|
290
326
|
|
291
327
|
this._super(array, index, removed, added);
|
292
328
|
},
|
@@ -318,6 +354,12 @@ DS.ModelArray = Ember.ArrayProxy.extend({
|
|
318
354
|
}
|
319
355
|
});
|
320
356
|
|
357
|
+
})({});
|
358
|
+
|
359
|
+
|
360
|
+
(function(exports) {
|
361
|
+
var get = Ember.get;
|
362
|
+
|
321
363
|
DS.FilteredModelArray = DS.ModelArray.extend({
|
322
364
|
filterFunction: null,
|
323
365
|
|
@@ -327,6 +369,12 @@ DS.FilteredModelArray = DS.ModelArray.extend({
|
|
327
369
|
}, 'filterFunction')
|
328
370
|
});
|
329
371
|
|
372
|
+
})({});
|
373
|
+
|
374
|
+
|
375
|
+
(function(exports) {
|
376
|
+
var get = Ember.get, set = Ember.set;
|
377
|
+
|
330
378
|
DS.AdapterPopulatedModelArray = DS.ModelArray.extend({
|
331
379
|
query: null,
|
332
380
|
isLoaded: false,
|
@@ -343,6 +391,11 @@ DS.AdapterPopulatedModelArray = DS.ModelArray.extend({
|
|
343
391
|
}
|
344
392
|
});
|
345
393
|
|
394
|
+
|
395
|
+
})({});
|
396
|
+
|
397
|
+
|
398
|
+
(function(exports) {
|
346
399
|
})({});
|
347
400
|
|
348
401
|
|
@@ -384,7 +437,8 @@ var OrderedSet = Ember.Object.extend({
|
|
384
437
|
},
|
385
438
|
|
386
439
|
forEach: function(fn, self) {
|
387
|
-
|
440
|
+
// allow mutation during iteration
|
441
|
+
get(this, 'list').slice().forEach(function(item) {
|
388
442
|
fn.call(self, item);
|
389
443
|
});
|
390
444
|
},
|
@@ -447,7 +501,8 @@ var Hash = Ember.Object.extend({
|
|
447
501
|
},
|
448
502
|
|
449
503
|
forEach: function(fn, binding) {
|
450
|
-
var keys = get(this, 'keys'),
|
504
|
+
var keys = get(this, 'keys'),
|
505
|
+
values = get(this, 'values');
|
451
506
|
|
452
507
|
keys.forEach(function(key) {
|
453
508
|
var guid = Ember.guidFor(key);
|
@@ -507,8 +562,17 @@ DS.Transaction = Ember.Object.extend({
|
|
507
562
|
dirty.forEach(function(type, models) {
|
508
563
|
if (models.isEmpty()) { return; }
|
509
564
|
|
510
|
-
|
511
|
-
|
565
|
+
var array = [];
|
566
|
+
|
567
|
+
models.forEach(function(model) {
|
568
|
+
model.send('willCommit');
|
569
|
+
|
570
|
+
if (get(model, 'isPending') === false) {
|
571
|
+
array.push(model);
|
572
|
+
}
|
573
|
+
});
|
574
|
+
|
575
|
+
fn.call(binding, type, array);
|
512
576
|
});
|
513
577
|
};
|
514
578
|
|
@@ -680,28 +744,27 @@ DS.Store = Ember.Object.extend({
|
|
680
744
|
// . CREATE NEW MODEL .
|
681
745
|
// ....................
|
682
746
|
|
683
|
-
createRecord: function(type,
|
684
|
-
|
747
|
+
createRecord: function(type, properties, transaction) {
|
748
|
+
properties = properties || {};
|
685
749
|
|
686
|
-
var id =
|
750
|
+
var id = properties[getPath(type, 'proto.primaryKey')] || null;
|
687
751
|
|
688
|
-
var model = type.
|
689
|
-
data: hash || {},
|
752
|
+
var model = type._create({
|
690
753
|
store: this,
|
691
754
|
transaction: transaction
|
692
755
|
});
|
693
756
|
|
694
|
-
|
757
|
+
var hash = {}, clientId;
|
695
758
|
|
696
|
-
|
697
|
-
|
759
|
+
clientId = this.pushHash(hash, id, type);
|
760
|
+
model.send('setData', hash);
|
698
761
|
|
699
|
-
var
|
762
|
+
var models = get(this, 'models');
|
700
763
|
|
701
764
|
set(model, 'clientId', clientId);
|
702
|
-
|
703
765
|
models[clientId] = model;
|
704
766
|
|
767
|
+
model.setProperties(properties);
|
705
768
|
this.updateModelArrays(type, clientId, hash);
|
706
769
|
|
707
770
|
return model;
|
@@ -712,7 +775,7 @@ DS.Store = Ember.Object.extend({
|
|
712
775
|
// ................
|
713
776
|
|
714
777
|
deleteRecord: function(model) {
|
715
|
-
model.deleteRecord
|
778
|
+
model.send('deleteRecord');
|
716
779
|
},
|
717
780
|
|
718
781
|
// ...............
|
@@ -739,7 +802,7 @@ DS.Store = Ember.Object.extend({
|
|
739
802
|
*/
|
740
803
|
find: function(type, id, query) {
|
741
804
|
if (id === undefined) {
|
742
|
-
return this.
|
805
|
+
return this.findAll(type);
|
743
806
|
}
|
744
807
|
|
745
808
|
if (query !== undefined) {
|
@@ -774,17 +837,17 @@ DS.Store = Ember.Object.extend({
|
|
774
837
|
if (!model) {
|
775
838
|
// create a new instance of the model in the
|
776
839
|
// 'isLoading' state
|
777
|
-
model = this.
|
840
|
+
model = this.materializeRecord(type, clientId);
|
778
841
|
|
779
842
|
// immediately set its data
|
780
|
-
model.setData
|
843
|
+
model.send('setData', data[clientId] || null);
|
781
844
|
}
|
782
845
|
} else {
|
783
846
|
clientId = this.pushHash(null, id, type);
|
784
847
|
|
785
848
|
// create a new instance of the model in the
|
786
849
|
// 'isLoading' state
|
787
|
-
model = this.
|
850
|
+
model = this.materializeRecord(type, clientId);
|
788
851
|
|
789
852
|
// let the adapter set the data, possibly async
|
790
853
|
var adapter = get(this, '_adapter');
|
@@ -898,20 +961,20 @@ DS.Store = Ember.Object.extend({
|
|
898
961
|
var data = this.clientIdToHashMap(model.constructor);
|
899
962
|
|
900
963
|
data[clientId] = hash;
|
901
|
-
model.
|
964
|
+
model.send('setData', hash);
|
902
965
|
}
|
903
966
|
|
904
|
-
model.
|
967
|
+
model.send('didCommit');
|
905
968
|
},
|
906
969
|
|
907
970
|
didDeleteRecords: function(array) {
|
908
971
|
array.forEach(function(model) {
|
909
|
-
model.
|
972
|
+
model.send('didCommit');
|
910
973
|
});
|
911
974
|
},
|
912
975
|
|
913
976
|
didDeleteRecord: function(model) {
|
914
|
-
model.
|
977
|
+
model.send('didCommit');
|
915
978
|
},
|
916
979
|
|
917
980
|
didCreateRecords: function(type, array, hashes) {
|
@@ -927,38 +990,55 @@ DS.Store = Ember.Object.extend({
|
|
927
990
|
clientId = get(model, 'clientId');
|
928
991
|
|
929
992
|
data[clientId] = hash;
|
930
|
-
|
993
|
+
model.send('setData', hash);
|
931
994
|
|
932
995
|
idToClientIdMap[id] = clientId;
|
933
996
|
idList.push(id);
|
934
997
|
|
935
|
-
model.
|
998
|
+
model.send('didCommit');
|
936
999
|
}
|
937
1000
|
},
|
938
1001
|
|
939
1002
|
didCreateRecord: function(model, hash) {
|
940
1003
|
var type = model.constructor;
|
941
1004
|
|
942
|
-
var id, clientId, primaryKey
|
1005
|
+
var id, clientId, primaryKey;
|
943
1006
|
|
944
1007
|
var idToClientIdMap = this.idToClientIdMap(type);
|
945
1008
|
var data = this.clientIdToHashMap(type);
|
946
1009
|
var idList = this.idList(type);
|
947
1010
|
|
948
|
-
|
1011
|
+
// The hash is optional, but if it is not provided, the client must have
|
1012
|
+
// provided a primary key.
|
1013
|
+
|
1014
|
+
primaryKey = getPath(type, 'proto.primaryKey');
|
1015
|
+
|
1016
|
+
// TODO: Make ember_assert more flexible and convert this into an ember_assert
|
1017
|
+
if (hash) {
|
1018
|
+
ember_assert("The server must provide a primary key: " + primaryKey, get(hash, primaryKey));
|
1019
|
+
} else {
|
1020
|
+
ember_assert("The server did not return data, and you did not create a primary key (" + primaryKey + ") on the client", get(get(model, 'data'), primaryKey));
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
// If a hash was provided, index it under the model's client ID
|
1024
|
+
// and update the model.
|
1025
|
+
if (arguments.length === 2) {
|
1026
|
+
id = hash[primaryKey];
|
1027
|
+
|
1028
|
+
data[clientId] = hash;
|
1029
|
+
set(model, 'data', hash);
|
1030
|
+
}
|
949
1031
|
|
950
1032
|
clientId = get(model, 'clientId');
|
951
|
-
data[clientId] = hash;
|
952
|
-
set(model, 'data', hash);
|
953
1033
|
|
954
1034
|
idToClientIdMap[id] = clientId;
|
955
1035
|
idList.push(id);
|
956
1036
|
|
957
|
-
model.
|
1037
|
+
model.send('didCommit');
|
958
1038
|
},
|
959
1039
|
|
960
1040
|
recordWasInvalid: function(record, errors) {
|
961
|
-
record.
|
1041
|
+
record.send('becameInvalid', errors);
|
962
1042
|
},
|
963
1043
|
|
964
1044
|
// ................
|
@@ -967,7 +1047,6 @@ DS.Store = Ember.Object.extend({
|
|
967
1047
|
|
968
1048
|
registerModelArray: function(array, type, filter) {
|
969
1049
|
var modelArrays = get(this, 'modelArrays');
|
970
|
-
var idToClientIdMap = this.idToClientIdMap(type);
|
971
1050
|
|
972
1051
|
modelArrays.push(array);
|
973
1052
|
|
@@ -987,7 +1066,7 @@ DS.Store = Ember.Object.extend({
|
|
987
1066
|
|
988
1067
|
updateModelArrayFilter: function(array, type, filter) {
|
989
1068
|
var data = this.clientIdToHashMap(type);
|
990
|
-
var allClientIds = this.clientIdList(type);
|
1069
|
+
var allClientIds = this.clientIdList(type), clientId, hash;
|
991
1070
|
|
992
1071
|
for (var i=0, l=allClientIds.length; i<l; i++) {
|
993
1072
|
clientId = allClientIds[i];
|
@@ -1001,11 +1080,12 @@ DS.Store = Ember.Object.extend({
|
|
1001
1080
|
},
|
1002
1081
|
|
1003
1082
|
updateModelArrays: function(type, clientId, hash) {
|
1004
|
-
var modelArrays = get(this, 'modelArrays')
|
1083
|
+
var modelArrays = get(this, 'modelArrays'),
|
1084
|
+
modelArrayType, filter;
|
1005
1085
|
|
1006
1086
|
modelArrays.forEach(function(array) {
|
1007
|
-
|
1008
|
-
|
1087
|
+
modelArrayType = get(array, 'type');
|
1088
|
+
filter = get(array, 'filterFunction');
|
1009
1089
|
|
1010
1090
|
if (type !== modelArrayType) { return; }
|
1011
1091
|
|
@@ -1138,8 +1218,7 @@ DS.Store = Ember.Object.extend({
|
|
1138
1218
|
|
1139
1219
|
var model = models[clientId];
|
1140
1220
|
if (model) {
|
1141
|
-
model.
|
1142
|
-
model.setData(hash);
|
1221
|
+
model.send('setData', hash);
|
1143
1222
|
}
|
1144
1223
|
} else {
|
1145
1224
|
clientId = this.pushHash(hash, id, type);
|
@@ -1208,13 +1287,21 @@ DS.Store = Ember.Object.extend({
|
|
1208
1287
|
// . MODEL MATERIALIZATION .
|
1209
1288
|
// .........................
|
1210
1289
|
|
1211
|
-
|
1290
|
+
materializeRecord: function(type, clientId) {
|
1212
1291
|
var model;
|
1213
1292
|
|
1214
|
-
get(this, 'models')[clientId] = model = type.
|
1293
|
+
get(this, 'models')[clientId] = model = type._create({ store: this, clientId: clientId });
|
1215
1294
|
set(model, 'clientId', clientId);
|
1216
|
-
model.loadingData
|
1295
|
+
model.send('loadingData');
|
1217
1296
|
return model;
|
1297
|
+
},
|
1298
|
+
|
1299
|
+
destroy: function() {
|
1300
|
+
if (get(DS, 'defaultStore') === this) {
|
1301
|
+
set(DS, 'defaultStore', null);
|
1302
|
+
}
|
1303
|
+
|
1304
|
+
return this._super();
|
1218
1305
|
}
|
1219
1306
|
});
|
1220
1307
|
|
@@ -1223,7 +1310,7 @@ DS.Store = Ember.Object.extend({
|
|
1223
1310
|
|
1224
1311
|
|
1225
1312
|
(function(exports) {
|
1226
|
-
var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
|
1313
|
+
var get = Ember.get, set = Ember.set, getPath = Ember.getPath, guidFor = Ember.guidFor;
|
1227
1314
|
|
1228
1315
|
var stateProperty = Ember.computed(function(key) {
|
1229
1316
|
var parent = get(this, 'parentState');
|
@@ -1232,6 +1319,14 @@ var stateProperty = Ember.computed(function(key) {
|
|
1232
1319
|
}
|
1233
1320
|
}).property();
|
1234
1321
|
|
1322
|
+
var isEmptyObject = function(object) {
|
1323
|
+
for (var name in object) {
|
1324
|
+
if (object.hasOwnProperty(name)) { return false; }
|
1325
|
+
}
|
1326
|
+
|
1327
|
+
return true;
|
1328
|
+
};
|
1329
|
+
|
1235
1330
|
DS.State = Ember.State.extend({
|
1236
1331
|
isLoaded: stateProperty,
|
1237
1332
|
isDirty: stateProperty,
|
@@ -1239,14 +1334,16 @@ DS.State = Ember.State.extend({
|
|
1239
1334
|
isDeleted: stateProperty,
|
1240
1335
|
isError: stateProperty,
|
1241
1336
|
isNew: stateProperty,
|
1242
|
-
isValid: stateProperty
|
1337
|
+
isValid: stateProperty,
|
1338
|
+
isPending: stateProperty,
|
1339
|
+
|
1340
|
+
// For states that are substates of a
|
1341
|
+
// DirtyState (updated or created), it is
|
1342
|
+
// useful to be able to determine which
|
1343
|
+
// type of dirty state it is.
|
1344
|
+
dirtyType: stateProperty
|
1243
1345
|
});
|
1244
1346
|
|
1245
|
-
var cantLoadData = function() {
|
1246
|
-
// TODO: get the current state name
|
1247
|
-
throw "You cannot load data into the store when its associated model is in its current state";
|
1248
|
-
};
|
1249
|
-
|
1250
1347
|
var isEmptyObject = function(obj) {
|
1251
1348
|
for (var prop in obj) {
|
1252
1349
|
if (!obj.hasOwnProperty(prop)) { continue; }
|
@@ -1259,89 +1356,287 @@ var isEmptyObject = function(obj) {
|
|
1259
1356
|
var setProperty = function(manager, context) {
|
1260
1357
|
var key = context.key, value = context.value;
|
1261
1358
|
|
1262
|
-
var model = get(manager, 'model'),
|
1263
|
-
|
1264
|
-
var data = get(model, 'data');
|
1359
|
+
var model = get(manager, 'model'),
|
1360
|
+
data = get(model, 'data');
|
1265
1361
|
|
1266
1362
|
data[key] = value;
|
1267
1363
|
|
1268
|
-
|
1364
|
+
// At the end of the run loop, notify model arrays that
|
1365
|
+
// this record has changed so they can re-evaluate its contents
|
1366
|
+
// to determine membership.
|
1367
|
+
Ember.run.once(model, model.notifyHashWasUpdated);
|
1269
1368
|
};
|
1270
1369
|
|
1271
|
-
//
|
1272
|
-
//
|
1370
|
+
// The waitingOn event shares common functionality
|
1371
|
+
// between the different dirty states, but each is
|
1372
|
+
// treated slightly differently. This method is exposed
|
1373
|
+
// so that each implementation can invoke the common
|
1374
|
+
// behavior, and then implement the behavior specific
|
1375
|
+
// to the state.
|
1376
|
+
var waitingOn = function(manager, object) {
|
1377
|
+
var model = get(manager, 'model'),
|
1378
|
+
pendingQueue = get(model, 'pendingQueue'),
|
1379
|
+
objectGuid = guidFor(object);
|
1380
|
+
|
1381
|
+
var observer = function() {
|
1382
|
+
if (get(object, 'id')) {
|
1383
|
+
manager.send('doneWaitingOn', object);
|
1384
|
+
Ember.removeObserver(object, 'id', observer);
|
1385
|
+
}
|
1386
|
+
};
|
1387
|
+
|
1388
|
+
pendingQueue[objectGuid] = [object, observer];
|
1389
|
+
Ember.addObserver(object, 'id', observer);
|
1390
|
+
};
|
1391
|
+
|
1392
|
+
// Implementation notes:
|
1393
|
+
//
|
1394
|
+
// Each state has a boolean value for all of the following flags:
|
1395
|
+
//
|
1396
|
+
// * isLoaded: The record has a populated `data` property. When a
|
1397
|
+
// record is loaded via `store.find`, `isLoaded` is false
|
1398
|
+
// until the adapter sets it. When a record is created locally,
|
1399
|
+
// its `isLoaded` property is always true.
|
1400
|
+
// * isDirty: The record has local changes that have not yet been
|
1401
|
+
// saved by the adapter. This includes records that have been
|
1402
|
+
// created (but not yet saved) or deleted.
|
1403
|
+
// * isSaving: The record's transaction has been committed, but
|
1404
|
+
// the adapter has not yet acknowledged that the changes have
|
1405
|
+
// been persisted to the backend.
|
1406
|
+
// * isDeleted: The record was marked for deletion. When `isDeleted`
|
1407
|
+
// is true and `isDirty` is true, the record is deleted locally
|
1408
|
+
// but the deletion was not yet persisted. When `isSaving` is
|
1409
|
+
// true, the change is in-flight. When both `isDirty` and
|
1410
|
+
// `isSaving` are false, the change has persisted.
|
1411
|
+
// * isError: The adapter reported that it was unable to save
|
1412
|
+
// local changes to the backend. This may also result in the
|
1413
|
+
// record having its `isValid` property become false if the
|
1414
|
+
// adapter reported that server-side validations failed.
|
1415
|
+
// * isNew: The record was created on the client and the adapter
|
1416
|
+
// did not yet report that it was successfully saved.
|
1417
|
+
// * isValid: No client-side validations have failed and the
|
1418
|
+
// adapter did not report any server-side validation failures.
|
1419
|
+
// * isPending: A record `isPending` when it belongs to an
|
1420
|
+
// association on another record and that record has not been
|
1421
|
+
// saved. A record in this state cannot be saved because it
|
1422
|
+
// lacks a "foreign key" that will be supplied by its parent
|
1423
|
+
// association when the parent record has been created. When
|
1424
|
+
// the adapter reports that the parent has saved, the
|
1425
|
+
// `isPending` property on all children will become `false`
|
1426
|
+
// and the transaction will try to commit the records.
|
1427
|
+
|
1428
|
+
|
1429
|
+
// The dirty state is a abstract state whose functionality is
|
1430
|
+
// shared between the `created` and `updated` states.
|
1431
|
+
//
|
1432
|
+
// The deleted state shares the `isDirty` flag with the
|
1433
|
+
// subclasses of `DirtyState`, but with a very different
|
1434
|
+
// implementation.
|
1273
1435
|
var DirtyState = DS.State.extend({
|
1274
|
-
|
1275
|
-
|
1276
|
-
//
|
1277
|
-
// child classes implement stateName.
|
1278
|
-
stateName: null,
|
1436
|
+
initialState: 'uncommitted',
|
1437
|
+
|
1438
|
+
// FLAGS
|
1279
1439
|
isDirty: true,
|
1280
|
-
willLoadData: cantLoadData,
|
1281
1440
|
|
1282
|
-
|
1283
|
-
var stateName = get(this, 'stateName'),
|
1284
|
-
model = get(manager, 'model');
|
1441
|
+
// SUBSTATES
|
1285
1442
|
|
1286
|
-
|
1287
|
-
|
1288
|
-
|
1289
|
-
|
1443
|
+
// When a record first becomes dirty, it is `uncommitted`.
|
1444
|
+
// This means that there are local pending changes,
|
1445
|
+
// but they have not yet begun to be saved.
|
1446
|
+
uncommitted: DS.State.extend({
|
1447
|
+
// TRANSITIONS
|
1448
|
+
enter: function(manager) {
|
1449
|
+
var dirtyType = get(this, 'dirtyType'),
|
1450
|
+
model = get(manager, 'model');
|
1290
1451
|
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1452
|
+
model.withTransaction(function (t) {
|
1453
|
+
t.modelBecameDirty(dirtyType, model);
|
1454
|
+
});
|
1455
|
+
},
|
1294
1456
|
|
1295
|
-
|
1457
|
+
exit: function(manager) {
|
1458
|
+
var model = get(manager, 'model');
|
1459
|
+
manager.send('invokeLifecycleCallbacks', model);
|
1460
|
+
},
|
1296
1461
|
|
1297
|
-
|
1298
|
-
|
1299
|
-
});
|
1300
|
-
},
|
1462
|
+
// EVENTS
|
1463
|
+
setProperty: setProperty,
|
1301
1464
|
|
1302
|
-
|
1465
|
+
deleteRecord: function(manager) {
|
1466
|
+
manager.goToState('deleted');
|
1467
|
+
},
|
1303
1468
|
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1469
|
+
waitingOn: function(manager, object) {
|
1470
|
+
waitingOn(manager, object);
|
1471
|
+
manager.goToState('pending');
|
1472
|
+
},
|
1307
1473
|
|
1308
|
-
|
1474
|
+
willCommit: function(manager) {
|
1475
|
+
manager.goToState('inFlight');
|
1476
|
+
}
|
1477
|
+
}),
|
1478
|
+
|
1479
|
+
// Once a record has been handed off to the adapter to be
|
1480
|
+
// saved, it is in the 'in flight' state. Changes to the
|
1481
|
+
// record cannot be made during this window.
|
1482
|
+
inFlight: DS.State.extend({
|
1483
|
+
// FLAGS
|
1309
1484
|
isSaving: true,
|
1310
1485
|
|
1311
|
-
|
1486
|
+
// TRANSITIONS
|
1487
|
+
enter: function(manager) {
|
1488
|
+
var dirtyType = get(this, 'dirtyType'),
|
1489
|
+
model = get(manager, 'model');
|
1490
|
+
|
1491
|
+
model.withTransaction(function (t) {
|
1492
|
+
t.modelBecameClean(dirtyType, model);
|
1493
|
+
});
|
1494
|
+
},
|
1495
|
+
|
1496
|
+
// EVENTS
|
1497
|
+
didCommit: function(manager) {
|
1312
1498
|
manager.goToState('loaded');
|
1313
1499
|
},
|
1314
1500
|
|
1315
|
-
|
1501
|
+
becameInvalid: function(manager, errors) {
|
1316
1502
|
var model = get(manager, 'model');
|
1317
1503
|
|
1318
1504
|
set(model, 'errors', errors);
|
1319
1505
|
manager.goToState('invalid');
|
1506
|
+
},
|
1507
|
+
|
1508
|
+
setData: function(manager, hash) {
|
1509
|
+
var model = get(manager, 'model');
|
1510
|
+
set(model, 'data', hash);
|
1320
1511
|
}
|
1321
1512
|
}),
|
1322
1513
|
|
1514
|
+
// If a record becomes associated with a newly created
|
1515
|
+
// parent record, it will be `pending` until the parent
|
1516
|
+
// record has successfully persisted. Once this happens,
|
1517
|
+
// this record can use the parent's primary key as its
|
1518
|
+
// foreign key.
|
1519
|
+
//
|
1520
|
+
// If the record's transaction had already started to
|
1521
|
+
// commit, the record will transition to the `inFlight`
|
1522
|
+
// state. If it had not, the record will transition to
|
1523
|
+
// the `uncommitted` state.
|
1524
|
+
pending: DS.State.extend({
|
1525
|
+
initialState: 'uncommitted',
|
1526
|
+
|
1527
|
+
// FLAGS
|
1528
|
+
isPending: true,
|
1529
|
+
|
1530
|
+
// SUBSTATES
|
1531
|
+
|
1532
|
+
// A pending record whose transaction has not yet
|
1533
|
+
// started to commit is in this state.
|
1534
|
+
uncommitted: DS.State.extend({
|
1535
|
+
// EVENTS
|
1536
|
+
setProperty: setProperty,
|
1537
|
+
|
1538
|
+
deleteRecord: function(manager) {
|
1539
|
+
var model = get(manager, 'model'),
|
1540
|
+
pendingQueue = get(model, 'pendingQueue'),
|
1541
|
+
tuple;
|
1542
|
+
|
1543
|
+
// since we are leaving the pending state, remove any
|
1544
|
+
// observers we have registered on other records.
|
1545
|
+
for (var prop in pendingQueue) {
|
1546
|
+
if (!pendingQueue.hasOwnProperty(prop)) { continue; }
|
1547
|
+
|
1548
|
+
tuple = pendingQueue[prop];
|
1549
|
+
Ember.removeObserver(tuple[0], 'id', tuple[1]);
|
1550
|
+
}
|
1551
|
+
|
1552
|
+
manager.goToState('deleted');
|
1553
|
+
},
|
1554
|
+
|
1555
|
+
willCommit: function(manager) {
|
1556
|
+
manager.goToState('committing');
|
1557
|
+
},
|
1558
|
+
|
1559
|
+
doneWaitingOn: function(manager, object) {
|
1560
|
+
var model = get(manager, 'model'),
|
1561
|
+
pendingQueue = get(model, 'pendingQueue'),
|
1562
|
+
objectGuid = guidFor(object);
|
1563
|
+
|
1564
|
+
delete pendingQueue[objectGuid];
|
1565
|
+
|
1566
|
+
if (isEmptyObject(pendingQueue)) {
|
1567
|
+
manager.send('doneWaiting');
|
1568
|
+
}
|
1569
|
+
},
|
1570
|
+
|
1571
|
+
doneWaiting: function(manager) {
|
1572
|
+
var dirtyType = get(this, 'dirtyType');
|
1573
|
+
manager.goToState(dirtyType + '.uncommitted');
|
1574
|
+
}
|
1575
|
+
}),
|
1576
|
+
|
1577
|
+
// A pending record whose transaction has started
|
1578
|
+
// to commit is in this state. Since it has not yet
|
1579
|
+
// been sent to the adapter, it is not `inFlight`
|
1580
|
+
// until all of its dependencies have been committed.
|
1581
|
+
committing: DS.State.extend({
|
1582
|
+
// FLAGS
|
1583
|
+
isSaving: true,
|
1584
|
+
|
1585
|
+
// EVENTS
|
1586
|
+
doneWaitingOn: function(manager, object) {
|
1587
|
+
var model = get(manager, 'model'),
|
1588
|
+
pendingQueue = get(model, 'pendingQueue'),
|
1589
|
+
objectGuid = guidFor(object);
|
1590
|
+
|
1591
|
+
delete pendingQueue[objectGuid];
|
1592
|
+
|
1593
|
+
if (isEmptyObject(pendingQueue)) {
|
1594
|
+
manager.send('doneWaiting');
|
1595
|
+
}
|
1596
|
+
},
|
1597
|
+
|
1598
|
+
doneWaiting: function(manager) {
|
1599
|
+
var dirtyType = get(this, 'dirtyType');
|
1600
|
+
manager.goToState(dirtyType + '.inFlight');
|
1601
|
+
}
|
1602
|
+
})
|
1603
|
+
}),
|
1604
|
+
|
1605
|
+
// A record is in the `invalid` state when its client-side
|
1606
|
+
// invalidations have failed, or if the adapter has indicated
|
1607
|
+
// the the record failed server-side invalidations.
|
1323
1608
|
invalid: DS.State.extend({
|
1609
|
+
// FLAGS
|
1324
1610
|
isValid: false,
|
1325
1611
|
|
1612
|
+
// EVENTS
|
1613
|
+
deleteRecord: function(manager) {
|
1614
|
+
manager.goToState('deleted');
|
1615
|
+
},
|
1616
|
+
|
1326
1617
|
setProperty: function(manager, context) {
|
1327
1618
|
setProperty(manager, context);
|
1328
1619
|
|
1329
|
-
var
|
1330
|
-
model = get(manager, 'model'),
|
1620
|
+
var model = get(manager, 'model'),
|
1331
1621
|
errors = get(model, 'errors'),
|
1332
1622
|
key = context.key;
|
1333
1623
|
|
1334
1624
|
delete errors[key];
|
1335
1625
|
|
1336
1626
|
if (isEmptyObject(errors)) {
|
1337
|
-
manager.
|
1627
|
+
manager.send('becameValid');
|
1338
1628
|
}
|
1629
|
+
},
|
1630
|
+
|
1631
|
+
becameValid: function(manager) {
|
1632
|
+
manager.goToState('uncommitted');
|
1339
1633
|
}
|
1340
1634
|
})
|
1341
1635
|
});
|
1342
1636
|
|
1343
1637
|
var states = {
|
1344
1638
|
rootState: Ember.State.create({
|
1639
|
+
// FLAGS
|
1345
1640
|
isLoaded: false,
|
1346
1641
|
isDirty: false,
|
1347
1642
|
isSaving: false,
|
@@ -1349,80 +1644,126 @@ var states = {
|
|
1349
1644
|
isError: false,
|
1350
1645
|
isNew: false,
|
1351
1646
|
isValid: true,
|
1647
|
+
isPending: false,
|
1352
1648
|
|
1353
|
-
|
1354
|
-
|
1355
|
-
didCreate: function(manager) {
|
1356
|
-
manager.goToState('loaded.created');
|
1357
|
-
},
|
1649
|
+
// SUBSTATES
|
1358
1650
|
|
1651
|
+
// A record begins its lifecycle in the `empty` state.
|
1652
|
+
// If its data will come from the adapter, it will
|
1653
|
+
// transition into the `loading` state. Otherwise, if
|
1654
|
+
// the record is being created on the client, it will
|
1655
|
+
// transition into the `created` state.
|
1359
1656
|
empty: DS.State.create({
|
1657
|
+
// EVENTS
|
1360
1658
|
loadingData: function(manager) {
|
1361
1659
|
manager.goToState('loading');
|
1660
|
+
},
|
1661
|
+
|
1662
|
+
setData: function(manager, hash) {
|
1663
|
+
var model = get(manager, 'model');
|
1664
|
+
set(model, 'data', hash);
|
1665
|
+
manager.goToState('loaded.created');
|
1362
1666
|
}
|
1363
1667
|
}),
|
1364
1668
|
|
1669
|
+
// A record enters this state when the store askes
|
1670
|
+
// the adapter for its data. It remains in this state
|
1671
|
+
// until the adapter provides the requested data.
|
1672
|
+
//
|
1673
|
+
// Usually, this process is asynchronous, using an
|
1674
|
+
// XHR to retrieve the data.
|
1365
1675
|
loading: DS.State.create({
|
1366
|
-
|
1367
|
-
|
1676
|
+
// TRANSITIONS
|
1368
1677
|
exit: function(manager) {
|
1369
1678
|
var model = get(manager, 'model');
|
1370
1679
|
model.didLoad();
|
1371
1680
|
},
|
1372
1681
|
|
1682
|
+
// EVENTS
|
1373
1683
|
setData: function(manager, data) {
|
1374
1684
|
var model = get(manager, 'model');
|
1375
1685
|
|
1376
1686
|
model.beginPropertyChanges();
|
1377
|
-
|
1687
|
+
set(model, 'data', data);
|
1378
1688
|
|
1379
1689
|
if (data !== null) {
|
1380
|
-
manager.
|
1690
|
+
manager.send('loadedData');
|
1381
1691
|
}
|
1382
1692
|
|
1383
1693
|
model.endPropertyChanges();
|
1694
|
+
},
|
1695
|
+
|
1696
|
+
loadedData: function(manager) {
|
1697
|
+
manager.goToState('loaded');
|
1384
1698
|
}
|
1385
1699
|
}),
|
1386
1700
|
|
1701
|
+
// A record enters this state when its data is populated.
|
1702
|
+
// Most of a record's lifecycle is spent inside substates
|
1703
|
+
// of the `loaded` state.
|
1387
1704
|
loaded: DS.State.create({
|
1705
|
+
initialState: 'saved',
|
1706
|
+
|
1707
|
+
// FLAGS
|
1388
1708
|
isLoaded: true,
|
1389
1709
|
|
1390
|
-
|
1710
|
+
// SUBSTATES
|
1391
1711
|
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
1712
|
+
// If there are no local changes to a record, it remains
|
1713
|
+
// in the `saved` state.
|
1714
|
+
saved: DS.State.create({
|
1715
|
+
// EVENTS
|
1716
|
+
setProperty: function(manager, context) {
|
1717
|
+
setProperty(manager, context);
|
1718
|
+
manager.goToState('updated');
|
1719
|
+
},
|
1396
1720
|
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1721
|
+
deleteRecord: function(manager) {
|
1722
|
+
manager.goToState('deleted');
|
1723
|
+
},
|
1400
1724
|
|
1725
|
+
waitingOn: function(manager, object) {
|
1726
|
+
waitingOn(manager, object);
|
1727
|
+
manager.goToState('updated.pending');
|
1728
|
+
}
|
1729
|
+
}),
|
1730
|
+
|
1731
|
+
// A record is in this state after it has been locally
|
1732
|
+
// created but before the adapter has indicated that
|
1733
|
+
// it has been saved.
|
1401
1734
|
created: DirtyState.create({
|
1402
|
-
|
1735
|
+
dirtyType: 'created',
|
1736
|
+
|
1737
|
+
// FLAGS
|
1403
1738
|
isNew: true,
|
1404
1739
|
|
1405
|
-
|
1740
|
+
// EVENTS
|
1741
|
+
invokeLifecycleCallbacks: function(manager, model) {
|
1406
1742
|
model.didCreate();
|
1407
1743
|
}
|
1408
1744
|
}),
|
1409
1745
|
|
1746
|
+
// A record is in this state if it has already been
|
1747
|
+
// saved to the server, but there are new local changes
|
1748
|
+
// that have not yet been saved.
|
1410
1749
|
updated: DirtyState.create({
|
1411
|
-
|
1750
|
+
dirtyType: 'updated',
|
1412
1751
|
|
1413
|
-
|
1752
|
+
// EVENTS
|
1753
|
+
invokeLifecycleCallbacks: function(manager, model) {
|
1414
1754
|
model.didUpdate();
|
1415
1755
|
}
|
1416
1756
|
})
|
1417
1757
|
}),
|
1418
1758
|
|
1759
|
+
// A record is in this state if it was deleted from the store.
|
1419
1760
|
deleted: DS.State.create({
|
1761
|
+
// FLAGS
|
1420
1762
|
isDeleted: true,
|
1421
1763
|
isLoaded: true,
|
1422
1764
|
isDirty: true,
|
1423
1765
|
|
1424
|
-
|
1425
|
-
|
1766
|
+
// TRANSITIONS
|
1426
1767
|
enter: function(manager) {
|
1427
1768
|
var model = get(manager, 'model');
|
1428
1769
|
var store = get(model, 'store');
|
@@ -1436,31 +1777,51 @@ var states = {
|
|
1436
1777
|
});
|
1437
1778
|
},
|
1438
1779
|
|
1439
|
-
|
1440
|
-
manager.goToState('saving');
|
1441
|
-
},
|
1780
|
+
// SUBSTATES
|
1442
1781
|
|
1443
|
-
|
1444
|
-
|
1782
|
+
// When a record is deleted, it enters the `start`
|
1783
|
+
// state. It will exit this state when the record's
|
1784
|
+
// transaction starts to commit.
|
1785
|
+
start: DS.State.create({
|
1786
|
+
willCommit: function(manager) {
|
1787
|
+
manager.goToState('inFlight');
|
1788
|
+
}
|
1789
|
+
}),
|
1445
1790
|
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1791
|
+
// After a record's transaction is committing, but
|
1792
|
+
// before the adapter indicates that the deletion
|
1793
|
+
// has saved to the server, a record is in the
|
1794
|
+
// `inFlight` substate of `deleted`.
|
1795
|
+
inFlight: DS.State.create({
|
1796
|
+
// FLAGS
|
1797
|
+
isSaving: true,
|
1449
1798
|
|
1799
|
+
// TRANSITIONS
|
1450
1800
|
exit: function(stateManager) {
|
1451
1801
|
var model = get(stateManager, 'model');
|
1452
1802
|
|
1453
1803
|
model.withTransaction(function(t) {
|
1454
1804
|
t.modelBecameClean('deleted', model);
|
1455
1805
|
});
|
1806
|
+
},
|
1807
|
+
|
1808
|
+
// EVENTS
|
1809
|
+
didCommit: function(manager) {
|
1810
|
+
manager.goToState('saved');
|
1456
1811
|
}
|
1457
1812
|
}),
|
1458
1813
|
|
1814
|
+
// Once the adapter indicates that the deletion has
|
1815
|
+
// been saved, the record enters the `saved` substate
|
1816
|
+
// of `deleted`.
|
1459
1817
|
saved: DS.State.create({
|
1460
1818
|
isDirty: false
|
1461
1819
|
})
|
1462
1820
|
}),
|
1463
1821
|
|
1822
|
+
// If the adapter indicates that there was an unknown
|
1823
|
+
// error saving a record, the record enters the `error`
|
1824
|
+
// state.
|
1464
1825
|
error: DS.State.create({
|
1465
1826
|
isError: true
|
1466
1827
|
})
|
@@ -1473,6 +1834,12 @@ DS.StateManager = Ember.StateManager.extend({
|
|
1473
1834
|
states: states
|
1474
1835
|
});
|
1475
1836
|
|
1837
|
+
})({});
|
1838
|
+
|
1839
|
+
|
1840
|
+
(function(exports) {
|
1841
|
+
var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
|
1842
|
+
|
1476
1843
|
var retrieveFromCurrentState = Ember.computed(function(key) {
|
1477
1844
|
return get(getPath(this, 'stateManager.currentState'), key);
|
1478
1845
|
}).property('stateManager.currentState').cacheable();
|
@@ -1484,6 +1851,7 @@ DS.Model = Ember.Object.extend({
|
|
1484
1851
|
isDeleted: retrieveFromCurrentState,
|
1485
1852
|
isError: retrieveFromCurrentState,
|
1486
1853
|
isNew: retrieveFromCurrentState,
|
1854
|
+
isPending: retrieveFromCurrentState,
|
1487
1855
|
isValid: retrieveFromCurrentState,
|
1488
1856
|
|
1489
1857
|
clientId: null,
|
@@ -1491,8 +1859,22 @@ DS.Model = Ember.Object.extend({
|
|
1491
1859
|
// because unknownProperty is used, any internal property
|
1492
1860
|
// must be initialized here.
|
1493
1861
|
primaryKey: 'id',
|
1862
|
+
id: Ember.computed(function(key, value) {
|
1863
|
+
var primaryKey = get(this, 'primaryKey'),
|
1864
|
+
data = get(this, 'data');
|
1865
|
+
|
1866
|
+
if (arguments.length === 2) {
|
1867
|
+
set(data, primaryKey, value);
|
1868
|
+
return value;
|
1869
|
+
}
|
1870
|
+
|
1871
|
+
return data && get(data, primaryKey);
|
1872
|
+
}).property('primaryKey', 'data'),
|
1873
|
+
|
1494
1874
|
data: null,
|
1875
|
+
pendingQueue: null,
|
1495
1876
|
transaction: null,
|
1877
|
+
errors: null,
|
1496
1878
|
|
1497
1879
|
didLoad: Ember.K,
|
1498
1880
|
didUpdate: Ember.K,
|
@@ -1503,100 +1885,101 @@ DS.Model = Ember.Object.extend({
|
|
1503
1885
|
model: this
|
1504
1886
|
});
|
1505
1887
|
|
1888
|
+
set(this, 'pendingQueue', {});
|
1506
1889
|
set(this, 'stateManager', stateManager);
|
1507
1890
|
stateManager.goToState('empty');
|
1508
1891
|
},
|
1509
1892
|
|
1510
|
-
withTransaction: function(fn) {
|
1511
|
-
var transaction = get(this, 'transaction') || getPath(this, 'store.defaultTransaction');
|
1512
|
-
|
1513
|
-
if (transaction) { fn(transaction); }
|
1514
|
-
},
|
1515
|
-
|
1516
|
-
setData: function(data) {
|
1517
|
-
var stateManager = get(this, 'stateManager');
|
1518
|
-
stateManager.send('setData', data);
|
1519
|
-
},
|
1520
|
-
|
1521
|
-
setProperty: function(key, value) {
|
1522
|
-
var stateManager = get(this, 'stateManager');
|
1523
|
-
stateManager.send('setProperty', { key: key, value: value });
|
1524
|
-
},
|
1525
|
-
|
1526
|
-
deleteRecord: function() {
|
1527
|
-
var stateManager = get(this, 'stateManager');
|
1528
|
-
stateManager.send('delete');
|
1529
|
-
},
|
1530
|
-
|
1531
1893
|
destroy: function() {
|
1532
|
-
this
|
1894
|
+
if (!get(this, 'isDeleted')) {
|
1895
|
+
this.deleteRecord();
|
1896
|
+
}
|
1533
1897
|
this._super();
|
1534
1898
|
},
|
1535
1899
|
|
1536
|
-
|
1537
|
-
|
1538
|
-
stateManager.send('loadingData');
|
1900
|
+
send: function(name, context) {
|
1901
|
+
return get(this, 'stateManager').send(name, context);
|
1539
1902
|
},
|
1540
1903
|
|
1541
|
-
|
1542
|
-
var
|
1543
|
-
|
1544
|
-
},
|
1545
|
-
|
1546
|
-
willCommit: function() {
|
1547
|
-
var stateManager = get(this, 'stateManager');
|
1548
|
-
stateManager.send('willCommit');
|
1904
|
+
withTransaction: function(fn) {
|
1905
|
+
var transaction = get(this, 'transaction') || getPath(this, 'store.defaultTransaction');
|
1906
|
+
if (transaction) { fn(transaction); }
|
1549
1907
|
},
|
1550
1908
|
|
1551
|
-
|
1552
|
-
|
1553
|
-
stateManager.send('didUpdate');
|
1909
|
+
setProperty: function(key, value) {
|
1910
|
+
this.send('setProperty', { key: key, value: value });
|
1554
1911
|
},
|
1555
1912
|
|
1556
|
-
|
1557
|
-
|
1558
|
-
stateManager.send('didCreate');
|
1913
|
+
deleteRecord: function() {
|
1914
|
+
this.send('deleteRecord');
|
1559
1915
|
},
|
1560
1916
|
|
1561
|
-
|
1562
|
-
|
1563
|
-
stateManager.send('didDelete');
|
1917
|
+
waitingOn: function(record) {
|
1918
|
+
this.send('waitingOn', record);
|
1564
1919
|
},
|
1565
1920
|
|
1566
|
-
|
1567
|
-
var
|
1568
|
-
|
1921
|
+
notifyHashWasUpdated: function() {
|
1922
|
+
var store = get(this, 'store');
|
1923
|
+
if (store) {
|
1924
|
+
store.hashWasUpdated(this.constructor, get(this, 'clientId'));
|
1925
|
+
}
|
1569
1926
|
},
|
1570
1927
|
|
1571
1928
|
unknownProperty: function(key) {
|
1572
1929
|
var data = get(this, 'data');
|
1573
1930
|
|
1574
|
-
if (data) {
|
1575
|
-
|
1931
|
+
if (data && key in data) {
|
1932
|
+
ember_assert("You attempted to access the " + key + " property on a model without defining an attribute.", false);
|
1576
1933
|
}
|
1577
1934
|
},
|
1578
1935
|
|
1579
1936
|
setUnknownProperty: function(key, value) {
|
1580
1937
|
var data = get(this, 'data');
|
1581
|
-
ember_assert("You cannot set a model attribute before its data is loaded.", !!data);
|
1582
1938
|
|
1583
|
-
|
1584
|
-
|
1939
|
+
if (data && key in data) {
|
1940
|
+
ember_assert("You attempted to set the " + key + " property on a model without defining an attribute.", false);
|
1941
|
+
} else {
|
1942
|
+
return this._super(key, value);
|
1943
|
+
}
|
1585
1944
|
}
|
1586
1945
|
});
|
1587
1946
|
|
1947
|
+
// Helper function to generate store aliases.
|
1948
|
+
// This returns a function that invokes the named alias
|
1949
|
+
// on the default store, but injects the class as the
|
1950
|
+
// first parameter.
|
1951
|
+
var storeAlias = function(methodName) {
|
1952
|
+
return function() {
|
1953
|
+
var store = get(DS, 'defaultStore'),
|
1954
|
+
args = [].slice.call(arguments);
|
1955
|
+
|
1956
|
+
args.unshift(this);
|
1957
|
+
return store[methodName].apply(store, args);
|
1958
|
+
};
|
1959
|
+
};
|
1960
|
+
|
1588
1961
|
DS.Model.reopenClass({
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1962
|
+
find: storeAlias('find'),
|
1963
|
+
filter: storeAlias('filter'),
|
1964
|
+
|
1965
|
+
_create: DS.Model.create,
|
1966
|
+
|
1967
|
+
create: function() {
|
1968
|
+
throw new Ember.Error("You should not call `create` on a model. Instead, call `createRecord` with the attributes you would like to set.");
|
1969
|
+
},
|
1970
|
+
|
1971
|
+
createRecord: storeAlias('createRecord')
|
1596
1972
|
});
|
1597
1973
|
|
1974
|
+
})({});
|
1975
|
+
|
1976
|
+
|
1977
|
+
(function(exports) {
|
1978
|
+
var get = Ember.get, getPath = Ember.getPath;
|
1598
1979
|
DS.attr = function(type, options) {
|
1599
1980
|
var transform = DS.attr.transforms[type];
|
1981
|
+
ember_assert("Could not find model attribute of type " + type, !!transform);
|
1982
|
+
|
1600
1983
|
var transformFrom = transform.from;
|
1601
1984
|
var transformTo = transform.to;
|
1602
1985
|
|
@@ -1618,73 +2001,24 @@ DS.attr = function(type, options) {
|
|
1618
2001
|
}
|
1619
2002
|
}).property('data');
|
1620
2003
|
};
|
1621
|
-
|
1622
|
-
var embeddedFindRecord = function(store, type, data, key, one) {
|
1623
|
-
var association = data ? get(data, key) : one ? null : [];
|
1624
|
-
if (one) {
|
1625
|
-
return association ? store.load(type, association).id : null;
|
1626
|
-
} else {
|
1627
|
-
return association ? store.loadMany(type, association).ids : [];
|
1628
|
-
}
|
1629
|
-
};
|
1630
|
-
|
1631
|
-
var referencedFindRecord = function(store, type, data, key, one) {
|
1632
|
-
return data ? get(data, key) : one ? null : [];
|
1633
|
-
};
|
1634
|
-
|
1635
|
-
var hasAssociation = function(type, options, one) {
|
1636
|
-
var embedded = options && options.embedded,
|
1637
|
-
findRecord = embedded ? embeddedFindRecord : referencedFindRecord;
|
1638
|
-
|
1639
|
-
return Ember.computed(function(key) {
|
1640
|
-
var data = get(this, 'data'), ids, id, association,
|
1641
|
-
store = get(this, 'store');
|
1642
|
-
|
1643
|
-
if (typeof type === 'string') {
|
1644
|
-
type = getPath(this, type, false) || getPath(window, type);
|
1645
|
-
}
|
1646
|
-
|
1647
|
-
key = (options && options.key) ? options.key : key;
|
1648
|
-
if (one) {
|
1649
|
-
id = findRecord(store, type, data, key, true);
|
1650
|
-
association = id ? store.find(type, id) : null;
|
1651
|
-
} else {
|
1652
|
-
ids = findRecord(store, type, data, key);
|
1653
|
-
association = store.findMany(type, ids);
|
1654
|
-
}
|
1655
|
-
|
1656
|
-
return association;
|
1657
|
-
}).property('data').cacheable().meta({ type: type });
|
1658
|
-
};
|
1659
|
-
|
1660
|
-
DS.hasMany = function(type, options) {
|
1661
|
-
ember_assert("The type passed to DS.hasMany must be defined", !!type);
|
1662
|
-
return hasAssociation(type, options);
|
1663
|
-
};
|
1664
|
-
|
1665
|
-
DS.hasOne = function(type, options) {
|
1666
|
-
ember_assert("The type passed to DS.hasOne must be defined", !!type);
|
1667
|
-
return hasAssociation(type, options, true);
|
1668
|
-
};
|
1669
|
-
|
1670
2004
|
DS.attr.transforms = {
|
1671
2005
|
string: {
|
1672
2006
|
from: function(serialized) {
|
1673
|
-
return
|
2007
|
+
return Ember.none(serialized) ? null : String(serialized);
|
1674
2008
|
},
|
1675
2009
|
|
1676
2010
|
to: function(deserialized) {
|
1677
|
-
return
|
2011
|
+
return Ember.none(deserialized) ? null : String(deserialized);
|
1678
2012
|
}
|
1679
2013
|
},
|
1680
2014
|
|
1681
2015
|
integer: {
|
1682
2016
|
from: function(serialized) {
|
1683
|
-
return
|
2017
|
+
return Ember.none(serialized) ? null : Number(serialized);
|
1684
2018
|
},
|
1685
2019
|
|
1686
2020
|
to: function(deserialized) {
|
1687
|
-
return
|
2021
|
+
return Ember.none(deserialized) ? null : Number(deserialized);
|
1688
2022
|
}
|
1689
2023
|
},
|
1690
2024
|
|
@@ -1746,6 +2080,76 @@ DS.attr.transforms = {
|
|
1746
2080
|
}
|
1747
2081
|
};
|
1748
2082
|
|
2083
|
+
|
2084
|
+
})({});
|
2085
|
+
|
2086
|
+
|
2087
|
+
(function(exports) {
|
2088
|
+
var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
|
2089
|
+
DS.Model.reopenClass({
|
2090
|
+
typeForAssociation: function(association) {
|
2091
|
+
var type = this.metaForProperty(association).type;
|
2092
|
+
if (typeof type === 'string') {
|
2093
|
+
type = getPath(this, type, false) || getPath(window, type);
|
2094
|
+
}
|
2095
|
+
return type;
|
2096
|
+
}
|
2097
|
+
});
|
2098
|
+
|
2099
|
+
|
2100
|
+
var embeddedFindRecord = function(store, type, data, key, one) {
|
2101
|
+
var association = data ? get(data, key) : one ? null : [];
|
2102
|
+
if (one) {
|
2103
|
+
return association ? store.load(type, association).id : null;
|
2104
|
+
} else {
|
2105
|
+
return association ? store.loadMany(type, association).ids : [];
|
2106
|
+
}
|
2107
|
+
};
|
2108
|
+
|
2109
|
+
var referencedFindRecord = function(store, type, data, key, one) {
|
2110
|
+
return data ? get(data, key) : one ? null : [];
|
2111
|
+
};
|
2112
|
+
|
2113
|
+
var hasAssociation = function(type, options, one) {
|
2114
|
+
var embedded = options && options.embedded,
|
2115
|
+
findRecord = embedded ? embeddedFindRecord : referencedFindRecord;
|
2116
|
+
|
2117
|
+
return Ember.computed(function(key) {
|
2118
|
+
var data = get(this, 'data'), ids, id, association,
|
2119
|
+
store = get(this, 'store');
|
2120
|
+
|
2121
|
+
if (typeof type === 'string') {
|
2122
|
+
type = getPath(this, type, false) || getPath(window, type);
|
2123
|
+
}
|
2124
|
+
|
2125
|
+
key = (options && options.key) ? options.key : key;
|
2126
|
+
if (one) {
|
2127
|
+
id = findRecord(store, type, data, key, true);
|
2128
|
+
association = id ? store.find(type, id) : null;
|
2129
|
+
} else {
|
2130
|
+
ids = findRecord(store, type, data, key);
|
2131
|
+
association = store.findMany(type, ids);
|
2132
|
+
set(association, 'parentRecord', this);
|
2133
|
+
}
|
2134
|
+
|
2135
|
+
return association;
|
2136
|
+
}).property('data').cacheable().meta({ type: type });
|
2137
|
+
};
|
2138
|
+
|
2139
|
+
DS.hasMany = function(type, options) {
|
2140
|
+
ember_assert("The type passed to DS.hasMany must be defined", !!type);
|
2141
|
+
return hasAssociation(type, options);
|
2142
|
+
};
|
2143
|
+
|
2144
|
+
DS.hasOne = function(type, options) {
|
2145
|
+
ember_assert("The type passed to DS.hasOne must be defined", !!type);
|
2146
|
+
return hasAssociation(type, options, true);
|
2147
|
+
};
|
2148
|
+
|
2149
|
+
})({});
|
2150
|
+
|
2151
|
+
|
2152
|
+
(function(exports) {
|
1749
2153
|
})({});
|
1750
2154
|
|
1751
2155
|
|