2150 |
mathias |
1 |
if(!dojo._hasResource["dijit.form.Textarea"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2 |
dojo._hasResource["dijit.form.Textarea"] = true;
|
|
|
3 |
dojo.provide("dijit.form.Textarea");
|
|
|
4 |
|
|
|
5 |
dojo.require("dijit.form._FormWidget");
|
|
|
6 |
dojo.require("dojo.i18n");
|
|
|
7 |
dojo.requireLocalization("dijit", "Textarea", null, "ROOT");
|
|
|
8 |
|
|
|
9 |
dojo.declare(
|
|
|
10 |
"dijit.form.Textarea",
|
|
|
11 |
dijit.form._FormWidget,
|
|
|
12 |
{
|
|
|
13 |
// summary
|
|
|
14 |
// A textarea that resizes vertically to contain the data.
|
|
|
15 |
// Takes nearly all the parameters (name, value, etc.) that a vanilla textarea takes.
|
|
|
16 |
// Cols is not supported and the width should be specified with style width.
|
|
|
17 |
// Rows is not supported since this widget adjusts the height.
|
|
|
18 |
// usage:
|
|
|
19 |
// <textarea dojoType="dijit.form.TextArea">...</textarea>
|
|
|
20 |
|
|
|
21 |
attributeMap: dojo.mixin(dojo.clone(dijit.form._FormWidget.prototype.attributeMap),
|
|
|
22 |
{style:"styleNode", 'class':"styleNode"}),
|
|
|
23 |
|
|
|
24 |
templateString: (dojo.isIE || dojo.isSafari || dojo.isMozilla) ?
|
|
|
25 |
((dojo.isIE || dojo.isSafari) ? '<fieldset id="${id}" class="dijitInline dijitInputField dijitTextArea" dojoAttachPoint="styleNode" waiRole="presentation"><div dojoAttachPoint="editNode,focusNode,eventNode" dojoAttachEvent="onpaste:_changing,oncut:_changing" waiRole="textarea" style="text-decoration:none;_padding-bottom:16px;display:block;overflow:auto;" contentEditable="true"></div>'
|
|
|
26 |
: '<span id="${id}" class="dijitReset">'+
|
|
|
27 |
'<iframe src="javascript:<html><head><title>${_iframeEditTitle}</title></head><body><script>var _postCreate=window.frameElement?window.frameElement.postCreate:null;if(_postCreate)_postCreate();</script></body></html>"'+
|
|
|
28 |
' dojoAttachPoint="iframe,styleNode" dojoAttachEvent="onblur:_onIframeBlur" class="dijitInline dijitInputField dijitTextArea"></iframe>')
|
|
|
29 |
+ '<textarea name="${name}" value="${value}" dojoAttachPoint="formValueNode" style="display:none;"></textarea>'
|
|
|
30 |
+ ((dojo.isIE || dojo.isSafari) ? '</fieldset>':'</span>')
|
|
|
31 |
: '<textarea id="${id}" name="${name}" value="${value}" dojoAttachPoint="formValueNode,editNode,focusNode,styleNode" class="dijitInputField dijitTextArea"></textarea>',
|
|
|
32 |
|
|
|
33 |
focus: function(){
|
|
|
34 |
// summary: Received focus, needed for the InlineEditBox widget
|
|
|
35 |
if(!this.disabled){
|
|
|
36 |
this._changing(); // set initial height
|
|
|
37 |
}
|
|
|
38 |
if(dojo.isMozilla){
|
|
|
39 |
dijit.focus(this.iframe);
|
|
|
40 |
}else{
|
|
|
41 |
dijit.focus(this.focusNode);
|
|
|
42 |
}
|
|
|
43 |
},
|
|
|
44 |
|
|
|
45 |
setValue: function(/*String*/ value, /*Boolean, optional*/ priorityChange){
|
|
|
46 |
var editNode = this.editNode;
|
|
|
47 |
if(typeof value == "string"){
|
|
|
48 |
editNode.innerHTML = ""; // wipe out old nodes
|
|
|
49 |
if(value.split){
|
|
|
50 |
var _this=this;
|
|
|
51 |
var isFirst = true;
|
|
|
52 |
dojo.forEach(value.split("\n"), function(line){
|
|
|
53 |
if(isFirst){ isFirst = false; }
|
|
|
54 |
else {
|
|
|
55 |
editNode.appendChild(document.createElement("BR")); // preserve line breaks
|
|
|
56 |
}
|
|
|
57 |
editNode.appendChild(document.createTextNode(line)); // use text nodes so that imbedded tags can be edited
|
|
|
58 |
});
|
|
|
59 |
}else{
|
|
|
60 |
editNode.appendChild(document.createTextNode(value));
|
|
|
61 |
}
|
|
|
62 |
}else{
|
|
|
63 |
// blah<BR>blah --> blah\nblah
|
|
|
64 |
// <P>blah</P><P>blah</P> --> blah\nblah
|
|
|
65 |
// <DIV>blah</DIV><DIV>blah</DIV> --> blah\nblah
|
|
|
66 |
// &<> -->&< >
|
|
|
67 |
value = editNode.innerHTML;
|
|
|
68 |
if(this.iframe){ // strip sizeNode
|
|
|
69 |
value = value.replace(/<div><\/div>\r?\n?$/i,"");
|
|
|
70 |
}
|
|
|
71 |
value = value.replace(/\s*\r?\n|^\s+|\s+$| /g,"").replace(/>\s+</g,"><").replace(/<\/(p|div)>$|^<(p|div)[^>]*>/gi,"").replace(/([^>])<div>/g,"$1\n").replace(/<\/p>\s*<p[^>]*>|<br[^>]*>/gi,"\n").replace(/<[^>]*>/g,"").replace(/&/gi,"\&").replace(/</gi,"<").replace(/>/gi,">");
|
|
|
72 |
}
|
|
|
73 |
this.value = this.formValueNode.value = value;
|
|
|
74 |
if(this.iframe){
|
|
|
75 |
var sizeNode = document.createElement('div');
|
|
|
76 |
editNode.appendChild(sizeNode);
|
|
|
77 |
var newHeight = sizeNode.offsetTop;
|
|
|
78 |
if(editNode.scrollWidth > editNode.clientWidth){ newHeight+=16; } // scrollbar space needed?
|
|
|
79 |
if(this.lastHeight != newHeight){ // cache size so that we don't get a resize event because of a resize event
|
|
|
80 |
if(newHeight == 0){ newHeight = 16; } // height = 0 causes the browser to not set scrollHeight
|
|
|
81 |
dojo.contentBox(this.iframe, {h: newHeight});
|
|
|
82 |
this.lastHeight = newHeight;
|
|
|
83 |
}
|
|
|
84 |
editNode.removeChild(sizeNode);
|
|
|
85 |
}
|
|
|
86 |
dijit.form.Textarea.superclass.setValue.call(this, this.getValue(), priorityChange);
|
|
|
87 |
},
|
|
|
88 |
|
|
|
89 |
getValue: function(){
|
|
|
90 |
return this.formValueNode.value.replace(/\r/g,"");
|
|
|
91 |
},
|
|
|
92 |
|
|
|
93 |
postMixInProperties: function(){
|
|
|
94 |
dijit.form.Textarea.superclass.postMixInProperties.apply(this,arguments);
|
|
|
95 |
// don't let the source text be converted to a DOM structure since we just want raw text
|
|
|
96 |
if(this.srcNodeRef && this.srcNodeRef.innerHTML != ""){
|
|
|
97 |
this.value = this.srcNodeRef.innerHTML;
|
|
|
98 |
this.srcNodeRef.innerHTML = "";
|
|
|
99 |
}
|
|
|
100 |
if((!this.value || this.value == "") && this.srcNodeRef && this.srcNodeRef.value){
|
|
|
101 |
this.value = this.srcNodeRef.value;
|
|
|
102 |
}
|
|
|
103 |
if(!this.value){ this.value = ""; }
|
|
|
104 |
this.value = this.value.replace(/\r\n/g,"\n").replace(/>/g,">").replace(/</g,"<").replace(/&/g,"&");
|
|
|
105 |
if(dojo.isMozilla){
|
|
|
106 |
// In the case of Firefox an iframe is used and when the text gets focus,
|
|
|
107 |
// focus is fired from the document object. There isn't a way to put a
|
|
|
108 |
// waiRole on the document object and as a result screen readers don't
|
|
|
109 |
// announce the role. As a result screen reader users are lost.
|
|
|
110 |
//
|
|
|
111 |
// An additional problem is that the browser gives the document object a
|
|
|
112 |
// very cryptic accessible name, e.g.
|
|
|
113 |
// wysiwyg://13/http://archive.dojotoolkit.org/nightly/dojotoolkit/dijit/tests/form/test_InlineEditBox.html
|
|
|
114 |
// When focus is fired from the document object, the screen reader speaks
|
|
|
115 |
// the accessible name. The cyptic accessile name is confusing.
|
|
|
116 |
//
|
|
|
117 |
// A workaround for both of these problems is to give the iframe's
|
|
|
118 |
// document a title, the name of which is similar to a role name, i.e.
|
|
|
119 |
// "edit area". This will be used as the accessible name which will replace
|
|
|
120 |
// the cryptic name and will also convey the role information to the user.
|
|
|
121 |
// Because it is read directly to the user, the string must be localized.
|
|
|
122 |
// In addition, since a <label> element can not be associated with an iframe, if
|
|
|
123 |
// this control has a label, insert the text into the title as well.
|
|
|
124 |
var _nlsResources = dojo.i18n.getLocalization("dijit", "Textarea");
|
|
|
125 |
this._iframeEditTitle = _nlsResources.iframeEditTitle;
|
|
|
126 |
this._iframeFocusTitle = _nlsResources.iframeFocusTitle;
|
|
|
127 |
var label=dojo.query('label[for="'+this.id+'"]');
|
|
|
128 |
if(label.length){
|
|
|
129 |
this._iframeEditTitle = label[0].innerHTML + " " + this._iframeEditTitle;
|
|
|
130 |
}
|
|
|
131 |
var body = this.focusNode = this.editNode = document.createElement('BODY');
|
|
|
132 |
body.style.margin="0px";
|
|
|
133 |
body.style.padding="0px";
|
|
|
134 |
body.style.border="0px";
|
|
|
135 |
}
|
|
|
136 |
},
|
|
|
137 |
|
|
|
138 |
postCreate: function(){
|
|
|
139 |
if(dojo.isIE || dojo.isSafari){
|
|
|
140 |
this.domNode.style.overflowY = 'hidden';
|
|
|
141 |
}else if(dojo.isMozilla){
|
|
|
142 |
var w = this.iframe.contentWindow;
|
|
|
143 |
try { // #4715: peeking at the title can throw a security exception during iframe setup
|
|
|
144 |
var title = this.iframe.contentDocument.title;
|
|
|
145 |
} catch(e) { var title = ''; }
|
|
|
146 |
if(!w || !title){
|
|
|
147 |
this.iframe.postCreate = dojo.hitch(this, this.postCreate);
|
|
|
148 |
return;
|
|
|
149 |
}
|
|
|
150 |
var d = w.document;
|
|
|
151 |
d.getElementsByTagName('HTML')[0].replaceChild(this.editNode, d.getElementsByTagName('BODY')[0]);
|
|
|
152 |
if(!this.isLeftToRight()){
|
|
|
153 |
d.getElementsByTagName('HTML')[0].dir = "rtl";
|
|
|
154 |
}
|
|
|
155 |
this.iframe.style.overflowY = 'hidden';
|
|
|
156 |
this.eventNode = d;
|
|
|
157 |
// this.connect won't destroy this handler cleanly since its on the iframe's window object
|
|
|
158 |
// resize is a method of window, not document
|
|
|
159 |
w.addEventListener("resize", dojo.hitch(this, this._changed), false); // resize is only on the window object
|
|
|
160 |
}else{
|
|
|
161 |
this.focusNode = this.domNode;
|
|
|
162 |
}
|
|
|
163 |
if(this.eventNode){
|
|
|
164 |
this.connect(this.eventNode, "keypress", this._onKeyPress);
|
|
|
165 |
this.connect(this.eventNode, "mousemove", this._changed);
|
|
|
166 |
this.connect(this.eventNode, "focus", this._focused);
|
|
|
167 |
this.connect(this.eventNode, "blur", this._blurred);
|
|
|
168 |
}
|
|
|
169 |
if(this.editNode){
|
|
|
170 |
this.connect(this.editNode, "change", this._changed); // needed for mouse paste events per #3479
|
|
|
171 |
}
|
|
|
172 |
this.inherited('postCreate', arguments);
|
|
|
173 |
},
|
|
|
174 |
|
|
|
175 |
// event handlers, you can over-ride these in your own subclasses
|
|
|
176 |
_focused: function(e){
|
|
|
177 |
dojo.addClass(this.iframe||this.domNode, "dijitInputFieldFocused");
|
|
|
178 |
this._changed(e);
|
|
|
179 |
},
|
|
|
180 |
|
|
|
181 |
_blurred: function(e){
|
|
|
182 |
dojo.removeClass(this.iframe||this.domNode, "dijitInputFieldFocused");
|
|
|
183 |
this._changed(e, true);
|
|
|
184 |
},
|
|
|
185 |
|
|
|
186 |
_onIframeBlur: function(){
|
|
|
187 |
// Reset the title back to "edit area".
|
|
|
188 |
this.iframe.contentDocument.title = this._iframeEditTitle;
|
|
|
189 |
},
|
|
|
190 |
|
|
|
191 |
_onKeyPress: function(e){
|
|
|
192 |
if(e.keyCode == dojo.keys.TAB && !e.shiftKey && !e.ctrlKey && !e.altKey && this.iframe){
|
|
|
193 |
// Pressing the tab key in the iframe (with designMode on) will cause the
|
|
|
194 |
// entry of a tab character so we have to trap that here. Since we don't
|
|
|
195 |
// know the next focusable object we put focus on the iframe and then the
|
|
|
196 |
// user has to press tab again (which then does the expected thing).
|
|
|
197 |
// A problem with that is that the screen reader user hears "edit area"
|
|
|
198 |
// announced twice which causes confusion. By setting the
|
|
|
199 |
// contentDocument's title to "edit area frame" the confusion should be
|
|
|
200 |
// eliminated.
|
|
|
201 |
this.iframe.contentDocument.title = this._iframeFocusTitle;
|
|
|
202 |
// Place focus on the iframe. A subsequent tab or shift tab will put focus
|
|
|
203 |
// on the correct control.
|
|
|
204 |
// Note: Can't use this.focus() because that results in a call to
|
|
|
205 |
// dijit.focus and if that receives an iframe target it will set focus
|
|
|
206 |
// on the iframe's contentWindow.
|
|
|
207 |
this.iframe.focus(); // this.focus(); won't work
|
|
|
208 |
dojo.stopEvent(e);
|
|
|
209 |
}else if(e.keyCode == dojo.keys.ENTER){
|
|
|
210 |
e.stopPropagation();
|
|
|
211 |
}else if(this.inherited("_onKeyPress", arguments) && this.iframe){
|
|
|
212 |
// #3752:
|
|
|
213 |
// The key press will not make it past the iframe.
|
|
|
214 |
// If a widget is listening outside of the iframe, (like InlineEditBox)
|
|
|
215 |
// it will not hear anything.
|
|
|
216 |
// Create an equivalent event so everyone else knows what is going on.
|
|
|
217 |
var te = document.createEvent("KeyEvents");
|
|
|
218 |
te.initKeyEvent("keypress", true, true, null, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.keyCode, e.charCode);
|
|
|
219 |
this.iframe.dispatchEvent(te);
|
|
|
220 |
}
|
|
|
221 |
this._changing();
|
|
|
222 |
},
|
|
|
223 |
|
|
|
224 |
_changing: function(e){
|
|
|
225 |
// summary: event handler for when a change is imminent
|
|
|
226 |
setTimeout(dojo.hitch(this, "_changed", e, false), 1);
|
|
|
227 |
},
|
|
|
228 |
|
|
|
229 |
_changed: function(e, priorityChange){
|
|
|
230 |
// summary: event handler for when a change has already happened
|
|
|
231 |
if(this.iframe && this.iframe.contentDocument.designMode != "on"){
|
|
|
232 |
this.iframe.contentDocument.designMode="on"; // in case this failed on init due to being hidden
|
|
|
233 |
}
|
|
|
234 |
this.setValue(null, priorityChange);
|
|
|
235 |
}
|
|
|
236 |
});
|
|
|
237 |
|
|
|
238 |
}
|