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
@@ -5,9 +5,9 @@
5
5
  // License: Licensed under MIT license (see license.js)
6
6
  // ==========================================================================
7
7
 
8
- sc_require('views/field') ;
9
- sc_require('system/text_selection') ;
10
- sc_require('mixins/static_layout') ;
8
+ sc_require('views/field');
9
+ sc_require('system/text_selection');
10
+ sc_require('mixins/static_layout');
11
11
  sc_require('mixins/editable');
12
12
 
13
13
  SC.AUTOCAPITALIZE_NONE = 'none';
@@ -350,7 +350,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
350
350
 
351
351
  init: function () {
352
352
  var val = this.get('value');
353
- this._hintON = ((!val || val && val.length===0) && !this.get('hintOnFocus')) ? YES : NO;
353
+ this._hintON = ((!val || val && val.length === 0) && !this.get('hintOnFocus')) ? YES : NO;
354
354
 
355
355
  var continuouslyUpdatesValue = this.get('continouslyUpdatesValue');
356
356
  if (continuouslyUpdatesValue !== null && continuouslyUpdatesValue !== undefined) {
@@ -398,62 +398,59 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
398
398
  end = null;
399
399
 
400
400
  if (!element.value) {
401
- start = end = 0 ;
402
- }
403
- else {
401
+ start = end = 0;
402
+ } else {
404
403
  // In IE8, input elements don't have hasOwnProperty() defined.
405
404
  try {
406
405
  if ('selectionStart' in element) {
407
- start = element.selectionStart ;
406
+ start = element.selectionStart;
408
407
  }
409
408
  if ('selectionEnd' in element) {
410
- end = element.selectionEnd ;
409
+ end = element.selectionEnd;
411
410
  }
412
411
  }
413
412
  // In Firefox when you ask the selectionStart or End of a hidden
414
413
  // input, sometimes it throws a weird error.
415
414
  // Adding this to just ignore it.
416
- catch (e){
415
+ catch (e) {
417
416
  return null;
418
417
  }
419
418
 
420
419
  // Support Internet Explorer.
421
- if (start === null || end === null ) {
422
- var selection = document.selection ;
420
+ if (start === null || end === null) {
421
+ var selection = document.selection;
423
422
  if (selection) {
424
- var type = selection.type ;
423
+ var type = selection.type;
425
424
  if (type && (type === 'None' || type === 'Text')) {
426
- range = selection.createRange() ;
425
+ range = selection.createRange();
427
426
 
428
427
  if (!this.get('isTextArea')) {
429
428
  // Input tag support. Figure out the starting position by
430
429
  // moving the range's start position as far left as possible
431
430
  // and seeing how many characters it actually moved over.
432
- var length = range.text.length ;
433
- start = Math.abs(range.moveStart('character', 0 - (element.value.length + 1))) ;
434
- end = start + length ;
435
- }
436
- else {
431
+ var length = range.text.length;
432
+ start = Math.abs(range.moveStart('character', 0 - (element.value.length + 1)));
433
+ end = start + length;
434
+ } else {
437
435
  // Textarea support. Unfortunately, this case is a bit more
438
436
  // complicated than the input tag case. We need to create a
439
437
  // "dummy" range to help in the calculations.
440
- var dummyRange = range.duplicate() ;
441
- dummyRange.moveToElementText(element) ;
442
- dummyRange.setEndPoint('EndToStart', range) ;
443
- start = dummyRange.text.length ;
444
- end = start + range.text.length ;
438
+ var dummyRange = range.duplicate();
439
+ dummyRange.moveToElementText(element);
440
+ dummyRange.setEndPoint('EndToStart', range);
441
+ start = dummyRange.text.length;
442
+ end = start + range.text.length;
445
443
  }
446
444
  }
447
445
  }
448
446
  }
449
447
  }
450
- return SC.TextSelection.create({ start:start, end:end }) ;
451
- }
452
- else {
448
+
449
+ return SC.TextSelection.create({ start: start, end: end });
450
+ } else {
453
451
  return null;
454
452
  }
455
- }
456
- else {
453
+ } else {
457
454
  // The client is setting the value. Make sure the new value is a text
458
455
  // selection object.
459
456
  if (!value || !value.kindOf || !value.kindOf(SC.TextSelection)) {
@@ -462,17 +459,17 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
462
459
 
463
460
  if (element) {
464
461
  if (element.setSelectionRange) {
465
- element.setSelectionRange(value.get('start'), value.get('end')) ;
466
- }
467
- else {
462
+ element.setSelectionRange(value.get('start'), value.get('end'));
463
+ } else {
468
464
  // Support Internet Explorer.
469
- range = element.createTextRange() ;
470
- start = value.get('start') ;
471
- range.move('character', start) ;
472
- range.moveEnd('character', value.get('end') - start) ;
473
- range.select() ;
465
+ range = element.createTextRange();
466
+ start = value.get('start');
467
+ range.move('character', start);
468
+ range.moveEnd('character', value.get('end') - start);
469
+ range.select();
474
470
  }
475
471
  }
472
+
476
473
  return value;
477
474
  }
478
475
 
@@ -487,8 +484,11 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
487
484
  // INTERNAL SUPPORT
488
485
  //
489
486
 
490
- // Note: isEnabled is required here because it is used in the render function.
491
- displayProperties: ['isBrowserFocusable','formattedHint', 'fieldValue', 'isEditing', 'isEditable', 'isEnabled', 'leftAccessoryView', 'rightAccessoryView', 'isTextArea'],
487
+ // Note: isEnabledInPane is required here because it is used in the renderMixin function of
488
+ // SC.Control. It is not a display property directly in SC.Control, because the use of it in
489
+ // SC.Control is only applied to input fields, which very few consumers of SC.Control have.
490
+ // TODO: Pull the disabled attribute updating out of SC.Control.
491
+ displayProperties: ['isBrowserFocusable', 'formattedHint', 'fieldValue', 'isEditing', 'isEditable', 'isEnabledInPane', 'leftAccessoryView', 'rightAccessoryView', 'isTextArea'],
492
492
 
493
493
  createChildViews: function () {
494
494
  sc_super();
@@ -502,29 +502,29 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
502
502
  accessoryViewObserver: function () {
503
503
  var classNames,
504
504
  viewProperties = ['leftAccessoryView', 'rightAccessoryView'],
505
- len = viewProperties.length , i, viewProperty, previousView,
505
+ len = viewProperties.length, i, viewProperty, previousView,
506
506
  accessoryView;
507
507
 
508
- for (i=0; i<len; i++) {
508
+ for (i = 0; i < len; i++) {
509
509
  viewProperty = viewProperties[i];
510
510
 
511
511
  // Is there an accessory view specified?
512
- previousView = this['_'+viewProperty] ;
513
- accessoryView = this.get(viewProperty) ;
512
+ previousView = this['_' + viewProperty];
513
+ accessoryView = this.get(viewProperty);
514
514
 
515
515
  // If the view is the same, there's nothing to do. Otherwise, remove
516
516
  // the old one (if any) and add the new one.
517
517
  if (! (previousView &&
518
518
  accessoryView &&
519
- (previousView === accessoryView) ) ) {
519
+ (previousView === accessoryView))) {
520
520
 
521
521
  // If there was a previous previous accessory view, remove it now.
522
522
  if (previousView) {
523
523
  // Remove the "sc-text-field-accessory-view" class name that we had
524
524
  // added earlier.
525
- classNames = previousView.get('classNames') ;
526
- classNames = classNames.without('sc-text-field-accessory-view') ;
527
- previousView.set('classNames', classNames) ;
525
+ classNames = previousView.get('classNames');
526
+ classNames = classNames.without('sc-text-field-accessory-view');
527
+ previousView.set('classNames', classNames);
528
528
 
529
529
  if (previousView.createdByParent) {
530
530
  this.removeChildAndDestroy(previousView);
@@ -533,7 +533,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
533
533
  }
534
534
 
535
535
  // Tidy up.
536
- previousView = this['_'+viewProperty] = this['_created' + viewProperty] = null;
536
+ previousView = this['_' + viewProperty] = this['_created' + viewProperty] = null;
537
537
  }
538
538
 
539
539
  // If there's a new accessory view to add, do so now.
@@ -551,24 +551,23 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
551
551
 
552
552
  // Add in the "sc-text-field-accessory-view" class name so that the
553
553
  // z-index gets set correctly.
554
- classNames = accessoryView.get('classNames') ;
555
- var className = 'sc-text-field-accessory-view' ;
554
+ classNames = accessoryView.get('classNames');
555
+ var className = 'sc-text-field-accessory-view';
556
556
  if (classNames.indexOf(className) < 0) {
557
557
  classNames = SC.clone(classNames);
558
- classNames.push(className) ;
558
+ classNames.push(className);
559
559
  accessoryView.set('classNames', classNames);
560
560
  }
561
561
 
562
562
  // Actually add the view to our hierarchy and cache a reference.
563
- this.appendChild(accessoryView) ;
564
- this['_'+viewProperty] = accessoryView ;
563
+ this.appendChild(accessoryView);
564
+ this['_' + viewProperty] = accessoryView;
565
565
  }
566
566
  }
567
567
  }
568
568
  }.observes('leftAccessoryView', 'rightAccessoryView'),
569
569
 
570
570
  render: function (context, firstTime) {
571
- sc_super() ;
572
571
  var v, accessoryViewWidths, leftAdjustment, rightAdjustment;
573
572
 
574
573
  // always have at least an empty string
@@ -584,12 +583,12 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
584
583
  // if we could add in the original padding, too, but there's no efficient
585
584
  // way to do that without first rendering the element somewhere on/off-
586
585
  // screen, and we don't want to take the performance hit.)
587
- accessoryViewWidths = this._getAccessoryViewWidths() ;
588
- leftAdjustment = accessoryViewWidths['left'] ;
589
- rightAdjustment = accessoryViewWidths['right'] ;
586
+ accessoryViewWidths = this._getAccessoryViewWidths();
587
+ leftAdjustment = accessoryViewWidths.left;
588
+ rightAdjustment = accessoryViewWidths.right;
590
589
 
591
- if (leftAdjustment) leftAdjustment += 'px' ;
592
- if (rightAdjustment) rightAdjustment += 'px' ;
590
+ if (leftAdjustment) leftAdjustment += 'px';
591
+ if (rightAdjustment) rightAdjustment += 'px';
593
592
 
594
593
  this._renderField(context, firstTime, v, leftAdjustment, rightAdjustment);
595
594
  },
@@ -602,7 +601,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
602
601
  _forceRenderFirstTime: NO,
603
602
 
604
603
  /** @private */
605
- _renderFieldLikeFirstTime: function (){
604
+ _renderFieldLikeFirstTime: function () {
606
605
  this.set('_forceRenderFirstTime', YES);
607
606
  }.observes('isTextArea'),
608
607
 
@@ -611,33 +610,33 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
611
610
  // TODO: The cleanest thing might be to create a sub- rendering context
612
611
  // here, but currently SC.RenderContext will render sibling
613
612
  // contexts as parent/child.
614
-
615
613
  var hint = this.get('formattedHint'),
616
- hintOnFocus = this.get('hintOnFocus'),
617
- hintString = '',
618
- maxLength = this.get('maxLength'),
619
- isTextArea = this.get('isTextArea'),
620
- isEnabled = this.get('isEnabled'),
621
- isEditable = this.get('isEditable'),
622
- autoCorrect = this.get('autoCorrect'),
623
- autoCapitalize = this.get('autoCapitalize'),
624
- isBrowserFocusable = this.get('isBrowserFocusable'),
625
- spellCheckString='', autocapitalizeString='', autocorrectString='',
626
- name, adjustmentStyle, type, hintElements, element, paddingElementStyle,
627
- fieldClassNames, isOldSafari, activeState, browserFocusable;
614
+ hintOnFocus = this.get('hintOnFocus'),
615
+ hintString = '',
616
+ maxLength = this.get('maxLength'),
617
+ isTextArea = this.get('isTextArea'),
618
+ isEnabledInPane = this.get('isEnabledInPane'),
619
+ isEditable = this.get('isEditable'),
620
+ autoCorrect = this.get('autoCorrect'),
621
+ autoCapitalize = this.get('autoCapitalize'),
622
+ isBrowserFocusable = this.get('isBrowserFocusable'),
623
+ spellCheckString = '', autocapitalizeString = '', autocorrectString = '',
624
+ activeStateString = '', browserFocusableString = '',
625
+ name, adjustmentStyle, type, paddingElementStyle,
626
+ fieldClassNames, isOldSafari;
628
627
 
629
628
  context.setClass('text-area', isTextArea);
630
629
 
631
630
  //Adding this to differentiate between older and newer versions of safari
632
631
  //since the internal default field padding changed
633
- isOldSafari= SC.browser.isWebkit &&
634
- SC.browser.compare(SC.browser.engineVersion, '532')<0;
632
+ isOldSafari = SC.browser.isWebkit &&
633
+ SC.browser.compare(SC.browser.engineVersion, '532') < 0;
635
634
  context.setClass('oldWebKitFieldPadding', isOldSafari);
636
635
 
637
636
 
638
637
  if (firstTime || this._forceRenderFirstTime) {
639
638
  this._forceRenderFirstTime = NO;
640
- activeState = isEnabled ? (isEditable ? '' : 'readonly="readonly"') : 'disabled="disabled"' ;
639
+ activeStateString = isEnabledInPane ? (isEditable ? '' : ' readonly="readonly"') : ' disabled="disabled"';
641
640
  name = this.get('layerId');
642
641
 
643
642
  spellCheckString = this.get('spellCheckEnabled') ? ' spellcheck="true"' : ' spellcheck="false"';
@@ -655,10 +654,10 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
655
654
  }
656
655
 
657
656
  if (!isBrowserFocusable) {
658
- browserFocusable = 'tabindex="-1"';
657
+ browserFocusableString = ' tabindex="-1"';
659
658
  }
660
659
 
661
- // if hint is on and we don't want it to show on focus, create one
660
+ // if hint is on and we don't want it to show on focus, create one
662
661
  if (SC.platform.input.placeholder && !hintOnFocus) {
663
662
  hintString = ' placeholder="' + hint + '"';
664
663
  }
@@ -667,24 +666,24 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
667
666
 
668
667
  // Render the padding element, with any necessary positioning
669
668
  // adjustments to accommodate accessory views.
670
- adjustmentStyle = '' ;
669
+ adjustmentStyle = '';
671
670
  if (leftAdjustment || rightAdjustment) {
672
- adjustmentStyle = 'style="' ;
673
- if (leftAdjustment) adjustmentStyle += 'left:' + leftAdjustment + ';' ;
674
- if (rightAdjustment) adjustmentStyle += 'right:' + rightAdjustment + ';' ;
675
- adjustmentStyle += '"' ;
671
+ adjustmentStyle = 'style="';
672
+ if (leftAdjustment) adjustmentStyle += 'left:' + leftAdjustment + ';';
673
+ if (rightAdjustment) adjustmentStyle += 'right:' + rightAdjustment + ';';
674
+ adjustmentStyle += '"';
676
675
  }
677
- context.push('<div class="padding" '+adjustmentStyle+'>');
676
+ context.push('<div class="padding" ' + adjustmentStyle + '>');
678
677
 
679
678
  value = this.get('escapeHTML') ? SC.RenderContext.escapeHTML(value) : value;
680
- if (this._hintON && !SC.platform.input.placeholder && (!value || (value && value.length===0))) {
679
+ if (this._hintON && !SC.platform.input.placeholder && (!value || (value && value.length === 0))) {
681
680
  value = hint;
682
681
  context.setClass('sc-hint', YES);
683
682
  }
684
683
 
685
684
  if (hintOnFocus) {
686
- var hintStr = '<div aria-hidden="true" class="hint '+
687
- (isTextArea ? '':'ellipsis')+'%@">'+ hint + '</div>';
685
+ var hintStr = '<div aria-hidden="true" class="hint ' +
686
+ (isTextArea ? '':'ellipsis') + '%@">' + hint + '</div>';
688
687
  context.push(hintStr.fmt(value ? ' sc-hidden': ''));
689
688
  }
690
689
 
@@ -692,13 +691,12 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
692
691
 
693
692
  // Render the input/textarea field itself, and close off the padding.
694
693
  if (isTextArea) {
695
- context.push('<textarea aria-label="' + hint + '" aria-multiline="true" class="'+fieldClassNames+'" name="'+ name+
696
- '" '+ activeState + hintString +
697
- spellCheckString + autocorrectString + browserFocusable +
698
- autocapitalizeString + ' maxlength="'+ maxLength+ '">'+
699
- value+ '</textarea></div>') ;
700
- }
701
- else {
694
+ context.push('<textarea aria-label="' + hint + '" class="' + fieldClassNames + '" aria-multiline="true"' +
695
+ '" name="' + name + '"' + activeStateString + hintString +
696
+ spellCheckString + autocorrectString + autocapitalizeString +
697
+ browserFocusableString + ' maxlength="' + maxLength +
698
+ '">' + value + '</textarea></div>');
699
+ } else {
702
700
  type = this.get('type');
703
701
 
704
702
  // Internet Explorer won't let us change the type attribute later
@@ -711,20 +709,19 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
711
709
  type = 'password';
712
710
  }
713
711
 
714
- context.push('<input aria-label="' + hint + '" class="'+fieldClassNames+'" type="'+ type+
715
- '" name="'+ name + '" '+ activeState + ' value="'+ value + '"' +
716
- hintString + spellCheckString+ browserFocusable +
717
- ' maxlength="'+ maxLength+ '" '+autocorrectString+' ' +
718
- autocapitalizeString+'/></div>') ;
712
+ context.push('<input aria-label="' + hint + '" class="' + fieldClassNames + '" type="' + type +
713
+ '" name="' + name + '"' + activeStateString + hintString +
714
+ spellCheckString + autocorrectString + autocapitalizeString +
715
+ browserFocusableString + ' maxlength="' + maxLength +
716
+ '" value="' + value + '"' + '/></div>');
719
717
  }
720
- }
721
- else {
722
- var input= this.$input(),
723
- elem = input[0],
724
- val = this.get('value');
718
+ } else {
719
+ var input = this.$input(),
720
+ element = input[0],
721
+ val = this.get('value');
725
722
 
726
- if (hintOnFocus) this.$('.hint')[0].innerHTML = hint;
727
- else if (!hintOnFocus) elem.placeholder = hint;
723
+ if (hintOnFocus) context.$('.hint')[0].innerHTML = hint;
724
+ else if (!hintOnFocus) element.placeholder = hint;
728
725
 
729
726
  // IE8 has problems aligning the input text in the center
730
727
  // This is a workaround for centering it.
@@ -733,18 +730,17 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
733
730
  }
734
731
 
735
732
  if (!val || (val && val.length === 0)) {
736
- if (this.get('isPassword')) { elem.type = 'password'; }
733
+ if (this.get('isPassword')) { element.type = 'password'; }
737
734
 
738
735
  if (!SC.platform.input.placeholder && this._hintON) {
739
736
  if (!this.get('isFirstResponder')) {
740
- // Internet Explorer doesn't allow you to modify the type afterwards
741
- // jQuery throws an exception as well, so set attribute directly
742
-
743
- context.setClass('sc-hint', YES);
744
- input.val(hint);
737
+ // Internet Explorer doesn't allow you to modify the type afterwards
738
+ // jQuery throws an exception as well, so set attribute directly
739
+ context.setClass('sc-hint', YES);
740
+ input.val(hint);
745
741
  } else {
746
- // Internet Explorer doesn't allow you to modify the type afterwards
747
- // jQuery throws an exception as well, so set attribute directly
742
+ // Internet Explorer doesn't allow you to modify the type afterwards
743
+ // jQuery throws an exception as well, so set attribute directly
748
744
  context.setClass('sc-hint', NO);
749
745
  input.val('');
750
746
  }
@@ -774,38 +770,31 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
774
770
  } else {
775
771
  input.attr('tabindex', '-1');
776
772
  }
773
+
777
774
  // Enable/disable the actual input/textarea as appropriate.
778
- element = input[0];
779
- if (element) {
780
- if (!isEnabled) {
781
- element.disabled = 'true' ;
782
- element.readOnly = null ;
783
- } else if (!isEditable) {
784
- element.disabled = null ;
785
- element.readOnly = 'true' ;
786
- } else {
787
- element.disabled = null ;
788
- element.readOnly = null ;
789
- }
775
+ if (!isEditable) {
776
+ input.attr('readOnly', true);
777
+ } else {
778
+ input.attr('readOnly', null);
779
+ }
790
780
 
781
+ if (element) {
791
782
  // Adjust the padding element to accommodate any accessory views.
792
783
  paddingElementStyle = element.parentNode.style;
793
784
  if (leftAdjustment) {
794
785
  if (paddingElementStyle.left !== leftAdjustment) {
795
- paddingElementStyle.left = leftAdjustment ;
786
+ paddingElementStyle.left = leftAdjustment;
796
787
  }
797
- }
798
- else {
799
- paddingElementStyle.left = null ;
788
+ } else {
789
+ paddingElementStyle.left = null;
800
790
  }
801
791
 
802
792
  if (rightAdjustment) {
803
793
  if (paddingElementStyle.right !== rightAdjustment) {
804
- paddingElementStyle.right = rightAdjustment ;
794
+ paddingElementStyle.right = rightAdjustment;
805
795
  }
806
- }
807
- else {
808
- paddingElementStyle.right = null ;
796
+ } else {
797
+ paddingElementStyle.right = null;
809
798
  }
810
799
  }
811
800
  }
@@ -815,7 +804,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
815
804
  var widths = {},
816
805
  accessoryViewPositions = ['left', 'right'],
817
806
  numberOfAccessoryViewPositions = accessoryViewPositions.length, i,
818
- position, accessoryView, frames, width, layout, offset, frame;
807
+ position, accessoryView, width, layout, offset, frame;
819
808
  for (i = 0; i < numberOfAccessoryViewPositions; i++) {
820
809
  position = accessoryViewPositions[i];
821
810
  accessoryView = this['_' + position + 'AccessoryView'];
@@ -842,16 +831,19 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
842
831
  // HANDLE NATIVE CONTROL EVENTS
843
832
  //
844
833
 
834
+ /**
835
+ Override of SC.FieldView.prototype.didCreateLayer.
836
+ */
845
837
  didCreateLayer: function () {
846
838
  sc_super();
839
+
847
840
  if (!SC.platform.input.placeholder) this.invokeLast(this._setInitialPlaceHolderIE);
848
841
  // For some strange reason if we add focus/blur events to textarea
849
842
  // inmediately they won't work. However if I add them at the end of the
850
843
  // runLoop it works fine.
851
844
  if (this.get('isTextArea')) {
852
845
  this.invokeLast(this._addTextAreaEvents);
853
- }
854
- else {
846
+ } else {
855
847
  this._addTextAreaEvents();
856
848
 
857
849
  // In Firefox, for input fields only (that is, not textarea elements),
@@ -865,11 +857,15 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
865
857
  SC.Event.add(input, 'keypress', this, this._firefox_dispatch_keypress);
866
858
  }
867
859
  }
860
+ },
868
861
 
869
- if (this.get('hintOnFocus') ||
870
- (SC.browser.name === SC.BROWSER.ie && SC.browser.version <= 8 && !this.get('isTextArea'))) {
871
- this.invokeLast(this._fixupTextLayout);
872
- }
862
+ /**
863
+ SC.View view state callback.
864
+
865
+ Once the view is appended, fix up the text layout to sc-hints and inputs.
866
+ */
867
+ didAppendToDocument: function () {
868
+ this._fixupTextLayout();
873
869
  },
874
870
 
875
871
  /** @private
@@ -884,7 +880,9 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
884
880
  }
885
881
 
886
882
  if (this.get('hintOnFocus') && !this.get('isTextArea')) {
887
- this.$('.hint').css('line-height', this.$('.hint').outerHeight() + 'px');
883
+ var hintJQ = this.$('.hint');
884
+
885
+ hintJQ.css('line-height', hintJQ.outerHeight() + 'px');
888
886
  }
889
887
  },
890
888
 
@@ -895,7 +893,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
895
893
  if (!SC.platform.input.placeholder && this._hintON) {
896
894
  var input = this.$input(),
897
895
  currentValue = input.val();
898
- if (!currentValue || (currentValue && currentValue.length===0)) {
896
+ if (!currentValue || (currentValue && currentValue.length === 0)) {
899
897
  input.val(this.get('formattedHint'));
900
898
  }
901
899
  }
@@ -940,10 +938,10 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
940
938
  */
941
939
  _textField_fieldDidFocus: function (evt) {
942
940
  SC.run(function () {
943
- this.set('focused',YES);
941
+ this.set('focused', YES);
944
942
  this.fieldDidFocus(evt);
945
943
  var val = this.get('value');
946
- if (!SC.platform.input.placeholder && ((!val) || (val && val.length===0))) {
944
+ if (!SC.platform.input.placeholder && ((!val) || (val && val.length === 0))) {
947
945
  this._hintON = NO;
948
946
  }
949
947
  }, this);
@@ -954,13 +952,13 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
954
952
  */
955
953
  _textField_fieldDidBlur: function (evt) {
956
954
  SC.run(function () {
957
- this.set('focused',NO);
955
+ this.set('focused', NO);
958
956
  // passing the original event here instead that was potentially set from
959
- // loosing the responder on the inline text editor so that we can
957
+ // losing the responder on the inline text editor so that we can
960
958
  // use it for the delegate to end editing
961
959
  this.fieldDidBlur(this._origEvent || evt);
962
960
  var val = this.get('value');
963
- if (!SC.platform.input.placeholder && !this.get('hintOnFocus') && ((!val) || (val && val.length===0))) {
961
+ if (!SC.platform.input.placeholder && !this.get('hintOnFocus') && ((!val) || (val && val.length === 0))) {
964
962
  this._hintON = YES;
965
963
  }
966
964
  }, this);
@@ -990,7 +988,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
990
988
  },
991
989
 
992
990
  fieldDidBlur: function (evt) {
993
- this.resignFirstResponder(evt) ;
991
+ this.resignFirstResponder(evt);
994
992
 
995
993
  if (this.get('commitOnBlur')) this.commitEditing(evt);
996
994
 
@@ -1004,7 +1002,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1004
1002
 
1005
1003
  /** @private */
1006
1004
  _field_fieldValueDidChange: function (evt) {
1007
- if (this.get('focused')){
1005
+ if (this.get('focused')) {
1008
1006
  SC.run(function () {
1009
1007
  this.fieldValueDidChange(NO);
1010
1008
  }, this);
@@ -1019,9 +1017,9 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1019
1017
  I welcome someone else to find a better solution to this problem. However, please make sure that it
1020
1018
  works with pasting via shortcut, context menu and the application menu on *All Browsers*.
1021
1019
  */
1022
- _textField_inputDidChange: function() {
1020
+ _textField_inputDidChange: function () {
1023
1021
  var timerNotPending = SC.empty(this._fieldValueDidChangeTimer) || !this._fieldValueDidChangeTimer.get('isValid');
1024
- if(this.get('applyImmediately') && timerNotPending) {
1022
+ if (this.get('applyImmediately') && timerNotPending) {
1025
1023
  this.invokeLater(this.fieldValueDidChange, 10);
1026
1024
  }
1027
1025
  },
@@ -1036,9 +1034,9 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1036
1034
 
1037
1035
  if (this.getFieldValue()) {
1038
1036
  this.$('.hint').addClass('sc-hidden');
1039
- }
1040
- else {
1037
+ } else {
1041
1038
  this.$('.hint').removeClass('sc-hidden');
1039
+ this._fixupTextLayout();
1042
1040
  }
1043
1041
  }.observes('value'),
1044
1042
 
@@ -1061,9 +1059,9 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1061
1059
  valueLen = value ? value.length : 0,
1062
1060
  responder;
1063
1061
 
1064
- if (!selection || ((selection.get('length') === 0 && (selection.get('start') === 0) || selection.get('end') === valueLen))) {
1062
+ if (!selection || ((selection.get('length') === 0 && (selection.get('start') === 0) || selection.get('end') === valueLen))) {
1065
1063
  responder = SC.RootResponder.responder;
1066
- if(evt.keyCode===9) return;
1064
+ if (evt.keyCode === 9) return;
1067
1065
  responder.keypress.call(responder, evt);
1068
1066
  evt.stopPropagation();
1069
1067
  }
@@ -1089,9 +1087,10 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1089
1087
  var inp = this.$input()[0];
1090
1088
  try {
1091
1089
  if (inp) inp.focus();
1092
- } catch(e){}
1090
+ } catch (e) {}
1091
+
1093
1092
  if (!this._txtFieldMouseDown) {
1094
- this.invokeLast(this._selectRootElement) ;
1093
+ this.invokeLast(this._selectRootElement);
1095
1094
  }
1096
1095
  }
1097
1096
  },
@@ -1111,8 +1110,8 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1111
1110
  SC.browser.compare(SC.browser.osVersion, '10.7') === 0;
1112
1111
 
1113
1112
  if (!(SC.browser.name === SC.BROWSER.safari &&
1114
- isLion && SC.buildLocale==='ko-kr')) {
1115
- inputElem.select() ;
1113
+ isLion && SC.buildLocale === 'ko-kr')) {
1114
+ inputElem.select();
1116
1115
  }
1117
1116
  }
1118
1117
  else this._textField_selectionDidChange();
@@ -1147,7 +1146,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1147
1146
  },
1148
1147
 
1149
1148
  /** @private */
1150
- insertText: function(chr, evt) {
1149
+ insertText: function (chr, evt) {
1151
1150
  var which = evt.which,
1152
1151
  keyCode = evt.keyCode,
1153
1152
  maxLengthReached = false;
@@ -1157,8 +1156,8 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1157
1156
  var val = this.get('value');
1158
1157
 
1159
1158
  // This code is nasty. It's thanks gecko .keycode table that has charters like & with the same keycode as up arrow key
1160
- if (val && ((!SC.browser.isMozilla && which>47) ||
1161
- (SC.browser.isMozilla && ((which>32 && which<43) || which>47) && !(keyCode>36 && keyCode<41))) &&
1159
+ if (val && ((!SC.browser.isMozilla && which > 47) ||
1160
+ (SC.browser.isMozilla && ((which > 32 && which < 43) || which > 47) && !(keyCode > 36 && keyCode < 41))) &&
1162
1161
  (val.length >= this.get('maxLength'))) {
1163
1162
  maxLengthReached = true;
1164
1163
  }
@@ -1166,7 +1165,6 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1166
1165
  // validate keyDown...
1167
1166
  // do not validate on touch, as it prevents return.
1168
1167
  if ((this.performValidateKeyDown(evt) || SC.platform.touch) && !maxLengthReached) {
1169
- this._isKeyDown = YES;
1170
1168
  evt.allowDefault();
1171
1169
  } else {
1172
1170
  evt.stop();
@@ -1183,20 +1181,44 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1183
1181
  },
1184
1182
 
1185
1183
  /** @private */
1186
- insertTab: function(evt) {
1184
+ insertTab: function (evt) {
1187
1185
  // Don't handle if default tabbing hasn't been enabled.
1188
- if (!this.get('defaultTabbingEnabled')) return NO;
1186
+ if (!this.get('defaultTabbingEnabled')) {
1187
+ evt.preventDefault();
1188
+ return false;
1189
+ }
1190
+
1189
1191
  // Otherwise, handle.
1190
- var view = evt.shiftKey ? this.get('previousValidKeyView') : this.get('nextValidKeyView');
1192
+ var view = this.get('nextValidKeyView');
1191
1193
  if (view) view.becomeFirstResponder();
1192
1194
  else evt.allowDefault();
1193
- return YES ; // handled
1195
+ return YES; // handled
1194
1196
  },
1195
1197
 
1196
- // If this is a multi-line field, then allow the new line to proceed.
1197
1198
  /** @private */
1198
- insertNewline: function(evt) {
1199
- if (this.get('isTextArea')) {
1199
+ insertBacktab: function (evt) {
1200
+ // Don't handle if default tabbing hasn't been enabled.
1201
+ if (!this.get('defaultTabbingEnabled')) {
1202
+ evt.preventDefault();
1203
+ return false;
1204
+ }
1205
+
1206
+ // Otherwise, handle.
1207
+ var view = this.get('previousValidKeyView');
1208
+ if (view) view.becomeFirstResponder();
1209
+ else evt.allowDefault();
1210
+ return YES; // handled
1211
+ },
1212
+
1213
+ /**
1214
+ @private
1215
+
1216
+ Invoked when the user presses return. If this is a multi-line field,
1217
+ then allow the newline to proceed. Otherwise, try to commit the
1218
+ edit.
1219
+ */
1220
+ insertNewline: function (evt) {
1221
+ if (this.get('isTextArea') || evt.isIMEInput) {
1200
1222
  evt.allowDefault();
1201
1223
  return YES; // handled
1202
1224
  }
@@ -1204,37 +1226,37 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1204
1226
  },
1205
1227
 
1206
1228
  /** @private */
1207
- deleteForward: function(evt) {
1229
+ deleteForward: function (evt) {
1208
1230
  evt.allowDefault();
1209
1231
  return YES;
1210
1232
  },
1211
1233
 
1212
1234
  /** @private */
1213
- deleteBackward: function(evt) {
1235
+ deleteBackward: function (evt) {
1214
1236
  evt.allowDefault();
1215
1237
  return YES;
1216
1238
  },
1217
1239
 
1218
1240
  /** @private */
1219
- moveLeft: function(evt) {
1241
+ moveLeft: function (evt) {
1220
1242
  evt.allowDefault();
1221
1243
  return YES;
1222
1244
  },
1223
1245
 
1224
1246
  /** @private */
1225
- moveRight: function(evt) {
1247
+ moveRight: function (evt) {
1226
1248
  evt.allowDefault();
1227
1249
  return YES;
1228
1250
  },
1229
1251
 
1230
1252
  /** @private */
1231
- selectAll: function(evt) {
1253
+ selectAll: function (evt) {
1232
1254
  evt.allowDefault();
1233
1255
  return YES;
1234
1256
  },
1235
1257
 
1236
1258
  /** @private */
1237
- moveUp: function(evt) {
1259
+ moveUp: function (evt) {
1238
1260
  if (this.get('isTextArea')) {
1239
1261
  evt.allowDefault();
1240
1262
  return YES;
@@ -1243,7 +1265,7 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1243
1265
  },
1244
1266
 
1245
1267
  /** @private */
1246
- moveDown: function(evt) {
1268
+ moveDown: function (evt) {
1247
1269
  if (this.get('isTextArea')) {
1248
1270
  evt.allowDefault();
1249
1271
  return YES;
@@ -1259,34 +1281,34 @@ SC.TextFieldView = SC.FieldView.extend(SC.Editable,
1259
1281
  // element's values won't be updated until after this event is finished
1260
1282
  // processing.
1261
1283
  this.notifyPropertyChange('selection');
1262
- this._isKeyDown = NO;
1263
1284
  evt.allowDefault();
1264
1285
  return YES;
1265
1286
  },
1266
1287
 
1267
1288
  mouseDown: function (evt) {
1268
- var fieldValue = this.get('fieldValue'); // use 'fieldValue' since we want actual text
1269
- this._txtFieldMouseDown=YES;
1270
- this.becomeFirstResponder();
1271
1289
  if (!this.get('isEnabledInPane')) {
1272
1290
  evt.stop();
1273
1291
  return YES;
1274
1292
  } else {
1293
+ this._txtFieldMouseDown = YES;
1294
+ this.becomeFirstResponder();
1295
+
1275
1296
  return sc_super();
1276
1297
  }
1277
1298
  },
1278
1299
 
1279
1300
  mouseUp: function (evt) {
1280
- this._txtFieldMouseDown=NO;
1281
- // The caret/selection could have moved. In some browsers, though, the
1282
- // element's values won't be updated until after this event is finished
1283
- // processing.
1284
- this.notifyPropertyChange('selection');
1301
+ this._txtFieldMouseDown = NO;
1285
1302
 
1286
1303
  if (!this.get('isEnabledInPane')) {
1287
1304
  evt.stop();
1288
1305
  return YES;
1289
1306
  }
1307
+
1308
+ // The caret/selection could have moved. In some browsers, though, the
1309
+ // element's values won't be updated until after this event is finished
1310
+ // processing.
1311
+ this.notifyPropertyChange('selection');
1290
1312
  return sc_super();
1291
1313
  },
1292
1314