ember-rails 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|