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
@@ -29,12 +29,21 @@ SC.CoreView.mixin(
29
29
 
30
30
  /**
31
31
  The view is enabled itself, but is effectively disabled in the pane due to
32
- a disabled parent view.
32
+ a disabled ancestor.
33
33
 
34
34
  @static
35
35
  @constant
36
36
  */
37
- DISABLED_BY_PARENT: 0x12 // 18
37
+ DISABLED_BY_PARENT: 0x12, // 18
38
+
39
+ /**
40
+ The view is disabled itself and is also disabled in the pane due to
41
+ a disabled ancestor.
42
+
43
+ @static
44
+ @constant
45
+ */
46
+ DISABLED_AND_BY_PARENT: 0x13 // 19
38
47
 
39
48
  });
40
49
 
@@ -112,11 +121,16 @@ SC.View.reopen(
112
121
 
113
122
  /** @private */
114
123
  _doEnable: function () {
115
- var handled = true;
124
+ var handled = true,
125
+ enabledState = this.get('enabledState');
116
126
 
117
- if (this.get('enabledState') & SC.CoreView.IS_DISABLED) {
127
+ if (enabledState === SC.CoreView.DISABLED) {
128
+ // If the view itself is disabled, then we can enable it.
118
129
  this._callOnChildViews('_parentDidEnableInPane');
119
130
  this._gotoEnabledState();
131
+ } else if (enabledState === SC.CoreView.DISABLED_AND_BY_PARENT) {
132
+ // The view is no longer disabled itself, but still disabled by an ancestor.
133
+ this._gotoDisabledByParentState();
120
134
  } else {
121
135
  handled = false;
122
136
  }
@@ -126,15 +140,20 @@ SC.View.reopen(
126
140
 
127
141
  /** @private */
128
142
  _doDisable: function () {
129
- var handled = true;
143
+ var handled = true,
144
+ enabledState = this.get('enabledState');
130
145
 
131
- if (this.get('enabledState') !== SC.CoreView.DISABLED) {
146
+ // If the view is not itself disabled, then we can disable it.
147
+ if (enabledState === SC.CoreView.ENABLED) {
132
148
  if (this.get('isFirstResponder')) {
133
149
  this.resignFirstResponder();
134
150
  }
135
151
 
136
152
  this._callOnChildViews('_parentDidDisableInPane');
137
153
  this._gotoDisabledState();
154
+ } else if (enabledState === SC.CoreView.DISABLED_BY_PARENT) {
155
+ // The view is now disabled itself and disabled by an ancestor.
156
+ this._gotoDisabledAndByParentState();
138
157
  } else {
139
158
  handled = false;
140
159
  }
@@ -146,6 +165,14 @@ SC.View.reopen(
146
165
  // Methods
147
166
  //
148
167
 
168
+ /** @private */
169
+ init: function (original) {
170
+ original();
171
+
172
+ // If the view is pre-configured as disabled, then go to the proper initial state.
173
+ if (!this.get('isEnabled')) { this._doDisable(); }
174
+ }.enhance(),
175
+
149
176
  /** @private
150
177
  Observes the isEnabled property and resigns first responder if set to NO.
151
178
  This will avoid cases where, for example, a disabled text field retains
@@ -206,10 +233,18 @@ SC.View.reopen(
206
233
 
207
234
  /** @private */
208
235
  _parentDidEnableInPane: function () {
209
- var isEnabled = this.get('isEnabled');
236
+ var enabledState = this.get('enabledState');
210
237
 
211
- if (isEnabled) {
212
- this._gotoEnabledState();
238
+ if (this.get('shouldInheritEnabled')) {
239
+
240
+ if (enabledState === SC.CoreView.DISABLED_BY_PARENT) { // Was enabled before.
241
+ this._gotoEnabledState();
242
+ } else if (enabledState === SC.CoreView.DISABLED_AND_BY_PARENT) { // Was disabled before.
243
+ this._gotoDisabledState();
244
+
245
+ // There's no need to continue to further child views.
246
+ return false;
247
+ }
213
248
  } else {
214
249
  // There's no need to continue to further child views.
215
250
  return false;
@@ -218,10 +253,19 @@ SC.View.reopen(
218
253
 
219
254
  /** @private */
220
255
  _parentDidDisableInPane: function () {
221
- var isEnabled = this.get('isEnabled');
256
+ var enabledState = this.get('enabledState');
257
+
258
+ if (this.get('shouldInheritEnabled')) {
222
259
 
223
- if (isEnabled && this.get('shouldInheritEnabled')) {
224
- this._gotoDisableByParentState();
260
+ if (enabledState === SC.CoreView.ENABLED) { // Was enabled.
261
+ this._gotoDisabledByParentState();
262
+ } else if (enabledState === SC.CoreView.DISABLED) { // Was disabled.
263
+ this._gotoDisabledAndByParentState();
264
+ } else { // Was already disabled by ancestor.
265
+
266
+ // There's no need to continue to further child views.
267
+ return false;
268
+ }
225
269
  } else {
226
270
  // There's no need to continue to further child views.
227
271
  return false;
@@ -249,7 +293,13 @@ SC.View.reopen(
249
293
  },
250
294
 
251
295
  /** @private */
252
- _gotoDisableByParentState: function () {
296
+ _gotoDisabledAndByParentState: function () {
297
+ // Update the state.
298
+ this.set('enabledState', SC.CoreView.DISABLED_AND_BY_PARENT);
299
+ },
300
+
301
+ /** @private */
302
+ _gotoDisabledByParentState: function () {
253
303
  // Update the state.
254
304
  this.set('enabledState', SC.CoreView.DISABLED_BY_PARENT);
255
305
  }
@@ -42,13 +42,13 @@ SC.Record = SC.Object.extend(
42
42
 
43
43
  //@if(debug)
44
44
  /* BEGIN DEBUG ONLY PROPERTIES AND METHODS */
45
+
45
46
  /** @private
46
47
  Creates string representation of record, with status.
47
48
 
48
49
  @returns {String}
49
50
  */
50
-
51
- toString: function() {
51
+ toString: function () {
52
52
  // We won't use 'readOnlyAttributes' here because accessing them directly
53
53
  // avoids a SC.clone() -- we'll be careful not to edit anything.
54
54
  var attrs = this.get('store').readDataHash(this.get('storeKey'));
@@ -61,7 +61,7 @@ SC.Record = SC.Object.extend(
61
61
  @returns {String}
62
62
  */
63
63
 
64
- statusString: function() {
64
+ statusString: function () {
65
65
  var ret = [], status = this.get('status');
66
66
 
67
67
  for(var prop in SC.Record) {
@@ -59,10 +59,16 @@ SC.SingleAttribute = SC.RecordAttribute.extend(
59
59
  if (newRec !== undefined && this.get('isEditable')) {
60
60
 
61
61
  // can only take other records or null
62
+ //@if(debug)
62
63
  if (newRec && !SC.kindOf(newRec, SC.Record)) {
63
- throw new Error("%@ is not an instance of SC.Record".fmt(newRec));
64
+ throw new Error("Developer Error: %@ is not an instance of SC.Record.".fmt(newRec));
64
65
  }
65
66
 
67
+ if (newRec && SC.none(newRec.get('id'))) {
68
+ throw new Error("Developer Error: Attempted to add a record without a primary key to a to-one relationship. Relationships require that the id always be specified. The record, \"%@\", must be assigned an id (i.e. be saved) before it can be used in the '%@' relationship.".fmt(newRec, attrKey));
69
+ }
70
+ //@endif
71
+
66
72
  inverseKey = this.get('inverse');
67
73
  if (inverseKey) oldRec = this._scsa_call(record, key);
68
74
 
@@ -23,6 +23,20 @@
23
23
  SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
24
24
  /** @scope SC.ManyArray.prototype */ {
25
25
 
26
+ //@if(debug)
27
+ /* BEGIN DEBUG ONLY PROPERTIES AND METHODS */
28
+
29
+ /* @private */
30
+ toString: function () {
31
+ var readOnlyStoreIds = this.get('readOnlyStoreIds'),
32
+ length = this.get('length');
33
+
34
+ return "%@({\n ids: [%@],\n length: %@,\n … })".fmt(this.constructor.toString(), readOnlyStoreIds, length);
35
+ },
36
+
37
+ /* END DEBUG ONLY PROPERTIES AND METHODS */
38
+ //@endif
39
+
26
40
  /**
27
41
  `recordType` will tell what type to transform the record to when
28
42
  materializing the record.
@@ -222,10 +236,11 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
222
236
  records, which can be converted to `storeId`s.
223
237
  */
224
238
  replace: function(idx, amt, recs) {
225
-
239
+ //@if(debug)
226
240
  if (!this.get('isEditable')) {
227
- throw new Error("%@.%@[] is not editable".fmt(this.get('record'), this.get('propertyName')));
241
+ throw new Error("Developer Error: %@.%@[] is not editable.".fmt(this.get('record'), this.get('propertyName')));
228
242
  }
243
+ //@endif
229
244
 
230
245
  var storeIds = this.get('editableStoreIds'),
231
246
  len = recs ? (recs.get ? recs.get('length') : recs.length) : 0,
@@ -235,12 +250,20 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
235
250
 
236
251
  // map to store keys
237
252
  ids = [] ;
238
- for(i=0;i<len;i++) ids[i] = recs.objectAt(i).get('id');
253
+ for(i=0;i<len;i++) {
254
+ //@if(debug)
255
+ if (SC.none(recs.objectAt(i).get('id'))) {
256
+ throw new Error("Developer Error: Attempted to add a record without a primary key to a to-many relationship. Relationships require that the id always be specified. The record, \"%@\", must be assigned an id (i.e. be saved) before it can be used in the '%@' relationship.".fmt(recs.objectAt(i), pname));
257
+ }
258
+ //@endif
259
+
260
+ ids[i] = recs.objectAt(i).get('id');
261
+ }
239
262
 
240
263
  // if we have an inverse - collect the list of records we are about to
241
264
  // remove
242
265
  inverse = this.get('inverse');
243
- if (inverse && amt>0) {
266
+ if (inverse && amt > 0) {
244
267
  toRemove = SC.ManyArray._toRemove;
245
268
  if (toRemove) SC.ManyArray._toRemove = null; // reuse if possible
246
269
  else toRemove = [];
@@ -456,4 +479,4 @@ SC.ManyArray = SC.Object.extend(SC.Enumerable, SC.Array,
456
479
  this.recordPropertyDidChange();
457
480
  }
458
481
 
459
- }) ;
482
+ });
@@ -139,6 +139,21 @@ sc_require('models/record');
139
139
  SC.Query = SC.Object.extend(SC.Copyable, SC.Freezable,
140
140
  /** @scope SC.Query.prototype */ {
141
141
 
142
+ //@if(debug)
143
+ /* BEGIN DEBUG ONLY PROPERTIES AND METHODS */
144
+
145
+ /* @private */
146
+ toString: function () {
147
+ var conditions = this.get('conditions'),
148
+ location = this.get('location'),
149
+ parameters = this.get('parameters');
150
+
151
+ return "%@.%@({ conditions: '%@', parameters: %@, … })".fmt(this.constructor.toString(), location, conditions, SC.inspect(parameters));
152
+ },
153
+
154
+ /* END DEBUG ONLY PROPERTIES AND METHODS */
155
+ //@endif
156
+
142
157
  // ..........................................................
143
158
  // PROPERTIES
144
159
  //
@@ -56,6 +56,35 @@ sc_require('models/record');
56
56
  SC.RecordArray = SC.Object.extend(SC.Enumerable, SC.Array,
57
57
  /** @scope SC.RecordArray.prototype */ {
58
58
 
59
+ //@if(debug)
60
+ /* BEGIN DEBUG ONLY PROPERTIES AND METHODS */
61
+
62
+ /* @private */
63
+ toString: function () {
64
+ var statusString = this.statusString(),
65
+ storeKeys = this.get('storeKeys'),
66
+ query = this.get('query'),
67
+ length = this.get('length');
68
+
69
+ return "%@({\n query: %@,\n storeKeys: [%@],\n length: %@,\n … }) %@".fmt(this.constructor.toString(), query, storeKeys, length, statusString);
70
+ },
71
+
72
+ /** @private */
73
+ statusString: function() {
74
+ var ret = [], status = this.get('status');
75
+
76
+ for (var prop in SC.Record) {
77
+ if (prop.match(/[A-Z_]$/) && SC.Record[prop] === status) {
78
+ ret.push(prop);
79
+ }
80
+ }
81
+
82
+ return ret.join(" ");
83
+ },
84
+
85
+ /* END DEBUG ONLY PROPERTIES AND METHODS */
86
+ //@endif
87
+
59
88
  /**
60
89
  The store that owns this record array. All record arrays must have a
61
90
  store to function properly.
@@ -676,9 +705,7 @@ SC.RecordArray = SC.Object.extend(SC.Enumerable, SC.Array,
676
705
  _storeKeysDidChange: function() {
677
706
  var storeKeys = this.get('storeKeys');
678
707
 
679
- var prev = this._prevStoreKeys, oldLen, newLen,
680
- f = this._storeKeysContentDidChange,
681
- fs = this._storeKeysStateDidChange;
708
+ var prev = this._prevStoreKeys, oldLen, newLen;
682
709
 
683
710
  if (storeKeys === prev) { return; } // nothing to do
684
711
 
@@ -1057,7 +1057,11 @@ SC.Store = SC.Object.extend( /** @scope SC.Store.prototype */ {
1057
1057
  @returns {SC.Record} Returns a record instance.
1058
1058
  */
1059
1059
  materializeRecord: function (storeKey) {
1060
- var records = this.records, ret, recordType, attrs;
1060
+ var records = this.records,
1061
+ //@if(debug)
1062
+ updatingRecords = this.updatingRecords,
1063
+ //@endif
1064
+ ret, recordType, attrs;
1061
1065
 
1062
1066
  // look up in cached records
1063
1067
  if (!records) records = this.records = {}; // load cached records
@@ -1071,8 +1075,26 @@ SC.Store = SC.Object.extend( /** @scope SC.Store.prototype */ {
1071
1075
  attrs = this._TMP_REC_ATTRS ;
1072
1076
  attrs.storeKey = storeKey ;
1073
1077
  attrs.store = this ;
1078
+
1079
+ //@if(debug)
1080
+ // Add some developer support to prevent a tough to diagnose bug that if
1081
+ // materializeRecord is called during the creation of a record, the store
1082
+ // will inadvertently create a duplicate record instance not because the
1083
+ // actual instance won't have been cached to this.records yet.
1084
+ if (!this.updatingRecords) { updatingRecords = this.updatingRecords = {}; }
1085
+ if (updatingRecords[storeKey]) {
1086
+ throw new Error("Developer Error: The record of type, %@, with storeKey, %@, was materialized a second time before the first call had finished. This will result in two separate instances of the same object being created and should be fixed. A likely cause is using `.observes` code in the record class, which can cause the record to be retrieved somehow while it is still being created.".fmt(recordType, storeKey));
1087
+ }
1088
+
1089
+ updatingRecords[storeKey] = storeKey;
1090
+ //@endif
1091
+
1074
1092
  ret = records[storeKey] = recordType.create(attrs);
1075
1093
 
1094
+ //@if(debug)
1095
+ updatingRecords[storeKey] = null;
1096
+ //@endif
1097
+
1076
1098
  return ret ;
1077
1099
  },
1078
1100