sproutcore 1.0.1009 → 1.0.1024

Sign up to get free protection for your applications and to get access to all the features.
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
+ });