sproutcore 1.10.2 → 1.10.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG +11 -0
  3. data/VERSION.yml +1 -1
  4. data/lib/frameworks/sproutcore/CHANGELOG.md +34 -0
  5. data/lib/frameworks/sproutcore/frameworks/core_foundation/child_view_layouts/horizontal_stack_layout.js +3 -1
  6. data/lib/frameworks/sproutcore/frameworks/core_foundation/child_view_layouts/vertical_stack_layout.js +3 -1
  7. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +79 -80
  8. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +115 -22
  9. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +54 -17
  10. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/statechart.js +76 -34
  11. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select/methods.js +18 -5
  12. data/lib/frameworks/sproutcore/frameworks/desktop/views/grid.js +14 -5
  13. data/lib/frameworks/sproutcore/frameworks/desktop/views/select.js +42 -18
  14. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/editable.js +41 -41
  15. data/lib/frameworks/sproutcore/frameworks/foundation/tests/transitions/view_transitions_test.js +235 -0
  16. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/bounce_transition.js +8 -4
  17. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/fade_transition.js +6 -2
  18. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/pop_transition.js +8 -4
  19. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/scale_transition.js +6 -2
  20. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/slide_transition.js +6 -2
  21. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/spring_transition.js +8 -4
  22. data/lib/frameworks/sproutcore/frameworks/foundation/views/inline_text_field.js +5 -4
  23. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +1 -1
  24. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +2 -2
  25. data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +124 -80
  26. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +134 -0
  27. data/lib/sproutcore.rb +1 -1
  28. data/lib/sproutcore/models/manifest.rb +12 -6
  29. data/lib/sproutcore/rack/builder.rb +20 -12
  30. data/lib/sproutcore/tools.rb +3 -3
  31. data/lib/sproutcore/tools/build.rb +22 -22
  32. data/sproutcore.gemspec +2 -5
  33. data/vendor/sproutcore/lib/yuicompressor-2.4.8.jar +0 -0
  34. metadata +10 -23
  35. data/vendor/sproutcore/lib/yuicompressor-2.4.6.jar +0 -0
@@ -105,8 +105,10 @@ SC.mixin(SC.View,
105
105
  { value: value, duration: duration, timing: 'ease-in-out' }
106
106
  ];
107
107
 
108
- var callback = function () {
109
- view.didTransitionIn();
108
+ var callback = function (data) {
109
+ if (!data.isCancelled) {
110
+ view.didTransitionIn();
111
+ }
110
112
  };
111
113
 
112
114
  // Animate through the frames.
@@ -198,8 +200,10 @@ SC.mixin(SC.View,
198
200
  { value: finalValue, duration: duration, timing: 'ease-in' }
199
201
  ];
200
202
 
201
- var callback = function () {
202
- view.didTransitionOut();
203
+ var callback = function (data) {
204
+ if (!data.isCancelled) {
205
+ view.didTransitionOut();
206
+ }
203
207
  };
204
208
 
205
209
  // Animate through the frames.
@@ -28,7 +28,9 @@ SC.mixin(SC.View,
28
28
  duration: options.duration || 0.4,
29
29
  timing: options.timing || 'ease'
30
30
  }, function (data) {
31
- this.didTransitionIn();
31
+ if (!data.isCancelled) {
32
+ this.didTransitionIn();
33
+ }
32
34
  });
33
35
  }
34
36
  },
@@ -48,7 +50,9 @@ SC.mixin(SC.View,
48
50
  duration: options.duration || 0.4,
49
51
  timing: options.timing || 'ease'
50
52
  }, function (data) {
51
- this.didTransitionOut();
53
+ if (!data.isCancelled) {
54
+ this.didTransitionOut();
55
+ }
52
56
  });
53
57
  }
54
58
 
@@ -37,8 +37,10 @@ SC.mixin(SC.View,
37
37
  { value: { scale: scale }, duration: duration * 0.4, timing: 'ease-in-out' }
38
38
  ];
39
39
 
40
- var callback = function () {
41
- view.didTransitionIn();
40
+ var callback = function (data) {
41
+ if (!data.isCancelled) {
42
+ view.didTransitionIn();
43
+ }
42
44
  };
43
45
 
44
46
  // Animate through the frames.
@@ -71,8 +73,10 @@ SC.mixin(SC.View,
71
73
  { value: { scale: 0 }, duration: duration * 0.6, timing: 'ease-in-out' }
72
74
  ];
73
75
 
74
- var callback = function () {
75
- view.didTransitionOut();
76
+ var callback = function (data) {
77
+ if (!data.isCancelled) {
78
+ view.didTransitionOut();
79
+ }
76
80
  };
77
81
 
78
82
  // Animate through the frames.
@@ -27,7 +27,9 @@ SC.mixin(SC.View,
27
27
  duration: options.duration || 0.4,
28
28
  timing: options.timing || 'ease'
29
29
  }, function (data) {
30
- this.didTransitionIn();
30
+ if (!data.isCancelled) {
31
+ this.didTransitionIn();
32
+ }
31
33
  });
32
34
  }
33
35
  },
@@ -46,7 +48,9 @@ SC.mixin(SC.View,
46
48
  duration: options.duration || 0.4,
47
49
  timing: options.timing || 'ease'
48
50
  }, function (data) {
49
- this.didTransitionOut();
51
+ if (!data.isCancelled) {
52
+ this.didTransitionOut();
53
+ }
50
54
  });
51
55
  }
52
56
 
@@ -71,7 +71,9 @@ SC.mixin(SC.View,
71
71
  duration: options.duration || 0.4,
72
72
  timing: options.timing || 'ease'
73
73
  }, function (data) {
74
- this.didTransitionIn();
74
+ if (!data.isCancelled) {
75
+ this.didTransitionIn();
76
+ }
75
77
  });
76
78
  }
77
79
  },
@@ -132,7 +134,9 @@ SC.mixin(SC.View,
132
134
  duration: options.duration || 0.4,
133
135
  timing: options.timing || 'ease'
134
136
  }, function (data) {
135
- this.didTransitionOut();
137
+ if (!data.isCancelled) {
138
+ this.didTransitionOut();
139
+ }
136
140
  });
137
141
  }
138
142
  }
@@ -108,8 +108,10 @@ SC.mixin(SC.View,
108
108
  { value: value, duration: duration, timing: 'ease-in-out' } // Hit target.
109
109
  ];
110
110
 
111
- var callback = function () {
112
- view.didTransitionIn();
111
+ var callback = function (data) {
112
+ if (!data.isCancelled) {
113
+ view.didTransitionIn();
114
+ }
113
115
  };
114
116
 
115
117
  // Animate through the frames.
@@ -192,8 +194,10 @@ SC.mixin(SC.View,
192
194
  { value: finalValue, duration: duration, timing: 'ease-in' }
193
195
  ];
194
196
 
195
- var callback = function () {
196
- view.didTransitionOut();
197
+ var callback = function (data) {
198
+ if (!data.isCancelled) {
199
+ view.didTransitionOut();
200
+ }
197
201
  };
198
202
 
199
203
  // Animate through the frames.
@@ -335,8 +335,11 @@ SC.InlineTextFieldView = SC.TextFieldView.extend(SC.InlineEditor,
335
335
  */
336
336
  // TODO: this seems to do almost the same thing as fieldDidBlur
337
337
  blurEditor: function(evt) {
338
- if (!this.get('isEditing')) return YES ;
339
- return this.commitOnBlur ? this.commitEditing() : this.discardEditing();
338
+ if (this.get('isEditing')) {
339
+ return this.commitOnBlur ? this.commitEditing() : this.discardEditing();
340
+ } else {
341
+ return true;
342
+ }
340
343
  },
341
344
 
342
345
  /**
@@ -436,7 +439,6 @@ SC.InlineTextFieldView = SC.TextFieldView.extend(SC.InlineEditor,
436
439
  insertTab: function(evt) {
437
440
  var target = this.target; // removed by commitEditing()
438
441
  this.resignFirstResponder();
439
- this.commitEditing() ;
440
442
  if(target){
441
443
  var next = target.get('nextValidKeyView');
442
444
  if(next && next.beginEditing) next.beginEditing();
@@ -448,7 +450,6 @@ SC.InlineTextFieldView = SC.TextFieldView.extend(SC.InlineEditor,
448
450
  insertBacktab: function(evt) {
449
451
  var target = this.target; // removed by commitEditing()
450
452
  this.resignFirstResponder();
451
- this.commitEditing() ;
452
453
  if(target){
453
454
  var prev = target.get('previousValidKeyView');
454
455
  if(prev && prev.beginEditing) prev.beginEditing();
@@ -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.2';
62
+ SC.VERSION = '1.10.3';
63
63
 
64
64
  /**
65
65
  @private
@@ -1179,7 +1179,7 @@ SC.Observable = /** @scope SC.Observable.prototype */{
1179
1179
  // observer during that round of notification. Similarly, if you're
1180
1180
  // added as an observer during the notification round by another
1181
1181
  // observer, you will not be notified until the next time.)
1182
- members = SC.clone(observers.getMembers());
1182
+ members = observers.getMembers();
1183
1183
  membersLength = members.length;
1184
1184
  for (memberLoc = 0; memberLoc < membersLength; memberLoc++) {
1185
1185
  member = members[memberLoc];
@@ -1224,7 +1224,7 @@ SC.Observable = /** @scope SC.Observable.prototype */{
1224
1224
  if (starObservers && key !== '*') {
1225
1225
  // We clone the structure per the justification, above, for regular
1226
1226
  // observers.
1227
- members = SC.clone(starObservers.getMembers());
1227
+ members = starObservers.getMembers();
1228
1228
  membersLength = members.length;
1229
1229
  for (memberLoc = 0; memberLoc < membersLength; memberLoc++) {
1230
1230
  member = members[memberLoc];
@@ -267,6 +267,12 @@ SC.Binding = /** @scope SC.Binding.prototype */{
267
267
  beget: function (fromPath) {
268
268
  var ret = SC.beget(this);
269
269
  ret.parentBinding = this;
270
+ // Logic gates must be recreated on beget.
271
+ if (ret._LogicGate) {
272
+ ret._logicGate = ret._LogicGate.create(ret._logicGateHash);
273
+ ret = ret.from('logicProperty', ret._logicGate).oneWay();
274
+ }
275
+ // Enables duplicate API calls for SC.Binding.beget and SC.Binding.from
270
276
  if (fromPath !== undefined) ret = ret.from(fromPath);
271
277
  return ret;
272
278
  },
@@ -471,8 +477,13 @@ SC.Binding = /** @scope SC.Binding.prototype */{
471
477
  // Mark it destroyed.
472
478
  this.isDestroyed = YES;
473
479
 
474
- // Destroy the logic gate, if any. (See and & or methods.)
475
- if (this._logicGate) this._logicGate.destroy();
480
+ // Clean up the logic gate, if any. (See logic gate methods.)
481
+ if (this._logicGate) {
482
+ this._logicGate.destroy();
483
+ this._logicGate = null;
484
+ this._LogicGate = null;
485
+ this._logicGateHash = null;
486
+ }
476
487
 
477
488
  // Disconnect the binding.
478
489
  this.disconnect();
@@ -494,6 +505,20 @@ SC.Binding = /** @scope SC.Binding.prototype */{
494
505
  fromPropertyDidChange: function (target, key) {
495
506
  var v = target ? target.get(key) : null;
496
507
 
508
+ // In rare circumstances, getting a property can result in observers firing,
509
+ // which may in turn run code that disconnects the binding. The cause of
510
+ // this pattern has been difficult to determine and so until a concrete test
511
+ // scenario and a lower level fix can be found, show a warning and ignore
512
+ // the update.
513
+ if (!this.isConnected) {
514
+ //@if(debug)
515
+ SC.Logger.warn("Developer Warning: A binding attempted to update after it was disconnected. The update will be ignored for binding: %@".fmt(this._fromPropertyPath, this._fromTarget, this));
516
+ //@endif
517
+
518
+ // Break early.
519
+ return;
520
+ }
521
+
497
522
  // if the new value is different from the current binding value, then
498
523
  // schedule to register an update.
499
524
  if (v !== this._bindingValue || key === '[]') {
@@ -523,6 +548,20 @@ SC.Binding = /** @scope SC.Binding.prototype */{
523
548
 
524
549
  var v = target.get(key);
525
550
 
551
+ // In rare circumstances, getting a property can result in observers firing,
552
+ // which may in turn run code that disconnects the binding. The cause of
553
+ // this pattern has been difficult to determine and so until a concrete test
554
+ // scenario and a lower level fix can be found, show a warning and ignore
555
+ // the update.
556
+ if (!this.isConnected) {
557
+ //@if(debug)
558
+ SC.Logger.warn("Developer Warning: A binding attempted to update after it was disconnected. The update will be ignored for binding: %@".fmt(this));
559
+ //@endif
560
+
561
+ // Break early.
562
+ return;
563
+ }
564
+
526
565
  // if the new value is different from the current binding value, then
527
566
  // schedule to register an update.
528
567
  if (v !== this._transformedBindingValue) {
@@ -773,7 +812,7 @@ SC.Binding = /** @scope SC.Binding.prototype */{
773
812
  if (tuple) {
774
813
  this._toTarget = tuple[0];
775
814
  this._toPropertyKey = tuple[1];
776
- // Hook up _logicGate if needed (see and & or methods).
815
+ // Hook up _logicGate if needed (see logic gate methods).
777
816
  if (this._logicGate) {
778
817
  this._logicGate.set('localObject', this._toTarget);
779
818
  }
@@ -978,112 +1017,117 @@ SC.Binding = /** @scope SC.Binding.prototype */{
978
1017
  },
979
1018
 
980
1019
  /**
981
- Adds a transform that forwards the logical 'AND' of values at 'pathA' and
982
- 'pathB' whenever either source changes. Note that the transform acts strictly
983
- as a one-way binding, working only in the direction
984
-
985
- 'pathA' AND 'pathB' --> value (value returned is the result of ('pathA' && 'pathB'))
1020
+ Adds a transform to convert the value to the inverse of a bool value. This
1021
+ uses the same transform as bool() but inverts it.
986
1022
 
987
- Usage example where a delete button's 'isEnabled' value is determined by whether
988
- something is selected in a list and whether the current user is allowed to delete:
1023
+ @param {String} [fromPath]
1024
+ @returns {SC.Binding} this
1025
+ */
1026
+ not: function (fromPath) {
1027
+ return this.from(fromPath).transform(function (v) {
1028
+ var t = SC.typeOf(v);
1029
+ if (t === SC.T_ERROR) return v;
1030
+ return !((t == SC.T_ARRAY) ? (v.length > 0) : (v === '') ? NO : !!v);
1031
+ });
1032
+ },
989
1033
 
990
- deleteButton: SC.ButtonView.design({
991
- isEnabledBinding: SC.Binding.and('MyApp.itemsController.hasSelection', 'MyApp.userController.canDelete')
992
- })
1034
+ /**
1035
+ Adds a transform that will return YES if the value is null or undefined, NO otherwise.
993
1036
 
994
- @param {String} pathA The first part of the conditional
995
- @param {String} pathB The second part of the conditional
1037
+ @param {String} [fromPath]
1038
+ @returns {SC.Binding} this
996
1039
  */
997
- and: function (pathA, pathB) {
1040
+ isNull: function (fromPath) {
1041
+ return this.from(fromPath).transform(function (v) {
1042
+ var t = SC.typeOf(v);
1043
+ return (t === SC.T_ERROR) ? v : SC.none(v);
1044
+ });
1045
+ },
998
1046
 
999
- // If either path is local, append the localObject path to it.
1047
+ /* @private Used with the logic gate bindings. */
1048
+ _LogicGateAnd: SC.Object.extend({
1049
+ logicProperty: function() {
1050
+ return (this.get('valueA') && this.get('valueB'));
1051
+ }.property('valueA', 'valueB').cacheable()
1052
+ }),
1053
+ /* @private Used with the logic gate bindings. */
1054
+ _LogicGateOr: SC.Object.extend({
1055
+ logicProperty: function() {
1056
+ return (this.get('valueA') || this.get('valueB'));
1057
+ }.property('valueA', 'valueB').cacheable()
1058
+ }),
1059
+ /* @private Used by logic gate bindings. */
1060
+ _logicGateBinding: function (gateClass, pathA, pathB) {
1061
+ // If either path is local, remove any * chains and append the localObject path to it.
1000
1062
  if (pathA.indexOf('*') === 0 || pathA.indexOf('.') === 0) {
1001
- pathA = '*localObject.' + pathA.slice(1);
1063
+ pathA = pathA.slice(1).replace(/\*/g, '.');
1064
+ pathA = '*localObject.' + pathA;
1002
1065
  }
1003
1066
  if (pathB.indexOf('*') === 0 || pathB.indexOf('.') === 0) {
1004
- pathB = '*localObject.' + pathB.slice(1);
1067
+ pathB = pathB.slice(1).replace(/\*/g, '.');
1068
+ pathB = '*localObject.' + pathB;
1005
1069
  }
1006
1070
 
1007
- // create an object to do the logical computation
1008
- var gate = SC.Object.create({
1009
- localObject: null,
1010
-
1011
- valueABinding: SC.Binding.oneWay(pathA),
1012
- valueBBinding: SC.Binding.oneWay(pathB),
1013
-
1014
- and: function () {
1015
- return (this.get('valueA') && this.get('valueB'));
1016
- }.property('valueA', 'valueB').cacheable()
1017
- });
1018
-
1019
- // add a transform that depends on the result of that computation.
1020
- var ret = this.from('and', gate).oneWay();
1071
+ // Gets the gate class and instantiates a nice copy.
1072
+ var gateHash = {
1073
+ localObject: null,
1074
+ valueABinding: SC.Binding.oneWay(pathA),
1075
+ valueBBinding: SC.Binding.oneWay(pathB)
1076
+ },
1077
+ gate = gateClass.create(gateHash);
1078
+
1079
+ // Creates and populates the return binding.
1080
+ var ret = this.from('logicProperty', gate).oneWay();
1081
+ // This is all needed later on by beget, which must create a new logic gate instance
1082
+ // or risk bad behavior.
1083
+ ret._LogicGate = gateClass;
1084
+ ret._logicGateHash = gateHash;
1021
1085
  ret._logicGate = gate;
1086
+
1087
+ // On our way.
1022
1088
  return ret;
1023
1089
  },
1024
1090
 
1025
1091
  /**
1026
- Adds a transform that forwards the 'OR' of values at 'pathA' and
1092
+ Adds a transform that forwards the logical 'AND' of values at 'pathA' and
1027
1093
  'pathB' whenever either source changes. Note that the transform acts strictly
1028
1094
  as a one-way binding, working only in the direction
1029
1095
 
1030
- 'pathA' AND 'pathB' --> value (value returned is the result of ('pathA' || 'pathB'))
1096
+ 'pathA' AND 'pathB' --> value (value returned is the result of ('pathA' && 'pathB'))
1097
+
1098
+ Usage example where a delete button's 'isEnabled' value is determined by whether
1099
+ something is selected in a list and whether the current user is allowed to delete:
1100
+
1101
+ deleteButton: SC.ButtonView.design({
1102
+ isEnabledBinding: SC.Binding.and('MyApp.itemsController.hasSelection', 'MyApp.userController.canDelete')
1103
+ })
1031
1104
 
1032
1105
  @param {String} pathA The first part of the conditional
1033
1106
  @param {String} pathB The second part of the conditional
1034
1107
  */
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
- }
1043
-
1044
- // create an object to the logical computation
1045
- var gate = SC.Object.create({
1046
- localObject: null,
1047
-
1048
- valueABinding: pathA,
1049
- valueBBinding: pathB,
1050
-
1051
- or: function () {
1052
- return (this.get('valueA') || this.get('valueB'));
1053
- }.property('valueA', 'valueB').cacheable()
1054
- });
1055
-
1056
- var ret = this.from('or', gate).oneWay();
1057
- ret._logicGate = gate;
1058
- return ret;
1108
+ and: function (pathA, pathB) {
1109
+ return this._logicGateBinding(this._LogicGateAnd, pathA, pathB);
1059
1110
  },
1060
1111
 
1061
1112
  /**
1062
- Adds a transform to convert the value to the inverse of a bool value. This
1063
- uses the same transform as bool() but inverts it.
1113
+ Adds a transform that forwards the 'OR' of values at 'pathA' and
1114
+ 'pathB' whenever either source changes. Note that the transform acts strictly
1115
+ as a one-way binding, working only in the direction
1064
1116
 
1065
- @param {String} [fromPath]
1066
- @returns {SC.Binding} this
1067
- */
1068
- not: function (fromPath) {
1069
- return this.from(fromPath).transform(function (v) {
1070
- var t = SC.typeOf(v);
1071
- if (t === SC.T_ERROR) return v;
1072
- return !((t == SC.T_ARRAY) ? (v.length > 0) : (v === '') ? NO : !!v);
1073
- });
1074
- },
1117
+ 'pathA' OR 'pathB' --> value (value returned is the result of ('pathA' || 'pathB'))
1075
1118
 
1076
- /**
1077
- Adds a transform that will return YES if the value is null or undefined, NO otherwise.
1119
+ Usage example where a delete button's 'isEnabled' value is determined by if the
1120
+ content is editable, or if the user has admin rights:
1078
1121
 
1079
- @param {String} [fromPath]
1080
- @returns {SC.Binding} this
1122
+ deleteButton: SC.ButtonView.design({
1123
+ isEnabledBinding: SC.Binding.or('*content.isEditable', 'MyApp.userController.isAdmin')
1124
+ })
1125
+
1126
+ @param {String} pathA The first part of the conditional
1127
+ @param {String} pathB The second part of the conditional
1081
1128
  */
1082
- isNull: function (fromPath) {
1083
- return this.from(fromPath).transform(function (v) {
1084
- var t = SC.typeOf(v);
1085
- return (t === SC.T_ERROR) ? v : SC.none(v);
1086
- });
1129
+ or: function (pathA, pathB) {
1130
+ return this._logicGateBinding(this._LogicGateOr, pathA, pathB);
1087
1131
  },
1088
1132
 
1089
1133
  toString: function () {