_ExpandingTextAreaMixin.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. define("dijit/form/_ExpandingTextAreaMixin", [
  2. "dojo/_base/declare", // declare
  3. "dojo/dom-construct", // domConstruct.create
  4. "dojo/_base/lang", // lang.hitch
  5. "dojo/_base/window" // win.body
  6. ], function(declare, domConstruct, lang, win){
  7. // module:
  8. // dijit/form/_ExpandingTextAreaMixin
  9. // summary:
  10. // Mixin for textarea widgets to add auto-expanding capability
  11. // feature detection
  12. var needsHelpShrinking;
  13. return declare("dijit.form._ExpandingTextAreaMixin", null, {
  14. // summary:
  15. // Mixin for textarea widgets to add auto-expanding capability
  16. _setValueAttr: function(){
  17. this.inherited(arguments);
  18. this.resize();
  19. },
  20. postCreate: function(){
  21. this.inherited(arguments);
  22. var textarea = this.textbox;
  23. if(needsHelpShrinking == undefined){
  24. var te = domConstruct.create('textarea', {rows:"5", cols:"20", value: ' ', style: {zoom:1, fontSize:"12px", height:"96px", overflow:'hidden', visibility:'hidden', position:'absolute', border:"5px solid white", margin:"0", padding:"0", boxSizing: 'border-box', MsBoxSizing: 'border-box', WebkitBoxSizing: 'border-box', MozBoxSizing: 'border-box' }}, win.body(), "last");
  25. needsHelpShrinking = te.scrollHeight >= te.clientHeight;
  26. win.body().removeChild(te);
  27. }
  28. this.connect(textarea, "onresize", "_resizeLater");
  29. this.connect(textarea, "onfocus", "_resizeLater");
  30. textarea.style.overflowY = "hidden";
  31. },
  32. startup: function(){
  33. this.inherited(arguments);
  34. this._resizeLater();
  35. },
  36. _onInput: function(e){
  37. this.inherited(arguments);
  38. this.resize();
  39. },
  40. _estimateHeight: function(){
  41. // summary:
  42. // Approximate the height when the textarea is invisible with the number of lines in the text.
  43. // Fails when someone calls setValue with a long wrapping line, but the layout fixes itself when the user clicks inside so . . .
  44. // In IE, the resize event is supposed to fire when the textarea becomes visible again and that will correct the size automatically.
  45. //
  46. var textarea = this.textbox;
  47. // #rows = #newlines+1
  48. textarea.rows = (textarea.value.match(/\n/g) || []).length + 1;
  49. },
  50. _resizeLater: function(){
  51. this.defer("resize");
  52. },
  53. resize: function(){
  54. // summary:
  55. // Resizes the textarea vertically (should be called after a style/value change)
  56. var textarea = this.textbox;
  57. function textareaScrollHeight(){
  58. var empty = false;
  59. if(textarea.value === ''){
  60. textarea.value = ' ';
  61. empty = true;
  62. }
  63. var sh = textarea.scrollHeight;
  64. if(empty){ textarea.value = ''; }
  65. return sh;
  66. }
  67. if(textarea.style.overflowY == "hidden"){ textarea.scrollTop = 0; }
  68. if(this.busyResizing){ return; }
  69. this.busyResizing = true;
  70. if(textareaScrollHeight() || textarea.offsetHeight){
  71. var newH = textareaScrollHeight() + Math.max(textarea.offsetHeight - textarea.clientHeight, 0);
  72. var newHpx = newH + "px";
  73. if(newHpx != textarea.style.height){
  74. textarea.style.height = newHpx;
  75. textarea.rows = 1; // rows can act like a minHeight if not cleared
  76. }
  77. if(needsHelpShrinking){
  78. var origScrollHeight = textareaScrollHeight(),
  79. newScrollHeight = origScrollHeight,
  80. origMinHeight = textarea.style.minHeight,
  81. decrement = 4, // not too fast, not too slow
  82. thisScrollHeight,
  83. origScrollTop = textarea.scrollTop;
  84. textarea.style.minHeight = newHpx; // maintain current height
  85. textarea.style.height = "auto"; // allow scrollHeight to change
  86. while(newH > 0){
  87. textarea.style.minHeight = Math.max(newH - decrement, 4) + "px";
  88. thisScrollHeight = textareaScrollHeight();
  89. var change = newScrollHeight - thisScrollHeight;
  90. newH -= change;
  91. if(change < decrement){
  92. break; // scrollHeight didn't shrink
  93. }
  94. newScrollHeight = thisScrollHeight;
  95. decrement <<= 1;
  96. }
  97. textarea.style.height = newH + "px";
  98. textarea.style.minHeight = origMinHeight;
  99. textarea.scrollTop = origScrollTop;
  100. }
  101. textarea.style.overflowY = textareaScrollHeight() > textarea.clientHeight ? "auto" : "hidden";
  102. if(textarea.style.overflowY == "hidden"){ textarea.scrollTop = 0; }
  103. }else{
  104. // hidden content of unknown size
  105. this._estimateHeight();
  106. }
  107. this.busyResizing = false;
  108. }
  109. });
  110. });