sproutcore 1.10.1 → 1.10.2

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