ember-rails 0.6.0 → 0.7.0
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/README.md +1 -1
- data/lib/ember/handlebars/assets/ember-precompiler.js +1 -0
- data/lib/ember/rails/engine.rb +0 -10
- data/lib/ember/rails/version.rb +1 -1
- data/lib/ember_rails.rb +20 -6
- data/lib/generators/ember/bootstrap_generator.rb +0 -14
- data/lib/generators/ember/controller_generator.rb +3 -0
- data/lib/generators/ember/install_generator.rb +38 -2
- data/lib/generators/ember/resource_override.rb +1 -1
- data/lib/generators/ember/view_generator.rb +1 -0
- data/lib/generators/templates/app.js +1 -6
- data/lib/generators/templates/array_controller.js +1 -5
- data/lib/generators/templates/controller.js +2 -3
- data/lib/generators/templates/object_controller.js +3 -0
- data/lib/generators/templates/router.js +4 -2
- data/vendor/ember/development/ember-data.js +621 -195
- data/vendor/ember/development/ember.js +11731 -11171
- data/vendor/ember/production/ember-data.js +4165 -7
- data/vendor/ember/production/ember.js +12899 -12406
- data/vendor/ember/spade/ember-data.js +1 -1
- data/vendor/ember/spade/ember.js +1 -1
- metadata +3 -10
- data/vendor/ember/development/ember-runtime.js +0 -10233
- data/vendor/ember/production/ember-runtime.js +0 -10080
data/README.md
CHANGED
@@ -18,6 +18,7 @@ var jQuery = window.jQuery = function() { return jQuery; };
|
|
18
18
|
jQuery.ready = function() { return jQuery; };
|
19
19
|
jQuery.inArray = function() { return jQuery; };
|
20
20
|
jQuery.jquery = "1.7.2";
|
21
|
+
jQuery.event = {fixHooks: {}};
|
21
22
|
|
22
23
|
// Precompiler
|
23
24
|
var EmberRails = {
|
data/lib/ember/rails/engine.rb
CHANGED
@@ -17,16 +17,6 @@ module Ember
|
|
17
17
|
app.assets.register_engine '.handlebars', Ember::Handlebars::Template
|
18
18
|
app.assets.register_engine '.hbs', Ember::Handlebars::Template
|
19
19
|
app.assets.register_engine '.hjs', Ember::Handlebars::Template
|
20
|
-
|
21
|
-
# Add the gem's vendored ember to the end of the asset search path
|
22
|
-
variant = app.config.ember.variant
|
23
|
-
|
24
|
-
if variant.nil?
|
25
|
-
warn "[EMBER-RAILS] `ember.variant` was not found in your current environment"
|
26
|
-
end
|
27
|
-
|
28
|
-
ember_path = File.expand_path("../../../../vendor/ember/#{variant}", __FILE__)
|
29
|
-
app.config.assets.paths.unshift ember_path
|
30
20
|
end
|
31
21
|
end
|
32
22
|
end
|
data/lib/ember/rails/version.rb
CHANGED
data/lib/ember_rails.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'rails'
|
1
2
|
require 'ember/rails/version'
|
2
3
|
require 'ember/version'
|
3
4
|
require 'ember/handlebars/version'
|
@@ -19,15 +20,28 @@ module Ember
|
|
19
20
|
end
|
20
21
|
|
21
22
|
initializer "ember_rails.setup_vendor", :after => "ember_rails.setup", :group => :all do |app|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
if variant = app.config.ember.variant
|
24
|
+
# Add the gem's vendored ember to the end of the asset search path
|
25
|
+
ember_path = File.expand_path("../../vendor/ember/#{variant}", __FILE__)
|
26
|
+
app.config.assets.paths.push(ember_path.to_s)
|
27
|
+
|
28
|
+
# Allow a local variant override
|
29
|
+
ember_path = app.root.join("vendor/assets/ember/#{variant}")
|
30
|
+
app.config.assets.paths.unshift(ember_path.to_s) if ember_path.exist?
|
31
|
+
else
|
32
|
+
warn "No ember.js variant was specified in your config environment."
|
33
|
+
warn "You can set a specific variant in your application config in "
|
34
|
+
warn "order for sprockets to locate ember's assets:"
|
35
|
+
warn ""
|
36
|
+
warn " config.ember.variant = :development"
|
37
|
+
warn ""
|
38
|
+
warn "Valid values are :development and :production"
|
39
|
+
end
|
26
40
|
end
|
27
41
|
|
28
42
|
initializer "ember_rails.find_ember", :after => "ember_rails.setup_vendor", :group => :all do |app|
|
29
|
-
config.ember.ember_location
|
30
|
-
config.ember.handlebars_location
|
43
|
+
config.ember.ember_location ||= location_for(app, "ember.js")
|
44
|
+
config.ember.handlebars_location ||= location_for(app, "handlebars.js")
|
31
45
|
end
|
32
46
|
|
33
47
|
def location_for(app, file)
|
@@ -51,20 +51,6 @@ module Ember
|
|
51
51
|
def create_app_stubs
|
52
52
|
generate "ember:view", "application"
|
53
53
|
end
|
54
|
-
|
55
|
-
def inject_proper_ember_version
|
56
|
-
environment <<-RUBY.strip_heredoc, :env => :development
|
57
|
-
config.ember.variant = :development
|
58
|
-
RUBY
|
59
|
-
|
60
|
-
environment <<-RUBY.strip_heredoc, :env => :test
|
61
|
-
config.ember.variant = :development
|
62
|
-
RUBY
|
63
|
-
|
64
|
-
environment <<-RUBY.strip_heredoc, :env => :production
|
65
|
-
config.ember.variant = :production
|
66
|
-
RUBY
|
67
|
-
end
|
68
54
|
end
|
69
55
|
end
|
70
56
|
end
|
@@ -7,11 +7,14 @@ module Ember
|
|
7
7
|
|
8
8
|
desc "Creates a new Ember.js controller"
|
9
9
|
class_option :array, :type => :boolean, :default => false, :desc => "Create an Ember.ArrayController to represent multiple objects"
|
10
|
+
class_option :object, :type => :boolean, :default => false, :desc => "Create an Ember.ObjectController to represent a single object"
|
10
11
|
|
11
12
|
def create_controller_files
|
12
13
|
file_path = File.join('app/assets/javascripts/controllers', class_path, "#{file_name}_controller.js")
|
13
14
|
if options.array?
|
14
15
|
template 'array_controller.js', file_path
|
16
|
+
elsif options.object?
|
17
|
+
template 'object_controller.js', file_path
|
15
18
|
else
|
16
19
|
template 'controller.js', file_path
|
17
20
|
end
|
@@ -20,7 +20,7 @@ module Ember
|
|
20
20
|
cmd command
|
21
21
|
else
|
22
22
|
Dir.chdir git_root do
|
23
|
-
command = "git fetch
|
23
|
+
command = "git fetch origin && git reset origin/master --hard"
|
24
24
|
say_status("updating", command, :green)
|
25
25
|
|
26
26
|
cmd command
|
@@ -35,13 +35,49 @@ module Ember
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
|
38
|
+
source_paths << File.join(git_root, "dist")
|
39
39
|
|
40
40
|
copy_file "ember.js", "vendor/assets/ember/development/ember.js"
|
41
41
|
copy_file "ember.min.js", "vendor/assets/ember/production/ember.js"
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
def copy_ember_data
|
46
|
+
if options.head?
|
47
|
+
|
48
|
+
git_root = File.expand_path "~/.ember-data"
|
49
|
+
gem_file = File.join git_root, "Gemfile"
|
50
|
+
|
51
|
+
# If it doesn't exist yet
|
52
|
+
unless File.exist?(git_root)
|
53
|
+
command = %{git clone git://github.com/emberjs/data.git "#{git_root}"}
|
54
|
+
say_status("downloading", command, :green)
|
55
|
+
|
56
|
+
cmd command
|
57
|
+
else
|
58
|
+
Dir.chdir git_root do
|
59
|
+
command = "git fetch origin && git reset origin/master --hard"
|
60
|
+
say_status("updating", command, :green)
|
61
|
+
|
62
|
+
cmd command
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Dir.chdir git_root do
|
67
|
+
say_status("building", "bundle && bundle exec rake", :green)
|
68
|
+
Bundler.with_clean_env do
|
69
|
+
cmd "bundle --gemfile #{gem_file}"
|
70
|
+
cmd %{BUNDLE_GEMFILE="#{gem_file}" bundle exec rake}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
source_paths << File.join(git_root, "dist")
|
75
|
+
|
76
|
+
copy_file "ember-data.js", "vendor/assets/ember/development/ember-data.js"
|
77
|
+
copy_file "ember-data.min.js", "vendor/assets/ember/production/ember-data.js"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
45
81
|
private
|
46
82
|
|
47
83
|
def cmd(command)
|
@@ -14,7 +14,7 @@ module Rails
|
|
14
14
|
|
15
15
|
say_status :invoke, "ember controller and view (singular)", :white
|
16
16
|
with_padding do
|
17
|
-
invoke "ember:view"
|
17
|
+
invoke "ember:view", [singular_name], :object => true
|
18
18
|
end
|
19
19
|
|
20
20
|
@_invocations[Ember::Generators::ControllerGenerator].delete "create_controller_files"
|
@@ -7,6 +7,7 @@ module Ember
|
|
7
7
|
|
8
8
|
desc "Creates a new Ember.js view and associated Handlebars template"
|
9
9
|
class_option :array, :type => :boolean, :default => false, :desc => "Create an Ember.ArrayController to represent multiple objects"
|
10
|
+
class_option :object, :type => :boolean, :default => false, :desc => "Create an Ember.ObjectController to represent a single object"
|
10
11
|
|
11
12
|
def create_view_files
|
12
13
|
template 'view.js', File.join('app/assets/javascripts/views', class_path, "#{file_name}_view.js")
|
@@ -7,9 +7,4 @@
|
|
7
7
|
//= require_tree ./routes
|
8
8
|
//= require_self
|
9
9
|
|
10
|
-
|
11
|
-
location: 'hash'
|
12
|
-
});
|
13
|
-
|
14
|
-
<%= application_name.camelize %>.initialize(router);
|
15
|
-
|
10
|
+
<%= application_name.camelize %>.initialize();
|
@@ -1,6 +1,8 @@
|
|
1
1
|
<%= application_name.camelize %>.Router = Ember.Router.extend({
|
2
|
-
|
3
|
-
|
2
|
+
location: 'hash',
|
3
|
+
|
4
|
+
root: Ember.Route.extend({
|
5
|
+
index: Ember.Route.extend({
|
4
6
|
route: '/'
|
5
7
|
|
6
8
|
// You'll likely want to connect a view here.
|
@@ -36,42 +36,14 @@ DS.RecordArray = Ember.ArrayProxy.extend({
|
|
36
36
|
// The store that created this record array.
|
37
37
|
store: null,
|
38
38
|
|
39
|
-
init: function() {
|
40
|
-
set(this, 'recordCache', Ember.A([]));
|
41
|
-
this._super();
|
42
|
-
},
|
43
|
-
|
44
|
-
arrayDidChange: function(array, index, removed, added) {
|
45
|
-
var recordCache = get(this, 'recordCache');
|
46
|
-
recordCache.replace(index, 0, new Array(added));
|
47
|
-
|
48
|
-
this._super(array, index, removed, added);
|
49
|
-
},
|
50
|
-
|
51
|
-
arrayWillChange: function(array, index, removed, added) {
|
52
|
-
this._super(array, index, removed, added);
|
53
|
-
|
54
|
-
var recordCache = get(this, 'recordCache');
|
55
|
-
recordCache.replace(index, removed);
|
56
|
-
},
|
57
|
-
|
58
39
|
objectAtContent: function(index) {
|
59
|
-
var
|
60
|
-
|
61
|
-
|
62
|
-
if (!record) {
|
63
|
-
var store = get(this, 'store');
|
64
|
-
var content = get(this, 'content');
|
65
|
-
|
66
|
-
var contentObject = content.objectAt(index);
|
40
|
+
var content = get(this, 'content'),
|
41
|
+
clientId = content.objectAt(index),
|
42
|
+
store = get(this, 'store');
|
67
43
|
|
68
|
-
|
69
|
-
|
70
|
-
recordCache.replace(index, 1, [record]);
|
71
|
-
}
|
44
|
+
if (clientId !== undefined) {
|
45
|
+
return store.findByClientId(get(this, 'type'), clientId);
|
72
46
|
}
|
73
|
-
|
74
|
-
return record;
|
75
47
|
}
|
76
48
|
});
|
77
49
|
|
@@ -156,7 +128,7 @@ Set.prototype = {
|
|
156
128
|
|
157
129
|
delete hash[guid];
|
158
130
|
var list = this.list,
|
159
|
-
index = Ember.
|
131
|
+
index = Ember.EnumerableUtils.indexOf(this, item);
|
160
132
|
|
161
133
|
list.splice(index, 1);
|
162
134
|
},
|
@@ -166,7 +138,7 @@ Set.prototype = {
|
|
166
138
|
}
|
167
139
|
};
|
168
140
|
|
169
|
-
var
|
141
|
+
var LoadedState = Ember.State.extend({
|
170
142
|
recordWasAdded: function(manager, record) {
|
171
143
|
var dirty = manager.dirty, observer;
|
172
144
|
dirty.add(record);
|
@@ -195,7 +167,21 @@ var ManyArrayState = Ember.State.extend({
|
|
195
167
|
});
|
196
168
|
|
197
169
|
var states = {
|
198
|
-
|
170
|
+
loading: Ember.State.create({
|
171
|
+
isLoaded: false,
|
172
|
+
isDirty: false,
|
173
|
+
|
174
|
+
loadedRecords: function(manager, count) {
|
175
|
+
manager.decrement(count);
|
176
|
+
},
|
177
|
+
|
178
|
+
becameLoaded: function(manager) {
|
179
|
+
manager.transitionTo('clean');
|
180
|
+
}
|
181
|
+
}),
|
182
|
+
|
183
|
+
clean: LoadedState.create({
|
184
|
+
isLoaded: true,
|
199
185
|
isDirty: false,
|
200
186
|
|
201
187
|
recordWasAdded: function(manager, record) {
|
@@ -209,7 +195,8 @@ var states = {
|
|
209
195
|
}
|
210
196
|
}),
|
211
197
|
|
212
|
-
dirty:
|
198
|
+
dirty: LoadedState.create({
|
199
|
+
isLoaded: true,
|
213
200
|
isDirty: true,
|
214
201
|
|
215
202
|
childWasSaved: function(manager, child) {
|
@@ -222,17 +209,37 @@ var states = {
|
|
222
209
|
arrayBecameSaved: function(manager) {
|
223
210
|
manager.goToState('clean');
|
224
211
|
}
|
225
|
-
})
|
212
|
+
})
|
226
213
|
};
|
227
214
|
|
228
215
|
DS.ManyArrayStateManager = Ember.StateManager.extend({
|
229
216
|
manyArray: null,
|
230
|
-
initialState: '
|
217
|
+
initialState: 'loading',
|
231
218
|
states: states,
|
232
219
|
|
220
|
+
/**
|
221
|
+
This number is used to keep track of the number of outstanding
|
222
|
+
records that must be loaded before the array is considered
|
223
|
+
loaded. As results stream in, this number is decremented until
|
224
|
+
it becomes zero, at which case the `isLoaded` flag will be set
|
225
|
+
to true
|
226
|
+
*/
|
227
|
+
counter: 0,
|
228
|
+
|
233
229
|
init: function() {
|
234
230
|
this._super();
|
235
231
|
this.dirty = new Set();
|
232
|
+
this.counter = get(this, 'manyArray.length');
|
233
|
+
},
|
234
|
+
|
235
|
+
decrement: function(count) {
|
236
|
+
var counter = this.counter = this.counter - count;
|
237
|
+
|
238
|
+
Ember.assert("Somehow the ManyArray loaded counter went below 0. This is probably an ember-data bug. Please report it at https://github.com/emberjs/data/issues", counter >= 0);
|
239
|
+
|
240
|
+
if (counter === 0) {
|
241
|
+
this.send('becameLoaded');
|
242
|
+
}
|
236
243
|
}
|
237
244
|
});
|
238
245
|
|
@@ -241,7 +248,7 @@ DS.ManyArrayStateManager = Ember.StateManager.extend({
|
|
241
248
|
|
242
249
|
|
243
250
|
(function() {
|
244
|
-
var get = Ember.get, set = Ember.set
|
251
|
+
var get = Ember.get, set = Ember.set;
|
245
252
|
|
246
253
|
DS.ManyArray = DS.RecordArray.extend({
|
247
254
|
init: function() {
|
@@ -253,23 +260,27 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
253
260
|
parentRecord: null,
|
254
261
|
|
255
262
|
isDirty: Ember.computed(function() {
|
256
|
-
return
|
263
|
+
return get(this, 'stateManager.currentState.isDirty');
|
264
|
+
}).property('stateManager.currentState').cacheable(),
|
265
|
+
|
266
|
+
isLoaded: Ember.computed(function() {
|
267
|
+
return get(this, 'stateManager.currentState.isLoaded');
|
257
268
|
}).property('stateManager.currentState').cacheable(),
|
258
269
|
|
270
|
+
send: function(event, context) {
|
271
|
+
this.get('stateManager').send(event, context);
|
272
|
+
},
|
273
|
+
|
259
274
|
fetch: function() {
|
260
275
|
var clientIds = get(this, 'content'),
|
261
276
|
store = get(this, 'store'),
|
262
277
|
type = get(this, 'type');
|
263
278
|
|
264
|
-
|
265
|
-
return store.clientIdToId[clientId];
|
266
|
-
});
|
267
|
-
|
268
|
-
store.fetchMany(type, ids);
|
279
|
+
store.fetchUnloadedClientIds(type, clientIds);
|
269
280
|
},
|
270
281
|
|
271
282
|
// Overrides Ember.Array's replace method to implement
|
272
|
-
|
283
|
+
replaceContent: function(index, removed, added) {
|
273
284
|
var parentRecord = get(this, 'parentRecord');
|
274
285
|
var pendingParent = parentRecord && !get(parentRecord, 'id');
|
275
286
|
var stateManager = get(this, 'stateManager');
|
@@ -286,7 +297,10 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
286
297
|
record.send('waitingOn', parentRecord);
|
287
298
|
}
|
288
299
|
|
289
|
-
this.assignInverse(record, parentRecord);
|
300
|
+
var oldParent = this.assignInverse(record, parentRecord);
|
301
|
+
|
302
|
+
record.get('transaction')
|
303
|
+
.relationshipBecameDirty(record, oldParent, parentRecord);
|
290
304
|
|
291
305
|
stateManager.send('recordWasAdded', record);
|
292
306
|
|
@@ -299,7 +313,10 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
299
313
|
for (var i = index; i < len; i++) {
|
300
314
|
// TODO: null out inverse FK
|
301
315
|
record = this.objectAt(i);
|
302
|
-
this.assignInverse(record, parentRecord, true);
|
316
|
+
var oldParent = this.assignInverse(record, parentRecord, true);
|
317
|
+
|
318
|
+
record.get('transaction')
|
319
|
+
.relationshipBecameDirty(record, parentRecord, null);
|
303
320
|
|
304
321
|
// If we put the child record into a pending state because
|
305
322
|
// we were waiting on the parent record to get an id, we
|
@@ -317,7 +334,7 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
317
334
|
assignInverse: function(record, parentRecord, remove) {
|
318
335
|
var associationMap = get(record.constructor, 'associations'),
|
319
336
|
possibleAssociations = associationMap.get(parentRecord.constructor),
|
320
|
-
possible, actual;
|
337
|
+
possible, actual, oldParent;
|
321
338
|
|
322
339
|
if (!possibleAssociations) { return; }
|
323
340
|
|
@@ -331,7 +348,9 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
331
348
|
}
|
332
349
|
|
333
350
|
if (actual) {
|
351
|
+
oldParent = get(record, actual.name);
|
334
352
|
set(record, actual.name, remove ? null : parentRecord);
|
353
|
+
return oldParent;
|
335
354
|
}
|
336
355
|
},
|
337
356
|
|
@@ -362,7 +381,8 @@ DS.ManyArray = DS.RecordArray.extend({
|
|
362
381
|
|
363
382
|
|
364
383
|
(function() {
|
365
|
-
var get = Ember.get, set = Ember.set,
|
384
|
+
var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt,
|
385
|
+
removeObject = Ember.EnumerableUtils.removeObject;
|
366
386
|
|
367
387
|
/**
|
368
388
|
A transaction allows you to collect multiple records into a unit of work
|
@@ -381,7 +401,7 @@ var get = Ember.get, set = Ember.set, getPath = Ember.getPath, fmt = Ember.Strin
|
|
381
401
|
If you do not explicitly create a transaction, a record is assigned to
|
382
402
|
an implicit transaction called the default transaction. In these cases,
|
383
403
|
you can treat your application's instance of `DS.Store` as a transaction
|
384
|
-
and call the `commit()` and `rollback()` methods on the store itself.
|
404
|
+
and call the `commit()` and `rollback()` methods on the store itself.
|
385
405
|
|
386
406
|
Once a record has been successfully committed or rolled back, it will
|
387
407
|
be moved back to the implicit transaction. Because it will now be in
|
@@ -457,6 +477,12 @@ DS.Transaction = Ember.Object.extend({
|
|
457
477
|
deleted: Ember.Map.create(),
|
458
478
|
inflight: Ember.Map.create()
|
459
479
|
});
|
480
|
+
|
481
|
+
this.dirtyRelationships = {
|
482
|
+
byChild: Ember.Map.create(),
|
483
|
+
byNewParent: Ember.Map.create(),
|
484
|
+
byOldParent: Ember.Map.create()
|
485
|
+
};
|
460
486
|
},
|
461
487
|
|
462
488
|
/**
|
@@ -487,7 +513,7 @@ DS.Transaction = Ember.Object.extend({
|
|
487
513
|
Ember.assert("Once a record has changed, you cannot move it into a different transaction", !get(record, 'isDirty'));
|
488
514
|
|
489
515
|
var recordTransaction = get(record, 'transaction'),
|
490
|
-
defaultTransaction =
|
516
|
+
defaultTransaction = get(this, 'store.defaultTransaction');
|
491
517
|
|
492
518
|
Ember.assert("Models cannot belong to more than one transaction at a time.", recordTransaction === defaultTransaction);
|
493
519
|
|
@@ -599,7 +625,7 @@ DS.Transaction = Ember.Object.extend({
|
|
599
625
|
@param {DS.Model} record
|
600
626
|
*/
|
601
627
|
remove: function(record) {
|
602
|
-
var defaultTransaction =
|
628
|
+
var defaultTransaction = get(this, 'store.defaultTransaction');
|
603
629
|
defaultTransaction.adoptRecord(record);
|
604
630
|
},
|
605
631
|
|
@@ -696,6 +722,113 @@ DS.Transaction = Ember.Object.extend({
|
|
696
722
|
records.remove(record);
|
697
723
|
},
|
698
724
|
|
725
|
+
/**
|
726
|
+
@private
|
727
|
+
|
728
|
+
Called by a ManyArray when a new record is added to it. This
|
729
|
+
method will index a relationship description by the child
|
730
|
+
record, its old parent, and its new parent.
|
731
|
+
|
732
|
+
The store will provide this description to the adapter's
|
733
|
+
shouldCommit method, so it can determine whether any of
|
734
|
+
the records is pending another record. The store will also
|
735
|
+
provide a list of these descriptions to the adapter's commit
|
736
|
+
method.
|
737
|
+
|
738
|
+
@param {DS.Model} record the new child record
|
739
|
+
@param {DS.Model} oldParent the parent that the child is
|
740
|
+
moving from, or null
|
741
|
+
@param {DS.Model} newParent the parent that the child is
|
742
|
+
moving to, or null
|
743
|
+
*/
|
744
|
+
relationshipBecameDirty: function(child, oldParent, newParent) {
|
745
|
+
var relationships = this.dirtyRelationships, relationship;
|
746
|
+
|
747
|
+
var relationshipsForChild = relationships.byChild.get(child),
|
748
|
+
possibleRelationship,
|
749
|
+
needsNewEntries = true;
|
750
|
+
|
751
|
+
// If the child has any existing dirty relationships in this
|
752
|
+
// transaction, we need to collapse the old relationship
|
753
|
+
// into the new one. For example, if we change the parent of
|
754
|
+
// a child record before saving, there is no need to save the
|
755
|
+
// record that was its parent temporarily.
|
756
|
+
if (relationshipsForChild) {
|
757
|
+
|
758
|
+
// Loop through all of the relationships we know about that
|
759
|
+
// contain the same child as the new relationship.
|
760
|
+
for (var i=0, l=relationshipsForChild.length; i<l; i++) {
|
761
|
+
relationship = relationshipsForChild[i];
|
762
|
+
|
763
|
+
// If the parent of the child record has changed, there is
|
764
|
+
// no need to update the old parent that had not yet been saved.
|
765
|
+
//
|
766
|
+
// This case is two changes in a record's parent:
|
767
|
+
//
|
768
|
+
// A -> B
|
769
|
+
// B -> C
|
770
|
+
//
|
771
|
+
// In this case, there is no need to remember the A->B
|
772
|
+
// change. We can collapse both changes into:
|
773
|
+
//
|
774
|
+
// A -> C
|
775
|
+
//
|
776
|
+
// Another possible case is:
|
777
|
+
//
|
778
|
+
// A -> B
|
779
|
+
// B -> A
|
780
|
+
//
|
781
|
+
// In this case, we don't need to do anything. We can
|
782
|
+
// simply remove the original A->B change and call it
|
783
|
+
// a day.
|
784
|
+
if (relationship.newParent === oldParent) {
|
785
|
+
oldParent = relationship.oldParent;
|
786
|
+
this.removeRelationship(relationship);
|
787
|
+
|
788
|
+
// This is the case of A->B followed by B->A.
|
789
|
+
if (relationship.oldParent === newParent) {
|
790
|
+
needsNewEntries = false;
|
791
|
+
}
|
792
|
+
}
|
793
|
+
}
|
794
|
+
}
|
795
|
+
|
796
|
+
relationship = {
|
797
|
+
child: child,
|
798
|
+
oldParent: oldParent,
|
799
|
+
newParent: newParent
|
800
|
+
};
|
801
|
+
|
802
|
+
// If we didn't go A->B and then B->A, add new dirty relationship
|
803
|
+
// entries.
|
804
|
+
if (needsNewEntries) {
|
805
|
+
this.addRelationshipTo('byChild', child, relationship);
|
806
|
+
this.addRelationshipTo('byOldParent', oldParent, relationship);
|
807
|
+
this.addRelationshipTo('byNewParent', newParent, relationship);
|
808
|
+
}
|
809
|
+
},
|
810
|
+
|
811
|
+
removeRelationship: function(relationship) {
|
812
|
+
var relationships = this.dirtyRelationships;
|
813
|
+
|
814
|
+
removeObject(relationships.byOldParent.get(relationship.oldParent), relationship);
|
815
|
+
removeObject(relationships.byNewParent.get(relationship.newParent), relationship);
|
816
|
+
removeObject(relationships.byChild.get(relationship.child), relationship);
|
817
|
+
},
|
818
|
+
|
819
|
+
addRelationshipTo: function(type, record, description) {
|
820
|
+
var map = this.dirtyRelationships[type];
|
821
|
+
|
822
|
+
var relationships = map.get(record);
|
823
|
+
|
824
|
+
if (!relationships) {
|
825
|
+
relationships = [ description ];
|
826
|
+
map.set(record, relationships);
|
827
|
+
} else {
|
828
|
+
relationships.push(description);
|
829
|
+
}
|
830
|
+
},
|
831
|
+
|
699
832
|
/**
|
700
833
|
@private
|
701
834
|
|
@@ -746,7 +879,7 @@ DS.Transaction = Ember.Object.extend({
|
|
746
879
|
|
747
880
|
(function() {
|
748
881
|
/*globals Ember*/
|
749
|
-
var get = Ember.get, set = Ember.set,
|
882
|
+
var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
|
750
883
|
|
751
884
|
var DATA_PROXY = {
|
752
885
|
get: function(name) {
|
@@ -824,6 +957,13 @@ DS.Store = Ember.Object.extend({
|
|
824
957
|
this.clientIdToId = {};
|
825
958
|
this.recordArraysByClientId = {};
|
826
959
|
|
960
|
+
// Internally, we maintain a map of all unloaded IDs requested by
|
961
|
+
// a ManyArray. As the adapter loads hashes into the store, the
|
962
|
+
// store notifies any interested ManyArrays. When the ManyArray's
|
963
|
+
// total number of loading records drops to zero, it becomes
|
964
|
+
// `isLoaded` and fires a `didLoad` event.
|
965
|
+
this.loadingRecordArrays = {};
|
966
|
+
|
827
967
|
set(this, 'defaultTransaction', this.transaction());
|
828
968
|
|
829
969
|
return this._super();
|
@@ -872,7 +1012,7 @@ DS.Store = Ember.Object.extend({
|
|
872
1012
|
_adapter: Ember.computed(function() {
|
873
1013
|
var adapter = get(this, 'adapter');
|
874
1014
|
if (typeof adapter === 'string') {
|
875
|
-
return
|
1015
|
+
return get(this, adapter, false) || get(window, adapter);
|
876
1016
|
}
|
877
1017
|
return adapter;
|
878
1018
|
}).property('adapter').cacheable(),
|
@@ -1048,8 +1188,7 @@ DS.Store = Ember.Object.extend({
|
|
1048
1188
|
|
1049
1189
|
findByClientId: function(type, clientId, id) {
|
1050
1190
|
var recordCache = get(this, 'recordCache'),
|
1051
|
-
dataCache
|
1052
|
-
record;
|
1191
|
+
dataCache, record;
|
1053
1192
|
|
1054
1193
|
// If there is already a clientId assigned for this
|
1055
1194
|
// type/id combination, try to find an existing
|
@@ -1064,6 +1203,8 @@ DS.Store = Ember.Object.extend({
|
|
1064
1203
|
// 'isLoading' state
|
1065
1204
|
record = this.materializeRecord(type, clientId);
|
1066
1205
|
|
1206
|
+
dataCache = this.typeMapFor(type).cidToHash;
|
1207
|
+
|
1067
1208
|
if (typeof dataCache[clientId] === 'object') {
|
1068
1209
|
record.send('didChangeData');
|
1069
1210
|
}
|
@@ -1087,78 +1228,123 @@ DS.Store = Ember.Object.extend({
|
|
1087
1228
|
/**
|
1088
1229
|
@private
|
1089
1230
|
|
1090
|
-
|
1231
|
+
Given a type and array of `clientId`s, determines which of those
|
1232
|
+
`clientId`s has not yet been loaded.
|
1233
|
+
|
1234
|
+
In preparation for loading, this method also marks any unloaded
|
1235
|
+
`clientId`s as loading.
|
1236
|
+
*/
|
1237
|
+
neededClientIds: function(type, clientIds) {
|
1238
|
+
var neededClientIds = [],
|
1239
|
+
typeMap = this.typeMapFor(type),
|
1240
|
+
dataCache = typeMap.cidToHash,
|
1241
|
+
clientId;
|
1242
|
+
|
1243
|
+
for (var i=0, l=clientIds.length; i<l; i++) {
|
1244
|
+
clientId = clientIds[i];
|
1245
|
+
if (dataCache[clientId] === UNLOADED) {
|
1246
|
+
neededClientIds.push(clientId);
|
1247
|
+
dataCache[clientId] = LOADING;
|
1248
|
+
}
|
1249
|
+
}
|
1250
|
+
|
1251
|
+
return neededClientIds;
|
1252
|
+
},
|
1091
1253
|
|
1092
|
-
|
1093
|
-
|
1094
|
-
the remaining `id`s to the adapter.
|
1254
|
+
/**
|
1255
|
+
@private
|
1095
1256
|
|
1096
|
-
|
1097
|
-
|
1098
|
-
@param {Object} query
|
1257
|
+
This method is the entry point that associations use to update
|
1258
|
+
themselves when their underlying data changes.
|
1099
1259
|
|
1100
|
-
|
1101
|
-
|
1260
|
+
First, it determines which of its `clientId`s are still unloaded,
|
1261
|
+
then converts the needed `clientId`s to IDs and invokes `findMany`
|
1262
|
+
on the adapter.
|
1102
1263
|
*/
|
1103
|
-
|
1104
|
-
var
|
1105
|
-
|
1106
|
-
|
1107
|
-
data = typeMap.cidToHash,
|
1108
|
-
needed;
|
1264
|
+
fetchUnloadedClientIds: function(type, clientIds) {
|
1265
|
+
var neededClientIds = this.neededClientIds(type, clientIds);
|
1266
|
+
this.fetchMany(type, neededClientIds);
|
1267
|
+
},
|
1109
1268
|
|
1110
|
-
|
1269
|
+
/**
|
1270
|
+
@private
|
1111
1271
|
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
ids.forEach(function(id) {
|
1116
|
-
// Get the clientId for the given id
|
1117
|
-
var clientId = idToClientIdMap[id];
|
1118
|
-
|
1119
|
-
// If there is no `clientId` yet
|
1120
|
-
if (clientId === undefined) {
|
1121
|
-
// Create a new `clientId`, marking its data hash
|
1122
|
-
// as loading. Once the adapter returns the data
|
1123
|
-
// hash, it will be updated
|
1124
|
-
clientId = this.pushHash(LOADING, id, type);
|
1125
|
-
needed.push(id);
|
1126
|
-
|
1127
|
-
// If there is a clientId, but its data hash is
|
1128
|
-
// marked as unloaded (this happens when a
|
1129
|
-
// hasMany association creates clientIds for its
|
1130
|
-
// referenced ids before they were loaded)
|
1131
|
-
} else if (clientId && data[clientId] === UNLOADED) {
|
1132
|
-
// change the data hash marker to loading
|
1133
|
-
dataCache[clientId] = LOADING;
|
1134
|
-
needed.push(id);
|
1135
|
-
}
|
1272
|
+
This method takes a type and list of `clientId`s, converts the
|
1273
|
+
`clientId`s into IDs, and then invokes the adapter's `findMany`
|
1274
|
+
method.
|
1136
1275
|
|
1137
|
-
|
1138
|
-
|
1139
|
-
|
1140
|
-
|
1141
|
-
|
1142
|
-
|
1143
|
-
needed = null;
|
1144
|
-
}
|
1276
|
+
It is used both by a brand new association (via the `findMany`
|
1277
|
+
method) or when the data underlying an existing association
|
1278
|
+
changes (via the `fetchUnloadedClientIds` method).
|
1279
|
+
*/
|
1280
|
+
fetchMany: function(type, clientIds) {
|
1281
|
+
var clientIdToId = this.clientIdToId;
|
1145
1282
|
|
1146
|
-
|
1147
|
-
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
}
|
1283
|
+
var neededIds = Ember.EnumerableUtils.map(clientIds, function(clientId) {
|
1284
|
+
return clientIdToId[clientId];
|
1285
|
+
});
|
1286
|
+
|
1287
|
+
if (!neededIds.length) { return; }
|
1152
1288
|
|
1153
|
-
|
1289
|
+
var adapter = get(this, '_adapter');
|
1290
|
+
if (adapter && adapter.findMany) { adapter.findMany(this, type, neededIds); }
|
1291
|
+
else { throw fmt("Adapter is either null or does not implement `findMany` method", this); }
|
1154
1292
|
},
|
1155
1293
|
|
1156
|
-
/**
|
1294
|
+
/**
|
1295
|
+
@private
|
1296
|
+
|
1297
|
+
`findMany` is the entry point that associations use to generate a
|
1298
|
+
new `ManyArray` for the list of IDs specified by the server for
|
1299
|
+
the association.
|
1300
|
+
|
1301
|
+
Its responsibilities are:
|
1302
|
+
|
1303
|
+
* convert the IDs into clientIds
|
1304
|
+
* determine which of the clientIds still need to be loaded
|
1305
|
+
* create a new ManyArray whose content is *all* of the clientIds
|
1306
|
+
* notify the ManyArray of the number of its elements that are
|
1307
|
+
already loaded
|
1308
|
+
* insert the unloaded clientIds into the `loadingRecordArrays`
|
1309
|
+
bookkeeping structure, which will allow the `ManyArray` to know
|
1310
|
+
when all of its loading elements are loaded from the server.
|
1311
|
+
* ask the adapter to load the unloaded elements, by invoking
|
1312
|
+
findMany with the still-unloaded IDs.
|
1157
1313
|
*/
|
1158
|
-
findMany: function(type, ids
|
1159
|
-
|
1314
|
+
findMany: function(type, ids) {
|
1315
|
+
// 1. Convert ids to client ids
|
1316
|
+
// 2. Determine which of the client ids need to be loaded
|
1317
|
+
// 3. Create a new ManyArray whose content is ALL of the clientIds
|
1318
|
+
// 4. Decrement the ManyArray's counter by the number of loaded clientIds
|
1319
|
+
// 5. Put the ManyArray into our bookkeeping data structure, keyed on
|
1320
|
+
// the needed clientIds
|
1321
|
+
// 6. Ask the adapter to load the records for the unloaded clientIds (but
|
1322
|
+
// convert them back to ids)
|
1323
|
+
|
1324
|
+
var clientIds = this.clientIdsForIds(type, ids);
|
1325
|
+
|
1326
|
+
var neededClientIds = this.neededClientIds(type, clientIds),
|
1327
|
+
manyArray = this.createManyArray(type, Ember.A(clientIds)),
|
1328
|
+
loadedCount = clientIds.length - neededClientIds.length,
|
1329
|
+
loadingRecordArrays = this.loadingRecordArrays,
|
1330
|
+
clientId, i, l;
|
1331
|
+
|
1332
|
+
manyArray.send('loadedRecords', loadedCount);
|
1333
|
+
|
1334
|
+
if (neededClientIds.length) {
|
1335
|
+
for (i=0, l=neededClientIds.length; i<l; i++) {
|
1336
|
+
clientId = neededClientIds[i];
|
1337
|
+
if (loadingRecordArrays[clientId]) {
|
1338
|
+
loadingRecordArrays[clientId].push(manyArray);
|
1339
|
+
} else {
|
1340
|
+
this.loadingRecordArrays[clientId] = [ manyArray ];
|
1341
|
+
}
|
1342
|
+
}
|
1343
|
+
|
1344
|
+
this.fetchMany(type, neededClientIds);
|
1345
|
+
}
|
1160
1346
|
|
1161
|
-
return
|
1347
|
+
return manyArray;
|
1162
1348
|
},
|
1163
1349
|
|
1164
1350
|
findQuery: function(type, query) {
|
@@ -1201,6 +1387,10 @@ DS.Store = Ember.Object.extend({
|
|
1201
1387
|
return array;
|
1202
1388
|
},
|
1203
1389
|
|
1390
|
+
recordIsLoaded: function(type, id) {
|
1391
|
+
return !Ember.none(this.typeMapFor(type).idToCid[id]);
|
1392
|
+
},
|
1393
|
+
|
1204
1394
|
// ............
|
1205
1395
|
// . UPDATING .
|
1206
1396
|
// ............
|
@@ -1361,21 +1551,28 @@ DS.Store = Ember.Object.extend({
|
|
1361
1551
|
clientIds = typeMap.clientIds,
|
1362
1552
|
clientId, hash, proxy;
|
1363
1553
|
|
1364
|
-
var recordCache = get(this, 'recordCache'),
|
1554
|
+
var recordCache = get(this, 'recordCache'),
|
1555
|
+
foundRecord,
|
1556
|
+
record;
|
1365
1557
|
|
1366
1558
|
for (var i=0, l=clientIds.length; i<l; i++) {
|
1367
1559
|
clientId = clientIds[i];
|
1560
|
+
foundRecord = false;
|
1368
1561
|
|
1369
1562
|
hash = dataCache[clientId];
|
1370
1563
|
if (typeof hash === 'object') {
|
1371
1564
|
if (record = recordCache[clientId]) {
|
1372
|
-
|
1565
|
+
if (!get(record, 'isDeleted')) {
|
1566
|
+
proxy = get(record, 'data');
|
1567
|
+
foundRecord = true;
|
1568
|
+
}
|
1373
1569
|
} else {
|
1374
1570
|
DATA_PROXY.savedData = hash;
|
1375
1571
|
proxy = DATA_PROXY;
|
1572
|
+
foundRecord = true;
|
1376
1573
|
}
|
1377
1574
|
|
1378
|
-
this.updateRecordArray(array, filter, type, clientId, proxy);
|
1575
|
+
if (foundRecord) { this.updateRecordArray(array, filter, type, clientId, proxy); }
|
1379
1576
|
}
|
1380
1577
|
}
|
1381
1578
|
},
|
@@ -1388,6 +1585,18 @@ DS.Store = Ember.Object.extend({
|
|
1388
1585
|
filter = get(array, 'filterFunction');
|
1389
1586
|
this.updateRecordArray(array, filter, type, clientId, dataProxy);
|
1390
1587
|
}, this);
|
1588
|
+
|
1589
|
+
// loop through all manyArrays containing an unloaded copy of this
|
1590
|
+
// clientId and notify them that the record was loaded.
|
1591
|
+
var manyArrays = this.loadingRecordArrays[clientId], manyArray;
|
1592
|
+
|
1593
|
+
if (manyArrays) {
|
1594
|
+
for (var i=0, l=manyArrays.length; i<l; i++) {
|
1595
|
+
manyArrays[i].send('loadedRecords', 1);
|
1596
|
+
}
|
1597
|
+
|
1598
|
+
this.loadingRecordArrays[clientId] = null;
|
1599
|
+
}
|
1391
1600
|
},
|
1392
1601
|
|
1393
1602
|
updateRecordArray: function(array, filter, type, clientId, dataProxy) {
|
@@ -1473,6 +1682,24 @@ DS.Store = Ember.Object.extend({
|
|
1473
1682
|
return this.pushHash(UNLOADED, id, type);
|
1474
1683
|
},
|
1475
1684
|
|
1685
|
+
/**
|
1686
|
+
@private
|
1687
|
+
|
1688
|
+
This method works exactly like `clientIdForId`, but does not
|
1689
|
+
require looking up the `typeMap` for every `clientId` and
|
1690
|
+
invoking a method per `clientId`.
|
1691
|
+
*/
|
1692
|
+
clientIdsForIds: function(type, ids) {
|
1693
|
+
var typeMap = this.typeMapFor(type),
|
1694
|
+
idToClientIdMap = typeMap.idToCid;
|
1695
|
+
|
1696
|
+
return Ember.EnumerableUtils.map(ids, function(id) {
|
1697
|
+
var clientId = idToClientIdMap[id];
|
1698
|
+
if (clientId) { return clientId; }
|
1699
|
+
return this.pushHash(UNLOADED, id, type);
|
1700
|
+
}, this);
|
1701
|
+
},
|
1702
|
+
|
1476
1703
|
// ................
|
1477
1704
|
// . LOADING DATA .
|
1478
1705
|
// ................
|
@@ -1527,7 +1754,7 @@ DS.Store = Ember.Object.extend({
|
|
1527
1754
|
ids = [];
|
1528
1755
|
var primaryKey = type.proto().primaryKey;
|
1529
1756
|
|
1530
|
-
ids = Ember.
|
1757
|
+
ids = Ember.EnumerableUtils.map(hashes, function(hash) {
|
1531
1758
|
return hash[primaryKey];
|
1532
1759
|
});
|
1533
1760
|
}
|
@@ -1607,7 +1834,7 @@ DS.Store = Ember.Object.extend({
|
|
1607
1834
|
|
1608
1835
|
|
1609
1836
|
(function() {
|
1610
|
-
var get = Ember.get, set = Ember.set,
|
1837
|
+
var get = Ember.get, set = Ember.set, guidFor = Ember.guidFor;
|
1611
1838
|
|
1612
1839
|
/**
|
1613
1840
|
This file encapsulates the various states that a record can transition
|
@@ -1636,7 +1863,7 @@ var get = Ember.get, set = Ember.set, getPath = Ember.getPath, guidFor = Ember.g
|
|
1636
1863
|
string. You can determine a record's current state by getting its manager's
|
1637
1864
|
current state path:
|
1638
1865
|
|
1639
|
-
record.
|
1866
|
+
record.get('stateManager.currentState.path');
|
1640
1867
|
//=> "created.uncommitted"
|
1641
1868
|
|
1642
1869
|
The `DS.Model` states are themselves stateless. What we mean is that,
|
@@ -1722,7 +1949,7 @@ var get = Ember.get, set = Ember.set, getPath = Ember.getPath, guidFor = Ember.g
|
|
1722
1949
|
state in a more user-friendly way than examining its state path. For example,
|
1723
1950
|
instead of doing this:
|
1724
1951
|
|
1725
|
-
var statePath = record.
|
1952
|
+
var statePath = record.get('stateManager.currentState.path');
|
1726
1953
|
if (statePath === 'created.inFlight') {
|
1727
1954
|
doSomething();
|
1728
1955
|
}
|
@@ -1889,7 +2116,7 @@ var waitingOn = function(manager, object) {
|
|
1889
2116
|
// super points to the class definition.
|
1890
2117
|
var Uncommitted = Ember.Mixin.create({
|
1891
2118
|
setProperty: setProperty,
|
1892
|
-
setAssociation: setAssociation
|
2119
|
+
setAssociation: setAssociation
|
1893
2120
|
});
|
1894
2121
|
|
1895
2122
|
// These mixins are mixed into substates of the concrete
|
@@ -1983,7 +2210,7 @@ var DirtyState = DS.State.extend({
|
|
1983
2210
|
t.recordBecameClean(dirtyType, record);
|
1984
2211
|
});
|
1985
2212
|
|
1986
|
-
manager.goToState('
|
2213
|
+
manager.goToState('saved');
|
1987
2214
|
}
|
1988
2215
|
}, Uncommitted),
|
1989
2216
|
|
@@ -2013,7 +2240,7 @@ var DirtyState = DS.State.extend({
|
|
2013
2240
|
t.recordBecameClean('inflight', record);
|
2014
2241
|
});
|
2015
2242
|
|
2016
|
-
manager.goToState('
|
2243
|
+
manager.goToState('saved');
|
2017
2244
|
manager.send('invokeLifecycleCallbacks', dirtyType);
|
2018
2245
|
},
|
2019
2246
|
|
@@ -2164,7 +2391,7 @@ var DirtyState = DS.State.extend({
|
|
2164
2391
|
errors = get(record, 'errors'),
|
2165
2392
|
key = context.key;
|
2166
2393
|
|
2167
|
-
|
2394
|
+
set(errors, key, null);
|
2168
2395
|
|
2169
2396
|
if (!hasDefinedProperties(errors)) {
|
2170
2397
|
manager.send('becameValid');
|
@@ -2182,7 +2409,7 @@ var DirtyState = DS.State.extend({
|
|
2182
2409
|
|
2183
2410
|
invokeLifecycleCallbacks: function(manager) {
|
2184
2411
|
var record = get(manager, 'record');
|
2185
|
-
record.
|
2412
|
+
record.trigger('becameInvalid', record);
|
2186
2413
|
}
|
2187
2414
|
})
|
2188
2415
|
});
|
@@ -2272,7 +2499,7 @@ var states = {
|
|
2272
2499
|
// TRANSITIONS
|
2273
2500
|
exit: function(manager) {
|
2274
2501
|
var record = get(manager, 'record');
|
2275
|
-
record.
|
2502
|
+
record.trigger('didLoad');
|
2276
2503
|
},
|
2277
2504
|
|
2278
2505
|
// EVENTS
|
@@ -2326,9 +2553,9 @@ var states = {
|
|
2326
2553
|
invokeLifecycleCallbacks: function(manager, dirtyType) {
|
2327
2554
|
var record = get(manager, 'record');
|
2328
2555
|
if (dirtyType === 'created') {
|
2329
|
-
record.
|
2556
|
+
record.trigger('didCreate', record);
|
2330
2557
|
} else {
|
2331
|
-
record.
|
2558
|
+
record.trigger('didUpdate', record);
|
2332
2559
|
}
|
2333
2560
|
}
|
2334
2561
|
}),
|
@@ -2431,7 +2658,7 @@ var states = {
|
|
2431
2658
|
|
2432
2659
|
invokeLifecycleCallbacks: function(manager) {
|
2433
2660
|
var record = get(manager, 'record');
|
2434
|
-
record.
|
2661
|
+
record.trigger('didDelete', record);
|
2435
2662
|
}
|
2436
2663
|
})
|
2437
2664
|
}),
|
@@ -2446,7 +2673,7 @@ var states = {
|
|
2446
2673
|
|
2447
2674
|
invokeLifecycleCallbacks: function(manager) {
|
2448
2675
|
var record = get(manager, 'record');
|
2449
|
-
record.
|
2676
|
+
record.trigger('becameError', record);
|
2450
2677
|
}
|
2451
2678
|
})
|
2452
2679
|
})
|
@@ -2609,10 +2836,10 @@ DataProxy.prototype = {
|
|
2609
2836
|
|
2610
2837
|
|
2611
2838
|
(function() {
|
2612
|
-
var get = Ember.get, set = Ember.set,
|
2839
|
+
var get = Ember.get, set = Ember.set, none = Ember.none;
|
2613
2840
|
|
2614
2841
|
var retrieveFromCurrentState = Ember.computed(function(key) {
|
2615
|
-
return get(
|
2842
|
+
return get(get(this, 'stateManager.currentState'), key);
|
2616
2843
|
}).property('stateManager.currentState').cacheable();
|
2617
2844
|
|
2618
2845
|
DS.Model = Ember.Object.extend(Ember.Evented, {
|
@@ -2903,12 +3130,18 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
2903
3130
|
cachedValue = this.cacheFor(name);
|
2904
3131
|
|
2905
3132
|
if (cachedValue) {
|
2906
|
-
var key = association.options.key || name,
|
3133
|
+
var key = association.options.key || get(this, 'namingConvention').keyToJSONKey(name),
|
2907
3134
|
ids = data.get(key) || [];
|
2908
|
-
|
2909
|
-
|
2910
|
-
|
2911
|
-
|
3135
|
+
|
3136
|
+
var clientIds;
|
3137
|
+
if(association.options.embedded) {
|
3138
|
+
clientIds = store.loadMany(association.type, ids).clientIds;
|
3139
|
+
} else {
|
3140
|
+
clientIds = Ember.EnumerableUtils.map(ids, function(id) {
|
3141
|
+
return store.clientIdForId(association.type, id);
|
3142
|
+
});
|
3143
|
+
}
|
3144
|
+
|
2912
3145
|
set(cachedValue, 'content', Ember.A(clientIds));
|
2913
3146
|
cachedValue.fetch();
|
2914
3147
|
}
|
@@ -2922,8 +3155,8 @@ DS.Model = Ember.Object.extend(Ember.Evented, {
|
|
2922
3155
|
Override the default event firing from Ember.Evented to
|
2923
3156
|
also call methods with the given name.
|
2924
3157
|
*/
|
2925
|
-
|
2926
|
-
|
3158
|
+
trigger: function(name) {
|
3159
|
+
Ember.tryInvoke(this, name, [].slice.call(arguments, 1));
|
2927
3160
|
this._super.apply(this, arguments);
|
2928
3161
|
}
|
2929
3162
|
});
|
@@ -2943,6 +3176,7 @@ var storeAlias = function(methodName) {
|
|
2943
3176
|
};
|
2944
3177
|
|
2945
3178
|
DS.Model.reopenClass({
|
3179
|
+
isLoaded: storeAlias('recordIsLoaded'),
|
2946
3180
|
find: storeAlias('find'),
|
2947
3181
|
filter: storeAlias('filter'),
|
2948
3182
|
|
@@ -2960,7 +3194,7 @@ DS.Model.reopenClass({
|
|
2960
3194
|
|
2961
3195
|
|
2962
3196
|
(function() {
|
2963
|
-
var get = Ember.get
|
3197
|
+
var get = Ember.get;
|
2964
3198
|
DS.Model.reopenClass({
|
2965
3199
|
attributes: Ember.computed(function() {
|
2966
3200
|
var map = Ember.Map.create();
|
@@ -2985,6 +3219,17 @@ DS.Model.reopenClass({
|
|
2985
3219
|
}
|
2986
3220
|
});
|
2987
3221
|
|
3222
|
+
function getAttr(record, options, key) {
|
3223
|
+
var data = get(record, 'data');
|
3224
|
+
var value = get(data, key);
|
3225
|
+
|
3226
|
+
if (value === undefined) {
|
3227
|
+
value = options.defaultValue;
|
3228
|
+
}
|
3229
|
+
|
3230
|
+
return value;
|
3231
|
+
}
|
3232
|
+
|
2988
3233
|
DS.attr = function(type, options) {
|
2989
3234
|
var transform = DS.attr.transforms[type];
|
2990
3235
|
Ember.assert("Could not find model attribute of type " + type, !!transform);
|
@@ -3014,14 +3259,12 @@ DS.attr = function(type, options) {
|
|
3014
3259
|
|
3015
3260
|
if (arguments.length === 2) {
|
3016
3261
|
value = transformTo(value);
|
3017
|
-
this.setProperty(key, value);
|
3018
|
-
} else {
|
3019
|
-
data = get(this, 'data');
|
3020
|
-
value = get(data, key);
|
3021
3262
|
|
3022
|
-
if (value
|
3023
|
-
value
|
3263
|
+
if (value !== getAttr(this, options, key)) {
|
3264
|
+
this.setProperty(key, value);
|
3024
3265
|
}
|
3266
|
+
} else {
|
3267
|
+
value = getAttr(this, options, key);
|
3025
3268
|
}
|
3026
3269
|
|
3027
3270
|
return transformFrom(value);
|
@@ -3122,7 +3365,7 @@ DS.attr.transforms = {
|
|
3122
3365
|
|
3123
3366
|
|
3124
3367
|
(function() {
|
3125
|
-
var get = Ember.get, set = Ember.set,
|
3368
|
+
var get = Ember.get, set = Ember.set,
|
3126
3369
|
none = Ember.none;
|
3127
3370
|
|
3128
3371
|
var embeddedFindRecord = function(store, type, data, key, one) {
|
@@ -3147,12 +3390,12 @@ var hasAssociation = function(type, options, one) {
|
|
3147
3390
|
store = get(this, 'store');
|
3148
3391
|
|
3149
3392
|
if (typeof type === 'string') {
|
3150
|
-
type =
|
3393
|
+
type = get(this, type, false) || get(window, type);
|
3151
3394
|
}
|
3152
3395
|
|
3153
3396
|
if (arguments.length === 2) {
|
3154
3397
|
key = options.key || get(this, 'namingConvention').foreignKey(key);
|
3155
|
-
this.send('setAssociation', { key: key, value: value
|
3398
|
+
this.send('setAssociation', { key: key, value: Ember.none(value) ? null : get(value, 'clientId') });
|
3156
3399
|
//data.setAssociation(key, get(value, 'clientId'));
|
3157
3400
|
// put the client id in `key` in the data hash
|
3158
3401
|
return value;
|
@@ -3185,7 +3428,7 @@ DS.belongsTo = function(type, options) {
|
|
3185
3428
|
|
3186
3429
|
|
3187
3430
|
(function() {
|
3188
|
-
var get = Ember.get, set = Ember.set
|
3431
|
+
var get = Ember.get, set = Ember.set;
|
3189
3432
|
var embeddedFindRecord = function(store, type, data, key) {
|
3190
3433
|
var association = get(data, key);
|
3191
3434
|
return association ? store.loadMany(type, association).ids : [];
|
@@ -3209,12 +3452,12 @@ var hasAssociation = function(type, options) {
|
|
3209
3452
|
ids, id, association;
|
3210
3453
|
|
3211
3454
|
if (typeof type === 'string') {
|
3212
|
-
type =
|
3455
|
+
type = get(this, type, false) || get(window, type);
|
3213
3456
|
}
|
3214
3457
|
|
3215
3458
|
key = options.key || get(this, 'namingConvention').keyToJSONKey(key);
|
3216
3459
|
ids = findRecord(store, type, data, key);
|
3217
|
-
association = store.findMany(type, ids);
|
3460
|
+
association = store.findMany(type, ids || []);
|
3218
3461
|
set(association, 'parentRecord', this);
|
3219
3462
|
|
3220
3463
|
return association;
|
@@ -3231,7 +3474,7 @@ DS.hasMany = function(type, options) {
|
|
3231
3474
|
|
3232
3475
|
|
3233
3476
|
(function() {
|
3234
|
-
var get = Ember.get
|
3477
|
+
var get = Ember.get;
|
3235
3478
|
|
3236
3479
|
DS.Model.reopenClass({
|
3237
3480
|
typeForAssociation: function(name) {
|
@@ -3248,7 +3491,7 @@ DS.Model.reopenClass({
|
|
3248
3491
|
typeList = map.get(type);
|
3249
3492
|
|
3250
3493
|
if (typeof type === 'string') {
|
3251
|
-
type =
|
3494
|
+
type = get(this, type, false) || get(window, type);
|
3252
3495
|
meta.type = type;
|
3253
3496
|
}
|
3254
3497
|
|
@@ -3273,7 +3516,7 @@ DS.Model.reopenClass({
|
|
3273
3516
|
type = meta.type;
|
3274
3517
|
|
3275
3518
|
if (typeof type === 'string') {
|
3276
|
-
type =
|
3519
|
+
type = get(this, type, false) || get(window, type);
|
3277
3520
|
meta.type = type;
|
3278
3521
|
}
|
3279
3522
|
|
@@ -3430,9 +3673,28 @@ DS.Adapter = Ember.Object.extend({
|
|
3430
3673
|
var set = Ember.set;
|
3431
3674
|
|
3432
3675
|
Ember.onLoad('application', function(app) {
|
3433
|
-
app.registerInjection(
|
3434
|
-
|
3435
|
-
|
3676
|
+
app.registerInjection({
|
3677
|
+
name: "store",
|
3678
|
+
before: "controllers",
|
3679
|
+
|
3680
|
+
injection: function(app, stateManager, property) {
|
3681
|
+
if (property === 'Store') {
|
3682
|
+
set(stateManager, 'store', app[property].create());
|
3683
|
+
}
|
3684
|
+
}
|
3685
|
+
});
|
3686
|
+
|
3687
|
+
app.registerInjection({
|
3688
|
+
name: "giveStoreToControllers",
|
3689
|
+
|
3690
|
+
injection: function(app, stateManager, property) {
|
3691
|
+
if (property.match(/Controller$/)) {
|
3692
|
+
var controllerName = property.charAt(0).toLowerCase() + property.substr(1);
|
3693
|
+
var store = stateManager.get('store');
|
3694
|
+
var controller = stateManager.get(controllerName);
|
3695
|
+
|
3696
|
+
controller.set('store', store);
|
3697
|
+
}
|
3436
3698
|
}
|
3437
3699
|
});
|
3438
3700
|
});
|
@@ -3442,34 +3704,138 @@ Ember.onLoad('application', function(app) {
|
|
3442
3704
|
|
3443
3705
|
|
3444
3706
|
(function() {
|
3445
|
-
|
3707
|
+
var get = Ember.get;
|
3708
|
+
|
3709
|
+
DS.FixtureAdapter = DS.Adapter.extend({
|
3710
|
+
|
3711
|
+
simulateRemoteResponse: true,
|
3712
|
+
|
3713
|
+
latency: 50,
|
3714
|
+
|
3715
|
+
/*
|
3716
|
+
Implement this method in order to provide data associated with a type
|
3717
|
+
*/
|
3718
|
+
fixturesForType: function(type) {
|
3719
|
+
return type.FIXTURES ? Ember.A(type.FIXTURES) : null;
|
3720
|
+
},
|
3721
|
+
|
3722
|
+
/*
|
3723
|
+
Implement this method in order to query fixtures data
|
3724
|
+
*/
|
3725
|
+
queryFixtures: function(fixtures, query) {
|
3726
|
+
return fixtures;
|
3727
|
+
},
|
3728
|
+
|
3729
|
+
/*
|
3730
|
+
Implement this method in order to provide provide json for CRUD methods
|
3731
|
+
*/
|
3732
|
+
mockJSON: function(type, record) {
|
3733
|
+
return record.toJSON({associations: true});
|
3734
|
+
},
|
3735
|
+
|
3736
|
+
/*
|
3737
|
+
Adapter methods
|
3738
|
+
*/
|
3739
|
+
generateIdForRecord: function(store, record) {
|
3740
|
+
return Ember.guidFor(record);
|
3741
|
+
},
|
3742
|
+
|
3446
3743
|
find: function(store, type, id) {
|
3447
|
-
var fixtures = type
|
3744
|
+
var fixtures = this.fixturesForType(type);
|
3448
3745
|
|
3449
3746
|
Ember.assert("Unable to find fixtures for model type "+type.toString(), !!fixtures);
|
3450
|
-
if (fixtures.hasLoaded) { return; }
|
3451
3747
|
|
3452
|
-
|
3453
|
-
|
3454
|
-
|
3455
|
-
|
3748
|
+
if (fixtures) {
|
3749
|
+
fixtures = fixtures.findProperty('id', id);
|
3750
|
+
}
|
3751
|
+
|
3752
|
+
if (fixtures) {
|
3753
|
+
this.simulateRemoteCall(function() {
|
3754
|
+
store.load(type, fixtures);
|
3755
|
+
}, store, type);
|
3756
|
+
}
|
3456
3757
|
},
|
3457
3758
|
|
3458
|
-
findMany: function() {
|
3459
|
-
this.
|
3759
|
+
findMany: function(store, type, ids) {
|
3760
|
+
var fixtures = this.fixturesForType(type);
|
3761
|
+
|
3762
|
+
Ember.assert("Unable to find fixtures for model type "+type.toString(), !!fixtures);
|
3763
|
+
|
3764
|
+
if (fixtures) {
|
3765
|
+
fixtures = fixtures.filter(function(item) {
|
3766
|
+
return ids.indexOf(item.id) !== -1;
|
3767
|
+
});
|
3768
|
+
}
|
3769
|
+
|
3770
|
+
if (fixtures) {
|
3771
|
+
this.simulateRemoteCall(function() {
|
3772
|
+
store.loadMany(type, fixtures);
|
3773
|
+
}, store, type);
|
3774
|
+
}
|
3460
3775
|
},
|
3461
3776
|
|
3462
3777
|
findAll: function(store, type) {
|
3463
|
-
var fixtures = type
|
3778
|
+
var fixtures = this.fixturesForType(type);
|
3464
3779
|
|
3465
3780
|
Ember.assert("Unable to find fixtures for model type "+type.toString(), !!fixtures);
|
3466
3781
|
|
3467
|
-
|
3468
|
-
|
3469
|
-
|
3782
|
+
this.simulateRemoteCall(function() {
|
3783
|
+
store.loadMany(type, fixtures);
|
3784
|
+
}, store, type);
|
3785
|
+
},
|
3786
|
+
|
3787
|
+
findQuery: function(store, type, query, array) {
|
3788
|
+
var fixtures = this.fixturesForType(type);
|
3789
|
+
|
3790
|
+
Ember.assert("Unable to find fixtures for model type "+type.toString(), !!fixtures);
|
3791
|
+
|
3792
|
+
fixtures = this.queryFixtures(fixtures, query);
|
3470
3793
|
|
3794
|
+
if (fixtures) {
|
3795
|
+
this.simulateRemoteCall(function() {
|
3796
|
+
array.load(fixtures);
|
3797
|
+
}, store, type);
|
3798
|
+
}
|
3799
|
+
},
|
3800
|
+
|
3801
|
+
createRecord: function(store, type, record) {
|
3802
|
+
var fixture = this.mockJSON(type, record);
|
3803
|
+
|
3804
|
+
fixture.id = this.generateIdForRecord(store, record);
|
3805
|
+
|
3806
|
+
this.simulateRemoteCall(function() {
|
3807
|
+
store.didCreateRecord(record, fixture);
|
3808
|
+
}, store, type, record);
|
3809
|
+
},
|
3810
|
+
|
3811
|
+
updateRecord: function(store, type, record) {
|
3812
|
+
var fixture = this.mockJSON(type, record);
|
3813
|
+
|
3814
|
+
this.simulateRemoteCall(function() {
|
3815
|
+
store.didUpdateRecord(record, fixture);
|
3816
|
+
}, store, type, record);
|
3817
|
+
},
|
3818
|
+
|
3819
|
+
deleteRecord: function(store, type, record) {
|
3820
|
+
this.simulateRemoteCall(function() {
|
3821
|
+
store.didDeleteRecord(record);
|
3822
|
+
}, store, type, record);
|
3823
|
+
},
|
3824
|
+
|
3825
|
+
/*
|
3826
|
+
@private
|
3827
|
+
*/
|
3828
|
+
simulateRemoteCall: function(callback, store, type, record) {
|
3829
|
+
if (get(this, 'simulateRemoteResponse')) {
|
3830
|
+
setTimeout(callback, get(this, 'latency'));
|
3831
|
+
} else {
|
3832
|
+
callback();
|
3833
|
+
}
|
3834
|
+
}
|
3471
3835
|
});
|
3472
3836
|
|
3837
|
+
DS.fixtureAdapter = DS.FixtureAdapter.create();
|
3838
|
+
|
3473
3839
|
})();
|
3474
3840
|
|
3475
3841
|
|
@@ -3477,7 +3843,7 @@ DS.fixtureAdapter = DS.Adapter.create({
|
|
3477
3843
|
(function() {
|
3478
3844
|
/*global jQuery*/
|
3479
3845
|
|
3480
|
-
var get = Ember.get, set = Ember.set
|
3846
|
+
var get = Ember.get, set = Ember.set;
|
3481
3847
|
|
3482
3848
|
DS.RESTAdapter = DS.Adapter.extend({
|
3483
3849
|
bulkCommit: false,
|
@@ -3490,13 +3856,20 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
3490
3856
|
|
3491
3857
|
this.ajax(this.buildURL(root), "POST", {
|
3492
3858
|
data: data,
|
3859
|
+
context: this,
|
3493
3860
|
success: function(json) {
|
3494
|
-
this.
|
3495
|
-
store.didCreateRecord(record, json[root]);
|
3861
|
+
this.didCreateRecord(store, type, record, json);
|
3496
3862
|
}
|
3497
3863
|
});
|
3498
3864
|
},
|
3499
3865
|
|
3866
|
+
didCreateRecord: function(store, type, record, json) {
|
3867
|
+
var root = this.rootForType(type);
|
3868
|
+
|
3869
|
+
this.sideload(store, type, json, root);
|
3870
|
+
store.didCreateRecord(record, json[root]);
|
3871
|
+
},
|
3872
|
+
|
3500
3873
|
createRecords: function(store, type, records) {
|
3501
3874
|
if (get(this, 'bulkCommit') === false) {
|
3502
3875
|
return this._super(store, type, records);
|
@@ -3512,14 +3885,20 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
3512
3885
|
|
3513
3886
|
this.ajax(this.buildURL(root), "POST", {
|
3514
3887
|
data: data,
|
3515
|
-
|
3888
|
+
context: this,
|
3516
3889
|
success: function(json) {
|
3517
|
-
this.
|
3518
|
-
store.didCreateRecords(type, records, json[plural]);
|
3890
|
+
this.didCreateRecords(store, type, records, json);
|
3519
3891
|
}
|
3520
3892
|
});
|
3521
3893
|
},
|
3522
3894
|
|
3895
|
+
didCreateRecords: function(store, type, records, json) {
|
3896
|
+
var root = this.pluralize(this.rootForType(type));
|
3897
|
+
|
3898
|
+
this.sideload(store, type, json, root);
|
3899
|
+
store.didCreateRecords(type, records, json[root]);
|
3900
|
+
},
|
3901
|
+
|
3523
3902
|
updateRecord: function(store, type, record) {
|
3524
3903
|
var id = get(record, 'id');
|
3525
3904
|
var root = this.rootForType(type);
|
@@ -3529,13 +3908,20 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
3529
3908
|
|
3530
3909
|
this.ajax(this.buildURL(root, id), "PUT", {
|
3531
3910
|
data: data,
|
3911
|
+
context: this,
|
3532
3912
|
success: function(json) {
|
3533
|
-
this.
|
3534
|
-
store.didUpdateRecord(record, json && json[root]);
|
3913
|
+
this.didUpdateRecord(store, type, record, json);
|
3535
3914
|
}
|
3536
3915
|
});
|
3537
3916
|
},
|
3538
3917
|
|
3918
|
+
didUpdateRecord: function(store, type, record, json) {
|
3919
|
+
var root = this.rootForType(type);
|
3920
|
+
|
3921
|
+
this.sideload(store, type, json, root);
|
3922
|
+
store.didUpdateRecord(record, json && json[root]);
|
3923
|
+
},
|
3924
|
+
|
3539
3925
|
updateRecords: function(store, type, records) {
|
3540
3926
|
if (get(this, 'bulkCommit') === false) {
|
3541
3927
|
return this._super(store, type, records);
|
@@ -3551,25 +3937,37 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
3551
3937
|
|
3552
3938
|
this.ajax(this.buildURL(root, "bulk"), "PUT", {
|
3553
3939
|
data: data,
|
3940
|
+
context: this,
|
3554
3941
|
success: function(json) {
|
3555
|
-
this.
|
3556
|
-
store.didUpdateRecords(records, json[plural]);
|
3942
|
+
this.didUpdateRecords(store, type, records, json);
|
3557
3943
|
}
|
3558
3944
|
});
|
3559
3945
|
},
|
3560
3946
|
|
3947
|
+
didUpdateRecords: function(store, type, records, json) {
|
3948
|
+
var root = this.pluralize(this.rootForType(type));
|
3949
|
+
|
3950
|
+
this.sideload(store, type, json, root);
|
3951
|
+
store.didUpdateRecords(records, json[root]);
|
3952
|
+
},
|
3953
|
+
|
3561
3954
|
deleteRecord: function(store, type, record) {
|
3562
3955
|
var id = get(record, 'id');
|
3563
3956
|
var root = this.rootForType(type);
|
3564
3957
|
|
3565
3958
|
this.ajax(this.buildURL(root, id), "DELETE", {
|
3959
|
+
context: this,
|
3566
3960
|
success: function(json) {
|
3567
|
-
|
3568
|
-
store.didDeleteRecord(record);
|
3961
|
+
this.didDeleteRecord(store, type, record, json);
|
3569
3962
|
}
|
3570
3963
|
});
|
3571
3964
|
},
|
3572
3965
|
|
3966
|
+
didDeleteRecord: function(store, type, record, json) {
|
3967
|
+
if (json) { this.sideload(store, type, json); }
|
3968
|
+
store.didDeleteRecord(record);
|
3969
|
+
},
|
3970
|
+
|
3573
3971
|
deleteRecords: function(store, type, records) {
|
3574
3972
|
if (get(this, 'bulkCommit') === false) {
|
3575
3973
|
return this._super(store, type, records);
|
@@ -3585,20 +3983,25 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
3585
3983
|
|
3586
3984
|
this.ajax(this.buildURL(root, 'bulk'), "DELETE", {
|
3587
3985
|
data: data,
|
3986
|
+
context: this,
|
3588
3987
|
success: function(json) {
|
3589
|
-
|
3590
|
-
store.didDeleteRecords(records);
|
3988
|
+
this.didDeleteRecords(store, type, records, json);
|
3591
3989
|
}
|
3592
3990
|
});
|
3593
3991
|
},
|
3594
3992
|
|
3993
|
+
didDeleteRecords: function(store, type, records, json) {
|
3994
|
+
if (json) { this.sideload(store, type, json); }
|
3995
|
+
store.didDeleteRecords(records);
|
3996
|
+
},
|
3997
|
+
|
3595
3998
|
find: function(store, type, id) {
|
3596
3999
|
var root = this.rootForType(type);
|
3597
4000
|
|
3598
4001
|
this.ajax(this.buildURL(root, id), "GET", {
|
3599
4002
|
success: function(json) {
|
3600
|
-
store.load(type, json[root]);
|
3601
4003
|
this.sideload(store, type, json, root);
|
4004
|
+
store.load(type, json[root]);
|
3602
4005
|
}
|
3603
4006
|
});
|
3604
4007
|
},
|
@@ -3609,8 +4012,8 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
3609
4012
|
this.ajax(this.buildURL(root), "GET", {
|
3610
4013
|
data: { ids: ids },
|
3611
4014
|
success: function(json) {
|
3612
|
-
store.loadMany(type, json[plural]);
|
3613
4015
|
this.sideload(store, type, json, plural);
|
4016
|
+
store.loadMany(type, json[plural]);
|
3614
4017
|
}
|
3615
4018
|
});
|
3616
4019
|
},
|
@@ -3620,8 +4023,8 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
3620
4023
|
|
3621
4024
|
this.ajax(this.buildURL(root), "GET", {
|
3622
4025
|
success: function(json) {
|
3623
|
-
store.loadMany(type, json[plural]);
|
3624
4026
|
this.sideload(store, type, json, plural);
|
4027
|
+
store.loadMany(type, json[plural]);
|
3625
4028
|
}
|
3626
4029
|
});
|
3627
4030
|
},
|
@@ -3632,8 +4035,8 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
3632
4035
|
this.ajax(this.buildURL(root), "GET", {
|
3633
4036
|
data: query,
|
3634
4037
|
success: function(json) {
|
3635
|
-
recordArray.load(json[plural]);
|
3636
4038
|
this.sideload(store, type, json, plural);
|
4039
|
+
recordArray.load(json[plural]);
|
3637
4040
|
}
|
3638
4041
|
});
|
3639
4042
|
},
|
@@ -3672,7 +4075,9 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
3672
4075
|
},
|
3673
4076
|
|
3674
4077
|
sideload: function(store, type, json, root) {
|
3675
|
-
var sideloadedType, mappings;
|
4078
|
+
var sideloadedType, mappings, loaded = {};
|
4079
|
+
|
4080
|
+
loaded[root] = true;
|
3676
4081
|
|
3677
4082
|
for (var prop in json) {
|
3678
4083
|
if (!json.hasOwnProperty(prop)) { continue; }
|
@@ -3685,13 +4090,34 @@ DS.RESTAdapter = DS.Adapter.extend({
|
|
3685
4090
|
Ember.assert("Your server returned a hash with the key " + prop + " but you have no mappings", !!mappings);
|
3686
4091
|
|
3687
4092
|
sideloadedType = get(mappings, prop);
|
4093
|
+
|
4094
|
+
if (typeof sideloadedType === 'string') {
|
4095
|
+
sideloadedType = get(window, sideloadedType);
|
4096
|
+
}
|
4097
|
+
|
3688
4098
|
Ember.assert("Your server returned a hash with the key " + prop + " but you have no mapping for it", !!sideloadedType);
|
3689
4099
|
}
|
3690
4100
|
|
3691
|
-
this.
|
4101
|
+
this.sideloadAssociations(store, sideloadedType, json, prop, loaded);
|
3692
4102
|
}
|
3693
4103
|
},
|
3694
4104
|
|
4105
|
+
sideloadAssociations: function(store, type, json, prop, loaded) {
|
4106
|
+
loaded[prop] = true;
|
4107
|
+
|
4108
|
+
get(type, 'associationsByName').forEach(function(key, meta) {
|
4109
|
+
key = meta.key || key;
|
4110
|
+
if (meta.kind === 'belongsTo') {
|
4111
|
+
key = this.pluralize(key);
|
4112
|
+
}
|
4113
|
+
if (json[key] && !loaded[key]) {
|
4114
|
+
this.sideloadAssociations(store, meta.type, json, key, loaded);
|
4115
|
+
}
|
4116
|
+
}, this);
|
4117
|
+
|
4118
|
+
this.loadValue(store, type, json[prop]);
|
4119
|
+
},
|
4120
|
+
|
3695
4121
|
loadValue: function(store, type, value) {
|
3696
4122
|
if (value instanceof Array) {
|
3697
4123
|
store.loadMany(type, value);
|