~cdparra/gelee/trunk

« back to all changes in this revision

Viewing changes to webui/extjs/source/widgets/form/Action.js

  • Committer: parra
  • Date: 2010-03-15 15:56:56 UTC
  • Revision ID: svn-v4:ac5bba68-f036-4e09-846e-8f32731cc928:trunk/gelee:1448
merged gelee at svn

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Ext JS Library 3.0 RC2
 
3
 * Copyright(c) 2006-2009, Ext JS, LLC.
 
4
 * licensing@extjs.com
 
5
 * 
 
6
 * http://extjs.com/license
 
7
 */
 
8
 
 
9
/**
 
10
 * @class Ext.form.Action
 
11
 * <p>The subclasses of this class provide actions to perform upon {@link Ext.form.BasicForm Form}s.</p>
 
12
 * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when
 
13
 * the Form needs to perform an action such as submit or load. The Configuration options
 
14
 * listed for this class are set through the Form's action methods: {@link Ext.form.BasicForm#submit submit},
 
15
 * {@link Ext.form.BasicForm#load load} and {@link Ext.form.BasicForm#doAction doAction}</p>
 
16
 * <p>The instance of Action which performed the action is passed to the success
 
17
 * and failure callbacks of the Form's action methods ({@link Ext.form.BasicForm#submit submit},
 
18
 * {@link Ext.form.BasicForm#load load} and {@link Ext.form.BasicForm#doAction doAction}),
 
19
 * and to the {@link Ext.form.BasicForm#actioncomplete actioncomplete} and
 
20
 * {@link Ext.form.BasicForm#actionfailed actionfailed} event handlers.</p>
 
21
 */
 
22
Ext.form.Action = function(form, options){
 
23
    this.form = form;
 
24
    this.options = options || {};
 
25
};
 
26
 
 
27
/**
 
28
 * Failure type returned when client side validation of the Form fails
 
29
 * thus aborting a submit action. Client side validation is performed unless
 
30
 * {@link #clientValidation} is explicitly set to <tt>false</tt>.
 
31
 * @type {String}
 
32
 * @static
 
33
 */
 
34
Ext.form.Action.CLIENT_INVALID = 'client';
 
35
/**
 
36
 * <p>Failure type returned when server side processing fails and the {@link #result}'s
 
37
 * <tt style="font-weight:bold">success</tt> property is set to <tt>false</tt>.</p>
 
38
 * <p>In the case of a form submission, field-specific error messages may be returned in the
 
39
 * {@link #result}'s <tt style="font-weight:bold">errors</tt> property.</p>
 
40
 * @type {String}
 
41
 * @static
 
42
 */
 
43
Ext.form.Action.SERVER_INVALID = 'server';
 
44
/**
 
45
 * Failure type returned when a communication error happens when attempting
 
46
 * to send a request to the remote server. The {@link #response} may be examined to
 
47
 * provide further information.
 
48
 * @type {String}
 
49
 * @static
 
50
 */
 
51
Ext.form.Action.CONNECT_FAILURE = 'connect';
 
52
/**
 
53
 * Failure type returned when the response's <tt style="font-weight:bold">success</tt>
 
54
 * property is set to <tt>false</tt>, or no field values are returned in the response's
 
55
 * <tt style="font-weight:bold">data</tt> property.
 
56
 * @type {String}
 
57
 * @static
 
58
 */
 
59
Ext.form.Action.LOAD_FAILURE = 'load';
 
60
 
 
61
Ext.form.Action.prototype = {
 
62
/**
 
63
 * @cfg {String} url The URL that the Action is to invoke.
 
64
 */
 
65
/**
 
66
 * @cfg {Boolean} reset When set to <tt><b>true</b></tt>, causes the Form to be
 
67
 * {@link Ext.form.BasicForm.reset reset} on Action success. If specified, this happens
 
68
 * <b>before</b> the {@link #success} callback is called and before the Form's
 
69
 * {@link Ext.form.BasicForm.actioncomplete actioncomplete} event fires.
 
70
 */
 
71
/**
 
72
 * @cfg {String} method The HTTP method to use to access the requested URL. Defaults to the
 
73
 * {@link Ext.form.BasicForm}'s method, or if that is not specified, the underlying DOM form's method.
 
74
 */
 
75
/**
 
76
 * @cfg {Mixed} params <p>Extra parameter values to pass. These are added to the Form's
 
77
 * {@link Ext.form.BasicForm#baseParams} and passed to the specified URL along with the Form's
 
78
 * input fields.</p>
 
79
 * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p>
 
80
 */
 
81
/**
 
82
 * @cfg {Number} timeout The number of seconds to wait for a server response before
 
83
 * failing with the {@link #failureType} as {@link #Action.CONNECT_FAILURE}. If not specified,
 
84
 * defaults to the configured <tt>{@link Ext.form.BasicForm#timeout timeout}</tt> of the
 
85
 * {@link Ext.form.BasicForm form}.
 
86
 */
 
87
/**
 
88
 * @cfg {Function} success The function to call when a valid success return packet is recieved.
 
89
 * The function is passed the following parameters:<ul class="mdetail-params">
 
90
 * <li><b>form</b> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>
 
91
 * <li><b>action</b> : Ext.form.Action<div class="sub-desc">The Action class. The {@link #result}
 
92
 * property of this object may be examined to perform custom postprocessing.</div></li>
 
93
 * </ul>
 
94
 */
 
95
/**
 
96
 * @cfg {Function} failure The function to call when a failure packet was recieved, or when an
 
97
 * error ocurred in the Ajax communication.
 
98
 * The function is passed the following parameters:<ul class="mdetail-params">
 
99
 * <li><b>form</b> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>
 
100
 * <li><b>action</b> : Ext.form.Action<div class="sub-desc">The Action class. If an Ajax
 
101
 * error ocurred, the failure type will be in {@link #failureType}. The {@link #result}
 
102
 * property of this object may be examined to perform custom postprocessing.</div></li>
 
103
 * </ul>
 
104
 */
 
105
/**
 
106
 * @cfg {Object} scope The scope in which to call the callback functions (The <tt>this</tt> reference
 
107
 * for the callback functions).
 
108
 */
 
109
/**
 
110
 * @cfg {String} waitMsg The message to be displayed by a call to {@link Ext.MessageBox#wait}
 
111
 * during the time the action is being processed.
 
112
 */
 
113
/**
 
114
 * @cfg {String} waitTitle The title to be displayed by a call to {@link Ext.MessageBox#wait}
 
115
 * during the time the action is being processed.
 
116
 */
 
117
 
 
118
/**
 
119
 * The type of action this Action instance performs.
 
120
 * Currently only "submit" and "load" are supported.
 
121
 * @type {String}
 
122
 */
 
123
    type : 'default',
 
124
/**
 
125
 * The type of failure detected will be one of these: {@link #CLIENT_INVALID},
 
126
 * {@link #SERVER_INVALID}, {@link #CONNECT_FAILURE}, or {@link #LOAD_FAILURE}.  Usage:
 
127
 * <pre><code>
 
128
var fp = new Ext.form.FormPanel({
 
129
...
 
130
buttons: [{
 
131
    text: 'Save',
 
132
    formBind: true,
 
133
    handler: function(){
 
134
        if(fp.getForm().isValid()){
 
135
            fp.getForm().submit({
 
136
                url: 'form-submit.php',
 
137
                waitMsg: 'Submitting your data...',
 
138
                success: function(form, action){
 
139
                    // server responded with success = true
 
140
                    var result = action.{@link #result};
 
141
                },
 
142
                failure: function(form, action){
 
143
                    if (action.{@link #failureType} === Ext.form.Action.{@link #CONNECT_FAILURE}) {
 
144
                        Ext.Msg.alert('Error',
 
145
                            'Status:'+action.{@link #response}.status+': '+
 
146
                            action.{@link #response}.statusText);
 
147
                    }
 
148
                    if (action.failureType === Ext.form.Action.{@link #SERVER_INVALID}){
 
149
                        // server responded with success = false
 
150
                        Ext.Msg.alert('Invalid', action.{@link #result}.errormsg);
 
151
                    }
 
152
                }
 
153
            });
 
154
        }
 
155
    }
 
156
},{
 
157
    text: 'Reset',
 
158
    handler: function(){
 
159
        fp.getForm().reset();
 
160
    }
 
161
}]
 
162
 * </code></pre>
 
163
 * @property failureType
 
164
 * @type {String}
 
165
 */
 
166
 /**
 
167
 * The XMLHttpRequest object used to perform the action.
 
168
 * @property response
 
169
 * @type {Object}
 
170
 */
 
171
 /**
 
172
 * The decoded response object containing a boolean <tt style="font-weight:bold">success</tt> property and
 
173
 * other, action-specific properties.
 
174
 * @property result
 
175
 * @type {Object}
 
176
 */
 
177
 
 
178
    // interface method
 
179
    run : function(options){
 
180
 
 
181
    },
 
182
 
 
183
    // interface method
 
184
    success : function(response){
 
185
 
 
186
    },
 
187
 
 
188
    // interface method
 
189
    handleResponse : function(response){
 
190
 
 
191
    },
 
192
 
 
193
    // default connection failure
 
194
    failure : function(response){
 
195
        this.response = response;
 
196
        this.failureType = Ext.form.Action.CONNECT_FAILURE;
 
197
        this.form.afterAction(this, false);
 
198
    },
 
199
 
 
200
    // private
 
201
    // shared code among all Actions to validate that there was a response
 
202
    // with either responseText or responseXml
 
203
    processResponse : function(response){
 
204
        this.response = response;
 
205
        if(!response.responseText && !response.responseXML){
 
206
            return true;
 
207
        }
 
208
        this.result = this.handleResponse(response);
 
209
        return this.result;
 
210
    },
 
211
 
 
212
    // utility functions used internally
 
213
    getUrl : function(appendParams){
 
214
        var url = this.options.url || this.form.url || this.form.el.dom.action;
 
215
        if(appendParams){
 
216
            var p = this.getParams();
 
217
            if(p){
 
218
                url += (url.indexOf('?') != -1 ? '&' : '?') + p;
 
219
            }
 
220
        }
 
221
        return url;
 
222
    },
 
223
 
 
224
    // private
 
225
    getMethod : function(){
 
226
        return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
 
227
    },
 
228
 
 
229
    // private
 
230
    getParams : function(){
 
231
        var bp = this.form.baseParams;
 
232
        var p = this.options.params;
 
233
        if(p){
 
234
            if(typeof p == "object"){
 
235
                p = Ext.urlEncode(Ext.applyIf(p, bp));
 
236
            }else if(typeof p == 'string' && bp){
 
237
                p += '&' + Ext.urlEncode(bp);
 
238
            }
 
239
        }else if(bp){
 
240
            p = Ext.urlEncode(bp);
 
241
        }
 
242
        return p;
 
243
    },
 
244
 
 
245
    // private
 
246
    createCallback : function(opts){
 
247
                var opts = opts || {};
 
248
        return {
 
249
            success: this.success,
 
250
            failure: this.failure,
 
251
            scope: this,
 
252
            timeout: (opts.timeout*1000) || (this.form.timeout*1000),
 
253
            upload: this.form.fileUpload ? this.success : undefined
 
254
        };
 
255
    }
 
256
};
 
257
 
 
258
/**
 
259
 * @class Ext.form.Action.Submit
 
260
 * @extends Ext.form.Action
 
261
 * <p>A class which handles submission of data from {@link Ext.form.BasicForm Form}s
 
262
 * and processes the returned response.</p>
 
263
 * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when
 
264
 * {@link Ext.form.BasicForm#submit submit}ting.</p>
 
265
 * <p>A response packet must contain a boolean <tt style="font-weight:bold">success</tt> property, and, optionally
 
266
 * an <tt style="font-weight:bold">errors</tt> property. The <tt style="font-weight:bold">errors</tt> property contains error
 
267
 * messages for invalid fields.</p>
 
268
 * <p>By default, response packets are assumed to be JSON, so a typical response
 
269
 * packet may look like this:</p><pre><code>
 
270
{
 
271
    success: false,
 
272
    errors: {
 
273
        clientCode: "Client not found",
 
274
        portOfLoading: "This field must not be null"
 
275
    }
 
276
}</code></pre>
 
277
 * <p>Other data may be placed into the response for processing by the {@link Ext.form.BasicForm}'s callback
 
278
 * or event handler methods. The object decoded from this JSON is available in the {@link #result} property.</p>
 
279
 * <p>Alternatively, if an {@link #errorReader} is specified as an {@link Ext.data.XmlReader XmlReader}:</p><pre><code>
 
280
    errorReader: new Ext.data.XmlReader({
 
281
            record : 'field',
 
282
            success: '@success'
 
283
        }, [
 
284
            'id', 'msg'
 
285
        ]
 
286
    )
 
287
</code></pre>
 
288
 * <p>then the results may be sent back in XML format:</p><pre><code>
 
289
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
 
290
&lt;message success="false"&gt;
 
291
&lt;errors&gt;
 
292
    &lt;field&gt;
 
293
        &lt;id&gt;clientCode&lt;/id&gt;
 
294
        &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;
 
295
    &lt;/field&gt;
 
296
    &lt;field&gt;
 
297
        &lt;id&gt;portOfLoading&lt;/id&gt;
 
298
        &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;
 
299
    &lt;/field&gt;
 
300
&lt;/errors&gt;
 
301
&lt;/message&gt;
 
302
</code></pre>
 
303
 * <p>Other elements may be placed into the response XML for processing by the {@link Ext.form.BasicForm}'s callback
 
304
 * or event handler methods. The XML document is available in the {@link #errorReader}'s {@link Ext.data.XmlReader#xmlData xmlData} property.</p>
 
305
 */
 
306
Ext.form.Action.Submit = function(form, options){
 
307
    Ext.form.Action.Submit.superclass.constructor.call(this, form, options);
 
308
};
 
309
 
 
310
Ext.extend(Ext.form.Action.Submit, Ext.form.Action, {
 
311
    /**
 
312
    * @cfg {Ext.data.DataReader} errorReader <b>Optional. JSON is interpreted with no need for an errorReader.</b>
 
313
    * <p>A Reader which reads a single record from the returned data. The DataReader's <b>success</b> property specifies
 
314
    * how submission success is determined. The Record's data provides the error messages to apply to any invalid form Fields.</p>.
 
315
    */
 
316
    /**
 
317
    * @cfg {boolean} clientValidation Determines whether a Form's fields are validated
 
318
    * in a final call to {@link Ext.form.BasicForm#isValid isValid} prior to submission.
 
319
    * Pass <tt>false</tt> in the Form's submit options to prevent this. If not defined, pre-submission field validation
 
320
    * is performed.
 
321
    */
 
322
    type : 'submit',
 
323
 
 
324
    // private
 
325
    run : function(){
 
326
        var o = this.options;
 
327
        var method = this.getMethod();
 
328
        var isGet = method == 'GET';
 
329
        if(o.clientValidation === false || this.form.isValid()){
 
330
            Ext.Ajax.request(Ext.apply(this.createCallback(o), {
 
331
                form:this.form.el.dom,
 
332
                url:this.getUrl(isGet),
 
333
                method: method,
 
334
                headers: o.headers,
 
335
                params:!isGet ? this.getParams() : null,
 
336
                isUpload: this.form.fileUpload
 
337
            }));
 
338
        }else if (o.clientValidation !== false){ // client validation failed
 
339
            this.failureType = Ext.form.Action.CLIENT_INVALID;
 
340
            this.form.afterAction(this, false);
 
341
        }
 
342
    },
 
343
 
 
344
    // private
 
345
    success : function(response){
 
346
        var result = this.processResponse(response);
 
347
        if(result === true || result.success){
 
348
            this.form.afterAction(this, true);
 
349
            return;
 
350
        }
 
351
        if(result.errors){
 
352
            this.form.markInvalid(result.errors);
 
353
            this.failureType = Ext.form.Action.SERVER_INVALID;
 
354
        }
 
355
        this.form.afterAction(this, false);
 
356
    },
 
357
 
 
358
    // private
 
359
    handleResponse : function(response){
 
360
        if(this.form.errorReader){
 
361
            var rs = this.form.errorReader.read(response);
 
362
            var errors = [];
 
363
            if(rs.records){
 
364
                for(var i = 0, len = rs.records.length; i < len; i++) {
 
365
                    var r = rs.records[i];
 
366
                    errors[i] = r.data;
 
367
                }
 
368
            }
 
369
            if(errors.length < 1){
 
370
                errors = null;
 
371
            }
 
372
            return {
 
373
                success : rs.success,
 
374
                errors : errors
 
375
            };
 
376
        }
 
377
        return Ext.decode(response.responseText);
 
378
    }
 
379
});
 
380
 
 
381
 
 
382
/**
 
383
 * @class Ext.form.Action.Load
 
384
 * @extends Ext.form.Action
 
385
 * <p>A class which handles loading of data from a server into the Fields of an {@link Ext.form.BasicForm}.</p>
 
386
 * <p>Instances of this class are only created by a {@link Ext.form.BasicForm Form} when
 
387
 * {@link Ext.form.BasicForm#load load}ing.</p>
 
388
 * <p>A response packet <b>must</b> contain a boolean <tt style="font-weight:bold">success</tt> property, and
 
389
 * a <tt style="font-weight:bold">data</tt> property. The <tt style="font-weight:bold">data</tt> property
 
390
 * contains the values of Fields to load. The individual value object for each Field
 
391
 * is passed to the Field's {@link Ext.form.Field#setValue setValue} method.</p>
 
392
 * <p>By default, response packets are assumed to be JSON, so a typical response
 
393
 * packet may look like this:</p><pre><code>
 
394
{
 
395
    success: true,
 
396
    data: {
 
397
        clientName: "Fred. Olsen Lines",
 
398
        portOfLoading: "FXT",
 
399
        portOfDischarge: "OSL"
 
400
    }
 
401
}</code></pre>
 
402
 * <p>Other data may be placed into the response for processing the {@link Ext.form.BasicForm Form}'s callback
 
403
 * or event handler methods. The object decoded from this JSON is available in the {@link #result} property.</p>
 
404
 */
 
405
Ext.form.Action.Load = function(form, options){
 
406
    Ext.form.Action.Load.superclass.constructor.call(this, form, options);
 
407
    this.reader = this.form.reader;
 
408
};
 
409
 
 
410
Ext.extend(Ext.form.Action.Load, Ext.form.Action, {
 
411
    // private
 
412
    type : 'load',
 
413
 
 
414
    // private
 
415
    run : function(){
 
416
        Ext.Ajax.request(Ext.apply(
 
417
                this.createCallback(this.options), {
 
418
                    method:this.getMethod(),
 
419
                    url:this.getUrl(false),
 
420
                    headers: this.options.headers,
 
421
                    params:this.getParams()
 
422
        }));
 
423
    },
 
424
 
 
425
    // private
 
426
    success : function(response){
 
427
        var result = this.processResponse(response);
 
428
        if(result === true || !result.success || !result.data){
 
429
            this.failureType = Ext.form.Action.LOAD_FAILURE;
 
430
            this.form.afterAction(this, false);
 
431
            return;
 
432
        }
 
433
        this.form.clearInvalid();
 
434
        this.form.setValues(result.data);
 
435
        this.form.afterAction(this, true);
 
436
    },
 
437
 
 
438
    // private
 
439
    handleResponse : function(response){
 
440
        if(this.form.reader){
 
441
            var rs = this.form.reader.read(response);
 
442
            var data = rs.records && rs.records[0] ? rs.records[0].data : null;
 
443
            return {
 
444
                success : rs.success,
 
445
                data : data
 
446
            };
 
447
        }
 
448
        return Ext.decode(response.responseText);
 
449
    }
 
450
});
 
451
 
 
452
 
 
453
 
 
454
/**
 
455
 * @class Ext.form.Action.DirectLoad
 
456
 * @extends Ext.form.Action.Load
 
457
 */
 
458
Ext.form.Action.DirectLoad = Ext.extend(Ext.form.Action.Load, {
 
459
    constructor: function(form, opts) {        
 
460
        Ext.form.Action.DirectLoad.superclass.constructor.call(this, form, opts);
 
461
    },
 
462
    type: 'directload',
 
463
    
 
464
    run : function(){
 
465
        var args = this.getParams();
 
466
        args.push(this.success, this);                
 
467
        this.form.api.load.apply(window, args);
 
468
    },
 
469
    
 
470
    getParams: function() {
 
471
        var buf = [], o = {};
 
472
        var bp = this.form.baseParams;
 
473
        var p = this.options.params;
 
474
        Ext.apply(o, p, bp);
 
475
        var paramOrder = this.form.paramOrder;
 
476
        if(paramOrder){
 
477
            for(var i = 0, len = paramOrder.length; i < len; i++){
 
478
                buf.push(o[paramOrder[i]]);
 
479
            }
 
480
        }else if(this.form.paramsAsHash){
 
481
            buf.push(o);
 
482
        }
 
483
        return buf;
 
484
    },
 
485
    // Direct actions have already been processed and therefore
 
486
    // we can directly set the result; Direct Actions do not have
 
487
    // a this.response property.
 
488
    processResponse: function(result) {
 
489
        this.result = result;
 
490
        return result;          
 
491
    }
 
492
});
 
493
 
 
494
/**
 
495
 * @class Ext.form.Action.DirectSubmit
 
496
 * @extends Ext.form.Action.Submit
 
497
 */
 
498
Ext.form.Action.DirectSubmit = Ext.extend(Ext.form.Action.Submit, {
 
499
    constructor: function(form, opts) {
 
500
        Ext.form.Action.DirectSubmit.superclass.constructor.call(this, form, opts);
 
501
    },
 
502
    type: 'directsubmit',
 
503
    // override of Submit
 
504
    run : function(){
 
505
        var o = this.options;
 
506
        if(o.clientValidation === false || this.form.isValid()){
 
507
            // tag on any additional params to be posted in the
 
508
            // form scope
 
509
            this.success.params = this.getParams();
 
510
            this.form.api.submit(this.form.el.dom, this.success, this);
 
511
        }else if (o.clientValidation !== false){ // client validation failed
 
512
            this.failureType = Ext.form.Action.CLIENT_INVALID;
 
513
            this.form.afterAction(this, false);
 
514
        }
 
515
    },
 
516
    
 
517
    getParams: function() {
 
518
        var o = {};
 
519
        var bp = this.form.baseParams;
 
520
        var p = this.options.params;
 
521
        Ext.apply(o, p, bp);
 
522
        return o;
 
523
    },    
 
524
    // Direct actions have already been processed and therefore
 
525
    // we can directly set the result; Direct Actions do not have
 
526
    // a this.response property.
 
527
    processResponse: function(result) {
 
528
        this.result = result;
 
529
        return result;          
 
530
    }
 
531
});
 
532
 
 
533
 
 
534
Ext.form.Action.ACTION_TYPES = {
 
535
    'load' : Ext.form.Action.Load,
 
536
    'submit' : Ext.form.Action.Submit,
 
537
    'directload': Ext.form.Action.DirectLoad,
 
538
    'directsubmit': Ext.form.Action.DirectSubmit
 
539
};