Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / src / widgets / form / Action.js
1 /*!
2  * Ext JS Library 3.0.3
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**\r
8  * @class Ext.form.Action\r
9  * <p>The subclasses of this class provide actions to perform upon {@link Ext.form.BasicForm Form}s.</p>\r
10  * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when\r
11  * the Form needs to perform an action such as submit or load. The Configuration options\r
12  * listed for this class are set through the Form's action methods: {@link Ext.form.BasicForm#submit submit},\r
13  * {@link Ext.form.BasicForm#load load} and {@link Ext.form.BasicForm#doAction doAction}</p>\r
14  * <p>The instance of Action which performed the action is passed to the success\r
15  * and failure callbacks of the Form's action methods ({@link Ext.form.BasicForm#submit submit},\r
16  * {@link Ext.form.BasicForm#load load} and {@link Ext.form.BasicForm#doAction doAction}),\r
17  * and to the {@link Ext.form.BasicForm#actioncomplete actioncomplete} and\r
18  * {@link Ext.form.BasicForm#actionfailed actionfailed} event handlers.</p>\r
19  */\r
20 Ext.form.Action = function(form, options){\r
21     this.form = form;\r
22     this.options = options || {};\r
23 };\r
24 \r
25 /**\r
26  * Failure type returned when client side validation of the Form fails\r
27  * thus aborting a submit action. Client side validation is performed unless\r
28  * {@link #clientValidation} is explicitly set to <tt>false</tt>.\r
29  * @type {String}\r
30  * @static\r
31  */\r
32 Ext.form.Action.CLIENT_INVALID = 'client';\r
33 /**\r
34  * <p>Failure type returned when server side processing fails and the {@link #result}'s\r
35  * <tt style="font-weight:bold">success</tt> property is set to <tt>false</tt>.</p>\r
36  * <p>In the case of a form submission, field-specific error messages may be returned in the\r
37  * {@link #result}'s <tt style="font-weight:bold">errors</tt> property.</p>\r
38  * @type {String}\r
39  * @static\r
40  */\r
41 Ext.form.Action.SERVER_INVALID = 'server';\r
42 /**\r
43  * Failure type returned when a communication error happens when attempting\r
44  * to send a request to the remote server. The {@link #response} may be examined to\r
45  * provide further information.\r
46  * @type {String}\r
47  * @static\r
48  */\r
49 Ext.form.Action.CONNECT_FAILURE = 'connect';\r
50 /**\r
51  * Failure type returned when the response's <tt style="font-weight:bold">success</tt>\r
52  * property is set to <tt>false</tt>, or no field values are returned in the response's\r
53  * <tt style="font-weight:bold">data</tt> property.\r
54  * @type {String}\r
55  * @static\r
56  */\r
57 Ext.form.Action.LOAD_FAILURE = 'load';\r
58 \r
59 Ext.form.Action.prototype = {\r
60 /**\r
61  * @cfg {String} url The URL that the Action is to invoke.\r
62  */\r
63 /**\r
64  * @cfg {Boolean} reset When set to <tt><b>true</b></tt>, causes the Form to be\r
65  * {@link Ext.form.BasicForm.reset reset} on Action success. If specified, this happens\r
66  * <b>before</b> the {@link #success} callback is called and before the Form's\r
67  * {@link Ext.form.BasicForm.actioncomplete actioncomplete} event fires.\r
68  */\r
69 /**\r
70  * @cfg {String} method The HTTP method to use to access the requested URL. Defaults to the\r
71  * {@link Ext.form.BasicForm}'s method, or if that is not specified, the underlying DOM form's method.\r
72  */\r
73 /**\r
74  * @cfg {Mixed} params <p>Extra parameter values to pass. These are added to the Form's\r
75  * {@link Ext.form.BasicForm#baseParams} and passed to the specified URL along with the Form's\r
76  * input fields.</p>\r
77  * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p>\r
78  */\r
79 /**\r
80  * @cfg {Number} timeout The number of seconds to wait for a server response before\r
81  * failing with the {@link #failureType} as {@link #Action.CONNECT_FAILURE}. If not specified,\r
82  * defaults to the configured <tt>{@link Ext.form.BasicForm#timeout timeout}</tt> of the\r
83  * {@link Ext.form.BasicForm form}.\r
84  */\r
85 /**\r
86  * @cfg {Function} success The function to call when a valid success return packet is recieved.\r
87  * The function is passed the following parameters:<ul class="mdetail-params">\r
88  * <li><b>form</b> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>\r
89  * <li><b>action</b> : Ext.form.Action<div class="sub-desc">The Action class. The {@link #result}\r
90  * property of this object may be examined to perform custom postprocessing.</div></li>\r
91  * </ul>\r
92  */\r
93 /**\r
94  * @cfg {Function} failure The function to call when a failure packet was recieved, or when an\r
95  * error ocurred in the Ajax communication.\r
96  * The function is passed the following parameters:<ul class="mdetail-params">\r
97  * <li><b>form</b> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>\r
98  * <li><b>action</b> : Ext.form.Action<div class="sub-desc">The Action class. If an Ajax\r
99  * error ocurred, the failure type will be in {@link #failureType}. The {@link #result}\r
100  * property of this object may be examined to perform custom postprocessing.</div></li>\r
101  * </ul>\r
102  */\r
103 /**\r
104  * @cfg {Object} scope The scope in which to call the callback functions (The <tt>this</tt> reference\r
105  * for the callback functions).\r
106  */\r
107 /**\r
108  * @cfg {String} waitMsg The message to be displayed by a call to {@link Ext.MessageBox#wait}\r
109  * during the time the action is being processed.\r
110  */\r
111 /**\r
112  * @cfg {String} waitTitle The title to be displayed by a call to {@link Ext.MessageBox#wait}\r
113  * during the time the action is being processed.\r
114  */\r
115 \r
116 /**\r
117  * The type of action this Action instance performs.\r
118  * Currently only "submit" and "load" are supported.\r
119  * @type {String}\r
120  */\r
121     type : 'default',\r
122 /**\r
123  * The type of failure detected will be one of these: {@link #CLIENT_INVALID},\r
124  * {@link #SERVER_INVALID}, {@link #CONNECT_FAILURE}, or {@link #LOAD_FAILURE}.  Usage:\r
125  * <pre><code>\r
126 var fp = new Ext.form.FormPanel({\r
127 ...\r
128 buttons: [{\r
129     text: 'Save',\r
130     formBind: true,\r
131     handler: function(){\r
132         if(fp.getForm().isValid()){\r
133             fp.getForm().submit({\r
134                 url: 'form-submit.php',\r
135                 waitMsg: 'Submitting your data...',\r
136                 success: function(form, action){\r
137                     // server responded with success = true\r
138                     var result = action.{@link #result};\r
139                 },\r
140                 failure: function(form, action){\r
141                     if (action.{@link #failureType} === Ext.form.Action.{@link #CONNECT_FAILURE}) {\r
142                         Ext.Msg.alert('Error',\r
143                             'Status:'+action.{@link #response}.status+': '+\r
144                             action.{@link #response}.statusText);\r
145                     }\r
146                     if (action.failureType === Ext.form.Action.{@link #SERVER_INVALID}){\r
147                         // server responded with success = false\r
148                         Ext.Msg.alert('Invalid', action.{@link #result}.errormsg);\r
149                     }\r
150                 }\r
151             });\r
152         }\r
153     }\r
154 },{\r
155     text: 'Reset',\r
156     handler: function(){\r
157         fp.getForm().reset();\r
158     }\r
159 }]\r
160  * </code></pre>\r
161  * @property failureType\r
162  * @type {String}\r
163  */\r
164  /**\r
165  * The XMLHttpRequest object used to perform the action.\r
166  * @property response\r
167  * @type {Object}\r
168  */\r
169  /**\r
170  * The decoded response object containing a boolean <tt style="font-weight:bold">success</tt> property and\r
171  * other, action-specific properties.\r
172  * @property result\r
173  * @type {Object}\r
174  */\r
175 \r
176     // interface method\r
177     run : function(options){\r
178 \r
179     },\r
180 \r
181     // interface method\r
182     success : function(response){\r
183 \r
184     },\r
185 \r
186     // interface method\r
187     handleResponse : function(response){\r
188 \r
189     },\r
190 \r
191     // default connection failure\r
192     failure : function(response){\r
193         this.response = response;\r
194         this.failureType = Ext.form.Action.CONNECT_FAILURE;\r
195         this.form.afterAction(this, false);\r
196     },\r
197 \r
198     // private\r
199     // shared code among all Actions to validate that there was a response\r
200     // with either responseText or responseXml\r
201     processResponse : function(response){\r
202         this.response = response;\r
203         if(!response.responseText && !response.responseXML){\r
204             return true;\r
205         }\r
206         this.result = this.handleResponse(response);\r
207         return this.result;\r
208     },\r
209 \r
210     // utility functions used internally\r
211     getUrl : function(appendParams){\r
212         var url = this.options.url || this.form.url || this.form.el.dom.action;\r
213         if(appendParams){\r
214             var p = this.getParams();\r
215             if(p){\r
216                 url = Ext.urlAppend(url, p);\r
217             }\r
218         }\r
219         return url;\r
220     },\r
221 \r
222     // private\r
223     getMethod : function(){\r
224         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();\r
225     },\r
226 \r
227     // private\r
228     getParams : function(){\r
229         var bp = this.form.baseParams;\r
230         var p = this.options.params;\r
231         if(p){\r
232             if(typeof p == "object"){\r
233                 p = Ext.urlEncode(Ext.applyIf(p, bp));\r
234             }else if(typeof p == 'string' && bp){\r
235                 p += '&' + Ext.urlEncode(bp);\r
236             }\r
237         }else if(bp){\r
238             p = Ext.urlEncode(bp);\r
239         }\r
240         return p;\r
241     },\r
242 \r
243     // private\r
244     createCallback : function(opts){\r
245         var opts = opts || {};\r
246         return {\r
247             success: this.success,\r
248             failure: this.failure,\r
249             scope: this,\r
250             timeout: (opts.timeout*1000) || (this.form.timeout*1000),\r
251             upload: this.form.fileUpload ? this.success : undefined\r
252         };\r
253     }\r
254 };\r
255 \r
256 /**\r
257  * @class Ext.form.Action.Submit\r
258  * @extends Ext.form.Action\r
259  * <p>A class which handles submission of data from {@link Ext.form.BasicForm Form}s\r
260  * and processes the returned response.</p>\r
261  * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when\r
262  * {@link Ext.form.BasicForm#submit submit}ting.</p>\r
263  * <p><u><b>Response Packet Criteria</b></u></p>\r
264  * <p>A response packet may contain:\r
265  * <div class="mdetail-params"><ul>\r
266  * <li><b><code>success</code></b> property : Boolean\r
267  * <div class="sub-desc">The <code>success</code> property is required.</div></li>\r
268  * <li><b><code>errors</code></b> property : Object\r
269  * <div class="sub-desc"><div class="sub-desc">The <code>errors</code> property,\r
270  * which is optional, contains error messages for invalid fields.</div></li>\r
271  * </ul></div>\r
272  * <p><u><b>JSON Packets</b></u></p>\r
273  * <p>By default, response packets are assumed to be JSON, so a typical response\r
274  * packet may look like this:</p><pre><code>\r
275 {\r
276     success: false,\r
277     errors: {\r
278         clientCode: "Client not found",\r
279         portOfLoading: "This field must not be null"\r
280     }\r
281 }</code></pre>\r
282  * <p>Other data may be placed into the response for processing by the {@link Ext.form.BasicForm}'s callback\r
283  * or event handler methods. The object decoded from this JSON is available in the\r
284  * {@link Ext.form.Action#result result} property.</p>\r
285  * <p>Alternatively, if an {@link #errorReader} is specified as an {@link Ext.data.XmlReader XmlReader}:</p><pre><code>\r
286     errorReader: new Ext.data.XmlReader({\r
287             record : 'field',\r
288             success: '@success'\r
289         }, [\r
290             'id', 'msg'\r
291         ]\r
292     )\r
293 </code></pre>\r
294  * <p>then the results may be sent back in XML format:</p><pre><code>\r
295 &lt;?xml version="1.0" encoding="UTF-8"?&gt;\r
296 &lt;message success="false"&gt;\r
297 &lt;errors&gt;\r
298     &lt;field&gt;\r
299         &lt;id&gt;clientCode&lt;/id&gt;\r
300         &lt;msg&gt;&lt;![CDATA[Code not found. &lt;br /&gt;&lt;i&gt;This is a test validation message from the server &lt;/i&gt;]]&gt;&lt;/msg&gt;\r
301     &lt;/field&gt;\r
302     &lt;field&gt;\r
303         &lt;id&gt;portOfLoading&lt;/id&gt;\r
304         &lt;msg&gt;&lt;![CDATA[Port not found. &lt;br /&gt;&lt;i&gt;This is a test validation message from the server &lt;/i&gt;]]&gt;&lt;/msg&gt;\r
305     &lt;/field&gt;\r
306 &lt;/errors&gt;\r
307 &lt;/message&gt;\r
308 </code></pre>\r
309  * <p>Other elements may be placed into the response XML for processing by the {@link Ext.form.BasicForm}'s callback\r
310  * or event handler methods. The XML document is available in the {@link #errorReader}'s {@link Ext.data.XmlReader#xmlData xmlData} property.</p>\r
311  */\r
312 Ext.form.Action.Submit = function(form, options){\r
313     Ext.form.Action.Submit.superclass.constructor.call(this, form, options);\r
314 };\r
315 \r
316 Ext.extend(Ext.form.Action.Submit, Ext.form.Action, {\r
317     /**\r
318      * @cfg {Ext.data.DataReader} errorReader <p><b>Optional. JSON is interpreted with\r
319      * no need for an errorReader.</b></p>\r
320      * <p>A Reader which reads a single record from the returned data. The DataReader's\r
321      * <b>success</b> property specifies how submission success is determined. The Record's\r
322      * data provides the error messages to apply to any invalid form Fields.</p>\r
323      */\r
324     /**\r
325      * @cfg {boolean} clientValidation Determines whether a Form's fields are validated\r
326      * in a final call to {@link Ext.form.BasicForm#isValid isValid} prior to submission.\r
327      * Pass <tt>false</tt> in the Form's submit options to prevent this. If not defined, pre-submission field validation\r
328      * is performed.\r
329      */\r
330     type : 'submit',\r
331 \r
332     // private\r
333     run : function(){\r
334         var o = this.options;\r
335         var method = this.getMethod();\r
336         var isGet = method == 'GET';\r
337         if(o.clientValidation === false || this.form.isValid()){\r
338             Ext.Ajax.request(Ext.apply(this.createCallback(o), {\r
339                 form:this.form.el.dom,\r
340                 url:this.getUrl(isGet),\r
341                 method: method,\r
342                 headers: o.headers,\r
343                 params:!isGet ? this.getParams() : null,\r
344                 isUpload: this.form.fileUpload\r
345             }));\r
346         }else if (o.clientValidation !== false){ // client validation failed\r
347             this.failureType = Ext.form.Action.CLIENT_INVALID;\r
348             this.form.afterAction(this, false);\r
349         }\r
350     },\r
351 \r
352     // private\r
353     success : function(response){\r
354         var result = this.processResponse(response);\r
355         if(result === true || result.success){\r
356             this.form.afterAction(this, true);\r
357             return;\r
358         }\r
359         if(result.errors){\r
360             this.form.markInvalid(result.errors);\r
361         }\r
362         this.failureType = Ext.form.Action.SERVER_INVALID;\r
363         this.form.afterAction(this, false);\r
364     },\r
365 \r
366     // private\r
367     handleResponse : function(response){\r
368         if(this.form.errorReader){\r
369             var rs = this.form.errorReader.read(response);\r
370             var errors = [];\r
371             if(rs.records){\r
372                 for(var i = 0, len = rs.records.length; i < len; i++) {\r
373                     var r = rs.records[i];\r
374                     errors[i] = r.data;\r
375                 }\r
376             }\r
377             if(errors.length < 1){\r
378                 errors = null;\r
379             }\r
380             return {\r
381                 success : rs.success,\r
382                 errors : errors\r
383             };\r
384         }\r
385         return Ext.decode(response.responseText);\r
386     }\r
387 });\r
388 \r
389 \r
390 /**\r
391  * @class Ext.form.Action.Load\r
392  * @extends Ext.form.Action\r
393  * <p>A class which handles loading of data from a server into the Fields of an {@link Ext.form.BasicForm}.</p>\r
394  * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when\r
395  * {@link Ext.form.BasicForm#load load}ing.</p>\r
396  * <p><u><b>Response Packet Criteria</b></u></p>\r
397  * <p>A response packet <b>must</b> contain:\r
398  * <div class="mdetail-params"><ul>\r
399  * <li><b><code>success</code></b> property : Boolean</li>\r
400  * <li><b><code>data</code></b> property : Object</li>\r
401  * <div class="sub-desc">The <code>data</code> property contains the values of Fields to load.\r
402  * The individual value object for each Field is passed to the Field's\r
403  * {@link Ext.form.Field#setValue setValue} method.</div></li>\r
404  * </ul></div>\r
405  * <p><u><b>JSON Packets</b></u></p>\r
406  * <p>By default, response packets are assumed to be JSON, so for the following form load call:<pre><code>\r
407 var myFormPanel = new Ext.form.FormPanel({\r
408     title: 'Client and routing info',\r
409     items: [{\r
410         fieldLabel: 'Client',\r
411         name: 'clientName'\r
412     }, {\r
413         fieldLabel: 'Port of loading',\r
414         name: 'portOfLoading'\r
415     }, {\r
416         fieldLabel: 'Port of discharge',\r
417         name: 'portOfDischarge'\r
418     }]\r
419 });\r
420 myFormPanel.{@link Ext.form.FormPanel#getForm getForm}().{@link Ext.form.BasicForm#load load}({\r
421     url: '/getRoutingInfo.php',\r
422     params: {\r
423         consignmentRef: myConsignmentRef\r
424     },\r
425     failure: function(form, action) {\r
426         Ext.Msg.alert("Load failed", action.result.errorMessage);\r
427     }\r
428 });\r
429 </code></pre>\r
430  * a <b>success response</b> packet may look like this:</p><pre><code>\r
431 {\r
432     success: true,\r
433     data: {\r
434         clientName: "Fred. Olsen Lines",\r
435         portOfLoading: "FXT",\r
436         portOfDischarge: "OSL"\r
437     }\r
438 }</code></pre>\r
439  * while a <b>failure response</b> packet may look like this:</p><pre><code>\r
440 {\r
441     success: false,\r
442     errorMessage: "Consignment reference not found"\r
443 }</code></pre>\r
444  * <p>Other data may be placed into the response for processing the {@link Ext.form.BasicForm Form}'s\r
445  * callback or event handler methods. The object decoded from this JSON is available in the\r
446  * {@link Ext.form.Action#result result} property.</p>\r
447  */\r
448 Ext.form.Action.Load = function(form, options){\r
449     Ext.form.Action.Load.superclass.constructor.call(this, form, options);\r
450     this.reader = this.form.reader;\r
451 };\r
452 \r
453 Ext.extend(Ext.form.Action.Load, Ext.form.Action, {\r
454     // private\r
455     type : 'load',\r
456 \r
457     // private\r
458     run : function(){\r
459         Ext.Ajax.request(Ext.apply(\r
460                 this.createCallback(this.options), {\r
461                     method:this.getMethod(),\r
462                     url:this.getUrl(false),\r
463                     headers: this.options.headers,\r
464                     params:this.getParams()\r
465         }));\r
466     },\r
467 \r
468     // private\r
469     success : function(response){\r
470         var result = this.processResponse(response);\r
471         if(result === true || !result.success || !result.data){\r
472             this.failureType = Ext.form.Action.LOAD_FAILURE;\r
473             this.form.afterAction(this, false);\r
474             return;\r
475         }\r
476         this.form.clearInvalid();\r
477         this.form.setValues(result.data);\r
478         this.form.afterAction(this, true);\r
479     },\r
480 \r
481     // private\r
482     handleResponse : function(response){\r
483         if(this.form.reader){\r
484             var rs = this.form.reader.read(response);\r
485             var data = rs.records && rs.records[0] ? rs.records[0].data : null;\r
486             return {\r
487                 success : rs.success,\r
488                 data : data\r
489             };\r
490         }\r
491         return Ext.decode(response.responseText);\r
492     }\r
493 });\r
494 \r
495 \r
496 \r
497 /**\r
498  * @class Ext.form.Action.DirectLoad\r
499  * @extends Ext.form.Action.Load\r
500  * <p>Provides Ext.direct support for loading form data.</p>\r
501  * <p>This example illustrates usage of Ext.Direct to <b>load</b> a form through Ext.Direct.</p>\r
502  * <pre><code>\r
503 var myFormPanel = new Ext.form.FormPanel({\r
504     // configs for FormPanel\r
505     title: 'Basic Information',\r
506     renderTo: document.body,\r
507     width: 300, height: 160,\r
508     padding: 10,\r
509 \r
510     // configs apply to child items\r
511     defaults: {anchor: '100%'},\r
512     defaultType: 'textfield',\r
513     items: [{\r
514         fieldLabel: 'Name',\r
515         name: 'name'\r
516     },{\r
517         fieldLabel: 'Email',\r
518         name: 'email'\r
519     },{\r
520         fieldLabel: 'Company',\r
521         name: 'company'\r
522     }],\r
523 \r
524     // configs for BasicForm\r
525     api: {\r
526         // The server-side method to call for load() requests\r
527         load: Profile.getBasicInfo,\r
528         // The server-side must mark the submit handler as a 'formHandler'\r
529         submit: Profile.updateBasicInfo\r
530     },\r
531     // specify the order for the passed params\r
532     paramOrder: ['uid', 'foo']\r
533 });\r
534 \r
535 // load the form\r
536 myFormPanel.getForm().load({\r
537     // pass 2 arguments to server side getBasicInfo method (len=2)\r
538     params: {\r
539         foo: 'bar',\r
540         uid: 34\r
541     }\r
542 });\r
543  * </code></pre>\r
544  * The data packet sent to the server will resemble something like:\r
545  * <pre><code>\r
546 [\r
547     {\r
548         "action":"Profile","method":"getBasicInfo","type":"rpc","tid":2,\r
549         "data":[34,"bar"] // note the order of the params\r
550     }\r
551 ]\r
552  * </code></pre>\r
553  * The form will process a data packet returned by the server that is similar\r
554  * to the following format:\r
555  * <pre><code>\r
556 [\r
557     {\r
558         "action":"Profile","method":"getBasicInfo","type":"rpc","tid":2,\r
559         "result":{\r
560             "success":true,\r
561             "data":{\r
562                 "name":"Fred Flintstone",\r
563                 "company":"Slate Rock and Gravel",\r
564                 "email":"fred.flintstone@slaterg.com"\r
565             }\r
566         }\r
567     }\r
568 ]\r
569  * </code></pre>\r
570  */\r
571 Ext.form.Action.DirectLoad = Ext.extend(Ext.form.Action.Load, {\r
572     constructor: function(form, opts) {\r
573         Ext.form.Action.DirectLoad.superclass.constructor.call(this, form, opts);\r
574     },\r
575     type : 'directload',\r
576 \r
577     run : function(){\r
578         var args = this.getParams();\r
579         args.push(this.success, this);\r
580         this.form.api.load.apply(window, args);\r
581     },\r
582 \r
583     getParams : function() {\r
584         var buf = [], o = {};\r
585         var bp = this.form.baseParams;\r
586         var p = this.options.params;\r
587         Ext.apply(o, p, bp);\r
588         var paramOrder = this.form.paramOrder;\r
589         if(paramOrder){\r
590             for(var i = 0, len = paramOrder.length; i < len; i++){\r
591                 buf.push(o[paramOrder[i]]);\r
592             }\r
593         }else if(this.form.paramsAsHash){\r
594             buf.push(o);\r
595         }\r
596         return buf;\r
597     },\r
598     // Direct actions have already been processed and therefore\r
599     // we can directly set the result; Direct Actions do not have\r
600     // a this.response property.\r
601     processResponse : function(result) {\r
602         this.result = result;\r
603         return result;\r
604     },\r
605     \r
606     success : function(response, trans){\r
607         if(trans.type == Ext.Direct.exceptions.SERVER){\r
608             response = {};\r
609         }\r
610         Ext.form.Action.DirectLoad.superclass.success.call(this, response);\r
611     }\r
612 });\r
613 \r
614 /**\r
615  * @class Ext.form.Action.DirectSubmit\r
616  * @extends Ext.form.Action.Submit\r
617  * <p>Provides Ext.direct support for submitting form data.</p>\r
618  * <p>This example illustrates usage of Ext.Direct to <b>submit</b> a form through Ext.Direct.</p>\r
619  * <pre><code>\r
620 var myFormPanel = new Ext.form.FormPanel({\r
621     // configs for FormPanel\r
622     title: 'Basic Information',\r
623     renderTo: document.body,\r
624     width: 300, height: 160,\r
625     padding: 10,\r
626     buttons:[{\r
627         text: 'Submit',\r
628         handler: function(){\r
629             myFormPanel.getForm().submit({\r
630                 params: {\r
631                     foo: 'bar',\r
632                     uid: 34\r
633                 }\r
634             });\r
635         }\r
636     }],\r
637 \r
638     // configs apply to child items\r
639     defaults: {anchor: '100%'},\r
640     defaultType: 'textfield',\r
641     items: [{\r
642         fieldLabel: 'Name',\r
643         name: 'name'\r
644     },{\r
645         fieldLabel: 'Email',\r
646         name: 'email'\r
647     },{\r
648         fieldLabel: 'Company',\r
649         name: 'company'\r
650     }],\r
651 \r
652     // configs for BasicForm\r
653     api: {\r
654         // The server-side method to call for load() requests\r
655         load: Profile.getBasicInfo,\r
656         // The server-side must mark the submit handler as a 'formHandler'\r
657         submit: Profile.updateBasicInfo\r
658     },\r
659     // specify the order for the passed params\r
660     paramOrder: ['uid', 'foo']\r
661 });\r
662  * </code></pre>\r
663  * The data packet sent to the server will resemble something like:\r
664  * <pre><code>\r
665 {\r
666     "action":"Profile","method":"updateBasicInfo","type":"rpc","tid":"6",\r
667     "result":{\r
668         "success":true,\r
669         "id":{\r
670             "extAction":"Profile","extMethod":"updateBasicInfo",\r
671             "extType":"rpc","extTID":"6","extUpload":"false",\r
672             "name":"Aaron Conran","email":"aaron@extjs.com","company":"Ext JS, LLC"\r
673         }\r
674     }\r
675 }\r
676  * </code></pre>\r
677  * The form will process a data packet returned by the server that is similar\r
678  * to the following:\r
679  * <pre><code>\r
680 // sample success packet (batched requests)\r
681 [\r
682     {\r
683         "action":"Profile","method":"updateBasicInfo","type":"rpc","tid":3,\r
684         "result":{\r
685             "success":true\r
686         }\r
687     }\r
688 ]\r
689 \r
690 // sample failure packet (one request)\r
691 {\r
692         "action":"Profile","method":"updateBasicInfo","type":"rpc","tid":"6",\r
693         "result":{\r
694             "errors":{\r
695                 "email":"already taken"\r
696             },\r
697             "success":false,\r
698             "foo":"bar"\r
699         }\r
700 }\r
701  * </code></pre>\r
702  * Also see the discussion in {@link Ext.form.Action.DirectLoad}.\r
703  */\r
704 Ext.form.Action.DirectSubmit = Ext.extend(Ext.form.Action.Submit, {\r
705     constructor : function(form, opts) {\r
706         Ext.form.Action.DirectSubmit.superclass.constructor.call(this, form, opts);\r
707     },\r
708     type : 'directsubmit',\r
709     // override of Submit\r
710     run : function(){\r
711         var o = this.options;\r
712         if(o.clientValidation === false || this.form.isValid()){\r
713             // tag on any additional params to be posted in the\r
714             // form scope\r
715             this.success.params = this.getParams();\r
716             this.form.api.submit(this.form.el.dom, this.success, this);\r
717         }else if (o.clientValidation !== false){ // client validation failed\r
718             this.failureType = Ext.form.Action.CLIENT_INVALID;\r
719             this.form.afterAction(this, false);\r
720         }\r
721     },\r
722 \r
723     getParams : function() {\r
724         var o = {};\r
725         var bp = this.form.baseParams;\r
726         var p = this.options.params;\r
727         Ext.apply(o, p, bp);\r
728         return o;\r
729     },\r
730     // Direct actions have already been processed and therefore\r
731     // we can directly set the result; Direct Actions do not have\r
732     // a this.response property.\r
733     processResponse : function(result) {\r
734         this.result = result;\r
735         return result;\r
736     },\r
737     \r
738     success : function(response, trans){\r
739         if(trans.type == Ext.Direct.exceptions.SERVER){\r
740             response = {};\r
741         }\r
742         Ext.form.Action.DirectSubmit.superclass.success.call(this, response);\r
743     }\r
744 });\r
745 \r
746 Ext.form.Action.ACTION_TYPES = {\r
747     'load' : Ext.form.Action.Load,\r
748     'submit' : Ext.form.Action.Submit,\r
749     'directload' : Ext.form.Action.DirectLoad,\r
750     'directsubmit' : Ext.form.Action.DirectSubmit\r
751 };\r