sproutcore 1.0.1009 → 1.0.1024

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.
Files changed (64) hide show
  1. data/DISTRIBUTION.yml +14 -0
  2. data/Rakefile +150 -23
  3. data/VERSION.yml +4 -2
  4. data/frameworks/sproutcore/Buildfile +1 -1
  5. data/frameworks/sproutcore/frameworks/bootstrap/system/loader.js +1 -0
  6. data/frameworks/sproutcore/frameworks/datastore/models/record.js +66 -5
  7. data/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +14 -0
  8. data/frameworks/sproutcore/frameworks/datastore/tests/models/record_attribute.js +28 -3
  9. data/frameworks/sproutcore/frameworks/desktop/english.lproj/alert.css +1 -1
  10. data/frameworks/sproutcore/frameworks/desktop/english.lproj/menu_item_view.css +22 -2
  11. data/frameworks/sproutcore/frameworks/desktop/english.lproj/panel.css +5 -1
  12. data/frameworks/sproutcore/frameworks/desktop/english.lproj/well.css +72 -0
  13. data/frameworks/sproutcore/frameworks/desktop/panes/alert.js +1 -1
  14. data/frameworks/sproutcore/frameworks/desktop/panes/picker.js +1 -1
  15. data/frameworks/sproutcore/frameworks/desktop/panes/select_button.js +33 -7
  16. data/frameworks/sproutcore/frameworks/desktop/system/root_responder.js +24 -23
  17. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_alternatingrows.js +130 -0
  18. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_row_heights.js +9 -10
  19. data/frameworks/sproutcore/frameworks/desktop/tests/views/list_item.js +4 -0
  20. data/frameworks/sproutcore/frameworks/desktop/tests/views/progress/ui.js +18 -9
  21. data/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/methods.js +7 -6
  22. data/frameworks/sproutcore/frameworks/desktop/tests/views/well/ui.js +54 -0
  23. data/frameworks/sproutcore/frameworks/desktop/views/button.js +21 -9
  24. data/frameworks/sproutcore/frameworks/desktop/views/checkbox.js +4 -3
  25. data/frameworks/sproutcore/frameworks/desktop/views/collection.js +1 -1
  26. data/frameworks/sproutcore/frameworks/desktop/views/grid.js +23 -14
  27. data/frameworks/sproutcore/frameworks/desktop/views/list_item.js +2 -2
  28. data/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +3 -3
  29. data/frameworks/sproutcore/frameworks/desktop/views/radio.js +1 -2
  30. data/frameworks/sproutcore/frameworks/desktop/views/scroll.js +1 -1
  31. data/frameworks/sproutcore/frameworks/desktop/views/segmented.js +1 -1
  32. data/frameworks/sproutcore/frameworks/desktop/views/slider.js +1 -1
  33. data/frameworks/sproutcore/frameworks/desktop/views/source_list_group.js +1 -1
  34. data/frameworks/sproutcore/frameworks/desktop/views/well.js +80 -0
  35. data/frameworks/sproutcore/frameworks/foundation/fixtures/malformed.json +11 -0
  36. data/frameworks/sproutcore/frameworks/foundation/mixins/button.js +1 -1
  37. data/frameworks/sproutcore/frameworks/foundation/mixins/inline_text_field.js +5 -1
  38. data/frameworks/sproutcore/frameworks/foundation/panes/pane.js +1 -1
  39. data/frameworks/sproutcore/frameworks/foundation/system/cursor.js +11 -10
  40. data/frameworks/sproutcore/frameworks/foundation/system/event.js +16 -15
  41. data/frameworks/sproutcore/frameworks/foundation/system/render_context.js +3 -3
  42. data/frameworks/sproutcore/frameworks/foundation/system/request.js +6 -5
  43. data/frameworks/sproutcore/frameworks/foundation/system/response.js +26 -8
  44. data/frameworks/sproutcore/frameworks/foundation/system/root_responder.js +2 -2
  45. data/frameworks/sproutcore/frameworks/foundation/system/timer.js +2 -2
  46. data/frameworks/sproutcore/frameworks/foundation/system/utils.js +122 -13
  47. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_core.js +2 -3
  48. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/tag.js +9 -9
  49. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/update.js +3 -3
  50. data/frameworks/sproutcore/frameworks/foundation/tests/system/request.js +27 -0
  51. data/frameworks/sproutcore/frameworks/foundation/tests/system/utils/rect.js +99 -0
  52. data/frameworks/sproutcore/frameworks/foundation/tests/views/image/ui.js +1 -1
  53. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/updateLayer.js +1 -1
  54. data/frameworks/sproutcore/frameworks/foundation/views/image.js +3 -1
  55. data/frameworks/sproutcore/frameworks/foundation/views/label.js +1 -1
  56. data/frameworks/sproutcore/frameworks/runtime/system/cookie.js +160 -0
  57. data/frameworks/sproutcore/frameworks/runtime/system/object.js +1 -1
  58. data/frameworks/sproutcore/frameworks/runtime/tests/system/cookie.js +163 -0
  59. data/frameworks/sproutcore/themes/standard_theme/english.lproj/pane.css +12 -2
  60. data/lib/sproutcore/rack/proxy.rb +4 -2
  61. data/sproutcore-abbot.gemspec +23 -9
  62. metadata +32 -5
  63. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/standard_fade/000000.png +0 -0
  64. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/standard_fade/ffffff.png +0 -0
@@ -0,0 +1,14 @@
1
+ # This file lists all subprojects that need to be installed in the directory
2
+ # for release. The Rakefile will track Git hash codes for each project in
3
+ # the VERSION.yml file
4
+ #
5
+ # Each entry should have the following format:
6
+ #
7
+ # path/to/item:
8
+ # repo: GIT/SVN URL
9
+ # scm: git|svn <- type of source control system. defaults to git
10
+ #
11
+
12
+ frameworks/sproutcore:
13
+ repo: git://github.com/sproutit/sproutcore.git
14
+
data/Rakefile CHANGED
@@ -12,6 +12,13 @@ ROOT_PATH = File.dirname(__FILE__)
12
12
  # files to ignore changes in
13
13
  IGNORE_CHANGES = %w[.gitignore .gitmodules .DS_Store .gemspec VERSION.yml ^pkg ^tmp ^coverage]
14
14
 
15
+ # Get the DISTRIBUTION info
16
+ require 'yaml'
17
+ DIST = YAML.load File.read(File.expand_path(File.join(ROOT_PATH, 'DISTRIBUTION.yml')))
18
+
19
+ # Make empty to not use sudo
20
+ SUDO = 'sudo'
21
+
15
22
  ################################################
16
23
  ## LOAD DEPENDENCIES
17
24
  ##
@@ -19,6 +26,7 @@ begin
19
26
  require 'rubygems'
20
27
  require 'jeweler'
21
28
  require 'extlib'
29
+ require 'fileutils'
22
30
  require 'spec/rake/spectask'
23
31
 
24
32
  $:.unshift(ROOT_PATH / 'lib')
@@ -26,6 +34,7 @@ begin
26
34
 
27
35
  rescue LoadError => e
28
36
  $stderr.puts "WARN: some required gems are not installed (try rake init to setup)"
37
+ $stderr.puts e
29
38
  end
30
39
 
31
40
 
@@ -45,7 +54,11 @@ Jeweler::Tasks.new do |gemspec|
45
54
  gemspec.add_dependency 'extlib', ">= 0.9.9"
46
55
  gemspec.add_dependency 'erubis', ">= 2.6.2"
47
56
  gemspec.add_dependency 'thor', '>= 0.11.7'
48
- gemspec.add_development_dependency 'jeweler', ">= 1.0.1"
57
+
58
+ gemspec.add_development_dependency 'gemcutter', ">= 0.1.0"
59
+ gemspec.add_development_dependency 'jeweler', ">= 1.0.0"
60
+ gemspec.add_development_dependency 'rspec', ">= 1.2.0"
61
+
49
62
  gemspec.rubyforge_project = "sproutcore"
50
63
  gemspec.extra_rdoc_files.include *%w[History.txt README.txt]
51
64
 
@@ -59,17 +72,109 @@ Jeweler::RubyforgeTasks.new do |rubyforge|
59
72
  rubyforge.doc_task = "rdoc"
60
73
  end
61
74
 
75
+ Jeweler::GemcutterTasks.new
76
+
77
+
78
+ def git(path, cmd, log=true)
79
+ $stdout.puts("#{path.sub(ROOT_PATH, '')}: git #{cmd}") if log
80
+ git_path = path / '.git'
81
+ git_index = git_path / 'index'
82
+
83
+ # The env can become polluted; breaking git. This will avoid that.
84
+ %x[GIT_DIR=#{git_path}; GIT_WORK_TREE=#{path}; GIT_INDEX_FILE=#{git_index}; git #{cmd}]
85
+ end
86
+
62
87
  ################################################
63
88
  ## CORE TASKS
64
89
  ##
65
90
 
66
- desc "performs an initial setup on the tools. Installs gems, init submodules"
67
- task :init do
91
+ desc "performs an initial setup on the tools. Installs gems, checkout"
92
+ task :init => [:install_gems, 'dist:init', 'dist:update']
93
+
94
+ task :install_gems do
68
95
  $stdout.puts "Installing gems (may ask for password)"
69
- `sudo gem install rack jeweler json_pure extlib erubis thor`
96
+ system %[#{SUDO} gem install rack json json_pure extlib erubis thor]
97
+ system %[#{SUDO} gem install jeweler gemcutter rspec] # dev req
98
+ end
99
+
100
+ namespace :dist do
101
+
102
+ desc "checkout any frameworks in the distribution"
103
+ task :init do
104
+ $stdout.puts "Setup distribution"
105
+
106
+ DIST.each do |rel_path, opts|
107
+ path = ROOT_PATH / rel_path
108
+ repo_url = opts['repo']
109
+
110
+ if !File.exists?(path / ".git")
111
+ $stdout.puts " Creating repo for #{rel_path}"
112
+ FileUtils.mkdir_p File.dirname(path)
113
+
114
+ $stdout.puts "\n> git clone #{repo_url} #{path}"
115
+ system %[git clone #{repo_url} #{path}]
116
+
117
+ else
118
+ $stdout.puts "Found #{rel_path}"
119
+ end
120
+ end
121
+ end
122
+
123
+ desc "make the version of each distribution item match the one in VERSION"
124
+ task :update => 'dist:init' do
125
+ $stdout.puts "Setup distribution"
126
+
127
+ # Use this to get the commit hash
128
+ version_file = ROOT_PATH / 'VERSION.yml'
129
+ if File.exist?(version_file)
130
+ versions = YAML.load File.read(version_file)
131
+ versions = (versions['dist'] || versions[:dist]) if versions
132
+ versions ||= {}
133
+ end
134
+
135
+ DIST.each do |rel_path, opts|
136
+ path = ROOT_PATH / rel_path
137
+
138
+ if File.exists?(path / ".git") && versions[rel_path]
139
+ sha = versions[rel_path]
140
+
141
+ $stdout.puts "\n> git fetch"
142
+ $stdout.puts git(path, 'fetch')
143
+
144
+ $stdout.puts "\n> git checkout #{sha}"
145
+ $stdout.puts git(path, 'checkout #{sha}')
146
+ else
147
+ $stdout.puts "WARN: cannot fix version for #{rel_path}"
148
+ end
149
+
150
+ end
151
+ end
152
+
153
+ end
154
+
155
+ namespace :release do
70
156
 
71
- $stdout.puts "Setup submodules"
72
- `git submodule update --init`
157
+ desc "tags the current repository and any distribution repositories. if you can push to distribution, then push tag as well"
158
+ task :tag => :update_version do
159
+ tag_name = "REL-#{RELEASE_VERSION}"
160
+ DIST.keys.push('abbot').each do |rel_path|
161
+ full_path = rel_path=='abbot' ? ROOT_PATH : (ROOT_PATH / rel_path)
162
+ git(full_path, "tag -f #{tag_name}")
163
+ end
164
+ end
165
+
166
+ desc "prepare release. verify clean, update version, tag"
167
+ task :prepare => ['git:verify_clean', :update_version, :tag]
168
+
169
+ desc "release to rubyforge for old skool folks"
170
+ task :rubyforge => [:prepare, 'rubyforge:release']
171
+
172
+ desc "release to gemcutter for new skool kids"
173
+ task :gemcutter => [:prepare, 'gemcutter:release']
174
+
175
+ desc "one release to rule them all"
176
+ task :all => [:prepare, 'release:rubyforge', 'release:gemcutter']
177
+
73
178
  end
74
179
 
75
180
  desc "computes the current hash of the code. used to autodetect build changes"
@@ -107,7 +212,7 @@ task :hash_content do
107
212
  paths.each do |path|
108
213
  mtime = File.mtime(path)
109
214
  mtime = mtime.nil? ? 0 : mtime.to_i
110
- puts "detected file change: #{path.gsub(ROOT_PATH,'')}" if mtime > hash_date
215
+ $stdout.puts "detected file change: #{path.gsub(ROOT_PATH,'')}" if mtime > hash_date
111
216
  cur_date = mtime if mtime > cur_date
112
217
  end
113
218
 
@@ -127,7 +232,7 @@ task :hash_content do
127
232
 
128
233
  # finally set the hash
129
234
  CONTENT_HASH = hash_digest
130
- puts "CONTENT_HASH = #{CONTENT_HASH}"
235
+ $stdout.puts "CONTENT_HASH = #{CONTENT_HASH}"
131
236
  end
132
237
 
133
238
  desc "updates the VERSION file, bumbing the build rev if the current commit has changed"
@@ -142,6 +247,7 @@ task :update_version => 'hash_content' do
142
247
  minor = 0
143
248
  build = 99
144
249
  rev = '-0-'
250
+ dist = {}
145
251
 
146
252
  if File.exist?(path)
147
253
  yaml = YAML.load_file(path)
@@ -154,12 +260,35 @@ task :update_version => 'hash_content' do
154
260
  build += 1 if rev != CONTENT_HASH #increment if needed
155
261
  rev = CONTENT_HASH
156
262
 
157
- puts "write version #{[major, minor, build].join('.')} => #{path}"
263
+ # Update distribution versions
264
+ DIST.each do |rel_path, ignored|
265
+ dist_path = ROOT_PATH / rel_path
266
+ if File.exists?(dist_path)
267
+ dist_rev = git(dist_path, "log HEAD^..HEAD")
268
+ dist_rev = dist_rev.split("\n").first.scan(/commit ([^\s]+)/)
269
+ dist_rev = ((dist_rev || []).first || []).first
270
+
271
+ if dist_rev.nil?
272
+ $stdout.puts " WARN: cannot find revision for #{rel_path}"
273
+ else
274
+ dist[rel_path] = dist_rev
275
+ end
276
+ end
277
+ end
278
+
279
+ $stdout.puts "write version #{[major, minor, build].join('.')} => #{path}"
158
280
  File.open(path, 'w+') do |f|
159
281
  YAML.dump({
160
- :major => major, :minor => minor, :patch => build, :digest => rev
282
+ :major => major,
283
+ :minor => minor,
284
+ :patch => build,
285
+ :digest => rev,
286
+ :dist => dist
161
287
  }, f)
162
288
  end
289
+
290
+ RELEASE_VERSION = "#{major}.#{minor}.#{build}"
291
+
163
292
  end
164
293
 
165
294
  def fixup_gemspec
@@ -177,8 +306,6 @@ task :build => 'gemspec:generate' do
177
306
  fixup_gemspec
178
307
  end
179
308
 
180
- #task "gemspec:generate" => 'git:verify_clean'
181
-
182
309
  # Extend gemspec to rename afterware
183
310
  task :gemspec do
184
311
  fixup_gemspec
@@ -195,19 +322,19 @@ namespace :git do
195
322
 
196
323
  desc "verifies there are no pending changes to commit to git"
197
324
  task :verify_clean do
198
- %w(abbot frameworks/sproutcore lib/thor).each do |repo_name|
199
- if repo_name == 'abbot'
200
- path = ROOT_PATH
201
- else
202
- path = File.join(repo_name.split('/').unshift(ROOT_PATH))
203
- end
325
+ DIST.keys.push('abbot').each do |repo_name|
326
+ full_path = repo_name=='abbot' ? ROOT_PATH : (ROOT_PATH / repo_name)
327
+
328
+ result = git(full_path, 'status')
204
329
 
205
- result = `cd #{path}; git status`
206
330
  if !(result =~ /nothing to commit \(working directory clean\)/)
207
- $stderr.puts "\nFATAL: Cannot complete task: changes are still pending in the '#{repo_name}' repository."
208
- $stderr.puts " Commit your changes to git to continue.\n\n"
209
- exit(1)
210
- end
331
+ if (repo_name != 'abbot') ||
332
+ (!(result =~ /#\n#\tmodified: VERSION.yml\n#\n/))
333
+ $stderr.puts "\nFATAL: Cannot complete task: changes are still pending in the '#{repo_name}' repository."
334
+ $stderr.puts " Commit your changes to git to continue.\n\n"
335
+ exit(1)
336
+ end
337
+ end
211
338
  end
212
339
  end
213
340
 
@@ -1,5 +1,7 @@
1
1
  ---
2
+ :patch: 1024
3
+ :digest: 94d8bc0e1216dc80ea2be5478115b759e1617e1a
2
4
  :major: 1
5
+ :dist:
6
+ frameworks/sproutcore: f9f7fe42cbb165a4021eeb616c6990914b83079d
3
7
  :minor: 0
4
- :patch: 1009
5
- :digest: 88cb568a49aec110427db79f1e1249ca840b2a66
@@ -20,7 +20,7 @@ config :all,
20
20
  # off in your project buildfile by referencing sproutcore specifically
21
21
  mode :debug do
22
22
  config :all,
23
- :combine_javascript => false,
23
+ :combine_javascript => true,
24
24
  :combine_stylesheet => true
25
25
  end
26
26
 
@@ -40,6 +40,7 @@ SC.setupBodyClassNames = function() {
40
40
  if(borderRad) classNames.push('border-rad');
41
41
  classNames.push(browser) ;
42
42
  classNames.push(platform) ;
43
+ if (SC.browser.msie==7) classNames.push('ie7') ;
43
44
  if (SC.browser.mobileSafari) classNames.push('mobile-safari') ;
44
45
  el.className = classNames.join(' ') ;
45
46
  } ;
@@ -76,7 +76,18 @@ SC.Record = SC.Object.extend(
76
76
  }.property('storeKey').cacheable(),
77
77
 
78
78
  /**
79
- The record's status changes as it is loaded from the server.
79
+ All records generally have a life cycle as they are created or loaded into
80
+ memory, modified, committed and finally destroyed. This life cycle is
81
+ managed by the status property on your record.
82
+
83
+ The status of a record is modelled as a finite state machine. Based on the
84
+ current state of the record, you can determine which operations are
85
+ currently allowed on the record and which are not.
86
+
87
+ In general, a record can be in one of five primary states; SC.Record.EMPTY,
88
+ SC.Record.BUSY, SC.Record.READY, SC.Record.DESTROYED, SC.Record.ERROR.
89
+ These are all described in more detail in the class mixin (below) where
90
+ they are defined.
80
91
 
81
92
  @property {Number}
82
93
  */
@@ -293,6 +304,7 @@ SC.Record = SC.Object.extend(
293
304
  storeKey = this.storeKey,
294
305
  status = store.peekStatus(storeKey),
295
306
  recordAttr = this[key],
307
+ recordType = SC.Store.recordTypeFor(storeKey),
296
308
  attrs;
297
309
 
298
310
  attrs = store.readEditableDataHash(storeKey);
@@ -310,10 +322,59 @@ SC.Record = SC.Object.extend(
310
322
  SC.Store.idsByStoreKey[storeKey] = attrs[key] ;
311
323
  this.propertyDidChange('id'); // Reset computed value
312
324
  }
313
-
325
+
326
+ // if any aggregates, propagate the state
327
+ if(!recordType.aggregates || recordType.aggregates.length>0) {
328
+ this.propagateToAggregates();
329
+ }
330
+
314
331
  return this ;
315
332
  },
316
333
 
334
+ /**
335
+ This will also ensure that any aggregate records are also marked dirty
336
+ if this record changes.
337
+
338
+ Should not have to be called manually.
339
+ */
340
+ propagateToAggregates: function() {
341
+ var storeKey = this.get('storeKey'),
342
+ recordType = SC.Store.recordTypeFor(storeKey),
343
+ idx, len, key, val, recs;
344
+
345
+ var aggregates = recordType.aggregates;
346
+
347
+ // if recordType aggregates are not set up yet, make sure to
348
+ // create the cache first
349
+ if(!aggregates) {
350
+ var dataHash = this.get('store').readDataHash(storeKey),
351
+ aggregates = [];
352
+ for(k in dataHash) {
353
+ if(this[k] && this[k].get && this[k].get('aggregate')===YES) {
354
+ aggregates.push(k);
355
+ }
356
+ }
357
+ recordType.aggregates = aggregates;
358
+ }
359
+
360
+ // now loop through all aggregate properties and mark their related
361
+ // record objects as dirty
362
+ for(idx=0,len=aggregates.length;idx<len;idx++) {
363
+ key = aggregates[idx];
364
+ val = this.get(key);
365
+
366
+ recs = SC.kindOf(val, SC.ManyArray) ? val : [val];
367
+ recs.forEach(function(rec) {
368
+ // write the dirty status
369
+ if(rec) {
370
+ rec.get('store').writeStatus(rec.get('storeKey'), this.get('status'));
371
+ rec.storeDidChangeProperties(YES);
372
+ }
373
+ }, this);
374
+ }
375
+
376
+ },
377
+
317
378
  /**
318
379
  Called by the store whenever the underlying data hash has changed. This
319
380
  will notify any observers interested in data hash properties that they
@@ -380,7 +441,9 @@ SC.Record = SC.Object.extend(
380
441
 
381
442
  if (!isRecord) {
382
443
  attrValue = this.get(key);
383
- if(attrValue!==undefined || attrValue!==null) dataHash[key] = attrValue;
444
+ if(attrValue!==undefined || (attrValue===null && includeNull)) {
445
+ dataHash[key] = attrValue;
446
+ }
384
447
  }
385
448
  else if(isRecord) {
386
449
  recHash = store.readDataHash(storeKey);
@@ -403,8 +466,6 @@ SC.Record = SC.Object.extend(
403
466
  }
404
467
  }
405
468
  }
406
-
407
- if (includeNull && dataHash[key]===undefined) dataHash[key] = null;
408
469
  }
409
470
  }
410
471
 
@@ -103,6 +103,20 @@ SC.RecordAttribute = SC.Object.extend(
103
103
  */
104
104
  useIsoDate: YES,
105
105
 
106
+ /**
107
+ Can only be used for toOne or toMany relationship attributes. If YES,
108
+ this flag will ensure that any related objects will also be marked
109
+ dirty when this record dirtied.
110
+
111
+ Useful when you might have multiple related objects that you want to
112
+ consider in an 'aggregated' state. For instance, by changing a child
113
+ object (image) you might also want to automatically mark the parent
114
+ (album) dirty as well.
115
+
116
+ @property {Boolean}
117
+ */
118
+ aggregate: NO,
119
+
106
120
  // ..........................................................
107
121
  // HELPER PROPERTIES
108
122
  //
@@ -15,6 +15,9 @@ module("SC.RecordAttribute core methods", {
15
15
  store: SC.Store.create()
16
16
  });
17
17
 
18
+ // stick it to the window object so that objectForPropertyPath works
19
+ window.MyApp = MyApp;
20
+
18
21
  MyApp.Foo = SC.Record.extend({
19
22
 
20
23
  // test simple reading of a pass-through prop
@@ -57,7 +60,10 @@ module("SC.RecordAttribute core methods", {
57
60
 
58
61
  });
59
62
 
60
- MyApp.Bar = SC.Record.extend({});
63
+ MyApp.Bar = SC.Record.extend({
64
+ parent: SC.Record.toOne('MyApp.Foo', { aggregate: YES }),
65
+ relatedMany: SC.Record.toMany('MyApp.Foo', { aggregate: YES })
66
+ });
61
67
 
62
68
  SC.RunLoop.begin();
63
69
  storeKeys = MyApp.store.loadRecords(MyApp.Foo, [
@@ -75,6 +81,7 @@ module("SC.RecordAttribute core methods", {
75
81
  firstName: "Jane",
76
82
  lastName: "Doe",
77
83
  relatedTo: 'foo1',
84
+ relatedToAggregate: 'bar1',
78
85
  anArray: 'notAnArray',
79
86
  anObject: 'notAnObject',
80
87
  nonIsoDate: "2009/06/10 8:55:50 +0000"
@@ -92,7 +99,7 @@ module("SC.RecordAttribute core methods", {
92
99
  ]);
93
100
 
94
101
  MyApp.store.loadRecords(MyApp.Bar, [
95
- { guid: 'bar1', city: "Chicago" }
102
+ { guid: 'bar1', city: "Chicago", parent: 'foo2', relatedMany: ['foo1', 'foo2'] }
96
103
  ]);
97
104
 
98
105
  SC.RunLoop.end();
@@ -165,7 +172,6 @@ test("writing pass-through should simply set value", function() {
165
172
  });
166
173
 
167
174
  test("writing a value should override default value", function() {
168
-
169
175
  equals(rec.get('defaultValue'), 'default', 'precond - returns default');
170
176
  rec.set('defaultValue', 'not-default');
171
177
  equals(rec.get('defaultValue'), 'not-default', 'newly written value should replace default value');
@@ -176,3 +182,22 @@ test("writing a date should generate an ISO date" ,function() {
176
182
  equals(rec.set('date', date), rec, 'returns reciever');
177
183
  equals(rec.readAttribute('date'), '2009-04-01T22:28:03-07:00', 'should have new time (%@)'.fmt(date.toString()));
178
184
  });
185
+
186
+ test("writing an attribute should make relationship aggregate dirty" ,function() {
187
+ equals(bar.get('status'), SC.Record.READY_CLEAN, "precond - bar should be READY_CLEAN");
188
+ equals(rec2.get('status'), SC.Record.READY_CLEAN, "precond - rec2 should be READY_CLEAN");
189
+
190
+ bar.set('city', 'Oslo');
191
+
192
+ equals(rec2.get('status'), SC.Record.READY_DIRTY, "foo2 should be READY_DIRTY");
193
+ });
194
+
195
+ test("writing an attribute should make many relationship aggregate dirty" ,function() {
196
+ equals(bar.get('status'), SC.Record.READY_CLEAN, "precond - bar should be READY_CLEAN");
197
+ equals(rec2.get('status'), SC.Record.READY_CLEAN, "precond - rec2 should be READY_CLEAN");
198
+
199
+ bar.set('city', 'Oslo');
200
+
201
+ equals(rec.get('status'), SC.Record.READY_DIRTY, "foo1 should be READY_DIRTY");
202
+ equals(rec2.get('status'), SC.Record.READY_DIRTY, "foo2 should be READY_DIRTY");
203
+ });