rightnow_oms 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ *Rightnow OMS 0.1.4 (Wed 11:57, Feb 22, 2012)*
2
+
3
+ * Upgraded Ember.JS to 0.9.5
4
+ * Fixed batch create and update errors
5
+
1
6
  *Rightnow OMS 0.1.3 (Fri 20:05, Feb 17, 2012)*
2
7
 
3
8
  * Don't count the children of cart items
data/README.md CHANGED
@@ -51,7 +51,7 @@ Create the migrations with:
51
51
  Run `bundle install` and require ember and ember-data in your `app/assets/javascripts/application.js`:
52
52
 
53
53
  ```
54
- = require rightnow_oms/vendor/ember
54
+ = require rightnow_oms/vendor/ember-0.9.5
55
55
  = require rightnow_oms/vendor/ember-data
56
56
  ```
57
57
 
@@ -150,6 +150,24 @@ You can add cartables to the cart by:
150
150
  })
151
151
  ```
152
152
 
153
+ ### Strategy to sync data with remote
154
+
155
+ By default, RightnowOms sync the data immediately when you change the
156
+ data objects in the store. But by setting `autoCommit` to `false`, you
157
+ can change the default behavior.
158
+
159
+ ```javascript
160
+ RightnowOms.config.set('autoCommit', false)
161
+ ```
162
+
163
+ If you turn off auto-commit, you need to sync the data explicitly. When
164
+ you have created, updated and deleted any data object in the client
165
+ side, you ought to commit these changes by yourself.
166
+
167
+ ```javascript
168
+ RightnowOms.commit(true)
169
+ ```
170
+
153
171
  Now you have all things done. Wish you have a good day.
154
172
 
155
173
  ## Development
@@ -1,5 +1,13 @@
1
1
  window.RightnowOms = Ember.Application.create
2
2
  rootElement: '#rightnow-oms'
3
+ commit: (force = false)->
4
+ clearTimeout(@_commitTimer) if @_commitTimer
5
+
6
+ @_commitTimer = setTimeout((->
7
+ window.RightnowOms.store.commit() if window.RightnowOms.config.get('autoCommit') || force
8
+ ), 500)
9
+
10
+ _commitTimer: null
3
11
 
4
12
  window.RightnowOms.store = DS.Store.create
5
13
  adapter:
@@ -8,3 +16,4 @@ window.RightnowOms.store = DS.Store.create
8
16
  namespace: 'rightnow_oms'
9
17
 
10
18
  window.RightnowOms.config = Em.Object.create()
19
+ window.RightnowOms.config.set('autoCommit', true)
@@ -9,19 +9,29 @@ RightnowOms.cartController = Ember.Object.create
9
9
  @set('content', RightnowOms.store.find(RightnowOms.Cart, @get('content').get('id')))
10
10
 
11
11
  # item: a hash
12
- addCartItem: (item, callback) ->
12
+ addCartItem: (item) ->
13
13
  cartItem = @get('content').addCartItem(item)
14
- @store.commit()
14
+ RightnowOms.commit()
15
15
 
16
- return unless callback
17
-
18
- return callback.call(@, cartItem) if cartItem.get('id')
16
+ return if !(item.children && item.children.length > 0)
19
17
 
20
18
  self = @
21
- cartItem.addObserver('isDirty', ->
19
+
20
+ addChildren = (parent, children) ->
21
+ children.forEach((c) ->
22
+ c.parent_id = parent.get('id')
23
+ self.addCartItem(c)
24
+ )
25
+
26
+ return addChildren(cartItem, item.children) if cartItem.get('id')?
27
+
28
+ afterCartItemCreated = ->
22
29
  if (!cartItem.get('isDirty')) && (!cartItem.get('isDeleted'))
23
- callback.call(self, cartItem)
24
- )
30
+ addChildren(cartItem, item.children)
31
+ cartItem.removeObserver('isDirty', afterCartItemCreated)
32
+ RightnowOms.commit(true) unless RightnowOms.config.get('autoCommit')
33
+
34
+ cartItem.addObserver('isDirty', afterCartItemCreated)
25
35
 
26
36
  # @id: id of the cart item to be updated
27
37
  # @properties: a hash which is the new properties of the cart item.
@@ -33,19 +43,31 @@ RightnowOms.cartController = Ember.Object.create
33
43
  # 'quantity': 2
34
44
  # })
35
45
  updateCartItem: (id, properties) ->
46
+ if RightnowOms.CartItem.findById(id).isProcessing()
47
+ alert('正在保存购物车,请稍后。。。')
48
+ return
49
+
36
50
  @get('content').updateCartItem(id, properties)
37
- @store.commit()
51
+ RightnowOms.commit()
38
52
 
39
53
  increaseCartItem: (id) ->
40
- @get('content').increaseCartItem(id)
41
- @store.commit()
54
+ if RightnowOms.CartItem.findById(id).isProcessing()
55
+ alert('正在保存购物车,请稍后。。。')
56
+ return
57
+
58
+ cartItem = @get('content').increaseCartItem(id)
59
+ RightnowOms.commit(true)
42
60
 
43
61
  decreaseCartItem: (id) ->
44
62
  cartItem = RightnowOms.CartItem.findById(id)
45
63
 
64
+ if cartItem.isProcessing()
65
+ alert('正在保存购物车,请稍后。。。')
66
+ return
67
+
46
68
  if cartItem.get('isDecreasable')
47
69
  @get('content').decreaseCartItem(id)
48
- @store.commit()
70
+ RightnowOms.commit(true)
49
71
  else
50
72
  @removeCartItem(id)
51
73
 
@@ -55,12 +77,12 @@ RightnowOms.cartController = Ember.Object.create
55
77
 
56
78
  if remove
57
79
  @get('content').removeCartItem(id)
58
- @store.commit()
80
+ RightnowOms.commit(true)
59
81
 
60
82
  cleanUp: ->
61
83
  if confirm('您确定要清空您的购物车吗?')
62
84
  @get('content').cleanUp()
63
- @store.commit()
85
+ RightnowOms.commit(true)
64
86
 
65
87
  # return: an array of cart items.
66
88
  #
@@ -70,15 +92,15 @@ RightnowOms.cartController = Ember.Object.create
70
92
  #
71
93
  # =>
72
94
  # [{
73
- # 'id': 1, 'cartable_id': 2, 'cartable_type': 'Product', 'name': 'product-1', 'original_price', 10.0, 'price': 10.0, 'group': 'booking', 'parent_id': null
95
+ # 'id': 1, 'cartable_id': 2, 'cartable_type': 'Product', 'name': 'product-1', 'original_price', 10.0, 'base_quantity': 1, 'price': 10.0, 'group': 'booking', 'parent_id': null
74
96
  # }, {
75
- # 'id': 2, 'cartable_id': 3, 'cartable_type': 'Product', 'name': 'product-2', 'original_price', 20.0, 'price': 20.0, 'group': 'booking', 'parent_id': 2
97
+ # 'id': 2, 'cartable_id': 3, 'cartable_type': 'Product', 'name': 'product-2', 'original_price', 20.0, 'base_quantity': 1, 'price': 20.0, 'group': 'booking', 'parent_id': 2
76
98
  # }]
77
99
  findCartItemsByGroup: (group) ->
78
100
  found = []
79
101
  cartItems = @get('content').findCartItemsByGroup(group)
80
102
 
81
103
  cartItems.forEach (item) ->
82
- found.push(item.getProperties('id', 'cartable_id', 'cartable_type', 'name', 'original_price', 'price', 'quantity', 'group', 'parent_id'))
104
+ found.push(item.getProperties('id', 'cartable_id', 'cartable_type', 'name', 'original_price', 'base_quantity', 'price', 'quantity', 'group', 'parent_id'))
83
105
 
84
106
  found
@@ -17,7 +17,7 @@ RightnowOms.Cart = DS.Model.extend
17
17
  total += item.get('price') * item.get('quantity') unless item.get('hasParent')
18
18
 
19
19
  round(total, 2)
20
- ).property("cartItems.@each.quantity")
20
+ ).property("cartItems.@each.quantity", "cartItems.@each.price")
21
21
 
22
22
  addCartItem: (item) ->
23
23
  return @createCartItem(item) if item.mergable == false
@@ -68,6 +68,9 @@ RightnowOms.CartItem = DS.Model.extend
68
68
 
69
69
  @_super()
70
70
 
71
+ isProcessing: ->
72
+ @get('isSaving') || @get('children').someProperty('isSaving', true)
73
+
71
74
  RightnowOms.CartItem.reopenClass
72
75
  all: ->
73
76
  RightnowOms.store.findAll(RightnowOms.CartItem)
@@ -1735,7 +1735,7 @@ if ('undefined' === typeof Ember) {
1735
1735
  /**
1736
1736
  @namespace
1737
1737
  @name Ember
1738
- @version 0.9.4
1738
+ @version 0.9.5
1739
1739
 
1740
1740
  All Ember methods and functions are defined inside of this namespace.
1741
1741
  You generally should not add new properties to this namespace as it may be
@@ -1767,10 +1767,10 @@ if ('undefined' !== typeof window) {
1767
1767
  /**
1768
1768
  @static
1769
1769
  @type String
1770
- @default '0.9.4'
1770
+ @default '0.9.5'
1771
1771
  @constant
1772
1772
  */
1773
- Ember.VERSION = '0.9.4';
1773
+ Ember.VERSION = '0.9.5';
1774
1774
 
1775
1775
  /**
1776
1776
  @static
@@ -6299,6 +6299,8 @@ function findNamespaces() {
6299
6299
  // get(window.globalStorage, 'isNamespace') would try to read the storage for domain isNamespace and cause exception in Firefox.
6300
6300
  // globalStorage is a storage obsoleted by the WhatWG storage specification. See https://developer.mozilla.org/en/DOM/Storage#globalStorage
6301
6301
  if (prop === "globalStorage" && window.StorageList && window.globalStorage instanceof window.StorageList) { continue; }
6302
+ // Don't access properties on parent window, which will throw "Access/Permission Denied" in IE/Firefox for windows on different domains
6303
+ if (prop === "parent" || prop === "top" || prop === "frameElement" || prop === "content") { continue; }
6302
6304
  // Unfortunately, some versions of IE don't support window.hasOwnProperty
6303
6305
  if (window.hasOwnProperty && !window.hasOwnProperty(prop)) { continue; }
6304
6306
 
@@ -11295,6 +11297,18 @@ Ember.View = Ember.Object.extend(
11295
11297
  */
11296
11298
  templateName: null,
11297
11299
 
11300
+ /**
11301
+ The name of the layout to lookup if no layout is provided.
11302
+
11303
+ Ember.View will look for a template with this name in this view's
11304
+ `templates` object. By default, this will be a global object
11305
+ shared in `Ember.TEMPLATES`.
11306
+
11307
+ @type String
11308
+ @default null
11309
+ */
11310
+ layoutName: null,
11311
+
11298
11312
  /**
11299
11313
  The hash in which to look for `templateName`.
11300
11314
 
@@ -11317,25 +11331,46 @@ Ember.View = Ember.Object.extend(
11317
11331
  template: Ember.computed(function(key, value) {
11318
11332
  if (value !== undefined) { return value; }
11319
11333
 
11320
- var templateName = get(this, 'templateName'), template;
11334
+ var templateName = get(this, 'templateName'),
11335
+ template = this.templateForName(templateName, 'template');
11321
11336
 
11322
- if (templateName) { template = get(get(this, 'templates'), templateName); }
11337
+ return template || get(this, 'defaultTemplate');
11338
+ }).property('templateName').cacheable(),
11323
11339
 
11324
- // If there is no template but a templateName has been specified,
11325
- // try to lookup as a spade module
11326
- if (!template && templateName) {
11327
- if ('undefined' !== require && require.exists) {
11328
- if (require.exists(templateName)) { template = require(templateName); }
11329
- }
11340
+ /**
11341
+ A view may contain a layout. A layout is a regular template but
11342
+ supercedes the `template` property during rendering. It is the
11343
+ responsibility of the layout template to retrieve the `template`
11344
+ property from the view and render it in the correct location.
11330
11345
 
11331
- if (!template) {
11332
- throw new Ember.Error(fmt('%@ - Unable to find template "%@".', [this, templateName]));
11333
- }
11346
+ This is useful for a view that has a shared wrapper, but which delegates
11347
+ the rendering of the contents of the wrapper to the `template` property
11348
+ on a subclass.
11349
+
11350
+ @field
11351
+ @type Function
11352
+ */
11353
+ layout: Ember.computed(function(key, value) {
11354
+ if (arguments.length === 2) { return value; }
11355
+
11356
+ var layoutName = get(this, 'layoutName'),
11357
+ layout = this.templateForName(layoutName, 'layout');
11358
+
11359
+ return layout || get(this, 'defaultLayout');
11360
+ }).property('layoutName').cacheable(),
11361
+
11362
+ templateForName: function(name, type) {
11363
+ if (!name) { return; }
11364
+
11365
+ var templates = get(this, 'templates'),
11366
+ template = get(templates, name);
11367
+
11368
+ if (!template) {
11369
+ throw new Ember.Error(fmt('%@ - Unable to find %@ "%@".', [this, type, name]));
11334
11370
  }
11335
11371
 
11336
- // return the template, or undefined if no template was found
11337
- return template || get(this, 'defaultTemplate');
11338
- }).property('templateName').cacheable(),
11372
+ return template;
11373
+ },
11339
11374
 
11340
11375
  /**
11341
11376
  The object from which templates should access properties.
@@ -11499,7 +11534,10 @@ Ember.View = Ember.Object.extend(
11499
11534
  @param {Ember.RenderBuffer} buffer The render buffer
11500
11535
  */
11501
11536
  render: function(buffer) {
11502
- var template = get(this, 'template');
11537
+ // If this view has a layout, it is the responsibility of the
11538
+ // the layout to render the view's template. Otherwise, render the template
11539
+ // directly.
11540
+ var template = get(this, 'layout') || get(this, 'template');
11503
11541
 
11504
11542
  if (template) {
11505
11543
  var context = get(this, 'templateContext'),
@@ -13412,8 +13450,6 @@ Ember.State = Ember.Object.extend({
13412
13450
 
13413
13451
  (function(exports) {
13414
13452
  var get = Ember.get, set = Ember.set, getPath = Ember.getPath, fmt = Ember.String.fmt;
13415
- Ember.LOG_STATE_TRANSITIONS = false;
13416
-
13417
13453
  /**
13418
13454
  @class
13419
13455
  */
@@ -13478,19 +13514,19 @@ Ember.StateManager = Ember.State.extend(
13478
13514
  },
13479
13515
 
13480
13516
  sendRecursively: function(event, currentState, context) {
13481
- var log = Ember.LOG_STATE_TRANSITIONS;
13517
+ var log = this.enableLogging;
13482
13518
 
13483
13519
  var action = currentState[event];
13484
13520
 
13485
13521
  if (action) {
13486
- if (log) { console.log(fmt("STATEMANAGER: Sending event '%@' to state %@.", [event, currentState.name])); }
13522
+ if (log) { console.log(fmt("STATEMANAGER: Sending event '%@' to state %@.", [event, get(currentState, 'path')])); }
13487
13523
  action.call(currentState, this, context);
13488
13524
  } else {
13489
13525
  var parentState = get(currentState, 'parentState');
13490
13526
  if (parentState) {
13491
13527
  this.sendRecursively(event, parentState, context);
13492
13528
  } else if (get(this, 'errorOnUnhandledEvent')) {
13493
- throw new Ember.Error(this.toString() + " could not respond to event " + event + " in state " + getPath(this, 'currentState.name') + ".");
13529
+ throw new Ember.Error(this.toString() + " could not respond to event " + event + " in state " + getPath(this, 'currentState.path') + ".");
13494
13530
  }
13495
13531
  }
13496
13532
  },
@@ -13598,7 +13634,7 @@ Ember.StateManager = Ember.State.extend(
13598
13634
  },
13599
13635
 
13600
13636
  enterState: function(exitStates, enterStates, state) {
13601
- var log = Ember.LOG_STATE_TRANSITIONS;
13637
+ var log = this.enableLogging;
13602
13638
 
13603
13639
  var stateManager = this;
13604
13640
 
@@ -13607,7 +13643,7 @@ Ember.StateManager = Ember.State.extend(
13607
13643
  state.exit(stateManager, transition);
13608
13644
  }, function() {
13609
13645
  this.asyncEach(enterStates, function(state, transition) {
13610
- if (log) { console.log("STATEMANAGER: Entering " + state.name); }
13646
+ if (log) { console.log("STATEMANAGER: Entering " + get(state, 'path')); }
13611
13647
  state.enter(stateManager, transition);
13612
13648
  }, function() {
13613
13649
  var startState = state, enteredState, initialState;
@@ -13622,7 +13658,7 @@ Ember.StateManager = Ember.State.extend(
13622
13658
  while (startState = get(get(startState, 'states'), initialState)) {
13623
13659
  enteredState = startState;
13624
13660
 
13625
- if (log) { console.log("STATEMANAGER: Entering " + startState.name); }
13661
+ if (log) { console.log("STATEMANAGER: Entering " + get(startState, 'path')); }
13626
13662
  startState.enter(stateManager);
13627
13663
 
13628
13664
  initialState = get(startState, 'initialState');
@@ -15739,6 +15775,27 @@ EmberHandlebars.registerHelper('action', function(actionName, options) {
15739
15775
  })({});
15740
15776
 
15741
15777
 
15778
+ (function(exports) {
15779
+ var get = Ember.get, set = Ember.set;
15780
+
15781
+ Ember.Handlebars.registerHelper('yield', function(options) {
15782
+ var view = options.data.view, template;
15783
+
15784
+ while (view && !get(view, 'layout')) {
15785
+ view = get(view, 'parentView');
15786
+ }
15787
+
15788
+ ember_assert("You called yield in a template that was not a layout", !!view);
15789
+
15790
+ template = get(view, 'template');
15791
+
15792
+ ember_assert("You called yield on " + view.toString() + " without supplying a template", !!template);
15793
+ template(this, options);
15794
+ });
15795
+
15796
+ })({});
15797
+
15798
+
15742
15799
  (function(exports) {
15743
15800
  // ==========================================================================
15744
15801
  // Project: Ember Handlebar Views
@@ -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,7 +81,6 @@ DS.fixtureAdapter = DS.Adapter.create({
81
81
 
82
82
 
83
83
  (function(exports) {
84
- /*global jQuery*/
85
84
  var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
86
85
 
87
86
  DS.RESTAdapter = DS.Adapter.extend({
@@ -121,7 +120,8 @@ DS.RESTAdapter = DS.Adapter.extend({
121
120
  },
122
121
 
123
122
  updateRecord: function(store, type, model) {
124
- var id = get(model, 'id');
123
+ var primaryKey = getPath(type, 'proto.primaryKey'),
124
+ id = get(model, primaryKey);
125
125
  var root = this.rootForType(type);
126
126
 
127
127
  var data = {};
@@ -159,7 +159,8 @@ DS.RESTAdapter = DS.Adapter.extend({
159
159
  },
160
160
 
161
161
  deleteRecord: function(store, type, model) {
162
- var id = get(model, 'id');
162
+ var primaryKey = getPath(type, 'proto.primaryKey'),
163
+ id = get(model, primaryKey);
163
164
  var root = this.rootForType(type);
164
165
 
165
166
  var url = ["", this.pluralize(root), id].join("/");
@@ -177,11 +178,12 @@ DS.RESTAdapter = DS.Adapter.extend({
177
178
  }
178
179
 
179
180
  var root = this.rootForType(type),
180
- plural = this.pluralize(root);
181
+ plural = this.pluralize(root),
182
+ primaryKey = getPath(type, 'proto.primaryKey');
181
183
 
182
184
  var data = {};
183
185
  data[plural] = models.map(function(model) {
184
- return get(model, 'id');
186
+ return get(model, primaryKey);
185
187
  });
186
188
 
187
189
  this.ajax("/" + this.pluralize(root) + "/delete", "POST", {
@@ -213,6 +215,7 @@ DS.RESTAdapter = DS.Adapter.extend({
213
215
  store.loadMany(type, ids, json[plural]);
214
216
  }
215
217
  });
218
+ var url = "/" + plural;
216
219
  },
217
220
 
218
221
  findAll: function(store, type) {
@@ -271,58 +274,19 @@ DS.RESTAdapter = DS.Adapter.extend({
271
274
  (function(exports) {
272
275
  var get = Ember.get, set = Ember.set;
273
276
 
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
-
282
277
  DS.ModelArray = Ember.ArrayProxy.extend({
283
-
284
- /**
285
- The model type contained by this model array.
286
-
287
- @type DS.Model
288
- */
289
278
  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.
295
279
  content: null,
296
-
297
- // The store that created this model array.
298
280
  store: null,
299
281
 
300
- // for associations, the model that this association belongs to.
301
- parentModel: null,
302
-
303
282
  init: function() {
304
283
  set(this, 'modelCache', Ember.A([]));
305
284
  this._super();
306
285
  },
307
286
 
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
-
323
287
  arrayDidChange: function(array, index, removed, added) {
324
288
  var modelCache = get(this, 'modelCache');
325
- modelCache.replace(index, 0, new Array(added));
289
+ modelCache.replace(index, 0, Array(added));
326
290
 
327
291
  this._super(array, index, removed, added);
328
292
  },
@@ -354,12 +318,6 @@ DS.ModelArray = Ember.ArrayProxy.extend({
354
318
  }
355
319
  });
356
320
 
357
- })({});
358
-
359
-
360
- (function(exports) {
361
- var get = Ember.get;
362
-
363
321
  DS.FilteredModelArray = DS.ModelArray.extend({
364
322
  filterFunction: null,
365
323
 
@@ -369,12 +327,6 @@ DS.FilteredModelArray = DS.ModelArray.extend({
369
327
  }, 'filterFunction')
370
328
  });
371
329
 
372
- })({});
373
-
374
-
375
- (function(exports) {
376
- var get = Ember.get, set = Ember.set;
377
-
378
330
  DS.AdapterPopulatedModelArray = DS.ModelArray.extend({
379
331
  query: null,
380
332
  isLoaded: false,
@@ -391,11 +343,6 @@ DS.AdapterPopulatedModelArray = DS.ModelArray.extend({
391
343
  }
392
344
  });
393
345
 
394
-
395
- })({});
396
-
397
-
398
- (function(exports) {
399
346
  })({});
400
347
 
401
348
 
@@ -437,8 +384,7 @@ var OrderedSet = Ember.Object.extend({
437
384
  },
438
385
 
439
386
  forEach: function(fn, self) {
440
- // allow mutation during iteration
441
- get(this, 'list').slice().forEach(function(item) {
387
+ get(this, 'list').forEach(function(item) {
442
388
  fn.call(self, item);
443
389
  });
444
390
  },
@@ -501,8 +447,7 @@ var Hash = Ember.Object.extend({
501
447
  },
502
448
 
503
449
  forEach: function(fn, binding) {
504
- var keys = get(this, 'keys'),
505
- values = get(this, 'values');
450
+ var keys = get(this, 'keys'), values = get(this, 'values');
506
451
 
507
452
  keys.forEach(function(key) {
508
453
  var guid = Ember.guidFor(key);
@@ -562,17 +507,8 @@ DS.Transaction = Ember.Object.extend({
562
507
  dirty.forEach(function(type, models) {
563
508
  if (models.isEmpty()) { return; }
564
509
 
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);
510
+ models.forEach(function(model) { model.willCommit(); });
511
+ fn.call(binding, type, models.toArray());
576
512
  });
577
513
  };
578
514
 
@@ -744,27 +680,28 @@ DS.Store = Ember.Object.extend({
744
680
  // . CREATE NEW MODEL .
745
681
  // ....................
746
682
 
747
- createRecord: function(type, properties, transaction) {
748
- properties = properties || {};
683
+ createRecord: function(type, hash, transaction) {
684
+ hash = hash || {};
749
685
 
750
- var id = properties[getPath(type, 'proto.primaryKey')] || null;
686
+ var id = hash[getPath(type, 'proto.primaryKey')] || null;
751
687
 
752
- var model = type._create({
688
+ var model = type.create({
689
+ data: hash || {},
753
690
  store: this,
754
691
  transaction: transaction
755
692
  });
756
693
 
757
- var hash = {}, clientId;
758
-
759
- clientId = this.pushHash(hash, id, type);
760
- model.send('setData', hash);
694
+ model.adapterDidCreate();
761
695
 
696
+ var data = this.clientIdToHashMap(type);
762
697
  var models = get(this, 'models');
763
698
 
699
+ var clientId = this.pushHash(hash, id, type);
700
+
764
701
  set(model, 'clientId', clientId);
702
+
765
703
  models[clientId] = model;
766
704
 
767
- model.setProperties(properties);
768
705
  this.updateModelArrays(type, clientId, hash);
769
706
 
770
707
  return model;
@@ -775,7 +712,7 @@ DS.Store = Ember.Object.extend({
775
712
  // ................
776
713
 
777
714
  deleteRecord: function(model) {
778
- model.send('deleteRecord');
715
+ model.deleteRecord();
779
716
  },
780
717
 
781
718
  // ...............
@@ -802,7 +739,7 @@ DS.Store = Ember.Object.extend({
802
739
  */
803
740
  find: function(type, id, query) {
804
741
  if (id === undefined) {
805
- return this.findAll(type);
742
+ return this.findMany(type, null, null);
806
743
  }
807
744
 
808
745
  if (query !== undefined) {
@@ -837,22 +774,22 @@ DS.Store = Ember.Object.extend({
837
774
  if (!model) {
838
775
  // create a new instance of the model in the
839
776
  // 'isLoading' state
840
- model = this.materializeRecord(type, clientId);
777
+ model = this.createModel(type, clientId);
841
778
 
842
779
  // immediately set its data
843
- model.send('setData', data[clientId] || null);
780
+ model.setData(data[clientId] || null);
844
781
  }
845
782
  } else {
846
783
  clientId = this.pushHash(null, id, type);
847
784
 
848
785
  // create a new instance of the model in the
849
786
  // 'isLoading' state
850
- model = this.materializeRecord(type, clientId);
787
+ model = this.createModel(type, clientId);
851
788
 
852
789
  // let the adapter set the data, possibly async
853
790
  var adapter = get(this, '_adapter');
854
791
  if (adapter && adapter.find) { adapter.find(this, type, id); }
855
- else { throw fmt("Adapter is either null or does not implement `find` method", this); }
792
+ else { throw fmt("Adapter is either null or do not implement `find` method", this); }
856
793
  }
857
794
 
858
795
  return model;
@@ -885,7 +822,7 @@ DS.Store = Ember.Object.extend({
885
822
  if ((needed && get(needed, 'length') > 0) || query) {
886
823
  var adapter = get(this, '_adapter');
887
824
  if (adapter && adapter.findMany) { adapter.findMany(this, type, needed, query); }
888
- else { throw fmt("Adapter is either null or does not implement `findMany` method", this); }
825
+ else { throw fmt("Adapter is either null or do not implement `findMany` method", this); }
889
826
  }
890
827
 
891
828
  return this.createModelArray(type, clientIds);
@@ -895,7 +832,7 @@ DS.Store = Ember.Object.extend({
895
832
  var array = DS.AdapterPopulatedModelArray.create({ type: type, content: Ember.A([]), store: this });
896
833
  var adapter = get(this, '_adapter');
897
834
  if (adapter && adapter.findQuery) { adapter.findQuery(this, type, query, array); }
898
- else { throw fmt("Adapter is either null or does not implement `findQuery` method", this); }
835
+ else { throw fmt("Adapter is either null or do not implement `findQuery` method", this); }
899
836
  return array;
900
837
  },
901
838
 
@@ -961,20 +898,20 @@ DS.Store = Ember.Object.extend({
961
898
  var data = this.clientIdToHashMap(model.constructor);
962
899
 
963
900
  data[clientId] = hash;
964
- model.send('setData', hash);
901
+ model.set('data', hash);
965
902
  }
966
903
 
967
- model.send('didCommit');
904
+ model.adapterDidUpdate();
968
905
  },
969
906
 
970
907
  didDeleteRecords: function(array) {
971
908
  array.forEach(function(model) {
972
- model.send('didCommit');
909
+ model.adapterDidDelete();
973
910
  });
974
911
  },
975
912
 
976
913
  didDeleteRecord: function(model) {
977
- model.send('didCommit');
914
+ model.adapterDidDelete();
978
915
  },
979
916
 
980
917
  didCreateRecords: function(type, array, hashes) {
@@ -990,55 +927,38 @@ DS.Store = Ember.Object.extend({
990
927
  clientId = get(model, 'clientId');
991
928
 
992
929
  data[clientId] = hash;
993
- model.send('setData', hash);
930
+ set(model, 'data', hash);
994
931
 
995
932
  idToClientIdMap[id] = clientId;
996
933
  idList.push(id);
997
934
 
998
- model.send('didCommit');
935
+ model.adapterDidUpdate();
999
936
  }
1000
937
  },
1001
938
 
1002
939
  didCreateRecord: function(model, hash) {
1003
940
  var type = model.constructor;
1004
941
 
1005
- var id, clientId, primaryKey;
942
+ var id, clientId, primaryKey = getPath(type, 'proto.primaryKey');
1006
943
 
1007
944
  var idToClientIdMap = this.idToClientIdMap(type);
1008
945
  var data = this.clientIdToHashMap(type);
1009
946
  var idList = this.idList(type);
1010
947
 
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
- }
948
+ id = hash[primaryKey];
1031
949
 
1032
950
  clientId = get(model, 'clientId');
951
+ data[clientId] = hash;
952
+ set(model, 'data', hash);
1033
953
 
1034
954
  idToClientIdMap[id] = clientId;
1035
955
  idList.push(id);
1036
956
 
1037
- model.send('didCommit');
957
+ model.adapterDidUpdate();
1038
958
  },
1039
959
 
1040
960
  recordWasInvalid: function(record, errors) {
1041
- record.send('becameInvalid', errors);
961
+ record.wasInvalid(errors);
1042
962
  },
1043
963
 
1044
964
  // ................
@@ -1047,6 +967,7 @@ DS.Store = Ember.Object.extend({
1047
967
 
1048
968
  registerModelArray: function(array, type, filter) {
1049
969
  var modelArrays = get(this, 'modelArrays');
970
+ var idToClientIdMap = this.idToClientIdMap(type);
1050
971
 
1051
972
  modelArrays.push(array);
1052
973
 
@@ -1066,7 +987,7 @@ DS.Store = Ember.Object.extend({
1066
987
 
1067
988
  updateModelArrayFilter: function(array, type, filter) {
1068
989
  var data = this.clientIdToHashMap(type);
1069
- var allClientIds = this.clientIdList(type), clientId, hash;
990
+ var allClientIds = this.clientIdList(type);
1070
991
 
1071
992
  for (var i=0, l=allClientIds.length; i<l; i++) {
1072
993
  clientId = allClientIds[i];
@@ -1080,12 +1001,11 @@ DS.Store = Ember.Object.extend({
1080
1001
  },
1081
1002
 
1082
1003
  updateModelArrays: function(type, clientId, hash) {
1083
- var modelArrays = get(this, 'modelArrays'),
1084
- modelArrayType, filter;
1004
+ var modelArrays = get(this, 'modelArrays');
1085
1005
 
1086
1006
  modelArrays.forEach(function(array) {
1087
- modelArrayType = get(array, 'type');
1088
- filter = get(array, 'filterFunction');
1007
+ modelArrayType = get(array, 'type');
1008
+ filter = get(array, 'filterFunction');
1089
1009
 
1090
1010
  if (type !== modelArrayType) { return; }
1091
1011
 
@@ -1218,7 +1138,8 @@ DS.Store = Ember.Object.extend({
1218
1138
 
1219
1139
  var model = models[clientId];
1220
1140
  if (model) {
1221
- model.send('setData', hash);
1141
+ model.willLoadData();
1142
+ model.setData(hash);
1222
1143
  }
1223
1144
  } else {
1224
1145
  clientId = this.pushHash(hash, id, type);
@@ -1287,21 +1208,13 @@ DS.Store = Ember.Object.extend({
1287
1208
  // . MODEL MATERIALIZATION .
1288
1209
  // .........................
1289
1210
 
1290
- materializeRecord: function(type, clientId) {
1211
+ createModel: function(type, clientId) {
1291
1212
  var model;
1292
1213
 
1293
- get(this, 'models')[clientId] = model = type._create({ store: this, clientId: clientId });
1214
+ get(this, 'models')[clientId] = model = type.create({ store: this, clientId: clientId });
1294
1215
  set(model, 'clientId', clientId);
1295
- model.send('loadingData');
1216
+ model.loadingData();
1296
1217
  return model;
1297
- },
1298
-
1299
- destroy: function() {
1300
- if (get(DS, 'defaultStore') === this) {
1301
- set(DS, 'defaultStore', null);
1302
- }
1303
-
1304
- return this._super();
1305
1218
  }
1306
1219
  });
1307
1220
 
@@ -1310,7 +1223,7 @@ DS.Store = Ember.Object.extend({
1310
1223
 
1311
1224
 
1312
1225
  (function(exports) {
1313
- var get = Ember.get, set = Ember.set, getPath = Ember.getPath, guidFor = Ember.guidFor;
1226
+ var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
1314
1227
 
1315
1228
  var stateProperty = Ember.computed(function(key) {
1316
1229
  var parent = get(this, 'parentState');
@@ -1319,14 +1232,6 @@ var stateProperty = Ember.computed(function(key) {
1319
1232
  }
1320
1233
  }).property();
1321
1234
 
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
-
1330
1235
  DS.State = Ember.State.extend({
1331
1236
  isLoaded: stateProperty,
1332
1237
  isDirty: stateProperty,
@@ -1334,16 +1239,14 @@ DS.State = Ember.State.extend({
1334
1239
  isDeleted: stateProperty,
1335
1240
  isError: stateProperty,
1336
1241
  isNew: 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
1242
+ isValid: stateProperty
1345
1243
  });
1346
1244
 
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
+
1347
1250
  var isEmptyObject = function(obj) {
1348
1251
  for (var prop in obj) {
1349
1252
  if (!obj.hasOwnProperty(prop)) { continue; }
@@ -1356,287 +1259,89 @@ var isEmptyObject = function(obj) {
1356
1259
  var setProperty = function(manager, context) {
1357
1260
  var key = context.key, value = context.value;
1358
1261
 
1359
- var model = get(manager, 'model'),
1360
- data = get(model, 'data');
1262
+ var model = get(manager, 'model'), type = model.constructor;
1263
+ var store = get(model, 'store');
1264
+ var data = get(model, 'data');
1361
1265
 
1362
1266
  data[key] = value;
1363
1267
 
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);
1268
+ if (store) { store.hashWasUpdated(type, get(model, 'clientId')); }
1368
1269
  };
1369
1270
 
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.
1271
+ // several states share extremely common functionality, so we are factoring
1272
+ // them out into a common class.
1435
1273
  var DirtyState = DS.State.extend({
1436
- initialState: 'uncommitted',
1437
-
1438
- // FLAGS
1274
+ // these states are virtually identical except that
1275
+ // they (thrice) use their states name explicitly.
1276
+ //
1277
+ // child classes implement stateName.
1278
+ stateName: null,
1439
1279
  isDirty: true,
1280
+ willLoadData: cantLoadData,
1440
1281
 
1441
- // SUBSTATES
1442
-
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');
1282
+ enter: function(manager) {
1283
+ var stateName = get(this, 'stateName'),
1284
+ model = get(manager, 'model');
1451
1285
 
1452
- model.withTransaction(function (t) {
1453
- t.modelBecameDirty(dirtyType, model);
1454
- });
1455
- },
1286
+ model.withTransaction(function (t) {
1287
+ t.modelBecameDirty(stateName, model);
1288
+ });
1289
+ },
1456
1290
 
1457
- exit: function(manager) {
1458
- var model = get(manager, 'model');
1459
- manager.send('invokeLifecycleCallbacks', model);
1460
- },
1291
+ exit: function(manager) {
1292
+ var stateName = get(this, 'stateName'),
1293
+ model = get(manager, 'model');
1461
1294
 
1462
- // EVENTS
1463
- setProperty: setProperty,
1295
+ this.notifyModel(model);
1464
1296
 
1465
- deleteRecord: function(manager) {
1466
- manager.goToState('deleted');
1467
- },
1297
+ model.withTransaction(function (t) {
1298
+ t.modelBecameClean(stateName, model);
1299
+ });
1300
+ },
1468
1301
 
1469
- waitingOn: function(manager, object) {
1470
- waitingOn(manager, object);
1471
- manager.goToState('pending');
1472
- },
1302
+ setProperty: setProperty,
1473
1303
 
1474
- willCommit: function(manager) {
1475
- manager.goToState('inFlight');
1476
- }
1477
- }),
1304
+ willCommit: function(manager) {
1305
+ manager.goToState('saving');
1306
+ },
1478
1307
 
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
1308
+ saving: DS.State.extend({
1484
1309
  isSaving: true,
1485
1310
 
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) {
1311
+ didUpdate: function(manager) {
1498
1312
  manager.goToState('loaded');
1499
1313
  },
1500
1314
 
1501
- becameInvalid: function(manager, errors) {
1315
+ wasInvalid: function(manager, errors) {
1502
1316
  var model = get(manager, 'model');
1503
1317
 
1504
1318
  set(model, 'errors', errors);
1505
1319
  manager.goToState('invalid');
1506
- },
1507
-
1508
- setData: function(manager, hash) {
1509
- var model = get(manager, 'model');
1510
- set(model, 'data', hash);
1511
1320
  }
1512
1321
  }),
1513
1322
 
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.
1608
1323
  invalid: DS.State.extend({
1609
- // FLAGS
1610
1324
  isValid: false,
1611
1325
 
1612
- // EVENTS
1613
- deleteRecord: function(manager) {
1614
- manager.goToState('deleted');
1615
- },
1616
-
1617
1326
  setProperty: function(manager, context) {
1618
1327
  setProperty(manager, context);
1619
1328
 
1620
- var model = get(manager, 'model'),
1329
+ var stateName = getPath(this, 'parentState.stateName'),
1330
+ model = get(manager, 'model'),
1621
1331
  errors = get(model, 'errors'),
1622
1332
  key = context.key;
1623
1333
 
1624
1334
  delete errors[key];
1625
1335
 
1626
1336
  if (isEmptyObject(errors)) {
1627
- manager.send('becameValid');
1337
+ manager.goToState(stateName);
1628
1338
  }
1629
- },
1630
-
1631
- becameValid: function(manager) {
1632
- manager.goToState('uncommitted');
1633
1339
  }
1634
1340
  })
1635
1341
  });
1636
1342
 
1637
1343
  var states = {
1638
1344
  rootState: Ember.State.create({
1639
- // FLAGS
1640
1345
  isLoaded: false,
1641
1346
  isDirty: false,
1642
1347
  isSaving: false,
@@ -1644,126 +1349,80 @@ var states = {
1644
1349
  isError: false,
1645
1350
  isNew: false,
1646
1351
  isValid: true,
1647
- isPending: false,
1648
1352
 
1649
- // SUBSTATES
1353
+ willLoadData: cantLoadData,
1354
+
1355
+ didCreate: function(manager) {
1356
+ manager.goToState('loaded.created');
1357
+ },
1650
1358
 
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.
1656
1359
  empty: DS.State.create({
1657
- // EVENTS
1658
1360
  loadingData: function(manager) {
1659
1361
  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');
1666
1362
  }
1667
1363
  }),
1668
1364
 
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.
1675
1365
  loading: DS.State.create({
1676
- // TRANSITIONS
1366
+ willLoadData: Ember.K,
1367
+
1677
1368
  exit: function(manager) {
1678
1369
  var model = get(manager, 'model');
1679
1370
  model.didLoad();
1680
1371
  },
1681
1372
 
1682
- // EVENTS
1683
1373
  setData: function(manager, data) {
1684
1374
  var model = get(manager, 'model');
1685
1375
 
1686
1376
  model.beginPropertyChanges();
1687
- set(model, 'data', data);
1377
+ model.set('data', data);
1688
1378
 
1689
1379
  if (data !== null) {
1690
- manager.send('loadedData');
1380
+ manager.goToState('loaded');
1691
1381
  }
1692
1382
 
1693
1383
  model.endPropertyChanges();
1694
- },
1695
-
1696
- loadedData: function(manager) {
1697
- manager.goToState('loaded');
1698
1384
  }
1699
1385
  }),
1700
1386
 
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.
1704
1387
  loaded: DS.State.create({
1705
- initialState: 'saved',
1706
-
1707
- // FLAGS
1708
1388
  isLoaded: true,
1709
1389
 
1710
- // SUBSTATES
1711
-
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
- },
1390
+ willLoadData: Ember.K,
1720
1391
 
1721
- deleteRecord: function(manager) {
1722
- manager.goToState('deleted');
1723
- },
1392
+ setProperty: function(manager, context) {
1393
+ setProperty(manager, context);
1394
+ manager.goToState('updated');
1395
+ },
1724
1396
 
1725
- waitingOn: function(manager, object) {
1726
- waitingOn(manager, object);
1727
- manager.goToState('updated.pending');
1728
- }
1729
- }),
1397
+ 'delete': function(manager) {
1398
+ manager.goToState('deleted');
1399
+ },
1730
1400
 
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.
1734
1401
  created: DirtyState.create({
1735
- dirtyType: 'created',
1736
-
1737
- // FLAGS
1402
+ stateName: 'created',
1738
1403
  isNew: true,
1739
1404
 
1740
- // EVENTS
1741
- invokeLifecycleCallbacks: function(manager, model) {
1405
+ notifyModel: function(model) {
1742
1406
  model.didCreate();
1743
1407
  }
1744
1408
  }),
1745
1409
 
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.
1749
1410
  updated: DirtyState.create({
1750
- dirtyType: 'updated',
1411
+ stateName: 'updated',
1751
1412
 
1752
- // EVENTS
1753
- invokeLifecycleCallbacks: function(manager, model) {
1413
+ notifyModel: function(model) {
1754
1414
  model.didUpdate();
1755
1415
  }
1756
1416
  })
1757
1417
  }),
1758
1418
 
1759
- // A record is in this state if it was deleted from the store.
1760
1419
  deleted: DS.State.create({
1761
- // FLAGS
1762
1420
  isDeleted: true,
1763
1421
  isLoaded: true,
1764
1422
  isDirty: true,
1765
1423
 
1766
- // TRANSITIONS
1424
+ willLoadData: cantLoadData,
1425
+
1767
1426
  enter: function(manager) {
1768
1427
  var model = get(manager, 'model');
1769
1428
  var store = get(model, 'store');
@@ -1777,51 +1436,31 @@ var states = {
1777
1436
  });
1778
1437
  },
1779
1438
 
1780
- // SUBSTATES
1781
-
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
- }),
1439
+ willCommit: function(manager) {
1440
+ manager.goToState('saving');
1441
+ },
1790
1442
 
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
1443
+ saving: DS.State.create({
1797
1444
  isSaving: true,
1798
1445
 
1799
- // TRANSITIONS
1446
+ didDelete: function(manager) {
1447
+ manager.goToState('saved');
1448
+ },
1449
+
1800
1450
  exit: function(stateManager) {
1801
1451
  var model = get(stateManager, 'model');
1802
1452
 
1803
1453
  model.withTransaction(function(t) {
1804
1454
  t.modelBecameClean('deleted', model);
1805
1455
  });
1806
- },
1807
-
1808
- // EVENTS
1809
- didCommit: function(manager) {
1810
- manager.goToState('saved');
1811
1456
  }
1812
1457
  }),
1813
1458
 
1814
- // Once the adapter indicates that the deletion has
1815
- // been saved, the record enters the `saved` substate
1816
- // of `deleted`.
1817
1459
  saved: DS.State.create({
1818
1460
  isDirty: false
1819
1461
  })
1820
1462
  }),
1821
1463
 
1822
- // If the adapter indicates that there was an unknown
1823
- // error saving a record, the record enters the `error`
1824
- // state.
1825
1464
  error: DS.State.create({
1826
1465
  isError: true
1827
1466
  })
@@ -1834,12 +1473,6 @@ DS.StateManager = Ember.StateManager.extend({
1834
1473
  states: states
1835
1474
  });
1836
1475
 
1837
- })({});
1838
-
1839
-
1840
- (function(exports) {
1841
- var get = Ember.get, set = Ember.set, getPath = Ember.getPath;
1842
-
1843
1476
  var retrieveFromCurrentState = Ember.computed(function(key) {
1844
1477
  return get(getPath(this, 'stateManager.currentState'), key);
1845
1478
  }).property('stateManager.currentState').cacheable();
@@ -1851,7 +1484,6 @@ DS.Model = Ember.Object.extend({
1851
1484
  isDeleted: retrieveFromCurrentState,
1852
1485
  isError: retrieveFromCurrentState,
1853
1486
  isNew: retrieveFromCurrentState,
1854
- isPending: retrieveFromCurrentState,
1855
1487
  isValid: retrieveFromCurrentState,
1856
1488
 
1857
1489
  clientId: null,
@@ -1859,22 +1491,8 @@ DS.Model = Ember.Object.extend({
1859
1491
  // because unknownProperty is used, any internal property
1860
1492
  // must be initialized here.
1861
1493
  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
-
1874
1494
  data: null,
1875
- pendingQueue: null,
1876
1495
  transaction: null,
1877
- errors: null,
1878
1496
 
1879
1497
  didLoad: Ember.K,
1880
1498
  didUpdate: Ember.K,
@@ -1885,101 +1503,100 @@ DS.Model = Ember.Object.extend({
1885
1503
  model: this
1886
1504
  });
1887
1505
 
1888
- set(this, 'pendingQueue', {});
1889
1506
  set(this, 'stateManager', stateManager);
1890
1507
  stateManager.goToState('empty');
1891
1508
  },
1892
1509
 
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
+
1893
1531
  destroy: function() {
1894
- if (!get(this, 'isDeleted')) {
1895
- this.deleteRecord();
1896
- }
1532
+ this.deleteRecord();
1897
1533
  this._super();
1898
1534
  },
1899
1535
 
1900
- send: function(name, context) {
1901
- return get(this, 'stateManager').send(name, context);
1536
+ loadingData: function() {
1537
+ var stateManager = get(this, 'stateManager');
1538
+ stateManager.send('loadingData');
1902
1539
  },
1903
1540
 
1904
- withTransaction: function(fn) {
1905
- var transaction = get(this, 'transaction') || getPath(this, 'store.defaultTransaction');
1906
- if (transaction) { fn(transaction); }
1541
+ willLoadData: function() {
1542
+ var stateManager = get(this, 'stateManager');
1543
+ stateManager.send('willLoadData');
1907
1544
  },
1908
1545
 
1909
- setProperty: function(key, value) {
1910
- this.send('setProperty', { key: key, value: value });
1546
+ willCommit: function() {
1547
+ var stateManager = get(this, 'stateManager');
1548
+ stateManager.send('willCommit');
1911
1549
  },
1912
1550
 
1913
- deleteRecord: function() {
1914
- this.send('deleteRecord');
1551
+ adapterDidUpdate: function() {
1552
+ var stateManager = get(this, 'stateManager');
1553
+ stateManager.send('didUpdate');
1915
1554
  },
1916
1555
 
1917
- waitingOn: function(record) {
1918
- this.send('waitingOn', record);
1556
+ adapterDidCreate: function() {
1557
+ var stateManager = get(this, 'stateManager');
1558
+ stateManager.send('didCreate');
1919
1559
  },
1920
1560
 
1921
- notifyHashWasUpdated: function() {
1922
- var store = get(this, 'store');
1923
- if (store) {
1924
- store.hashWasUpdated(this.constructor, get(this, 'clientId'));
1925
- }
1561
+ adapterDidDelete: function() {
1562
+ var stateManager = get(this, 'stateManager');
1563
+ stateManager.send('didDelete');
1564
+ },
1565
+
1566
+ wasInvalid: function(errors) {
1567
+ var stateManager = get(this, 'stateManager');
1568
+ stateManager.send('wasInvalid', errors);
1926
1569
  },
1927
1570
 
1928
1571
  unknownProperty: function(key) {
1929
1572
  var data = get(this, 'data');
1930
1573
 
1931
- if (data && key in data) {
1932
- ember_assert("You attempted to access the " + key + " property on a model without defining an attribute.", false);
1574
+ if (data) {
1575
+ return get(data, key);
1933
1576
  }
1934
1577
  },
1935
1578
 
1936
1579
  setUnknownProperty: function(key, value) {
1937
1580
  var data = get(this, 'data');
1581
+ ember_assert("You cannot set a model attribute before its data is loaded.", !!data);
1938
1582
 
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
- }
1583
+ this.setProperty(key, value);
1584
+ return value;
1944
1585
  }
1945
1586
  });
1946
1587
 
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
-
1961
1588
  DS.Model.reopenClass({
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')
1589
+ typeForAssociation: function(association) {
1590
+ var type = this.metaForProperty(association).type;
1591
+ if (typeof type === 'string') {
1592
+ type = getPath(this, type, false) || getPath(window, type);
1593
+ }
1594
+ return type;
1595
+ }
1972
1596
  });
1973
1597
 
1974
- })({});
1975
-
1976
-
1977
- (function(exports) {
1978
- var get = Ember.get, getPath = Ember.getPath;
1979
1598
  DS.attr = function(type, options) {
1980
1599
  var transform = DS.attr.transforms[type];
1981
- ember_assert("Could not find model attribute of type " + type, !!transform);
1982
-
1983
1600
  var transformFrom = transform.from;
1984
1601
  var transformTo = transform.to;
1985
1602
 
@@ -2001,24 +1618,73 @@ DS.attr = function(type, options) {
2001
1618
  }
2002
1619
  }).property('data');
2003
1620
  };
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
+
2004
1670
  DS.attr.transforms = {
2005
1671
  string: {
2006
1672
  from: function(serialized) {
2007
- return Ember.none(serialized) ? null : String(serialized);
1673
+ return Em.none(serialized) ? null : String(serialized);
2008
1674
  },
2009
1675
 
2010
1676
  to: function(deserialized) {
2011
- return Ember.none(deserialized) ? null : String(deserialized);
1677
+ return Em.none(deserialized) ? null : String(deserialized);
2012
1678
  }
2013
1679
  },
2014
1680
 
2015
1681
  integer: {
2016
1682
  from: function(serialized) {
2017
- return Ember.none(serialized) ? null : Number(serialized);
1683
+ return Em.none(serialized) ? null : Number(serialized);
2018
1684
  },
2019
1685
 
2020
1686
  to: function(deserialized) {
2021
- return Ember.none(deserialized) ? null : Number(deserialized);
1687
+ return Em.none(deserialized) ? null : Number(deserialized);
2022
1688
  }
2023
1689
  },
2024
1690
 
@@ -2080,76 +1746,6 @@ DS.attr.transforms = {
2080
1746
  }
2081
1747
  };
2082
1748
 
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) {
2153
1749
  })({});
2154
1750
 
2155
1751