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
@@ -4,9 +4,9 @@
4
4
  // portions copyright @2011 Apple Inc.
5
5
  // License: Licensed under MIT license (see license.js)
6
6
  // ==========================================================================
7
+ /*global module, test, ok, equals, stop, start */
7
8
 
8
- /*global module test htmlbody ok equals same stop start */
9
- (function() {
9
+ (function () {
10
10
  var pane = SC.ControlTestPane.design()
11
11
  .add("empty", SC.TextFieldView, {
12
12
  hint: "Full Name",
@@ -85,631 +85,669 @@
85
85
  isEditable: NO
86
86
  });
87
87
 
88
- // ..........................................................
89
- // VERIFY STANDARD STATES
90
- //
91
- pane.verifyEmpty = function verifyEmpty(view, expectedHint) {
92
- var input = view.$('input');
93
- var layer = view.$();
94
-
95
- ok(!layer.hasClass('not-empty'), 'layer should not have not-empty class');
96
- if(SC.browser.isWebkit || (SC.browser.isMozilla &&
97
- SC.browser.compare(SC.browser.engineVersion, '2.0') >= 0)) equals(input.val(), '', 'input should have empty value');
98
- else equals(input.val(), expectedHint, 'input should have expected hint as value');
99
- if (expectedHint) {
100
- var hint = view.$('.hint');
101
- if (hint.length===1) {
102
- hint = hint.text();
103
- } else {
104
- hint = view.$('input');
105
- hint = hint.attr('placeholder');
106
- }
107
- equals(hint, expectedHint, 'hint span should have expected hint'); }
88
+ // ..........................................................
89
+ // VERIFY STANDARD STATES
90
+ //
91
+ pane.verifyEmpty = function verifyEmpty(view, expectedHint) {
92
+ var input = view.$('input');
93
+ var layer = view.$();
94
+
95
+ ok(!layer.hasClass('not-empty'), 'layer should not have not-empty class');
96
+ if (SC.browser.isWebkit || (SC.browser.isMozilla &&
97
+ SC.browser.compare(SC.browser.engineVersion, '2.0') >= 0)) equals(input.val(), '', 'input should have empty value');
98
+ else equals(input.val(), expectedHint, 'input should have expected hint as value');
99
+ if (expectedHint) {
100
+ var hint = view.$('.hint');
101
+ if (hint.length === 1) {
102
+ hint = hint.text();
103
+ } else {
104
+ hint = view.$('input');
105
+ hint = hint.attr('placeholder');
106
+ }
107
+ equals(hint, expectedHint, 'hint span should have expected hint');
108
+ }
108
109
 
109
- };
110
+ };
110
111
 
111
- pane.verifyNotEmpty = function verifyNotEmpty(view, expectedValue, expectedHint) {
112
- var input = view.$('input');
113
- var layer = view.$();
112
+ pane.verifyNotEmpty = function verifyNotEmpty(view, expectedValue, expectedHint) {
113
+ var input = view.$('input');
114
+ var layer = view.$();
114
115
 
115
- ok(layer.hasClass('not-empty'), 'layer should have not-empty class');
116
- equals(input.val(), expectedValue, 'input should have value');
116
+ ok(layer.hasClass('not-empty'), 'layer should have not-empty class');
117
+ equals(input.val(), expectedValue, 'input should have value');
117
118
 
118
- if (expectedHint) {
119
- var hint = view.$('.hint');
120
- if (hint.length===1) {
121
- hint = hint.text();
122
- } else {
123
- hint = view.$('input');
124
- hint = hint.attr('placeholder');
125
- }
126
- equals(hint, expectedHint, 'hint span should have expected hint'); }
119
+ if (expectedHint) {
120
+ var hint = view.$('.hint');
121
+ if (hint.length === 1) {
122
+ hint = hint.text();
123
+ } else {
124
+ hint = view.$('input');
125
+ hint = hint.attr('placeholder');
126
+ }
127
+ equals(hint, expectedHint, 'hint span should have expected hint');
128
+ }
127
129
 
128
- };
130
+ };
129
131
 
130
- pane.verifyDisabled = function verifyDisabled(view, isDisabled) {
131
- var layer = view.$();
132
- var input = view.$('input');
132
+ pane.verifyDisabled = function verifyDisabled(view, isDisabled) {
133
+ var layer = view.$();
134
+ var input = view.$('input');
133
135
 
134
- if (isDisabled) {
135
- ok(layer.hasClass('disabled'), 'layer should have disabled class');
136
- ok(input.attr('disabled'), 'input should have disabled attr');
137
- } else {
138
- ok(!layer.hasClass('disabled'), 'layer should not have disabled class');
139
- ok(!input.attr('disabled'), 'input should not have disabled attr');
140
- }
141
- };
136
+ if (isDisabled) {
137
+ ok(layer.hasClass('disabled'), 'layer should have disabled class');
138
+ ok(input.attr('disabled'), 'input should have disabled attr');
139
+ } else {
140
+ ok(!layer.hasClass('disabled'), 'layer should not have disabled class');
141
+ ok(!input.attr('disabled'), 'input should not have disabled attr');
142
+ }
143
+ };
142
144
 
143
- pane.verifyReadOnly = function verifyReadonly(view, isReadOnly) {
144
- var input = view.$('input');
145
+ pane.verifyReadOnly = function verifyReadonly(view, isReadOnly) {
146
+ var input = view.$('input');
145
147
 
146
- if(isReadOnly) {
147
- ok(input.attr('readOnly'), 'input should have readOnly attr');
148
- } else {
149
- ok(!input.attr('readOnly'), 'input should not have readOnly attr');
150
- }
151
- };
152
-
153
- // ..........................................................
154
- // TEST INITIAL STATES
155
- //
156
-
157
- module('SC.TextFieldView ui', pane.standardSetup());
158
-
159
- test("empty", function() {
160
- var view = pane.view('empty');
161
- pane.verifyEmpty(view, 'Full Name');
162
- pane.verifyDisabled(view, NO);
163
- });
164
-
165
- test("with value", function() {
166
- var view = pane.view('with value');
167
- pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
168
- pane.verifyDisabled(view, NO);
169
- });
170
-
171
- test("password", function() {
172
- var view = pane.view('password');
173
- pane.verifyNotEmpty(view, 'I\'m so secret');
174
- pane.verifyDisabled(view, NO);
175
- });
176
-
177
- test("password with hint", function() {
178
- var view = pane.view('password-hint');
179
- pane.verifyNotEmpty(view, 'I\'m so secret', 'Passwerd');
180
- pane.verifyDisabled(view, NO);
181
- });
182
-
183
- test("disabled - empty", function() {
184
- var view = pane.view('disabled - empty');
185
- pane.verifyEmpty(view, 'Full Name');
186
- pane.verifyDisabled(view, YES);
187
- });
188
-
189
- test("disabled - with value", function() {
190
- var view = pane.view('disabled - with value');
191
- pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
192
- pane.verifyDisabled(view, YES);
193
- });
194
-
195
- test("enabled - not editable - with value", function() {
196
- var view = pane.view('enabled - not editable - with value');
197
- pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
198
- pane.verifyReadOnly(view, YES);
199
- });
200
-
201
- test("textarea - empty", function() {
202
- var view = pane.view('empty');
203
- pane.verifyEmpty(view, 'Full Name');
204
- pane.verifyDisabled(view, NO);
205
- });
206
-
207
- test("textarea - with value", function() {
208
- var view = pane.view('with value');
209
- pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
210
- pane.verifyDisabled(view, NO);
211
- });
212
-
213
- test("textarea - disabled - empty", function() {
214
- var view = pane.view('disabled - empty');
215
- pane.verifyEmpty(view, 'Full Name');
216
- pane.verifyDisabled(view, YES);
217
- });
218
-
219
- test("textarea - disabled - with value", function() {
220
- var view = pane.view('disabled - with value');
221
- pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
222
- pane.verifyDisabled(view, YES);
223
- });
224
-
225
- // ..........................................................
226
- // TEST CHANGING VIEWS
227
- //
228
-
229
- test("changing value from empty -> value", function() {
230
- var view = pane.view('empty');
231
-
232
- // test changing value updates like it should
233
- SC.RunLoop.begin();
234
- view.set('value', 'John Doe');
235
- SC.RunLoop.end();
236
- pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
237
- });
238
-
239
- test("disabling view", function() {
240
- var view = pane.view('empty');
241
-
242
- // test changing enabled state updates like it should
243
- SC.RunLoop.begin();
244
- view.set('isEnabled', NO);
245
- SC.RunLoop.end();
246
- pane.verifyDisabled(view, YES);
247
- });
248
-
249
- test("changing value to null", function() {
250
- var view = pane.view('with value');
251
-
252
- // test changing value updates like it should
253
- SC.RunLoop.begin();
254
- view.set('value', null);
255
- SC.RunLoop.end();
256
- equals(view.get('fieldValue'), null, 'should have empty fieldValue');
257
- pane.verifyEmpty(view, 'Full Name');
258
- });
259
-
260
- test("enabling disabled view", function() {
261
- var view = pane.view('disabled - empty');
262
-
263
- // test changing enabled state updates like it should
264
- SC.RunLoop.begin();
265
- view.set('isEnabled', YES);
266
- SC.RunLoop.end();
267
- pane.verifyDisabled(view, NO);
268
- });
269
-
270
- test("changing isEditable", function() {
271
- var view = pane.view('enabled - not editable - with value');
272
-
273
- // test changing isEditable state updates like it should
274
- SC.RunLoop.begin();
275
- view.set('isEditable', YES);
276
- SC.RunLoop.end();
277
- pane.verifyReadOnly(view, NO);
278
-
279
- // test changing isEditable state updates like it should
280
- SC.RunLoop.begin();
281
- view.set('isEditable', NO);
282
- SC.RunLoop.end();
283
- pane.verifyReadOnly(view, YES);
284
- });
285
-
286
- test("changing value from not a textarea to a textarea", function() {
287
- // test the the SC.Event for 'change' gets wired up properly to the DOM element when it changes from input to textarea
288
- var view = pane.view('empty');
289
- SC.RunLoop.begin();
290
- view.set('value', 'Original');
291
- view.set('isTextArea', YES);
292
- SC.RunLoop.end();
293
-
294
- var $textarea = view.$('textarea');
295
-
296
- SC.Event.trigger($textarea, 'focus');
297
-
298
- // simulate typing a letter
299
- SC.Event.trigger($textarea, 'keydown');
300
- $textarea.val("My New Value");
301
- SC.Event.trigger($textarea, 'keyup');
302
- SC.Event.trigger($textarea, 'change');
303
- view.fieldValueDidChange();
304
-
305
- // wait a little bit to let text field propogate changes
306
- stop();
307
-
308
- setTimeout(function() {
309
- start();
310
- equals(view.get("value"), "My New Value", "SC.Event for change should get wired up properly");
311
- }, 100);
312
-
313
- SC.RunLoop.begin();
314
- SC.RunLoop.end();
315
- });
316
-
317
-
318
- if (!SC.browser.isIE && !SC.platform.input.placeholder) {
319
- test("Changing value to null -- password field", function() {
320
- var view = pane.view('password-hint'),
321
- input = view.$('input');
322
-
323
- SC.run(function() {
148
+ if(isReadOnly) {
149
+ ok(input.attr('readOnly'), 'input should have readOnly attr');
150
+ } else {
151
+ ok(!input.attr('readOnly'), 'input should not have readOnly attr');
152
+ }
153
+ };
154
+
155
+ // ..........................................................
156
+ // TEST INITIAL STATES
157
+ //
158
+
159
+ module('SC.TextFieldView: Initial States', pane.standardSetup());
160
+
161
+ test("empty", function () {
162
+ var view = pane.view('empty');
163
+ pane.verifyEmpty(view, 'Full Name');
164
+ pane.verifyDisabled(view, NO);
165
+ });
166
+
167
+ test("with value", function () {
168
+ var view = pane.view('with value');
169
+ pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
170
+ pane.verifyDisabled(view, NO);
171
+ });
172
+
173
+ test("password", function () {
174
+ var view = pane.view('password');
175
+ pane.verifyNotEmpty(view, 'I\'m so secret');
176
+ pane.verifyDisabled(view, NO);
177
+ });
178
+
179
+ test("password with hint", function () {
180
+ var view = pane.view('password-hint');
181
+ pane.verifyNotEmpty(view, 'I\'m so secret', 'Passwerd');
182
+ pane.verifyDisabled(view, NO);
183
+ });
184
+
185
+ test("disabled - empty", function () {
186
+ var view = pane.view('disabled - empty');
187
+ pane.verifyEmpty(view, 'Full Name');
188
+ pane.verifyDisabled(view, YES);
189
+ });
190
+
191
+ test("disabled - with value", function () {
192
+ var view = pane.view('disabled - with value');
193
+ pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
194
+ pane.verifyDisabled(view, YES);
195
+ });
196
+
197
+ test("enabled - not editable - with value", function () {
198
+ var view = pane.view('enabled - not editable - with value');
199
+ pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
200
+ pane.verifyReadOnly(view, YES);
201
+ });
202
+
203
+ test("textarea - empty", function () {
204
+ var view = pane.view('empty');
205
+ pane.verifyEmpty(view, 'Full Name');
206
+ pane.verifyDisabled(view, NO);
207
+ });
208
+
209
+ test("textarea - with value", function () {
210
+ var view = pane.view('with value');
211
+ pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
212
+ pane.verifyDisabled(view, NO);
213
+ });
214
+
215
+ test("textarea - disabled - empty", function () {
216
+ var view = pane.view('disabled - empty');
217
+ pane.verifyEmpty(view, 'Full Name');
218
+ pane.verifyDisabled(view, YES);
219
+ });
220
+
221
+ test("textarea - disabled - with value", function () {
222
+ var view = pane.view('disabled - with value');
223
+ pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
224
+ pane.verifyDisabled(view, YES);
225
+ });
226
+
227
+ // ..........................................................
228
+ // TEST CHANGING VIEWS
229
+ //
230
+
231
+ module('SC.TextFieldView: Changing Values', pane.standardSetup());
232
+
233
+ test("changing value from empty -> value", function () {
234
+ var view = pane.view('empty');
235
+
236
+ // test changing value updates like it should
237
+ SC.run(function () {
238
+ view.set('value', 'John Doe');
239
+ });
240
+ pane.verifyNotEmpty(view, 'John Doe', 'Full Name');
241
+ });
242
+
243
+ test("disabling view", function () {
244
+ var view = pane.view('empty');
245
+
246
+ // test changing enabled state updates like it should
247
+ SC.run(function () {
248
+ view.set('isEnabled', NO);
249
+ });
250
+ pane.verifyDisabled(view, YES);
251
+ });
252
+
253
+ test("changing value to null", function () {
254
+ var view = pane.view('with value');
255
+
256
+ // test changing value updates like it should
257
+ SC.run(function () {
324
258
  view.set('value', null);
325
259
  });
260
+ equals(view.get('fieldValue'), null, 'should have empty fieldValue');
261
+ pane.verifyEmpty(view, 'Full Name');
262
+ });
263
+
264
+ test("enabling disabled view", function () {
265
+ var view = pane.view('disabled - empty');
326
266
 
327
- equals(input.attr('type'), 'text', "When nulled out, field was converted to type text");
328
- equals(input.val(), view.get('hint'), "When nulled out, field was given value equal to hint");
267
+ // test changing enabled state updates like it should
268
+ SC.run(function () {
269
+ view.set('isEnabled', YES);
270
+ });
271
+ pane.verifyDisabled(view, NO);
329
272
  });
330
- }
331
273
 
332
- // ..........................................................
333
- // TEST SELECTION SUPPORT
334
- //
274
+ test("changing isEditable", function () {
275
+ var view = pane.view('enabled - not editable - with value');
335
276
 
336
- test("Setting the selection to a null value should fail", function() {
337
- var view = pane.view('with value');
338
- var fieldElement = view.$input()[0];
339
- fieldElement.size = 10; // Avoid Firefox 3.5 issue
277
+ // test changing isEditable state updates like it should
278
+ SC.run(function () {
279
+ view.set('isEditable', YES);
280
+ });
281
+ pane.verifyReadOnly(view, NO);
340
282
 
341
- var thrownException = null;
342
- try {
343
- view.set('selection', null);
344
- } catch(e) {
345
- thrownException = e.message;
346
- }
347
- ok(thrownException.indexOf !== undefined, 'an exception should have been thrown');
348
- if (thrownException.indexOf !== undefined) {
349
- ok(thrownException.indexOf('must specify an SC.TextSelection instance') !== -1, 'the exception should be about not specifying an SC.TextSelection instance');
350
- }
351
- });
352
-
353
- test("Setting the selection to a non-SC.TextSelection value should fail", function() {
354
- var view = pane.view('with value');
355
- var fieldElement = view.$input()[0];
356
- fieldElement.size = 10; // Avoid Firefox 3.5 issue
357
-
358
- var thrownException = null;
359
- try {
360
- view.set('selection', {start: 0, end: 0});
361
- } catch(e) {
362
- thrownException = e.message;
363
- }
364
- ok(thrownException.indexOf !== undefined, 'an exception should have been thrown');
365
- if (thrownException.indexOf !== undefined) {
366
- ok(thrownException.indexOf('must specify an SC.TextSelection instance') !== -1, 'the exception should be about not specifying an SC.TextSelection instance');
283
+ // test changing isEditable state updates like it should
284
+ SC.run(function () {
285
+ view.set('isEditable', NO);
286
+ });
287
+ pane.verifyReadOnly(view, YES);
288
+ });
289
+
290
+ test("changing value from not a textarea to a textarea", function () {
291
+ // test the the SC.Event for 'change' gets wired up properly to the DOM element when it changes from input to textarea
292
+ var view = pane.view('empty');
293
+ SC.run(function () {
294
+ view.set('value', 'Original');
295
+ view.set('isTextArea', YES);
296
+ });
297
+
298
+ var $textarea = view.$('textarea');
299
+
300
+ SC.Event.trigger($textarea, 'focus');
301
+
302
+ // simulate typing a letter
303
+ SC.Event.trigger($textarea, 'keydown');
304
+ $textarea.val("My New Value");
305
+ SC.Event.trigger($textarea, 'keyup');
306
+ SC.Event.trigger($textarea, 'change');
307
+ SC.run(function () {
308
+ view.fieldValueDidChange();
309
+ });
310
+
311
+ // wait a little bit to let text field propogate changes
312
+ stop();
313
+
314
+ setTimeout(function () {
315
+ start();
316
+ equals(view.get("value"), "My New Value", "SC.Event for change should get wired up properly");
317
+ }, 100);
318
+
319
+ SC.run(function () {
320
+ });
321
+ });
322
+
323
+ /**
324
+ There was a bug that when a text field view has a value before it is appended,
325
+ the hint line-height gets set to 0px. So if the value is removed, the hint is
326
+ in the wrong spot.
327
+ */
328
+ test("When a manual hint is visible, the line-height of the hint should be correct", function () {
329
+ var view1 = pane.view('empty'),
330
+ view2 = pane.view('with value'),
331
+ hint = view1.$('.hint');
332
+
333
+ equals(hint.css('line-height'), "14px", "The line-height of the hint of an empty text field should be");
334
+
335
+ SC.run(function () {
336
+ view2.set('value', null);
337
+ });
338
+
339
+ hint = view2.$('.hint');
340
+ equals(hint.css('line-height'), "14px", "The line-height of the hint of a non-empty text field should be");
341
+ });
342
+
343
+
344
+ if (!SC.browser.isIE && !SC.platform.input.placeholder) {
345
+ test("Changing value to null -- password field", function () {
346
+ var view = pane.view('password-hint'),
347
+ input = view.$('input');
348
+
349
+ SC.run(function () {
350
+ view.set('value', null);
351
+ });
352
+
353
+ equals(input.attr('type'), 'text', "When nulled out, field was converted to type text");
354
+ equals(input.val(), view.get('hint'), "When nulled out, field was given value equal to hint");
355
+ });
367
356
  }
368
- });
369
-
370
- test("Setting and then getting back the selection", function() {
371
- var view = pane.view('with value');
372
- var fieldElement = view.$input()[0];
373
- fieldElement.focus();
374
- fieldElement.size = 10; // Avoid Firefox 3.5 issue
375
-
376
- var newSelection = SC.TextSelection.create({start:2, end:5});
377
- view.set('selection', newSelection);
378
357
 
379
- var fetchedSelection = view.get('selection');
380
- ok(fetchedSelection.get('start') === 2, 'the selection should start at index 2');
381
- ok(fetchedSelection.get('end') === 5, 'the selection should end at index 4');
382
- ok(fetchedSelection.get('length') === 3, 'the selection should have length 3');
383
- });
384
-
385
- // ..........................................................
386
- // TEST ACCESSORY VIEWS
387
- //
388
-
389
- test("Adding left accessory view", function() {
390
- var view = pane.view('with value');
391
-
392
- // test adding accessory view adds the view like it should
393
- SC.RunLoop.begin();
394
- var accessoryView = SC.View.create({
395
- layout: { top:1, left:2, width:16, height:16 }
396
- });
397
- view.set('leftAccessoryView', accessoryView);
398
- SC.RunLoop.end();
399
-
400
- ok(view.get('leftAccessoryView') === accessoryView, 'left accessory view should be set to ' + accessoryView.toString());
401
- ok(view.get('childViews').length === 1, 'there should only be one child view');
402
- ok(view.get('childViews')[0] === accessoryView, 'first child view should be set to ' + accessoryView.toString());
403
-
404
-
405
- // The hint and padding elements should automatically have their 'left'
406
- // values set to the accessory view's offset + width
407
- // (18 = 2 left offset + 16 width)
408
- var paddingElement = view.$('.padding')[0];
409
- ok(paddingElement.style.left === '18px', 'padding element should get 18px left');
410
-
411
- // Test removing the accessory view.
412
- SC.RunLoop.begin();
413
- view.set('leftAccessoryView', null);
414
- SC.RunLoop.end();
415
- ok(view.get('childViews').length === 0, 'after removing the left accessory view there should be no child views left');
416
- ok(!paddingElement.style.left, 'after removing the left accessory view the padding element should have no left style');
417
- });
418
-
419
- test("Adding left accessory view changes style -- using design()", function() {
420
- var view = pane.view('with value');
421
-
422
- // test adding accessory view adds the view like it should
423
- SC.RunLoop.begin();
424
- var accessoryView = SC.View.design({
425
- layout: { top:1, left:2, width:16, height:16 }
426
- });
427
- view.set('leftAccessoryView', accessoryView);
428
- SC.RunLoop.end();
358
+ // ..........................................................
359
+ // TEST SELECTION SUPPORT
360
+ //
361
+
362
+
363
+ module('SC.TextFieldView: Selection Support', pane.standardSetup());
429
364
 
430
- // The hint and padding elements should automatically have their 'left'
431
- // values set to the accessory view's offset + width
432
- // (18 = 2 left offset + 16 width)
433
- var paddingElement = view.$('.padding')[0];
434
- ok(paddingElement.style.left === '18px', 'padding element should get 18px left');
435
-
436
- // Test removing the accessory view.
437
- SC.RunLoop.begin();
438
- view.set('leftAccessoryView', null);
439
- SC.RunLoop.end();
440
- ok(!paddingElement.style.left, 'after removing the left accessory view the padding element should have no left style');
441
- });
365
+ test("Setting the selection to a null value should fail", function () {
366
+ var view = pane.view('with value');
367
+ var fieldElement = view.$input()[0];
368
+ fieldElement.size = 10; // Avoid Firefox 3.5 issue
442
369
 
443
- test("Adding right accessory view", function() {
444
- var view = pane.view('with value');
445
-
446
- // test adding accessory view adds the view like it should
447
- SC.RunLoop.begin();
448
- var accessoryView = SC.View.create({
449
- layout: { top:1, right:3, width:17, height:16 }
450
- });
451
- view.set('rightAccessoryView', accessoryView);
452
- SC.RunLoop.end();
453
-
454
- ok(view.get('rightAccessoryView') === accessoryView, 'right accessory view should be set to ' + accessoryView.toString());
455
- ok(view.get('childViews').length === 1, 'there should only be one child view');
456
- ok(view.get('childViews')[0] === accessoryView, 'first child view should be set to ' + accessoryView.toString());
457
-
458
-
459
- // The hint and padding elements should automatically have their 'right'
460
- // values set to the accessory view's offset + width
461
- // (20 = 3 right offset + 17 width)
462
- var paddingElement = view.$('.padding')[0];
463
- ok(paddingElement.style.right === '20px', 'padding element should get 20px right');
464
-
465
-
466
- // If a right accessory view is set with only 'left' (and not 'right')
467
- // defined in its layout, 'left' should be cleared out and 'right' should
468
- // be set to 0.
469
- SC.RunLoop.begin();
470
- accessoryView = SC.View.create({
471
- layout: { top:1, left:2, width:16, height:16 }
472
- });
473
- view.set('rightAccessoryView', accessoryView);
474
- SC.RunLoop.end();
475
-
476
- ok( SC.none(view.get('rightAccessoryView').get('layout').left), "right accessory view created with 'left' rather than 'right' in layout should not have a value for layout.left");
477
- ok(view.get('rightAccessoryView').get('layout').right === 0, "right accessory view created with 'left' rather than 'right' in layout should have layout.right set to 0");
478
-
479
-
480
- // Test removing the accessory view.
481
- SC.RunLoop.begin();
482
- view.set('rightAccessoryView', null);
483
- SC.RunLoop.end();
484
- ok(view.get('childViews').length === 0, 'after removing the right accessory view there should be no child views left');
485
- ok(!paddingElement.style.right, 'after removing the right accessory view the padding element should have no right style');
486
- });
487
-
488
- test("Adding right accessory view changes style -- using design()", function() {
489
- var view = pane.view('with value');
490
-
491
- // test adding accessory view adds the view like it should
492
- SC.RunLoop.begin();
493
- var accessoryView = SC.View.design({
494
- layout: { top:1, right:3, width:17, height:16 }
495
- });
496
- view.set('rightAccessoryView', accessoryView);
497
- SC.RunLoop.end();
498
-
499
- // The hint and padding elements should automatically have their 'right'
500
- // values set to the accessory view's offset + width
501
- // (20 = 3 right offset + 17 width)
502
- var paddingElement = view.$('.padding')[0];
503
- ok(paddingElement.style.right === '20px', 'padding element should get 20px right');
504
-
505
- // Test removing the accessory view.
506
- SC.RunLoop.begin();
507
- view.set('rightAccessoryView', null);
508
- SC.RunLoop.end();
509
- ok(!paddingElement.style.right, 'after removing the right accessory view the padding element should have no right style');
510
- });
511
-
512
-
513
- test("Adding both left and right accessory views", function() {
514
- var view = pane.view('with value');
515
-
516
- // test adding accessory view adds the view like it should
517
- SC.RunLoop.begin();
518
- var leftAccessoryView = SC.View.create({
519
- layout: { top:1, left:2, width:16, height:16 }
520
- });
521
- view.set('leftAccessoryView', leftAccessoryView);
522
- var rightAccessoryView = SC.View.create({
523
- layout: { top:1, right:3, width:17, height:16 }
524
- });
525
- view.set('rightAccessoryView', rightAccessoryView);
526
- SC.RunLoop.end();
527
-
528
- ok(view.get('childViews').length === 2, 'we should have two child views since we added both a left and a right accessory view');
529
-
530
-
531
- // The hint and padding elements should automatically have their 'left' and
532
- // 'right' values set to the accessory views' offset + width
533
- // * left: 18 = 2 left offset + 16 width)
534
- // * right: 20 = 3 left offset + 17 width)
535
- var paddingElement = view.$('.padding')[0];
536
- ok(paddingElement.style.left === '18px', 'padding element should get 18px left');
537
- ok(paddingElement.style.right === '20px', 'padding element should get 20px right');
538
-
539
-
540
- // Test removing the accessory views.
541
- SC.RunLoop.begin();
542
- view.set('rightAccessoryView', null);
543
- SC.RunLoop.end();
544
- ok(view.get('childViews').length === 1, 'after removing the right accessory view there should be one child view left (the left accessory view)');
545
- ok(!paddingElement.style.right, 'after removing the right accessory view the padding element should have no right style');
546
- SC.RunLoop.begin();
547
- view.set('leftAccessoryView', null);
548
- SC.RunLoop.end();
549
- ok(view.get('childViews').length === 0, 'after removing both accessory views there should be no child views left');
550
- ok(!paddingElement.style.left, 'after removing the left accessory view the padding element should have no left style');
551
- });
552
-
553
- test("Adding both left and right accessory views changes style -- using design()", function() {
554
- var view = pane.view('with value');
555
-
556
- // test adding accessory view adds the view like it should
557
- SC.RunLoop.begin();
558
- var leftAccessoryView = SC.View.design({
559
- layout: { top:1, left:2, width:16, height:16 }
560
- });
561
- view.set('leftAccessoryView', leftAccessoryView);
562
- var rightAccessoryView = SC.View.design({
563
- layout: { top:1, right:3, width:17, height:16 }
564
- });
565
- view.set('rightAccessoryView', rightAccessoryView);
566
- SC.RunLoop.end();
567
-
568
- // The hint and padding elements should automatically have their 'left' and
569
- // 'right' values set to the accessory views' offset + width
570
- // * left: 18 = 2 left offset + 16 width)
571
- // * right: 20 = 3 left offset + 17 width)
572
- var paddingElement = view.$('.padding')[0];
573
- ok(paddingElement.style.left === '18px', 'padding element should get 18px left');
574
- ok(paddingElement.style.right === '20px', 'padding element should get 20px right');
575
-
576
-
577
- // Test removing the accessory views.
578
- SC.RunLoop.begin();
579
- view.set('rightAccessoryView', null);
580
- SC.RunLoop.end();
581
- ok(!paddingElement.style.right, 'after removing the right accessory view the padding element should have no right style');
582
- SC.RunLoop.begin();
583
- view.set('leftAccessoryView', null);
584
- SC.RunLoop.end();
585
- ok(!paddingElement.style.left, 'after removing the left accessory view the padding element should have no left style');
586
- });
587
-
588
- test("Accessory views should only be instantiated once", function() {
589
- var view = pane.view('with value');
590
-
591
- // Test the left accessory view
592
- SC.RunLoop.begin();
593
- var leftAccessoryViewInitCount = 0;
594
- var leftAccessoryView = SC.View.design({
595
- layout: { top:1, left:2, width:16, height:16 },
596
- init: function() {
597
- sc_super();
598
- leftAccessoryViewInitCount++;
599
- }
600
- });
601
- view.set('leftAccessoryView', leftAccessoryView);
602
- SC.RunLoop.end();
603
-
604
- // Check it
605
- equals(leftAccessoryViewInitCount, 1, 'the left accessory view should only be initialized once');
606
-
607
- // Reset to null so it isn't created a second time when rightAccessoryView is set
608
- view.set('leftAccessoryView', null);
609
-
610
- // Test the right accessory view
611
- SC.RunLoop.begin();
612
- var rightAccessoryViewInitCount = 0;
613
- var rightAccessoryView = SC.View.design({
614
- layout: { top:1, right:3, width:17, height:16 },
615
- init: function() {
616
- sc_super();
617
- rightAccessoryViewInitCount++;
370
+ var thrownException = null;
371
+ try {
372
+ view.set('selection', null);
373
+ } catch (e) {
374
+ thrownException = e.message;
375
+ }
376
+ ok(thrownException.indexOf !== undefined, 'an exception should have been thrown');
377
+ if (thrownException.indexOf !== undefined) {
378
+ ok(thrownException.indexOf('must specify an SC.TextSelection instance') !== -1, 'the exception should be about not specifying an SC.TextSelection instance');
618
379
  }
619
380
  });
620
- view.set('rightAccessoryView', rightAccessoryView);
621
- SC.RunLoop.end();
622
381
 
623
- // Check it
624
- equals(rightAccessoryViewInitCount, 1, 'the right accessory view should only be initialized once');
625
- });
382
+ test("Setting the selection to a non-SC.TextSelection value should fail", function () {
383
+ var view = pane.view('with value');
384
+ var fieldElement = view.$input()[0];
385
+ fieldElement.size = 10; // Avoid Firefox 3.5 issue
626
386
 
387
+ var thrownException = null;
388
+ try {
389
+ view.set('selection', {start: 0, end: 0});
390
+ } catch (e) {
391
+ thrownException = e.message;
392
+ }
393
+ ok(thrownException.indexOf !== undefined, 'an exception should have been thrown');
394
+ if (thrownException.indexOf !== undefined) {
395
+ ok(thrownException.indexOf('must specify an SC.TextSelection instance') !== -1, 'the exception should be about not specifying an SC.TextSelection instance');
396
+ }
397
+ });
627
398
 
628
- // ..........................................................
629
- // TEST EVENTS
630
- //
399
+ test("Setting and then getting back the selection", function () {
400
+ var view = pane.view('with value');
401
+ var fieldElement = view.$input()[0];
402
+ fieldElement.focus();
403
+ fieldElement.size = 10; // Avoid Firefox 3.5 issue
631
404
 
632
- test("focus and blurring text field", function() {
633
- var view = pane.view('empty');
634
- var input = view.$('input');
405
+ var newSelection = SC.TextSelection.create({start: 2, end: 5});
406
+ view.set('selection', newSelection);
635
407
 
636
- // attempt to focus...
637
- SC.Event.trigger(input, 'focus');
408
+ var fetchedSelection = view.get('selection');
409
+ ok(fetchedSelection.get('start') === 2, 'the selection should start at index 2');
410
+ ok(fetchedSelection.get('end') === 5, 'the selection should end at index 4');
411
+ ok(fetchedSelection.get('length') === 3, 'the selection should have length 3');
412
+ });
638
413
 
639
- // verify editing state changed...
640
- ok(view.get('isEditing'), 'view.isEditing should be YES');
641
- ok(view.$().hasClass('focus'), 'view layer should have focus class');
642
414
 
643
- // simulate typing a letter
644
- SC.Event.trigger(input, 'keydown');
645
- SC.Event.trigger(input, 'keyup');
646
- input.val('f');
647
- SC.Event.trigger(input, 'change');
648
415
 
649
- // wait a little bit to let text field propagate changes
650
- stop();
416
+ // ..........................................................
417
+ // TEST ACCESSORY VIEWS
418
+ //
651
419
 
652
- setTimeout(function() {
653
- start();
420
+ module('SC.TextFieldView: Accessory Views', pane.standardSetup());
654
421
 
655
- equals(view.get('value'), 'f', 'view should have new value');
656
- ok(view.$().hasClass('not-empty'), 'should have not-empty class');
422
+ test("Adding left accessory view", function () {
423
+ var view = pane.view('with value'),
424
+ accessoryView;
425
+
426
+ // test adding accessory view adds the view like it should
427
+ SC.run(function () {
428
+ accessoryView = SC.View.create({
429
+ layout: { top: 1, left: 2, width: 16, height: 16 }
430
+ });
431
+ view.set('leftAccessoryView', accessoryView);
432
+ });
433
+
434
+ ok(view.get('leftAccessoryView') === accessoryView, 'left accessory view should be set to ' + accessoryView.toString());
435
+ ok(view.get('childViews').length === 1, 'there should only be one child view');
436
+ ok(view.get('childViews')[0] === accessoryView, 'first child view should be set to ' + accessoryView.toString());
657
437
 
658
- // attempt to blur...
659
- SC.Event.trigger(input, 'blur');
438
+
439
+ // The hint and padding elements should automatically have their 'left'
440
+ // values set to the accessory view's offset + width
441
+ // (18 = 2 left offset + 16 width)
442
+ var paddingElement = view.$('.padding')[0];
443
+ ok(paddingElement.style.left === '18px', 'padding element should get 18px left');
444
+
445
+ // Test removing the accessory view.
446
+ SC.run(function () {
447
+ view.set('leftAccessoryView', null);
448
+ });
449
+ ok(view.get('childViews').length === 0, 'after removing the left accessory view there should be no child views left');
450
+ ok(!paddingElement.style.left, 'after removing the left accessory view the padding element should have no left style');
451
+ });
452
+
453
+ test("Adding left accessory view changes style -- using design()", function () {
454
+ var view = pane.view('with value');
455
+
456
+ // test adding accessory view adds the view like it should
457
+ SC.run(function () {
458
+ var accessoryView = SC.View.design({
459
+ layout: { top: 1, left: 2, width: 16, height: 16 }
460
+ });
461
+ view.set('leftAccessoryView', accessoryView);
462
+ });
463
+
464
+ // The hint and padding elements should automatically have their 'left'
465
+ // values set to the accessory view's offset + width
466
+ // (18 = 2 left offset + 16 width)
467
+ var paddingElement = view.$('.padding')[0];
468
+ ok(paddingElement.style.left === '18px', 'padding element should get 18px left');
469
+
470
+ // Test removing the accessory view.
471
+ SC.run(function () {
472
+ view.set('leftAccessoryView', null);
473
+ });
474
+ ok(!paddingElement.style.left, 'after removing the left accessory view the padding element should have no left style');
475
+ });
476
+
477
+ test("Adding right accessory view", function () {
478
+ var view = pane.view('with value'),
479
+ accessoryView;
480
+
481
+ // test adding accessory view adds the view like it should
482
+ SC.run(function () {
483
+ accessoryView = SC.View.create({
484
+ layout: { top: 1, right: 3, width: 17, height: 16 }
485
+ });
486
+ view.set('rightAccessoryView', accessoryView);
487
+ });
488
+
489
+ ok(view.get('rightAccessoryView') === accessoryView, 'right accessory view should be set to ' + accessoryView.toString());
490
+ ok(view.get('childViews').length === 1, 'there should only be one child view');
491
+ ok(view.get('childViews')[0] === accessoryView, 'first child view should be set to ' + accessoryView.toString());
492
+
493
+
494
+ // The hint and padding elements should automatically have their 'right'
495
+ // values set to the accessory view's offset + width
496
+ // (20 = 3 right offset + 17 width)
497
+ var paddingElement = view.$('.padding')[0];
498
+ ok(paddingElement.style.right === '20px', 'padding element should get 20px right');
499
+
500
+
501
+ // If a right accessory view is set with only 'left' (and not 'right')
502
+ // defined in its layout, 'left' should be cleared out and 'right' should
503
+ // be set to 0.
504
+ SC.run(function () {
505
+ accessoryView = SC.View.create({
506
+ layout: { top: 1, left: 2, width: 16, height: 16 }
507
+ });
508
+ view.set('rightAccessoryView', accessoryView);
509
+ });
510
+
511
+ ok(SC.none(view.get('rightAccessoryView').get('layout').left), "right accessory view created with 'left' rather than 'right' in layout should not have a value for layout.left");
512
+ ok(view.get('rightAccessoryView').get('layout').right === 0, "right accessory view created with 'left' rather than 'right' in layout should have layout.right set to 0");
513
+
514
+
515
+ // Test removing the accessory view.
516
+ SC.run(function () {
517
+ view.set('rightAccessoryView', null);
518
+ });
519
+ ok(view.get('childViews').length === 0, 'after removing the right accessory view there should be no child views left');
520
+ ok(!paddingElement.style.right, 'after removing the right accessory view the padding element should have no right style');
521
+ });
522
+
523
+ test("Adding right accessory view changes style -- using design()", function () {
524
+ var view = pane.view('with value');
525
+
526
+ // test adding accessory view adds the view like it should
527
+ SC.run(function () {
528
+ var accessoryView = SC.View.design({
529
+ layout: { top: 1, right: 3, width: 17, height: 16 }
530
+ });
531
+ view.set('rightAccessoryView', accessoryView);
532
+ });
533
+
534
+ // The hint and padding elements should automatically have their 'right'
535
+ // values set to the accessory view's offset + width
536
+ // (20 = 3 right offset + 17 width)
537
+ var paddingElement = view.$('.padding')[0];
538
+ ok(paddingElement.style.right === '20px', 'padding element should get 20px right');
539
+
540
+ // Test removing the accessory view.
541
+ SC.run(function () {
542
+ view.set('rightAccessoryView', null);
543
+ });
544
+ ok(!paddingElement.style.right, 'after removing the right accessory view the padding element should have no right style');
545
+ });
546
+
547
+
548
+ test("Adding both left and right accessory views", function () {
549
+ var view = pane.view('with value');
550
+
551
+ // test adding accessory view adds the view like it should
552
+ SC.run(function () {
553
+ var leftAccessoryView = SC.View.create({
554
+ layout: { top: 1, left: 2, width: 16, height: 16 }
555
+ });
556
+ view.set('leftAccessoryView', leftAccessoryView);
557
+ var rightAccessoryView = SC.View.create({
558
+ layout: { top: 1, right: 3, width: 17, height: 16 }
559
+ });
560
+ view.set('rightAccessoryView', rightAccessoryView);
561
+ });
562
+
563
+ ok(view.get('childViews').length === 2, 'we should have two child views since we added both a left and a right accessory view');
564
+
565
+
566
+ // The hint and padding elements should automatically have their 'left' and
567
+ // 'right' values set to the accessory views' offset + width
568
+ // * left: 18 = 2 left offset + 16 width)
569
+ // * right: 20 = 3 left offset + 17 width)
570
+ var paddingElement = view.$('.padding')[0];
571
+ ok(paddingElement.style.left === '18px', 'padding element should get 18px left');
572
+ ok(paddingElement.style.right === '20px', 'padding element should get 20px right');
573
+
574
+
575
+ // Test removing the accessory views.
576
+ SC.run(function () {
577
+ view.set('rightAccessoryView', null);
578
+ });
579
+ ok(view.get('childViews').length === 1, 'after removing the right accessory view there should be one child view left (the left accessory view)');
580
+ ok(!paddingElement.style.right, 'after removing the right accessory view the padding element should have no right style');
581
+ SC.run(function () {
582
+ view.set('leftAccessoryView', null);
583
+ });
584
+ ok(view.get('childViews').length === 0, 'after removing both accessory views there should be no child views left');
585
+ ok(!paddingElement.style.left, 'after removing the left accessory view the padding element should have no left style');
586
+ });
587
+
588
+ test("Adding both left and right accessory views changes style -- using design()", function () {
589
+ var view = pane.view('with value');
590
+
591
+ // test adding accessory view adds the view like it should
592
+ SC.run(function () {
593
+ var leftAccessoryView = SC.View.design({
594
+ layout: { top: 1, left: 2, width: 16, height: 16 }
595
+ });
596
+ view.set('leftAccessoryView', leftAccessoryView);
597
+ var rightAccessoryView = SC.View.design({
598
+ layout: { top: 1, right: 3, width: 17, height: 16 }
599
+ });
600
+ view.set('rightAccessoryView', rightAccessoryView);
601
+ });
602
+
603
+ // The hint and padding elements should automatically have their 'left' and
604
+ // 'right' values set to the accessory views' offset + width
605
+ // * left: 18 = 2 left offset + 16 width)
606
+ // * right: 20 = 3 left offset + 17 width)
607
+ var paddingElement = view.$('.padding')[0];
608
+ ok(paddingElement.style.left === '18px', 'padding element should get 18px left');
609
+ ok(paddingElement.style.right === '20px', 'padding element should get 20px right');
610
+
611
+
612
+ // Test removing the accessory views.
613
+ SC.run(function () {
614
+ view.set('rightAccessoryView', null);
615
+ });
616
+ ok(!paddingElement.style.right, 'after removing the right accessory view the padding element should have no right style');
617
+ SC.run(function () {
618
+ view.set('leftAccessoryView', null);
619
+ });
620
+ ok(!paddingElement.style.left, 'after removing the left accessory view the padding element should have no left style');
621
+ });
622
+
623
+ test("Accessory views should only be instantiated once", function () {
624
+ var view = pane.view('with value');
625
+ var leftAccessoryViewInitCount = 0;
626
+ var rightAccessoryViewInitCount = 0;
627
+
628
+ // Test the left accessory view
629
+ SC.run(function () {
630
+ var leftAccessoryView = SC.View.design({
631
+ layout: { top: 1, left: 2, width: 16, height: 16 },
632
+ init: function () {
633
+ sc_super();
634
+ leftAccessoryViewInitCount++;
635
+ }
636
+ });
637
+ view.set('leftAccessoryView', leftAccessoryView);
638
+ });
639
+
640
+ // Check it
641
+ equals(leftAccessoryViewInitCount, 1, 'the left accessory view should only be initialized once');
642
+
643
+ // Reset to null so it isn't created a second time when rightAccessoryView is set
644
+ SC.run(function () {
645
+ view.set('leftAccessoryView', null);
646
+ });
647
+
648
+ // Test the right accessory view
649
+ SC.run(function () {
650
+ var rightAccessoryView = SC.View.design({
651
+ layout: { top: 1, right: 3, width: 17, height: 16 },
652
+ init: function () {
653
+ sc_super();
654
+ rightAccessoryViewInitCount++;
655
+ }
656
+ });
657
+ view.set('rightAccessoryView', rightAccessoryView);
658
+ });
659
+
660
+ // Check it
661
+ equals(rightAccessoryViewInitCount, 1, 'the right accessory view should only be initialized once');
662
+ });
663
+
664
+
665
+ // ..........................................................
666
+ // TEST EVENTS
667
+ //
668
+
669
+ module('SC.TextFieldView: Events', pane.standardSetup());
670
+
671
+ test("focus and blurring text field", function () {
672
+ var view = pane.view('empty');
673
+ var input = view.$('input');
674
+
675
+ // attempt to focus...
676
+ SC.Event.trigger(input, 'focus');
660
677
 
661
678
  // verify editing state changed...
662
- ok(!view.get('isEditing'), 'view.isEditing should be NO');
663
- ok(!view.$().hasClass('focus'), 'view layer should NOT have focus class');
664
- }, 100);
665
-
666
- });
667
-
668
- test("focus and blur an empty text field", function() {
669
- var view = pane.view('empty');
670
- var input = view.$('input');
671
-
672
- // verify the field is empty and the hint is properly set
673
- pane.verifyEmpty(view, 'Full Name');
674
-
675
- // focus and blur the text field
676
- SC.Event.trigger(input, 'focus');
677
- SC.Event.trigger(input, 'blur');
678
-
679
- // field should still be still be empty with hint properly set
680
- pane.verifyEmpty(view, 'Full Name');
681
- });
682
-
683
- test("loosing first responder should blur", function() {
684
- var view = pane.view('empty');
685
- var input = view.$('input');
686
- var testResponder = SC.Responder.create(SC.ResponderContext, {});
687
-
688
- // preliminary setup
689
- view.get('pane').becomeKeyPane();
690
- SC.Event.trigger(input, 'focus');
691
-
692
- // verify it did receive focus
693
- ok(view.get('focused'), 'view should have focus');
694
-
695
- // tell the pane to make our test responder the first responder
696
- view.get('pane').makeFirstResponder(testResponder);
697
-
698
- // verify it no longer has focus
699
- ok(!view.get('focused'), 'view should no longer have focus');
700
- });
701
-
702
- test("editing a field should not change the cursor position", function() {
703
- var textField = pane.view('empty');
704
- var input = textField.$('input');
705
- input.val('John Doe');
706
- textField.set('selection', SC.TextSelection.create({start:2, end:3}));
707
- SC.Event.trigger(input, 'change');
708
-
709
- ok(input.val() === 'John Doe', 'input value should be \'John Doe\'');
710
- var selection = textField.get('selection');
711
- console.log("Selection: %@".fmt(selection));
712
- ok(selection.get('start') == 2 && selection.get('end') == 3, 'cursor position should be unchanged');
713
- });
679
+ ok(view.get('isEditing'), 'view.isEditing should be YES');
680
+ ok(view.$().hasClass('focus'), 'view layer should have focus class');
681
+
682
+ // simulate typing a letter
683
+ SC.Event.trigger(input, 'keydown');
684
+ SC.Event.trigger(input, 'keyup');
685
+ input.val('f');
686
+ SC.Event.trigger(input, 'change');
687
+
688
+ // wait a little bit to let text field propagate changes
689
+ stop();
690
+
691
+ setTimeout(function () {
692
+ start();
693
+
694
+ equals(view.get('value'), 'f', 'view should have new value');
695
+ ok(view.$().hasClass('not-empty'), 'should have not-empty class');
696
+
697
+ // attempt to blur...
698
+ SC.Event.trigger(input, 'blur');
699
+
700
+ // verify editing state changed...
701
+ ok(!view.get('isEditing'), 'view.isEditing should be NO');
702
+ ok(!view.$().hasClass('focus'), 'view layer should NOT have focus class');
703
+ }, 100);
704
+
705
+ });
706
+
707
+ test("focus and blur an empty text field", function () {
708
+ var view = pane.view('empty');
709
+ var input = view.$('input');
710
+
711
+ // verify the field is empty and the hint is properly set
712
+ pane.verifyEmpty(view, 'Full Name');
713
+
714
+ // focus and blur the text field
715
+ SC.Event.trigger(input, 'focus');
716
+ SC.Event.trigger(input, 'blur');
717
+
718
+ // field should still be still be empty with hint properly set
719
+ pane.verifyEmpty(view, 'Full Name');
720
+ });
721
+
722
+ test("losing first responder should blur", function () {
723
+ var view = pane.view('empty');
724
+ var input = view.$('input');
725
+ var testResponder = SC.Responder.create(SC.ResponderContext, {});
726
+
727
+ // preliminary setup
728
+ view.get('pane').becomeKeyPane();
729
+ SC.Event.trigger(input, 'focus');
730
+
731
+ // verify it did receive focus
732
+ ok(view.get('focused'), 'view should have focus');
733
+
734
+ // tell the pane to make our test responder the first responder
735
+ view.get('pane').makeFirstResponder(testResponder);
736
+
737
+ // verify it no longer has focus
738
+ ok(!view.get('focused'), 'view should no longer have focus');
739
+ });
740
+
741
+ test("editing a field should not change the cursor position", function () {
742
+ var textField = pane.view('empty');
743
+ var input = textField.$('input');
744
+ input.val('John Doe');
745
+ textField.set('selection', SC.TextSelection.create({start: 2, end: 3}));
746
+ SC.Event.trigger(input, 'change');
747
+
748
+ ok(input.val() === 'John Doe', 'input value should be \'John Doe\'');
749
+ var selection = textField.get('selection');
750
+ ok(selection.get('start') == 2 && selection.get('end') == 3, 'cursor position should be unchanged');
751
+ });
714
752
 
715
753
  })();