sproutcore 1.10.1 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG +13 -0
  3. data/VERSION.yml +1 -1
  4. data/lib/frameworks/sproutcore/CHANGELOG.md +69 -31
  5. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +14 -0
  6. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/object.js +14 -0
  7. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +7 -2
  8. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +13 -9
  9. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +57 -23
  10. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/enabled_states_test.js +24 -6
  11. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +2 -2
  12. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/enabled.js +63 -13
  13. data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +3 -3
  14. data/lib/frameworks/sproutcore/frameworks/datastore/models/single_attribute.js +7 -1
  15. data/lib/frameworks/sproutcore/frameworks/datastore/system/many_array.js +28 -5
  16. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +15 -0
  17. data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +30 -3
  18. data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +23 -1
  19. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/many_attribute.js +135 -89
  20. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/single_attribute.js +12 -0
  21. data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +18 -6
  22. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/ui.js +58 -20
  23. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/date_field/methods.js +1 -1
  24. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select/methods.js +15 -1
  25. data/lib/frameworks/sproutcore/frameworks/desktop/views/button.js +1 -1
  26. data/lib/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +10 -0
  27. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +1 -1
  28. data/lib/frameworks/sproutcore/frameworks/desktop/views/select.js +24 -23
  29. data/lib/frameworks/sproutcore/frameworks/desktop/views/split.js +4 -0
  30. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/views/popup_button.js +10 -0
  31. data/lib/frameworks/sproutcore/frameworks/foundation/delegates/inline_text_field.js +4 -4
  32. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_mixin.js +33 -16
  33. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/content_value_support.js +14 -6
  34. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/control.js +23 -18
  35. data/lib/frameworks/sproutcore/frameworks/foundation/system/user_defaults.js +4 -4
  36. data/lib/frameworks/sproutcore/frameworks/foundation/tests/delegates/inline_text_field/inline_text_field.js +1 -0
  37. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_mixin_tests.js +78 -0
  38. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_resize_test.js +45 -1
  39. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/content_value_support/content.js +112 -58
  40. data/lib/frameworks/sproutcore/frameworks/foundation/tests/system/image_queue.js +2 -2
  41. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/container/transition_test.js +141 -0
  42. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/methods.js +27 -2
  43. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/ui.js +631 -593
  44. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/swap_fade_color_transition.js +5 -0
  45. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/swap_move_in_transition.js +5 -0
  46. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/swap_reveal_transition.js +68 -1
  47. data/lib/frameworks/sproutcore/frameworks/foundation/views/container.js +128 -49
  48. data/lib/frameworks/sproutcore/frameworks/foundation/views/field.js +33 -8
  49. data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +209 -187
  50. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
  51. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +7 -0
  52. data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +34 -4
  53. data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +0 -2
  54. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +68 -9
  55. data/lib/frameworks/sproutcore/frameworks/testing/system/runner.js +2 -1
  56. data/lib/sproutcore/rack/builder.rb +45 -25
  57. data/sproutcore.gemspec +1 -0
  58. metadata +17 -2
@@ -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