BasicForm.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:28k
源码类别:

中间件编程

开发平台:

JavaScript

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