128 lines
4.4 KiB
JavaScript
128 lines
4.4 KiB
JavaScript
|
define("dijit/form/_ExpandingTextAreaMixin", [
|
||
|
"dojo/_base/declare", // declare
|
||
|
"dojo/dom-construct", // domConstruct.create
|
||
|
"dojo/_base/lang", // lang.hitch
|
||
|
"dojo/_base/window" // win.body
|
||
|
], function(declare, domConstruct, lang, win){
|
||
|
|
||
|
// module:
|
||
|
// dijit/form/_ExpandingTextAreaMixin
|
||
|
// summary:
|
||
|
// Mixin for textarea widgets to add auto-expanding capability
|
||
|
|
||
|
// feature detection
|
||
|
var needsHelpShrinking;
|
||
|
|
||
|
return declare("dijit.form._ExpandingTextAreaMixin", null, {
|
||
|
// summary:
|
||
|
// Mixin for textarea widgets to add auto-expanding capability
|
||
|
|
||
|
_setValueAttr: function(){
|
||
|
this.inherited(arguments);
|
||
|
this.resize();
|
||
|
},
|
||
|
|
||
|
postCreate: function(){
|
||
|
this.inherited(arguments);
|
||
|
var textarea = this.textbox;
|
||
|
|
||
|
if(needsHelpShrinking == undefined){
|
||
|
var te = domConstruct.create('textarea', {rows:"5", cols:"20", value: ' ', style: {zoom:1, overflow:'hidden', visibility:'hidden', position:'absolute', border:"0px solid black", padding:"0px"}}, win.body(), "last");
|
||
|
needsHelpShrinking = te.scrollHeight >= te.clientHeight;
|
||
|
win.body().removeChild(te);
|
||
|
}
|
||
|
this.connect(textarea, "onscroll", "_resizeLater");
|
||
|
this.connect(textarea, "onresize", "_resizeLater");
|
||
|
this.connect(textarea, "onfocus", "_resizeLater");
|
||
|
textarea.style.overflowY = "hidden";
|
||
|
this._estimateHeight();
|
||
|
this._resizeLater();
|
||
|
},
|
||
|
|
||
|
_onInput: function(e){
|
||
|
this.inherited(arguments);
|
||
|
this.resize();
|
||
|
},
|
||
|
|
||
|
_estimateHeight: function(){
|
||
|
// summary:
|
||
|
// Approximate the height when the textarea is invisible with the number of lines in the text.
|
||
|
// Fails when someone calls setValue with a long wrapping line, but the layout fixes itself when the user clicks inside so . . .
|
||
|
// In IE, the resize event is supposed to fire when the textarea becomes visible again and that will correct the size automatically.
|
||
|
//
|
||
|
var textarea = this.textbox;
|
||
|
textarea.style.height = "auto";
|
||
|
// #rows = #newlines+1
|
||
|
// Note: on Moz, the following #rows appears to be 1 too many.
|
||
|
// Actually, Moz is reserving room for the scrollbar.
|
||
|
// If you increase the font size, this behavior becomes readily apparent as the last line gets cut off without the +1.
|
||
|
textarea.rows = (textarea.value.match(/\n/g) || []).length + 2;
|
||
|
},
|
||
|
|
||
|
_resizeLater: function(){
|
||
|
this.defer("resize");
|
||
|
},
|
||
|
|
||
|
resize: function(){
|
||
|
// summary:
|
||
|
// Resizes the textarea vertically (should be called after a style/value change)
|
||
|
function textareaScrollHeight(){
|
||
|
var empty = false;
|
||
|
if(textarea.value === ''){
|
||
|
textarea.value = ' ';
|
||
|
empty = true;
|
||
|
}
|
||
|
var sh = textarea.scrollHeight;
|
||
|
if(empty){ textarea.value = ''; }
|
||
|
return sh;
|
||
|
}
|
||
|
|
||
|
var textarea = this.textbox;
|
||
|
if(textarea.style.overflowY == "hidden"){ textarea.scrollTop = 0; }
|
||
|
if(this.busyResizing){ return; }
|
||
|
this.busyResizing = true;
|
||
|
if(textareaScrollHeight() || textarea.offsetHeight){
|
||
|
var currentHeight = textarea.style.height;
|
||
|
if(!(/px/.test(currentHeight))){
|
||
|
currentHeight = textareaScrollHeight();
|
||
|
textarea.rows = 1;
|
||
|
textarea.style.height = currentHeight + "px";
|
||
|
}
|
||
|
var newH = Math.max(Math.max(textarea.offsetHeight, parseInt(currentHeight)) - textarea.clientHeight, 0) + textareaScrollHeight();
|
||
|
var newHpx = newH + "px";
|
||
|
if(newHpx != textarea.style.height){
|
||
|
textarea.rows = 1;
|
||
|
textarea.style.height = newHpx;
|
||
|
}
|
||
|
if(needsHelpShrinking){
|
||
|
var origScrollHeight = textareaScrollHeight(),
|
||
|
newScrollHeight = origScrollHeight,
|
||
|
origMinHeight = textarea.style.minHeight,
|
||
|
decrement = 4, // not too fast, not too slow
|
||
|
thisScrollHeight;
|
||
|
textarea.style.minHeight = newHpx; // maintain current height
|
||
|
textarea.style.height = "auto"; // allow scrollHeight to change
|
||
|
while(newH > 0){
|
||
|
textarea.style.minHeight = Math.max(newH - decrement, 4) + "px";
|
||
|
thisScrollHeight = textareaScrollHeight();
|
||
|
var change = newScrollHeight - thisScrollHeight;
|
||
|
newH -= change;
|
||
|
if(change < decrement){
|
||
|
break; // scrollHeight didn't shrink
|
||
|
}
|
||
|
newScrollHeight = thisScrollHeight;
|
||
|
decrement <<= 1;
|
||
|
}
|
||
|
textarea.style.height = newH + "px";
|
||
|
textarea.style.minHeight = origMinHeight;
|
||
|
}
|
||
|
textarea.style.overflowY = textareaScrollHeight() > textarea.clientHeight ? "auto" : "hidden";
|
||
|
}else{
|
||
|
// hidden content of unknown size
|
||
|
this._estimateHeight();
|
||
|
}
|
||
|
this.busyResizing = false;
|
||
|
}
|
||
|
});
|
||
|
});
|