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