sproutcore 1.10.1 → 1.10.2

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 (58) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG +13 -0
  3. data/VERSION.yml +1 -1
  4. data/lib/frameworks/sproutcore/CHANGELOG.md +69 -31
  5. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +14 -0
  6. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/object.js +14 -0
  7. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +7 -2
  8. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +13 -9
  9. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +57 -23
  10. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/enabled_states_test.js +24 -6
  11. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +2 -2
  12. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/enabled.js +63 -13
  13. data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +3 -3
  14. data/lib/frameworks/sproutcore/frameworks/datastore/models/single_attribute.js +7 -1
  15. data/lib/frameworks/sproutcore/frameworks/datastore/system/many_array.js +28 -5
  16. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +15 -0
  17. data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +30 -3
  18. data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +23 -1
  19. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/many_attribute.js +135 -89
  20. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/single_attribute.js +12 -0
  21. data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +18 -6
  22. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/ui.js +58 -20
  23. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/date_field/methods.js +1 -1
  24. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select/methods.js +15 -1
  25. data/lib/frameworks/sproutcore/frameworks/desktop/views/button.js +1 -1
  26. data/lib/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +10 -0
  27. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +1 -1
  28. data/lib/frameworks/sproutcore/frameworks/desktop/views/select.js +24 -23
  29. data/lib/frameworks/sproutcore/frameworks/desktop/views/split.js +4 -0
  30. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/views/popup_button.js +10 -0
  31. data/lib/frameworks/sproutcore/frameworks/foundation/delegates/inline_text_field.js +4 -4
  32. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_mixin.js +33 -16
  33. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/content_value_support.js +14 -6
  34. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/control.js +23 -18
  35. data/lib/frameworks/sproutcore/frameworks/foundation/system/user_defaults.js +4 -4
  36. data/lib/frameworks/sproutcore/frameworks/foundation/tests/delegates/inline_text_field/inline_text_field.js +1 -0
  37. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_mixin_tests.js +78 -0
  38. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_resize_test.js +45 -1
  39. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/content_value_support/content.js +112 -58
  40. data/lib/frameworks/sproutcore/frameworks/foundation/tests/system/image_queue.js +2 -2
  41. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/container/transition_test.js +141 -0
  42. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/methods.js +27 -2
  43. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/ui.js +631 -593
  44. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/swap_fade_color_transition.js +5 -0
  45. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/swap_move_in_transition.js +5 -0
  46. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/swap_reveal_transition.js +68 -1
  47. data/lib/frameworks/sproutcore/frameworks/foundation/views/container.js +128 -49
  48. data/lib/frameworks/sproutcore/frameworks/foundation/views/field.js +33 -8
  49. data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +209 -187
  50. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
  51. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +7 -0
  52. data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +34 -4
  53. data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +0 -2
  54. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +68 -9
  55. data/lib/frameworks/sproutcore/frameworks/testing/system/runner.js +2 -1
  56. data/lib/sproutcore/rack/builder.rb +45 -25
  57. data/sproutcore.gemspec +1 -0
  58. metadata +17 -2
@@ -59,7 +59,7 @@ window.SproutCore = window.SproutCore || SC;
59
59
  */
60
60
  SC = window.SC; // This is dumb but necessary for jsdoc to get it right
61
61
 
62
- SC.VERSION = '1.10.1';
62
+ SC.VERSION = '1.10.2';
63
63
 
64
64
  /**
65
65
  @private
@@ -680,7 +680,7 @@ SC.mixin(/** @scope window.SC.prototype */ {
680
680
  if (SC.typeOf(v) === SC.T_FUNCTION) v = "function () { ... }";
681
681
  ret.push(key + ": " + v);
682
682
  }
683
- return "{" + ret.join(" , ") + "}";
683
+ return "{ " + ret.join(", ") + " }";
684
684
  },
685
685
 
686
686
  /**
@@ -1280,6 +1280,13 @@ SC.Observable = /** @scope SC.Observable.prototype */{
1280
1280
  bind: function (toKey, target, method) {
1281
1281
  var binding, pathType;
1282
1282
 
1283
+ //@if(debug)
1284
+ // Developer support.
1285
+ if (!target) {
1286
+ throw new Error("Developer Error: Attempt to bind key `%@` to null or undefined target".fmt(toKey));
1287
+ }
1288
+ //@endif
1289
+
1283
1290
  // normalize...
1284
1291
  if (method !== undefined) target = [target, method];
1285
1292
 
@@ -471,6 +471,9 @@ SC.Binding = /** @scope SC.Binding.prototype */{
471
471
  // Mark it destroyed.
472
472
  this.isDestroyed = YES;
473
473
 
474
+ // Destroy the logic gate, if any. (See and & or methods.)
475
+ if (this._logicGate) this._logicGate.destroy();
476
+
474
477
  // Disconnect the binding.
475
478
  this.disconnect();
476
479
 
@@ -770,6 +773,10 @@ SC.Binding = /** @scope SC.Binding.prototype */{
770
773
  if (tuple) {
771
774
  this._toTarget = tuple[0];
772
775
  this._toPropertyKey = tuple[1];
776
+ // Hook up _logicGate if needed (see and & or methods).
777
+ if (this._logicGate) {
778
+ this._logicGate.set('localObject', this._toTarget);
779
+ }
773
780
  }
774
781
  }
775
782
  },
@@ -989,10 +996,20 @@ SC.Binding = /** @scope SC.Binding.prototype */{
989
996
  */
990
997
  and: function (pathA, pathB) {
991
998
 
999
+ // If either path is local, append the localObject path to it.
1000
+ if (pathA.indexOf('*') === 0 || pathA.indexOf('.') === 0) {
1001
+ pathA = '*localObject.' + pathA.slice(1);
1002
+ }
1003
+ if (pathB.indexOf('*') === 0 || pathB.indexOf('.') === 0) {
1004
+ pathB = '*localObject.' + pathB.slice(1);
1005
+ }
1006
+
992
1007
  // create an object to do the logical computation
993
1008
  var gate = SC.Object.create({
994
- valueABinding: pathA,
995
- valueBBinding: pathB,
1009
+ localObject: null,
1010
+
1011
+ valueABinding: SC.Binding.oneWay(pathA),
1012
+ valueBBinding: SC.Binding.oneWay(pathB),
996
1013
 
997
1014
  and: function () {
998
1015
  return (this.get('valueA') && this.get('valueB'));
@@ -1000,7 +1017,9 @@ SC.Binding = /** @scope SC.Binding.prototype */{
1000
1017
  });
1001
1018
 
1002
1019
  // add a transform that depends on the result of that computation.
1003
- return this.from('and', gate).oneWay();
1020
+ var ret = this.from('and', gate).oneWay();
1021
+ ret._logicGate = gate;
1022
+ return ret;
1004
1023
  },
1005
1024
 
1006
1025
  /**
@@ -1014,9 +1033,18 @@ SC.Binding = /** @scope SC.Binding.prototype */{
1014
1033
  @param {String} pathB The second part of the conditional
1015
1034
  */
1016
1035
  or: function (pathA, pathB) {
1036
+ // If either path is local, append the localObject path to it.
1037
+ if (pathA.indexOf('*') === 0 || pathA.indexOf('.') === 0) {
1038
+ pathA = '*localObject.' + pathA.slice(1);
1039
+ }
1040
+ if (pathB.indexOf('*') === 0 || pathB.indexOf('.') === 0) {
1041
+ pathB = '*localObject.' + pathB.slice(1);
1042
+ }
1017
1043
 
1018
1044
  // create an object to the logical computation
1019
1045
  var gate = SC.Object.create({
1046
+ localObject: null,
1047
+
1020
1048
  valueABinding: pathA,
1021
1049
  valueBBinding: pathB,
1022
1050
 
@@ -1025,7 +1053,9 @@ SC.Binding = /** @scope SC.Binding.prototype */{
1025
1053
  }.property('valueA', 'valueB').cacheable()
1026
1054
  });
1027
1055
 
1028
- return this.from('or', gate).oneWay();
1056
+ var ret = this.from('or', gate).oneWay();
1057
+ ret._logicGate = gate;
1058
+ return ret;
1029
1059
  },
1030
1060
 
1031
1061
  /**
@@ -623,8 +623,6 @@ SC.Object.prototype = {
623
623
 
624
624
  Although the default init() method returns the receiver, the return
625
625
  value is ignored.
626
-
627
-
628
626
  */
629
627
  init: function () {
630
628
  this.initObservable();
@@ -376,7 +376,11 @@ module("AND binding", {
376
376
 
377
377
  toObject = SC.Object.create({
378
378
  value: null,
379
- valueBinding: SC.Binding.and('SC.testControllerA.value', 'SC.testControllerB.value')
379
+ valueBinding: SC.Binding.and('SC.testControllerA.value', 'SC.testControllerB.value'),
380
+ localValue1: NO,
381
+ localValue2: NO,
382
+ boundLocalValue: NO,
383
+ boundLocalValueBinding: SC.Binding.and('.localValue1', '.localValue2')
380
384
  });
381
385
  },
382
386
 
@@ -387,14 +391,22 @@ module("AND binding", {
387
391
 
388
392
  });
389
393
 
390
- test("toObject.value should be YES if both sources are YES", function () {
394
+ test("bound value should be YES if both sources are YES", function () {
391
395
  SC.RunLoop.begin();
392
396
  SC.testControllerA.set('value', YES);
393
397
  SC.testControllerB.set('value', YES);
394
398
  SC.RunLoop.end();
395
399
 
396
400
  SC.Binding.flushPendingChanges();
397
- equals(toObject.get('value'), YES);
401
+ equals(toObject.get('value'), YES, 'Bound value');
402
+
403
+ SC.RunLoop.begin();
404
+ toObject.set('localValue1', YES);
405
+ toObject.set('localValue2', YES);
406
+ SC.RunLoop.end();
407
+
408
+ SC.Binding.flushPendingChanges();
409
+ equals(toObject.get('boundLocalValue'), YES, 'Local bound value');
398
410
  });
399
411
 
400
412
  test("toObject.value should be NO if either source is NO", function () {
@@ -404,7 +416,7 @@ test("toObject.value should be NO if either source is NO", function () {
404
416
  SC.RunLoop.end();
405
417
 
406
418
  SC.Binding.flushPendingChanges();
407
- equals(toObject.get('value'), NO);
419
+ equals(toObject.get('value'), NO, 'Bound value on YES/NO');
408
420
 
409
421
  SC.RunLoop.begin();
410
422
  SC.testControllerA.set('value', YES);
@@ -412,7 +424,7 @@ test("toObject.value should be NO if either source is NO", function () {
412
424
  SC.RunLoop.end();
413
425
 
414
426
  SC.Binding.flushPendingChanges();
415
- equals(toObject.get('value'), YES);
427
+ equals(toObject.get('value'), YES, 'Bound value on YES/YES');
416
428
 
417
429
  SC.RunLoop.begin();
418
430
  SC.testControllerA.set('value', NO);
@@ -420,9 +432,34 @@ test("toObject.value should be NO if either source is NO", function () {
420
432
  SC.RunLoop.end();
421
433
 
422
434
  SC.Binding.flushPendingChanges();
423
- equals(toObject.get('value'), NO);
435
+ equals(toObject.get('value'), NO, 'Bound value on NO/YES');
436
+
437
+ SC.RunLoop.begin();
438
+ toObject.set('localValue1', YES);
439
+ toObject.set('localValue2', NO);
440
+ SC.RunLoop.end();
441
+
442
+ SC.Binding.flushPendingChanges();
443
+ equals(toObject.get('boundLocalValue'), NO, 'Local bound value on YES/NO');
444
+
445
+ SC.RunLoop.begin();
446
+ toObject.set('localValue1', YES);
447
+ toObject.set('localValue2', YES);
448
+ SC.RunLoop.end();
449
+
450
+ SC.Binding.flushPendingChanges();
451
+ equals(toObject.get('boundLocalValue'), YES, 'Local bound value on YES/YES');
452
+
453
+ SC.RunLoop.begin();
454
+ toObject.set('localValue1', NO);
455
+ toObject.set('localValue2', YES);
456
+ SC.RunLoop.end();
457
+
458
+ SC.Binding.flushPendingChanges();
459
+ equals(toObject.get('boundLocalValue'), NO, 'Local bound value on NO/YES');
424
460
  });
425
461
 
462
+
426
463
  module("OR binding", {
427
464
 
428
465
  setup: function () {
@@ -433,7 +470,11 @@ module("OR binding", {
433
470
 
434
471
  toObject = SC.Object.create({
435
472
  value: null,
436
- valueBinding: SC.Binding.or('SC.testControllerA.value', 'SC.testControllerB.value')
473
+ valueBinding: SC.Binding.or('SC.testControllerA.value', 'SC.testControllerB.value'),
474
+ localValue1: NO,
475
+ localValue2: NO,
476
+ boundLocalValue: NO,
477
+ boundLocalValueBinding: SC.Binding.or('.localValue1', '.localValue2')
437
478
  });
438
479
  },
439
480
 
@@ -451,7 +492,16 @@ test("toObject.value should be first value if first value is truthy", function (
451
492
  SC.RunLoop.end();
452
493
 
453
494
  SC.Binding.flushPendingChanges();
454
- equals(toObject.get('value'), 'first value');
495
+ equals(toObject.get('value'), 'first value', 'Bound value on truthy first value');
496
+
497
+ SC.RunLoop.begin();
498
+ toObject.set('localValue1', 'first value');
499
+ toObject.set('localValue2', 'second value');
500
+ SC.RunLoop.end();
501
+
502
+ SC.Binding.flushPendingChanges();
503
+ equals(toObject.get('boundLocalValue'), 'first value', 'Locally bound value on truthy first value');
504
+
455
505
  });
456
506
 
457
507
  test("toObject.value should be second value if first is falsy", function () {
@@ -461,7 +511,16 @@ test("toObject.value should be second value if first is falsy", function () {
461
511
  SC.RunLoop.end();
462
512
 
463
513
  SC.Binding.flushPendingChanges();
464
- equals(toObject.get('value'), 'second value');
514
+ equals(toObject.get('value'), 'second value', 'Bound value on falsy first value');
515
+
516
+ SC.RunLoop.begin();
517
+ toObject.set('localValue1', NO);
518
+ toObject.set('localValue2', 'second value');
519
+ SC.RunLoop.end();
520
+
521
+ SC.Binding.flushPendingChanges();
522
+ equals(toObject.get('boundLocalValue'), 'second value', 'Locally bound value on falsy first value');
523
+
465
524
  });
466
525
 
467
526
  module("Binding with '[]'", {
@@ -166,7 +166,8 @@ CoreTest.Runner = {
166
166
  // of the various events. (It is handy when looking at failed tests.)
167
167
  if (SC && SC.Event && SC.Event.unload) {
168
168
  try {
169
- SC.Event.unload();
169
+ var responder = SC.RootResponder.responder;
170
+ SC.Event.remove(document, 'selectstart', responder, responder.selectstart);
170
171
  }
171
172
  catch (e) {}
172
173
  }
@@ -216,38 +216,58 @@ module SC
216
216
  @project_file_count = files.size
217
217
  @project_mtime = files.map { |x| File.mtime(x).to_i }.max
218
218
 
219
- Thread.new do
220
- while @should_monitor
221
-
222
- # only need to start scanning again 2 seconds after the last
223
- # request was serviced.
224
- reload_delay = (Time.now - @last_reload_time)
225
- if reload_delay > 2
226
- files = Dir.glob(@project_root / '**' / '*')
227
- # follow 1-level of symlinks
228
- files += Dir.glob(@project_root / '**' / '*' / '**' / '*')
229
- tmp_path = /^#{Regexp.escape(@project_root / 'tmp')}/
230
- files.reject! { |f| f =~ tmp_path }
231
- files.reject! { |f| File.directory?(f) }
232
-
233
- cur_file_count = files.size
234
- cur_mtime = files.map { |x| File.mtime(x).to_i }.max
235
-
236
- if (@project_file_count != cur_file_count) || (@project_mtime != cur_mtime)
237
- SC.logger.info "Detected project change. Will rebuild manifest"
238
- @project_did_change = true
239
- @project_file_count = cur_file_count
240
- @project_mtime = cur_mtime
241
- end
219
+ begin
220
+ require 'listen'
221
+ @listener = Listen.to(@project_root, ignore: tmp_path) do |modified, added, removed|
222
+ SC.logger.info "Detected project change. Will rebuild manifest."
223
+ @project_did_change = true
224
+ end
225
+ @listener.start
226
+ rescue LoadError => e
227
+ puts $:.inspect
228
+ puts e.message
229
+ SC.logger.warn "The 'listen' gem was not found in your gem repository. Falling back to polling for filesystem changes, which is much more CPU intensive. You should run 'gem install listen' to fix this."
230
+ Thread.new do
231
+ while @should_monitor
232
+ check_for_updates
233
+
234
+ # Add a slight delay.
235
+ sleep 2
242
236
  end
243
-
244
- sleep(2)
245
237
  end
246
238
  end
247
239
  end
248
240
  end
249
241
 
242
+ def check_for_updates
243
+ # only need to start scanning again 2 seconds after the last
244
+ # request was serviced.
245
+ reload_delay = (Time.now - @last_reload_time)
246
+ if reload_delay > 2
247
+ files = Dir.glob(@project_root / '**' / '*')
248
+ # follow 1-level of symlinks
249
+ files += Dir.glob(@project_root / '**' / '*' / '**' / '*')
250
+ tmp_path = /^#{Regexp.escape(@project_root / 'tmp')}/
251
+ files.reject! { |f| f =~ tmp_path }
252
+ files.reject! { |f| File.directory?(f) }
253
+
254
+ cur_file_count = files.size
255
+ cur_mtime = files.map { |x| File.mtime(x).to_i }.max
256
+
257
+ if (@project_file_count != cur_file_count) || (@project_mtime != cur_mtime)
258
+ SC.logger.info "Detected project change. Will rebuild manifest"
259
+ @project_did_change = true
260
+ @project_file_count = cur_file_count
261
+ @project_mtime = cur_mtime
262
+ end
263
+ end
264
+ end
265
+
250
266
  def stop_monitor!
267
+ if @listener
268
+ @listener.stop
269
+ @listener = nil
270
+ end
251
271
  @should_monitor = false
252
272
  end
253
273
 
data/sproutcore.gemspec CHANGED
@@ -36,6 +36,7 @@ Gem::Specification.new do |s|
36
36
  s.add_dependency 'mongrel', '~> 1.1'
37
37
  else
38
38
  s.add_dependency 'thin', '~> 1.2'
39
+ s.add_dependency 'listen', '~> 2.0'
39
40
  end
40
41
 
41
42
  s.add_development_dependency 'gemcutter', "~> 0.6"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sproutcore
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.1
4
+ version: 1.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Strobe, Inc., Apple Inc. and contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-28 00:00:00.000000000 Z
11
+ date: 2013-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -192,6 +192,20 @@ dependencies:
192
192
  - - ~>
193
193
  - !ruby/object:Gem::Version
194
194
  version: '1.2'
195
+ - !ruby/object:Gem::Dependency
196
+ name: listen
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ~>
200
+ - !ruby/object:Gem::Version
201
+ version: '2.0'
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ~>
207
+ - !ruby/object:Gem::Version
208
+ version: '2.0'
195
209
  - !ruby/object:Gem::Dependency
196
210
  name: gemcutter
197
211
  requirement: !ruby/object:Gem::Requirement
@@ -1845,6 +1859,7 @@ files:
1845
1859
  - lib/frameworks/sproutcore/frameworks/foundation/tests/debug/control_test_pane/ui.js
1846
1860
  - lib/frameworks/sproutcore/frameworks/foundation/tests/delegates/inline_text_field/inline_text_field.js
1847
1861
  - lib/frameworks/sproutcore/frameworks/foundation/tests/integration/creating_views.js
1862
+ - lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_mixin_tests.js
1848
1863
  - lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_resize_test.js
1849
1864
  - lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/content_display.js
1850
1865
  - lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/content_value_support/content.js