~cdparra/gelee/trunk

« back to all changes in this revision

Viewing changes to webui/extjs/source/widgets/form/BasicForm.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.BasicForm
 
11
 * @extends Ext.util.Observable
 
12
 * <p>Encapsulates the DOM &lt;form> element at the heart of the {@link Ext.form.FormPanel FormPanel} class, and provides
 
13
 * input field management, validation, submission, and form loading services.</p>
 
14
 * <p>By default, Ext Forms are submitted through Ajax, using an instance of {@link Ext.form.Action.Submit}.
 
15
 * To enable normal browser submission of an Ext Form, use the {@link #standardSubmit} config option.</p>
 
16
 * <p><b><u>File Uploads</u></b></p>
 
17
 * <p>{@link #fileUpload File uploads} are not performed using Ajax submission, that
 
18
 * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard
 
19
 * manner with the DOM <tt>&lt;form></tt> element temporarily modified to have its
 
20
 * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
 
21
 * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
 
22
 * but removed after the return data has been gathered.</p>
 
23
 * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
 
24
 * server is using JSON to send the return object, then the
 
25
 * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
 
26
 * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
 
27
 * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
 
28
 * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>
 
29
 * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
 
30
 * is created containing a <tt>responseText</tt> property in order to conform to the
 
31
 * requirements of event handlers and callbacks.</p>
 
32
 * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
 
33
 * and some server technologies (notably JEE) may require some custom processing in order to
 
34
 * retrieve parameter names and parameter values from the packet content.</p>
 
35
 * @constructor
 
36
 * @param {Mixed} el The form element or its id
 
37
 * @param {Object} config Configuration options
 
38
 */
 
39
Ext.form.BasicForm = function(el, config){
 
40
    Ext.apply(this, config);
 
41
    if(typeof this.paramOrder == 'string'){
 
42
        this.paramOrder = this.paramOrder.split(/[\s,|]/);
 
43
    }    
 
44
    /*
 
45
     * @property items
 
46
     * A {@link Ext.util.MixedCollection MixedCollection) containing all the Ext.form.Fields in this form.
 
47
     * @type MixedCollection
 
48
     */
 
49
    this.items = new Ext.util.MixedCollection(false, function(o){
 
50
        return o.itemId || o.id || (o.id = Ext.id());
 
51
    });
 
52
    this.addEvents(
 
53
        /**
 
54
         * @event beforeaction
 
55
         * Fires before any action is performed. Return false to cancel the action.
 
56
         * @param {Form} this
 
57
         * @param {Action} action The {@link Ext.form.Action} to be performed
 
58
         */
 
59
        'beforeaction',
 
60
        /**
 
61
         * @event actionfailed
 
62
         * Fires when an action fails.
 
63
         * @param {Form} this
 
64
         * @param {Action} action The {@link Ext.form.Action} that failed
 
65
         */
 
66
        'actionfailed',
 
67
        /**
 
68
         * @event actioncomplete
 
69
         * Fires when an action is completed.
 
70
         * @param {Form} this
 
71
         * @param {Action} action The {@link Ext.form.Action} that completed
 
72
         */
 
73
        'actioncomplete'
 
74
    );
 
75
 
 
76
    if(el){
 
77
        this.initEl(el);
 
78
    }
 
79
    Ext.form.BasicForm.superclass.constructor.call(this);
 
80
};
 
81
 
 
82
Ext.extend(Ext.form.BasicForm, Ext.util.Observable, {
 
83
    /**
 
84
     * @cfg {String} method
 
85
     * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
 
86
     */
 
87
    /**
 
88
     * @cfg {DataReader} reader
 
89
     * An Ext.data.DataReader (e.g. {@link Ext.data.XmlReader}) to be used to read data when executing "load" actions.
 
90
     * This is optional as there is built-in support for processing JSON.
 
91
     */
 
92
    /**
 
93
     * @cfg {DataReader} errorReader
 
94
     * <p>An Ext.data.DataReader (e.g. {@link Ext.data.XmlReader}) to be used to read field error messages returned from "submit" actions.
 
95
     * This is completely optional as there is built-in support for processing JSON.</p>
 
96
     * <p>The Records which provide messages for the invalid Fields must use the Field name (or id) as the Record ID,
 
97
     * and must contain a field called "msg" which contains the error message.</p>
 
98
     * <p>The errorReader does not have to be a full-blown implementation of a DataReader. It simply needs to implement a 
 
99
     * <tt>read(xhr)</tt> function which returns an Array of Records in an object with the following structure:<pre><code>
 
100
{
 
101
    records: recordArray
 
102
}
 
103
</code></pre>
 
104
     */
 
105
    /**
 
106
     * @cfg {String} url
 
107
     * The URL to use for form actions if one isn't supplied in the {@link #doAction action} options.
 
108
     */
 
109
    /**
 
110
     * @cfg {Boolean} fileUpload
 
111
     * Set to true if this form is a file upload.
 
112
     * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
 
113
     * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
 
114
     * DOM <tt>&lt;form></tt> element temporarily modified to have its
 
115
     * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
 
116
     * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
 
117
     * but removed after the return data has been gathered.</p>
 
118
     * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
 
119
     * server is using JSON to send the return object, then the
 
120
     * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
 
121
     * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
 
122
     * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
 
123
     * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>
 
124
     * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
 
125
     * is created containing a <tt>responseText</tt> property in order to conform to the
 
126
     * requirements of event handlers and callbacks.</p>
 
127
     * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
 
128
     * and some server technologies (notably JEE) may require some custom processing in order to
 
129
     * retrieve parameter names and parameter values from the packet content.</p>
 
130
     */
 
131
    /**
 
132
     * @cfg {Object} baseParams
 
133
     * <p>Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.</p>
 
134
     * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p>
 
135
     */
 
136
    /**
 
137
     * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
 
138
     */
 
139
    timeout: 30,
 
140
 
 
141
    /**
 
142
     * @cfg {Object} api
 
143
     * Methods which have been imported by Ext.Direct can be specified here to load and submit
 
144
     * forms. 
 
145
     * Such as the following:<pre><code>
 
146
api: {
 
147
    load: App.ss.MyProfile.load,
 
148
    submit: App.ss.MyProfile.submit
 
149
}
 
150
</code></pre>
 
151
     * <p>Load actions can use paramOrder or paramsAsHash to customize how the load method is invoked.
 
152
     * Submit actions will always use a standard form submit. The formHandler configuration must be set
 
153
     * on the associated server-side method which has been imported by Ext.Direct</p>
 
154
     */
 
155
 
 
156
    /**
 
157
     * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. Only used for the api load configuration.
 
158
     * A list of params to be executed
 
159
     * server side.  Specify the params in the order in which they must be executed on the server-side
 
160
     * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,
 
161
     * comma, or pipe. For example,
 
162
     * any of the following would be acceptable:<pre><code>
 
163
paramOrder: ['param1','param2','param3']
 
164
paramOrder: 'param1 param2 param3'
 
165
paramOrder: 'param1,param2,param3'
 
166
paramOrder: 'param1|param2|param'
 
167
     </code></pre>
 
168
     */
 
169
    paramOrder: undefined,
 
170
 
 
171
    /**
 
172
     * @cfg {Boolean} paramsAsHash Only used for the api load configuration.
 
173
     * Send parameters as a collection of named arguments (defaults to <tt>false</tt>). Providing a
 
174
     * <tt>{@link #paramOrder}</tt> nullifies this configuration.
 
175
     */
 
176
    paramsAsHash: false,
 
177
 
 
178
 
 
179
    // private
 
180
    activeAction : null,
 
181
 
 
182
    /**
 
183
     * @cfg {Boolean} trackResetOnLoad If set to <tt>true</tt>, {@link #reset}() resets to the last loaded
 
184
     * or {@link #setValues}() data instead of when the form was first created.  Defaults to <tt>false</tt>.
 
185
     */
 
186
    trackResetOnLoad : false,
 
187
 
 
188
    /**
 
189
     * @cfg {Boolean} standardSubmit If set to true, standard HTML form submits are used instead of XHR (Ajax) style
 
190
     * form submissions. (defaults to false)<br>
 
191
     * <p><b>Note:</b> When using standardSubmit, the options to {@link #submit} are ignored because Ext's
 
192
     * Ajax infrastracture is bypassed. To pass extra parameters (baseParams and params), you will need to
 
193
     * create hidden fields within the form.</p>
 
194
     * <p>The url config option is also bypassed, so set the action as well:</p>
 
195
     * <pre><code>
 
196
PANEL.getForm().getEl().dom.action = 'URL'
 
197
     * </code></pre>
 
198
     * An example encapsulating the above:
 
199
     * <pre><code>
 
200
new Ext.FormPanel({
 
201
    standardSubmit: true,
 
202
    baseParams: {
 
203
        foo: 'bar'
 
204
    },
 
205
    url: "myProcess.php",
 
206
    items: [{
 
207
        xtype: "textfield",
 
208
        name: "userName"
 
209
    }],
 
210
    buttons: [{
 
211
        text: "Save",
 
212
        handler: function(){
 
213
            var O = this.ownerCt;
 
214
            if (O.getForm().isValid()) {
 
215
                if (O.url) 
 
216
                    O.getForm().getEl().dom.action = O.url;
 
217
                if (O.baseParams) {
 
218
                    for (i in O.baseParams) {
 
219
                        O.add({
 
220
                            xtype: "hidden",
 
221
                            name: i,
 
222
                            value: O.baseParams[i]
 
223
                        })
 
224
                    }
 
225
                    O.doLayout();
 
226
                }
 
227
                O.getForm().submit();
 
228
            }
 
229
        }
 
230
    }]
 
231
});
 
232
     * </code></pre>
 
233
     */
 
234
    /**
 
235
     * By default wait messages are displayed with Ext.MessageBox.wait. You can target a specific
 
236
     * element by passing it or its id or mask the form itself by passing in true.
 
237
     * @type Mixed
 
238
     * @property waitMsgTarget
 
239
     */
 
240
 
 
241
    // private
 
242
    initEl : function(el){
 
243
        this.el = Ext.get(el);
 
244
        this.id = this.el.id || Ext.id();
 
245
        if(!this.standardSubmit){
 
246
            this.el.on('submit', this.onSubmit, this);
 
247
        }
 
248
        this.el.addClass('x-form');
 
249
    },
 
250
 
 
251
    /**
 
252
     * Get the HTML form Element
 
253
     * @return Ext.Element
 
254
     */
 
255
    getEl: function(){
 
256
        return this.el;
 
257
    },
 
258
 
 
259
    // private
 
260
    onSubmit : function(e){
 
261
        e.stopEvent();
 
262
    },
 
263
 
 
264
    // private
 
265
    destroy: function() {
 
266
        this.items.each(function(f){
 
267
            Ext.destroy(f);
 
268
        });
 
269
        if(this.el){
 
270
            this.el.removeAllListeners();
 
271
            this.el.remove();
 
272
        }
 
273
        this.purgeListeners();
 
274
    },
 
275
 
 
276
    /**
 
277
     * Returns true if client-side validation on the form is successful.
 
278
     * @return Boolean
 
279
     */
 
280
    isValid : function(){
 
281
        var valid = true;
 
282
        this.items.each(function(f){
 
283
           if(!f.validate()){
 
284
               valid = false;
 
285
           }
 
286
        });
 
287
        return valid;
 
288
    },
 
289
 
 
290
    /**
 
291
     * <p>Returns true if any fields in this form have changed from their original values.</p>
 
292
     * <p>Note that if this BasicForm was configured with {@link #trackResetOnLoad} then the
 
293
     * Fields' <i>original values</i> are updated when the values are loaded by {@link #setValues}
 
294
     * or {@link #loadRecord}.</p>
 
295
     * @return Boolean
 
296
     */
 
297
    isDirty : function(){
 
298
        var dirty = false;
 
299
        this.items.each(function(f){
 
300
           if(f.isDirty()){
 
301
               dirty = true;
 
302
               return false;
 
303
           }
 
304
        });
 
305
        return dirty;
 
306
    },
 
307
 
 
308
    /**
 
309
     * Performs a predefined action ({@link Ext.form.Action.Submit} or
 
310
     * {@link Ext.form.Action.Load}) or a custom extension of {@link Ext.form.Action} 
 
311
     * to perform application-specific processing.
 
312
     * @param {String/Object} actionName The name of the predefined action type,
 
313
     * or instance of {@link Ext.form.Action} to perform.
 
314
     * @param {Object} options (optional) The options to pass to the {@link Ext.form.Action}. 
 
315
     * All of the config options listed below are supported by both the submit
 
316
     * and load actions unless otherwise noted (custom actions could also accept
 
317
     * other config options):<ul>
 
318
     * <li><b>url</b> : String<p class="sub-desc">The url for the action (defaults
 
319
     * to the form's {@link #url}.)</p></li>
 
320
     * <li><b>method</b> : String<p class="sub-desc">The form method to use (defaults
 
321
     * to the form's method, or POST if not defined)</p></li>
 
322
     * <li><b>params</b> : String/Object<div class="sub-desc"><p>The params to pass
 
323
     * (defaults to the form's baseParams, or none if not defined)</p>
 
324
     * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p></div></li>
 
325
     * <li><b>headers</b> : Object<p class="sub-desc">Request headers to set for the action
 
326
     * (defaults to the form's default headers)</p></li>
 
327
     * <li><b>success</b> : Function<p class="sub-desc">The callback that will
 
328
     * be invoked after a successful response. The function is passed the following parameters:<ul>
 
329
     * <li><tt>form</tt> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>
 
330
     * <li><tt>action</tt> : The {@link Ext.form.Action Action} object which performed the operation.
 
331
     * <div class="sub-desc">The action object contains these properties of interest:<ul>
 
332
     * <li><tt>{@link Ext.form.Action#response response}</tt></li>
 
333
     * <li><tt>{@link Ext.form.Action#result result}</tt> : interrogate for custom postprocessing</li>
 
334
     * <li><tt>{@link Ext.form.Action#type type}</tt></li>
 
335
     * </ul></p></li>
 
336
     * <li><b>failure</b> : Function
 
337
     * <div class="sub-desc">
 
338
     * <p>The callback that will be invoked after a failed transaction attempt. The function is
 
339
     * passed the following parameters:</p><ul>
 
340
     * <li><tt>form</tt> : The {@link Ext.form.BasicForm} that requested the action. 
 
341
     * <div class="sub-desc"></div></li>
 
342
     * <li><tt>action</tt> : The {@link Ext.form.Action Action} object which performed the operation.
 
343
     * <div class="sub-desc">The action object contains these properties of interest:<ul>
 
344
     * <li><tt>{@link Ext.form.Action#failureType failureType}</tt></li>
 
345
     * <li><tt>{@link Ext.form.Action#response response}</tt></li>
 
346
     * <li><tt>{@link Ext.form.Action#result result}</tt> : interrogate for custom postprocessing</li>
 
347
     * <li><tt>{@link Ext.form.Action#type type}</tt></li>
 
348
     * </ul></div></li></ul>
 
349
     * </div></li>
 
350
     * <li><b>scope</b> : Object<p class="sub-desc">The scope in which to call the
 
351
     * callback functions (The <tt>this</tt> reference for the callback functions).</p></li>
 
352
     * <li><b>clientValidation</b> : Boolean<p class="sub-desc">Submit Action only.
 
353
     * Determines whether a Form's fields are validated in a final call to
 
354
     * {@link Ext.form.BasicForm#isValid isValid} prior to submission. Set to <tt>false</tt>
 
355
     * to prevent this. If undefined, pre-submission field validation is performed.</p></li></ul>
 
356
     * @return {BasicForm} this
 
357
     */
 
358
    doAction : function(action, options){
 
359
        if(typeof action == 'string'){
 
360
            action = new Ext.form.Action.ACTION_TYPES[action](this, options);
 
361
        }
 
362
        if(this.fireEvent('beforeaction', this, action) !== false){
 
363
            this.beforeAction(action);
 
364
            action.run.defer(100, action);
 
365
        }
 
366
        return this;
 
367
    },
 
368
 
 
369
    /**
 
370
     * Shortcut to {@link #doAction do} a {@link Ext.form.Action.Submit submit action}.
 
371
     * @param {Object} options The options to pass to the action (see {@link #doAction} for details).<br>
 
372
     * <p><b>Note:</b> this is ignored when using the {@link #standardSubmit} option.</p>
 
373
     * <p>The following code:</p><pre><code>
 
374
myFormPanel.getForm().submit({
 
375
    clientValidation: true,
 
376
    url: 'updateConsignment.php',
 
377
    params: {
 
378
        newStatus: 'delivered'
 
379
    },
 
380
    success: function(form, action) {
 
381
       Ext.Msg.alert("Success", action.result.msg);
 
382
    },
 
383
    failure: function(form, action) {
 
384
        switch (action.failureType) {
 
385
            case Ext.form.Action.CLIENT_INVALID:
 
386
                Ext.Msg.alert("Failure", "Form fields may not be submitted with invalid values");
 
387
                break;
 
388
            case Ext.form.Action.CONNECT_FAILURE:
 
389
                Ext.Msg.alert("Failure", "Ajax communication failed");
 
390
                break;
 
391
            case Ext.form.Action.SERVER_INVALID:
 
392
               Ext.Msg.alert("Failure", action.result.msg);
 
393
       }
 
394
    }
 
395
});
 
396
</code></pre>
 
397
     * would process the following server response for a successful submission:<pre><code>
 
398
{
 
399
    success: true,
 
400
    msg: 'Consignment updated'
 
401
}
 
402
</code></pre>
 
403
     * and the following server response for a failed submission:<pre><code>
 
404
{
 
405
    success: false,
 
406
    msg: 'You do not have permission to perform this operation'
 
407
}
 
408
</code></pre>
 
409
     * @return {BasicForm} this
 
410
     */
 
411
    submit : function(options){
 
412
        if(this.standardSubmit){
 
413
            var v = this.isValid();
 
414
            if(v){
 
415
                this.el.dom.submit();
 
416
            }
 
417
            return v;
 
418
        }
 
419
        var submitAction = String.format('{0}submit', this.api ? 'direct' : '');
 
420
        this.doAction(submitAction, options);
 
421
        return this;
 
422
    },
 
423
 
 
424
    /**
 
425
     * Shortcut to {@link #doAction do} a {@link Ext.form.Action.Load load action}.
 
426
     * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
 
427
     * @return {BasicForm} this
 
428
     */
 
429
    load : function(options){
 
430
        var loadAction = String.format('{0}load', this.api ? 'direct' : '');
 
431
        this.doAction(loadAction, options);       
 
432
        return this;
 
433
    },
 
434
 
 
435
    /**
 
436
     * Persists the values in this form into the passed {@link Ext.data.Record} object in a beginEdit/endEdit block.
 
437
     * @param {Record} record The record to edit
 
438
     * @return {BasicForm} this
 
439
     */
 
440
    updateRecord : function(record){
 
441
        record.beginEdit();
 
442
        var fs = record.fields;
 
443
        fs.each(function(f){
 
444
            var field = this.findField(f.name);
 
445
            if(field){
 
446
                record.set(f.name, field.getValue());
 
447
            }
 
448
        }, this);
 
449
        record.endEdit();
 
450
        return this;
 
451
    },
 
452
 
 
453
    /**
 
454
     * Loads an {@link Ext.data.Record} into this form by calling {@link #setValues} with the
 
455
     * {@link Ext.data.Record#data record data}.
 
456
     * See also {@link #trackResetOnLoad}.
 
457
     * @param {Record} record The record to load
 
458
     * @return {BasicForm} this
 
459
     */
 
460
    loadRecord : function(record){
 
461
        this.setValues(record.data);
 
462
        return this;
 
463
    },
 
464
 
 
465
    // private
 
466
    beforeAction : function(action){
 
467
        var o = action.options;
 
468
        if(o.waitMsg){
 
469
            if(this.waitMsgTarget === true){
 
470
                this.el.mask(o.waitMsg, 'x-mask-loading');
 
471
            }else if(this.waitMsgTarget){
 
472
                this.waitMsgTarget = Ext.get(this.waitMsgTarget);
 
473
                this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
 
474
            }else{
 
475
                Ext.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
 
476
            }
 
477
        }
 
478
    },
 
479
 
 
480
    // private
 
481
    afterAction : function(action, success){
 
482
        this.activeAction = null;
 
483
        var o = action.options;
 
484
        if(o.waitMsg){
 
485
            if(this.waitMsgTarget === true){
 
486
                this.el.unmask();
 
487
            }else if(this.waitMsgTarget){
 
488
                this.waitMsgTarget.unmask();
 
489
            }else{
 
490
                Ext.MessageBox.updateProgress(1);
 
491
                Ext.MessageBox.hide();
 
492
            }
 
493
        }
 
494
        if(success){
 
495
            if(o.reset){
 
496
                this.reset();
 
497
            }
 
498
            Ext.callback(o.success, o.scope, [this, action]);
 
499
            this.fireEvent('actioncomplete', this, action);
 
500
        }else{
 
501
            Ext.callback(o.failure, o.scope, [this, action]);
 
502
            this.fireEvent('actionfailed', this, action);
 
503
        }
 
504
    },
 
505
 
 
506
    /**
 
507
     * Find a {@link Ext.form.Field} in this form.
 
508
     * @param {String} id The value to search for (specify either a {@link Ext.Component#id id},
 
509
     * {@link Ext.grid.Column#dataIndex dataIndex}, {@link Ext.form.Field#getName name or hiddenName}).
 
510
     * @return Field
 
511
     */
 
512
    findField : function(id){
 
513
        var field = this.items.get(id);
 
514
        if(!Ext.isObject(field)){
 
515
            this.items.each(function(f){
 
516
                if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
 
517
                    field = f;
 
518
                    return false;
 
519
                }
 
520
            });
 
521
        }
 
522
        return field || null;
 
523
    },
 
524
 
 
525
 
 
526
    /**
 
527
     * Mark fields in this form invalid in bulk.
 
528
     * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
 
529
     * @return {BasicForm} this
 
530
     */
 
531
    markInvalid : function(errors){
 
532
        if(Ext.isArray(errors)){
 
533
            for(var i = 0, len = errors.length; i < len; i++){
 
534
                var fieldError = errors[i];
 
535
                var f = this.findField(fieldError.id);
 
536
                if(f){
 
537
                    f.markInvalid(fieldError.msg);
 
538
                }
 
539
            }
 
540
        }else{
 
541
            var field, id;
 
542
            for(id in errors){
 
543
                if(!Ext.isFunction(errors[id]) && (field = this.findField(id))){
 
544
                    field.markInvalid(errors[id]);
 
545
                }
 
546
            }
 
547
        }
 
548
        return this;
 
549
    },
 
550
 
 
551
    /**
 
552
     * Set values for fields in this form in bulk.
 
553
     * @param {Array/Object} values Either an array in the form:<br><br><code><pre>
 
554
[{id:'clientName', value:'Fred. Olsen Lines'},
 
555
 {id:'portOfLoading', value:'FXT'},
 
556
 {id:'portOfDischarge', value:'OSL'} ]</pre></code><br><br>
 
557
     * or an object hash of the form:<br><br><code><pre>
 
558
{
 
559
    clientName: 'Fred. Olsen Lines',
 
560
    portOfLoading: 'FXT',
 
561
    portOfDischarge: 'OSL'
 
562
}</pre></code><br>
 
563
     * @return {BasicForm} this
 
564
     */
 
565
    setValues : function(values){
 
566
        if(Ext.isArray(values)){ // array of objects
 
567
            for(var i = 0, len = values.length; i < len; i++){
 
568
                var v = values[i];
 
569
                var f = this.findField(v.id);
 
570
                if(f){
 
571
                    f.setValue(v.value);
 
572
                    if(this.trackResetOnLoad){
 
573
                        f.originalValue = f.getValue();
 
574
                    }
 
575
                }
 
576
            }
 
577
        }else{ // object hash
 
578
            var field, id;
 
579
            for(id in values){
 
580
                if(!Ext.isFunction(values[id]) && (field = this.findField(id))){
 
581
                    field.setValue(values[id]);
 
582
                    if(this.trackResetOnLoad){
 
583
                        field.originalValue = field.getValue();
 
584
                    }
 
585
                }
 
586
            }
 
587
        }
 
588
        return this;
 
589
    },
 
590
 
 
591
    /**
 
592
     * <p>Returns the fields in this form as an object with key/value pairs as they would be submitted using a standard form submit.
 
593
     * If multiple fields exist with the same name they are returned as an array.</p>
 
594
     * <p><b>Note:</b> The values are collected from all enabled HTML input elements within the form, <u>not</u> from
 
595
     * the Ext Field objects. This means that all returned values are Strings (or Arrays of Strings) and that the
 
596
     * value can potentially be the emptyText of a field.</p>
 
597
     * @param {Boolean} asString (optional) Pass true to return the values as a string. (defaults to false, returning an Object)
 
598
     * @return {String/Object}
 
599
     */
 
600
    getValues : function(asString){
 
601
        var fs = Ext.lib.Ajax.serializeForm(this.el.dom);
 
602
        if(asString === true){
 
603
            return fs;
 
604
        }
 
605
        return Ext.urlDecode(fs);
 
606
    },
 
607
 
 
608
    getFieldValues : function(){
 
609
        var o = {};
 
610
        this.items.each(function(f){
 
611
           o[f.getName()] = f.getValue();
 
612
        });
 
613
        return o;
 
614
    },
 
615
 
 
616
    /**
 
617
     * Clears all invalid messages in this form.
 
618
     * @return {BasicForm} this
 
619
     */
 
620
    clearInvalid : function(){
 
621
        this.items.each(function(f){
 
622
           f.clearInvalid();
 
623
        });
 
624
        return this;
 
625
    },
 
626
 
 
627
    /**
 
628
     * Resets this form.
 
629
     * @return {BasicForm} this
 
630
     */
 
631
    reset : function(){
 
632
        this.items.each(function(f){
 
633
            f.reset();
 
634
        });
 
635
        return this;
 
636
    },
 
637
 
 
638
    /**
 
639
     * Add Ext.form Components to this form's Collection. This does not result in rendering of
 
640
     * the passed Component, it just enables the form to validate Fields, and distribute values to
 
641
     * Fields.
 
642
     * <p><b>You will not usually call this function. In order to be rendered, a Field must be added
 
643
     * to a {@link Ext.Container Container}, usually an {@link Ext.form.FormPanel FormPanel}.
 
644
     * The FormPanel to which the field is added takes care of adding the Field to the BasicForm's
 
645
     * collection.</b></p>
 
646
     * @param {Field} field1
 
647
     * @param {Field} field2 (optional)
 
648
     * @param {Field} etc (optional)
 
649
     * @return {BasicForm} this
 
650
     */
 
651
    add : function(){
 
652
        this.items.addAll(Array.prototype.slice.call(arguments, 0));
 
653
        return this;
 
654
    },
 
655
 
 
656
 
 
657
    /**
 
658
     * Removes a field from the items collection (does NOT remove its markup).
 
659
     * @param {Field} field
 
660
     * @return {BasicForm} this
 
661
     */
 
662
    remove : function(field){
 
663
        this.items.remove(field);
 
664
        return this;
 
665
    },
 
666
 
 
667
    /**
 
668
     * Iterates through the {@link Ext.form.Field Field}s which have been {@link #add add}ed to this BasicForm,
 
669
     * checks them for an id attribute, and calls {@link Ext.form.Field#applyToMarkup} on the existing dom element with that id.
 
670
     * @return {BasicForm} this
 
671
     */
 
672
    render : function(){
 
673
        this.items.each(function(f){
 
674
            if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
 
675
                f.applyToMarkup(f.id);
 
676
            }
 
677
        });
 
678
        return this;
 
679
    },
 
680
 
 
681
    /**
 
682
     * Calls {@link Ext#apply} for all fields in this form with the passed object.
 
683
     * @param {Object} values
 
684
     * @return {BasicForm} this
 
685
     */
 
686
    applyToFields : function(o){
 
687
        this.items.each(function(f){
 
688
           Ext.apply(f, o);
 
689
        });
 
690
        return this;
 
691
    },
 
692
 
 
693
    /**
 
694
     * Calls {@link Ext#applyIf} for all field in this form with the passed object.
 
695
     * @param {Object} values
 
696
     * @return {BasicForm} this
 
697
     */
 
698
    applyIfToFields : function(o){
 
699
        this.items.each(function(f){
 
700
           Ext.applyIf(f, o);
 
701
        });
 
702
        return this;
 
703
    },
 
704
 
 
705
    callFieldMethod : function(fnName, args){
 
706
        args = args || [];
 
707
        this.items.each(function(f){
 
708
            if(Ext.isFunction(f[fnName])){
 
709
                f[fnName].apply(f, args);
 
710
            }
 
711
        });
 
712
        return this;
 
713
    }
 
714
});
 
715
 
 
716
// back compat
 
717
Ext.BasicForm = Ext.form.BasicForm;
 
 
b'\\ No newline at end of file'