dijit
Version:
Dijit provides a complete collection of user interface controls based on Dojo, giving you the power to create web applications that are highly optimized for usability, performance, internationalization, accessibility, but above all deliver an incredible u
131 lines (117 loc) • 4.42 kB
JavaScript
define([
"dojo/_base/declare", // declare
"dojo/dom-construct", // domConstruct.create
"dojo/has",
"dojo/_base/lang", // lang.hitch
"dojo/on",
"dojo/_base/window", // win.body
"../Viewport"
], function(declare, domConstruct, has, lang, on, win, Viewport){
// module:
// dijit/form/_ExpandingTextAreaMixin
// feature detection, true for mozilla and webkit
has.add("textarea-needs-help-shrinking", function(){
var body = win.body(), // note: if multiple documents exist, doesn't matter which one we use
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' }
}, body, "last");
var needsHelpShrinking = te.scrollHeight >= te.clientHeight;
body.removeChild(te);
return 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;
textarea.style.overflowY = "hidden";
this.own(on(textarea, "focus, resize", lang.hitch(this, "_resizeLater")));
},
startup: function(){
this.inherited(arguments);
this.own(Viewport.on("resize", lang.hitch(this, "_resizeLater")));
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;
// #rows = #newlines+1
textarea.rows = (textarea.value.match(/\n/g) || []).length + 1;
},
_resizeLater: function(){
this.defer("resize");
},
resize: function(){
// summary:
// Resizes the textarea vertically (should be called after a style/value change)
var textarea = this.textbox;
function textareaScrollHeight(){
var empty = false;
if(textarea.value === ''){
textarea.value = ' ';
empty = true;
}
var sh = textarea.scrollHeight;
if(empty){ textarea.value = ''; }
return sh;
}
if(textarea.style.overflowY == "hidden"){ textarea.scrollTop = 0; }
if(this.busyResizing){ return; }
this.busyResizing = true;
if(textareaScrollHeight() || textarea.offsetHeight){
var newH = textareaScrollHeight() + Math.max(textarea.offsetHeight - textarea.clientHeight, 0);
var newHpx = newH + "px";
if(newHpx != textarea.style.height){
textarea.style.height = newHpx;
textarea.rows = 1; // rows can act like a minHeight if not cleared
}
if(has("textarea-needs-help-shrinking")){
var origScrollHeight = textareaScrollHeight(),
newScrollHeight = origScrollHeight,
origMinHeight = textarea.style.minHeight,
decrement = 4, // not too fast, not too slow
thisScrollHeight,
origScrollTop = textarea.scrollTop;
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.scrollTop = origScrollTop;
}
textarea.style.overflowY = textareaScrollHeight() > textarea.clientHeight ? "auto" : "hidden";
if(textarea.style.overflowY == "hidden"){ textarea.scrollTop = 0; }
}else{
// hidden content of unknown size
this._estimateHeight();
}
this.busyResizing = false;
}
});
});