1 if(!dojo._hasResource["dijit.form.Form"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dijit.form.Form"] = true;
3 dojo.provide("dijit.form.Form");
5 dojo.require("dijit._Widget");
6 dojo.require("dijit._Templated");
8 dojo.declare("dijit.form._FormMixin", null,
12 // Widget corresponding to HTML form tag, for validation and serialization
15 // | <form dojoType="dijit.form.Form" id="myForm">
16 // | Name: <input type="text" name="name" />
18 // | myObj = {name: "John Doe"};
19 // | dijit.byId('myForm').setValues(myObj);
21 // | myObj=dijit.byId('myForm').getValues();
25 // * better handling for arrays. Often form elements have names with [] like
26 // * people[3].sex (for a list of people [{name: Bill, sex: M}, ...])
31 dojo.forEach(this.getDescendants(), function(widget){
39 // summary: returns if the form is valid - same as isValid - but
40 // provides a few additional (ui-specific) features.
41 // 1 - it will highlight any sub-widgets that are not
43 // 2 - it will call focus() on the first invalid
46 return dojo.every(dojo.map(this.getDescendants(), function(widget){
47 // Need to set this so that "required" widgets get their
49 widget._hasBeenBlurred = true;
50 var valid = !widget.validate || widget.validate();
51 if (!valid && !didFocus) {
52 // Set focus of the first non-valid widget
53 dijit.scrollIntoView(widget.containerNode||widget.domNode);
61 setValues: function(/*object*/obj){
62 // summary: fill in form values from a JSON structure
64 // generate map from name --> [list of widgets with that name]
66 dojo.forEach(this.getDescendants(), function(widget){
67 if(!widget.name){ return; }
68 var entry = map[widget.name] || (map[widget.name] = [] );
72 // call setValue() or setAttribute('checked') for each widget, according to obj
74 var widgets = map[name], // array of widgets w/this name
75 values = dojo.getObject(name, false, obj); // list of values for those widgets
76 if(!dojo.isArray(values)){
79 if(typeof widgets[0].checked == 'boolean'){
80 // for checkbox/radio, values is a list of which widgets should be checked
81 dojo.forEach(widgets, function(w, i){
82 w.setValue(dojo.indexOf(values, w.value) != -1);
84 }else if(widgets[0]._multiValue){
85 // it takes an array (e.g. multi-select)
86 widgets[0].setValue(values);
88 // otherwise, values is a list of values to be assigned sequentially to each widget
89 dojo.forEach(widgets, function(w, i){
90 w.setValue(values[i]);
96 * TODO: code for plain input boxes (this shouldn't run for inputs that are part of widgets)
98 dojo.forEach(this.containerNode.elements, function(element){
99 if (element.name == ''){return}; // like "continue"
100 var namePath = element.name.split(".");
102 var name=namePath[namePath.length-1];
103 for(var j=1,len2=namePath.length;j<len2;++j){
104 var p=namePath[j - 1];
105 // repeater support block
106 var nameA=p.split("[");
107 if (nameA.length > 1){
108 if(typeof(myObj[nameA[0]]) == "undefined"){
112 nameIndex=parseInt(nameA[1]);
113 if(typeof(myObj[nameA[0]][nameIndex]) == "undefined"){
114 myObj[nameA[0]][nameIndex] = { };
116 myObj=myObj[nameA[0]][nameIndex];
118 } // repeater support ends
120 if(typeof(myObj[p]) == "undefined"){
127 if (typeof(myObj) == "undefined"){
128 return; // like "continue"
130 if (typeof(myObj[name]) == "undefined" && this.ignoreNullValues){
131 return; // like "continue"
134 // TODO: widget values (just call setValue() on the widget)
136 switch(element.type){
138 element.checked = (name in myObj) &&
139 dojo.some(myObj[name], function(val){ return val==element.value; });
142 element.checked = (name in myObj) && myObj[name]==element.value;
144 case "select-multiple":
145 element.selectedIndex=-1;
146 dojo.forEach(element.options, function(option){
147 option.selected = dojo.some(myObj[name], function(val){ return option.value == val; });
151 element.selectedIndex="0";
152 dojo.forEach(element.options, function(option){
153 option.selected = option.value == myObj[name];
160 element.value = myObj[name] || "";
167 getValues: function(){
168 // summary: generate JSON structure from form values
172 dojo.forEach(this.getDescendants(), function(widget){
173 var name = widget.name;
176 // Single value widget (checkbox, radio, or plain <input> type widget
177 var value = (widget.getValue && !widget._getValueDeprecated) ? widget.getValue() : widget.value;
179 // Store widget's value(s) as a scalar, except for checkboxes which are automatically arrays
180 if(typeof widget.checked == 'boolean'){
181 if(/Radio/.test(widget.declaredClass)){
184 dojo.setObject(name, value, obj);
187 // checkbox/toggle button
188 var ary=dojo.getObject(name, false, obj);
191 dojo.setObject(name, ary, obj);
199 dojo.setObject(name, value, obj);
204 * code for plain input boxes (see also dojo.formToObject, can we use that instead of this code?
205 * but it doesn't understand [] notation, presumably)
207 dojo.forEach(this.containerNode.elements, function(elm){
209 return; // like "continue"
211 var namePath = elm.name.split(".");
213 var name=namePath[namePath.length-1];
214 for(var j=1,len2=namePath.length;j<len2;++j){
215 var nameIndex = null;
216 var p=namePath[j - 1];
217 var nameA=p.split("[");
218 if (nameA.length > 1){
219 if(typeof(myObj[nameA[0]]) == "undefined"){
222 nameIndex=parseInt(nameA[1]);
223 if(typeof(myObj[nameA[0]][nameIndex]) == "undefined"){
224 myObj[nameA[0]][nameIndex] = { };
226 } else if(typeof(myObj[nameA[0]]) == "undefined"){
227 myObj[nameA[0]] = { }
230 if (nameA.length == 1){
231 myObj=myObj[nameA[0]];
233 myObj=myObj[nameA[0]][nameIndex];
237 if ((elm.type != "select-multiple" && elm.type != "checkbox" && elm.type != "radio") || (elm.type=="radio" && elm.checked)){
238 if(name == name.split("[")[0]){
239 myObj[name]=elm.value;
241 // can not set value when there is no name
243 } else if (elm.type == "checkbox" && elm.checked){
244 if(typeof(myObj[name]) == 'undefined'){
247 myObj[name].push(elm.value);
248 } else if (elm.type == "select-multiple"){
249 if(typeof(myObj[name]) == 'undefined'){
252 for (var jdx=0,len3=elm.options.length; jdx<len3; ++jdx){
253 if (elm.options[jdx].selected){
254 myObj[name].push(elm.options[jdx].value);
264 // TODO: ComboBox might need time to process a recently input value. This should be async?
266 // summary: make sure that every widget that has a validator function returns true
267 return dojo.every(this.getDescendants(), function(widget){
268 return !widget.isValid || widget.isValid();
275 [dijit._Widget, dijit._Templated, dijit.form._FormMixin],
278 // Adds conveniences to regular HTML form
280 // HTML <FORM> attributes
285 "accept-charset": "",
289 templateString: "<form dojoAttachPoint='containerNode' dojoAttachEvent='onreset:_onReset,onsubmit:_onSubmit' name='${name}'></form>",
291 attributeMap: dojo.mixin(dojo.clone(dijit._Widget.prototype.attributeMap),
292 {action: "", method: "", encType: "", "accept-charset": "", accept: "", target: ""}),
294 execute: function(/*Object*/ formContents){
296 // Deprecated: use submit()
299 onExecute: function(){
301 // Deprecated: use onSubmit()
304 setAttribute: function(/*String*/ attr, /*anything*/ value){
305 this.inherited(arguments);
308 if(dojo.isIE){ this.domNode.encoding = value; }
312 postCreate: function(){
313 // IE tries to hide encType
314 if(dojo.isIE && this.srcNodeRef && this.srcNodeRef.attributes){
315 var item = this.srcNodeRef.attributes.getNamedItem('encType');
316 if(item && !item.specified && (typeof item.value == "string")){
317 this.setAttribute('encType', item.value);
320 this.inherited(arguments);
323 onReset: function(/*Event?*/e){
325 // Callback when user resets the form. This method is intended
326 // to be over-ridden. When the `reset` method is called
327 // programmatically, the return value from `onReset` is used
328 // to compute whether or not resetting should proceed
329 return true; // Boolean
332 _onReset: function(e){
333 // create fake event so we can know if preventDefault() is called
335 returnValue: true, // the IE way
336 preventDefault: function(){ // not IE
337 this.returnValue = false;
339 stopPropagation: function(){}, currentTarget: e.currentTarget, target: e.target
341 // if return value is not exactly false, and haven't called preventDefault(), then reset
342 if(!(this.onReset(faux) === false) && faux.returnValue){
349 _onSubmit: function(e){
350 var fp = dijit.form.Form.prototype;
351 // TODO: remove ths if statement beginning with 2.0
352 if(this.execute != fp.execute || this.onExecute != fp.onExecute){
353 dojo.deprecated("dijit.form.Form:execute()/onExecute() are deprecated. Use onSubmit() instead.", "", "2.0");
355 this.execute(this.getValues());
357 if(this.onSubmit(e) === false){ // only exactly false stops submit
362 onSubmit: function(/*Event?*/e){
364 // Callback when user submits the form. This method is
365 // intended to be over-ridden, but by default it checks and
366 // returns the validity of form elements. When the `submit`
367 // method is called programmatically, the return value from
368 // `onSubmit` is used to compute whether or not submission
371 return this.isValid(); // Boolean
376 // programmatically submit form if and only if the `onSubmit` returns true
377 if(!(this.onSubmit() === false)){
378 this.containerNode.submit();