BasicForm.js
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:29k
源码类别:

JavaScript

开发平台:

JavaScript

  1. /*!
  2.  * Ext JS Library 3.1.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.      * A {@link Ext.util.MixedCollection MixedCollection} containing all the Ext.form.Fields in this form.
  44.      * @type MixedCollection
  45.      * @property items
  46.      */
  47.     this.items = new Ext.util.MixedCollection(false, function(o){
  48.         return o.getItemId();
  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.     
  182.     /**
  183.      * @cfg {String} waitTitle
  184.      * The default title to show for the waiting message box (defaults to <tt>'Please Wait...'</tt>)
  185.      */
  186.     waitTitle: 'Please Wait...',
  187.     // private
  188.     activeAction : null,
  189.     /**
  190.      * @cfg {Boolean} trackResetOnLoad If set to <tt>true</tt>, {@link #reset}() resets to the last loaded
  191.      * or {@link #setValues}() data instead of when the form was first created.  Defaults to <tt>false</tt>.
  192.      */
  193.     trackResetOnLoad : false,
  194.     /**
  195.      * @cfg {Boolean} standardSubmit
  196.      * <p>If set to <tt>true</tt>, standard HTML form submits are used instead
  197.      * of XHR (Ajax) style form submissions. Defaults to <tt>false</tt>.</p>
  198.      * <br><p><b>Note:</b> When using <code>standardSubmit</code>, the
  199.      * <code>options</code> to <code>{@link #submit}</code> are ignored because
  200.      * Ext's Ajax infrastracture is bypassed. To pass extra parameters (e.g.
  201.      * <code>baseParams</code> and <code>params</code>), utilize hidden fields
  202.      * to submit extra data, for example:</p>
  203.      * <pre><code>
  204. new Ext.FormPanel({
  205.     standardSubmit: true,
  206.     baseParams: {
  207.         foo: 'bar'
  208.     },
  209.     {@link url}: 'myProcess.php',
  210.     items: [{
  211.         xtype: 'textfield',
  212.         name: 'userName'
  213.     }],
  214.     buttons: [{
  215.         text: 'Save',
  216.         handler: function(){
  217.             var fp = this.ownerCt.ownerCt,
  218.                 form = fp.getForm();
  219.             if (form.isValid()) {
  220.                 // check if there are baseParams and if
  221.                 // hiddent items have been added already
  222.                 if (fp.baseParams && !fp.paramsAdded) {
  223.                     // add hidden items for all baseParams
  224.                     for (i in fp.baseParams) {
  225.                         fp.add({
  226.                             xtype: 'hidden',
  227.                             name: i,
  228.                             value: fp.baseParams[i]
  229.                         });
  230.                     }
  231.                     fp.doLayout();
  232.                     // set a custom flag to prevent re-adding
  233.                     fp.paramsAdded = true;
  234.                 }
  235.                 form.{@link #submit}();
  236.             }
  237.         }
  238.     }]
  239. });
  240.      * </code></pre>
  241.      */
  242.     /**
  243.      * By default wait messages are displayed with Ext.MessageBox.wait. You can target a specific
  244.      * element by passing it or its id or mask the form itself by passing in true.
  245.      * @type Mixed
  246.      * @property waitMsgTarget
  247.      */
  248.     // private
  249.     initEl : function(el){
  250.         this.el = Ext.get(el);
  251.         this.id = this.el.id || Ext.id();
  252.         if(!this.standardSubmit){
  253.             this.el.on('submit', this.onSubmit, this);
  254.         }
  255.         this.el.addClass('x-form');
  256.     },
  257.     /**
  258.      * Get the HTML form Element
  259.      * @return Ext.Element
  260.      */
  261.     getEl: function(){
  262.         return this.el;
  263.     },
  264.     // private
  265.     onSubmit : function(e){
  266.         e.stopEvent();
  267.     },
  268.     // private
  269.     destroy: function() {
  270.         this.items.each(function(f){
  271.             Ext.destroy(f);
  272.         });
  273.         if(this.el){
  274.             this.el.removeAllListeners();
  275.             this.el.remove();
  276.         }
  277.         this.purgeListeners();
  278.     },
  279.     /**
  280.      * Returns true if client-side validation on the form is successful.
  281.      * @return Boolean
  282.      */
  283.     isValid : function(){
  284.         var valid = true;
  285.         this.items.each(function(f){
  286.            if(!f.validate()){
  287.                valid = false;
  288.            }
  289.         });
  290.         return valid;
  291.     },
  292.     /**
  293.      * <p>Returns true if any fields in this form have changed from their original values.</p>
  294.      * <p>Note that if this BasicForm was configured with {@link #trackResetOnLoad} then the
  295.      * Fields' <i>original values</i> are updated when the values are loaded by {@link #setValues}
  296.      * or {@link #loadRecord}.</p>
  297.      * @return Boolean
  298.      */
  299.     isDirty : function(){
  300.         var dirty = false;
  301.         this.items.each(function(f){
  302.            if(f.isDirty()){
  303.                dirty = true;
  304.                return false;
  305.            }
  306.         });
  307.         return dirty;
  308.     },
  309.     /**
  310.      * Performs a predefined action ({@link Ext.form.Action.Submit} or
  311.      * {@link Ext.form.Action.Load}) or a custom extension of {@link Ext.form.Action}
  312.      * to perform application-specific processing.
  313.      * @param {String/Object} actionName The name of the predefined action type,
  314.      * or instance of {@link Ext.form.Action} to perform.
  315.      * @param {Object} options (optional) The options to pass to the {@link Ext.form.Action}.
  316.      * All of the config options listed below are supported by both the
  317.      * {@link Ext.form.Action.Submit submit} and {@link Ext.form.Action.Load load}
  318.      * actions unless otherwise noted (custom actions could also accept
  319.      * other config options):<ul>
  320.      *
  321.      * <li><b>url</b> : String<div class="sub-desc">The url for the action (defaults
  322.      * to the form's {@link #url}.)</div></li>
  323.      *
  324.      * <li><b>method</b> : String<div class="sub-desc">The form method to use (defaults
  325.      * to the form's method, or POST if not defined)</div></li>
  326.      *
  327.      * <li><b>params</b> : String/Object<div class="sub-desc"><p>The params to pass
  328.      * (defaults to the form's baseParams, or none if not defined)</p>
  329.      * <p>Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode}.</p></div></li>
  330.      *
  331.      * <li><b>headers</b> : Object<div class="sub-desc">Request headers to set for the action
  332.      * (defaults to the form's default headers)</div></li>
  333.      *
  334.      * <li><b>success</b> : Function<div class="sub-desc">The callback that will
  335.      * be invoked after a successful response (see top of
  336.      * {@link Ext.form.Action.Submit submit} and {@link Ext.form.Action.Load load}
  337.      * for a description of what constitutes a successful response).
  338.      * The function is passed the following parameters:<ul>
  339.      * <li><tt>form</tt> : Ext.form.BasicForm<div class="sub-desc">The form that requested the action</div></li>
  340.      * <li><tt>action</tt> : The {@link Ext.form.Action Action} object which performed the operation.
  341.      * <div class="sub-desc">The action object contains these properties of interest:<ul>
  342.      * <li><tt>{@link Ext.form.Action#response response}</tt></li>
  343.      * <li><tt>{@link Ext.form.Action#result result}</tt> : interrogate for custom postprocessing</li>
  344.      * <li><tt>{@link Ext.form.Action#type type}</tt></li>
  345.      * </ul></div></li></ul></div></li>
  346.      *
  347.      * <li><b>failure</b> : Function<div class="sub-desc">The callback that will be invoked after a
  348.      * failed transaction attempt. The function is passed the following parameters:<ul>
  349.      * <li><tt>form</tt> : The {@link Ext.form.BasicForm} that requested the action.</li>
  350.      * <li><tt>action</tt> : The {@link Ext.form.Action Action} object which performed the operation.
  351.      * <div class="sub-desc">The action object contains these properties of interest:<ul>
  352.      * <li><tt>{@link Ext.form.Action#failureType failureType}</tt></li>
  353.      * <li><tt>{@link Ext.form.Action#response response}</tt></li>
  354.      * <li><tt>{@link Ext.form.Action#result result}</tt> : interrogate for custom postprocessing</li>
  355.      * <li><tt>{@link Ext.form.Action#type type}</tt></li>
  356.      * </ul></div></li></ul></div></li>
  357.      *
  358.      * <li><b>scope</b> : Object<div class="sub-desc">The scope in which to call the
  359.      * callback functions (The <tt>this</tt> reference for the callback functions).</div></li>
  360.      *
  361.      * <li><b>clientValidation</b> : Boolean<div class="sub-desc">Submit Action only.
  362.      * Determines whether a Form's fields are validated in a final call to
  363.      * {@link Ext.form.BasicForm#isValid isValid} prior to submission. Set to <tt>false</tt>
  364.      * to prevent this. If undefined, pre-submission field validation is performed.</div></li></ul>
  365.      *
  366.      * @return {BasicForm} this
  367.      */
  368.     doAction : function(action, options){
  369.         if(Ext.isString(action)){
  370.             action = new Ext.form.Action.ACTION_TYPES[action](this, options);
  371.         }
  372.         if(this.fireEvent('beforeaction', this, action) !== false){
  373.             this.beforeAction(action);
  374.             action.run.defer(100, action);
  375.         }
  376.         return this;
  377.     },
  378.     /**
  379.      * Shortcut to {@link #doAction do} a {@link Ext.form.Action.Submit submit action}.
  380.      * @param {Object} options The options to pass to the action (see {@link #doAction} for details).<br>
  381.      * <p><b>Note:</b> this is ignored when using the {@link #standardSubmit} option.</p>
  382.      * <p>The following code:</p><pre><code>
  383. myFormPanel.getForm().submit({
  384.     clientValidation: true,
  385.     url: 'updateConsignment.php',
  386.     params: {
  387.         newStatus: 'delivered'
  388.     },
  389.     success: function(form, action) {
  390.        Ext.Msg.alert('Success', action.result.msg);
  391.     },
  392.     failure: function(form, action) {
  393.         switch (action.failureType) {
  394.             case Ext.form.Action.CLIENT_INVALID:
  395.                 Ext.Msg.alert('Failure', 'Form fields may not be submitted with invalid values');
  396.                 break;
  397.             case Ext.form.Action.CONNECT_FAILURE:
  398.                 Ext.Msg.alert('Failure', 'Ajax communication failed');
  399.                 break;
  400.             case Ext.form.Action.SERVER_INVALID:
  401.                Ext.Msg.alert('Failure', action.result.msg);
  402.        }
  403.     }
  404. });
  405. </code></pre>
  406.      * would process the following server response for a successful submission:<pre><code>
  407. {
  408.     "success":true, // note this is Boolean, not string
  409.     "msg":"Consignment updated"
  410. }
  411. </code></pre>
  412.      * and the following server response for a failed submission:<pre><code>
  413. {
  414.     "success":false, // note this is Boolean, not string
  415.     "msg":"You do not have permission to perform this operation"
  416. }
  417. </code></pre>
  418.      * @return {BasicForm} this
  419.      */
  420.     submit : function(options){
  421.         if(this.standardSubmit){
  422.             var v = this.isValid();
  423.             if(v){
  424.                 var el = this.el.dom;
  425.                 if(this.url && Ext.isEmpty(el.action)){
  426.                     el.action = this.url;
  427.                 }
  428.                 el.submit();
  429.             }
  430.             return v;
  431.         }
  432.         var submitAction = String.format('{0}submit', this.api ? 'direct' : '');
  433.         this.doAction(submitAction, options);
  434.         return this;
  435.     },
  436.     /**
  437.      * Shortcut to {@link #doAction do} a {@link Ext.form.Action.Load load action}.
  438.      * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
  439.      * @return {BasicForm} this
  440.      */
  441.     load : function(options){
  442.         var loadAction = String.format('{0}load', this.api ? 'direct' : '');
  443.         this.doAction(loadAction, options);
  444.         return this;
  445.     },
  446.     /**
  447.      * Persists the values in this form into the passed {@link Ext.data.Record} object in a beginEdit/endEdit block.
  448.      * @param {Record} record The record to edit
  449.      * @return {BasicForm} this
  450.      */
  451.     updateRecord : function(record){
  452.         record.beginEdit();
  453.         var fs = record.fields;
  454.         fs.each(function(f){
  455.             var field = this.findField(f.name);
  456.             if(field){
  457.                 record.set(f.name, field.getValue());
  458.             }
  459.         }, this);
  460.         record.endEdit();
  461.         return this;
  462.     },
  463.     /**
  464.      * Loads an {@link Ext.data.Record} into this form by calling {@link #setValues} with the
  465.      * {@link Ext.data.Record#data record data}.
  466.      * See also {@link #trackResetOnLoad}.
  467.      * @param {Record} record The record to load
  468.      * @return {BasicForm} this
  469.      */
  470.     loadRecord : function(record){
  471.         this.setValues(record.data);
  472.         return this;
  473.     },
  474.     // private
  475.     beforeAction : function(action){
  476.         var o = action.options;
  477.         if(o.waitMsg){
  478.             if(this.waitMsgTarget === true){
  479.                 this.el.mask(o.waitMsg, 'x-mask-loading');
  480.             }else if(this.waitMsgTarget){
  481.                 this.waitMsgTarget = Ext.get(this.waitMsgTarget);
  482.                 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
  483.             }else{
  484.                 Ext.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle);
  485.             }
  486.         }
  487.     },
  488.     // private
  489.     afterAction : function(action, success){
  490.         this.activeAction = null;
  491.         var o = action.options;
  492.         if(o.waitMsg){
  493.             if(this.waitMsgTarget === true){
  494.                 this.el.unmask();
  495.             }else if(this.waitMsgTarget){
  496.                 this.waitMsgTarget.unmask();
  497.             }else{
  498.                 Ext.MessageBox.updateProgress(1);
  499.                 Ext.MessageBox.hide();
  500.             }
  501.         }
  502.         if(success){
  503.             if(o.reset){
  504.                 this.reset();
  505.             }
  506.             Ext.callback(o.success, o.scope, [this, action]);
  507.             this.fireEvent('actioncomplete', this, action);
  508.         }else{
  509.             Ext.callback(o.failure, o.scope, [this, action]);
  510.             this.fireEvent('actionfailed', this, action);
  511.         }
  512.     },
  513.     /**
  514.      * Find a {@link Ext.form.Field} in this form.
  515.      * @param {String} id The value to search for (specify either a {@link Ext.Component#id id},
  516.      * {@link Ext.grid.Column#dataIndex dataIndex}, {@link Ext.form.Field#getName name or hiddenName}).
  517.      * @return Field
  518.      */
  519.     findField : function(id){
  520.         var field = this.items.get(id);
  521.         if(!Ext.isObject(field)){
  522.             this.items.each(function(f){
  523.                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
  524.                     field = f;
  525.                     return false;
  526.                 }
  527.             });
  528.         }
  529.         return field || null;
  530.     },
  531.     /**
  532.      * Mark fields in this form invalid in bulk.
  533.      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
  534.      * @return {BasicForm} this
  535.      */
  536.     markInvalid : function(errors){
  537.         if(Ext.isArray(errors)){
  538.             for(var i = 0, len = errors.length; i < len; i++){
  539.                 var fieldError = errors[i];
  540.                 var f = this.findField(fieldError.id);
  541.                 if(f){
  542.                     f.markInvalid(fieldError.msg);
  543.                 }
  544.             }
  545.         }else{
  546.             var field, id;
  547.             for(id in errors){
  548.                 if(!Ext.isFunction(errors[id]) && (field = this.findField(id))){
  549.                     field.markInvalid(errors[id]);
  550.                 }
  551.             }
  552.         }
  553.         return this;
  554.     },
  555.     /**
  556.      * Set values for fields in this form in bulk.
  557.      * @param {Array/Object} values Either an array in the form:<pre><code>
  558. [{id:'clientName', value:'Fred. Olsen Lines'},
  559.  {id:'portOfLoading', value:'FXT'},
  560.  {id:'portOfDischarge', value:'OSL'} ]</code></pre>
  561.      * or an object hash of the form:<pre><code>
  562. {
  563.     clientName: 'Fred. Olsen Lines',
  564.     portOfLoading: 'FXT',
  565.     portOfDischarge: 'OSL'
  566. }</code></pre>
  567.      * @return {BasicForm} this
  568.      */
  569.     setValues : function(values){
  570.         if(Ext.isArray(values)){ // array of objects
  571.             for(var i = 0, len = values.length; i < len; i++){
  572.                 var v = values[i];
  573.                 var f = this.findField(v.id);
  574.                 if(f){
  575.                     f.setValue(v.value);
  576.                     if(this.trackResetOnLoad){
  577.                         f.originalValue = f.getValue();
  578.                     }
  579.                 }
  580.             }
  581.         }else{ // object hash
  582.             var field, id;
  583.             for(id in values){
  584.                 if(!Ext.isFunction(values[id]) && (field = this.findField(id))){
  585.                     field.setValue(values[id]);
  586.                     if(this.trackResetOnLoad){
  587.                         field.originalValue = field.getValue();
  588.                     }
  589.                 }
  590.             }
  591.         }
  592.         return this;
  593.     },
  594.     /**
  595.      * <p>Returns the fields in this form as an object with key/value pairs as they would be submitted using a standard form submit.
  596.      * If multiple fields exist with the same name they are returned as an array.</p>
  597.      * <p><b>Note:</b> The values are collected from all enabled HTML input elements within the form, <u>not</u> from
  598.      * the Ext Field objects. This means that all returned values are Strings (or Arrays of Strings) and that the
  599.      * value can potentially be the emptyText of a field.</p>
  600.      * @param {Boolean} asString (optional) Pass true to return the values as a string. (defaults to false, returning an Object)
  601.      * @return {String/Object}
  602.      */
  603.     getValues : function(asString){
  604.         var fs = Ext.lib.Ajax.serializeForm(this.el.dom);
  605.         if(asString === true){
  606.             return fs;
  607.         }
  608.         return Ext.urlDecode(fs);
  609.     },
  610.     /**
  611.      * Retrieves the fields in the form as a set of key/value pairs, using the {@link Ext.form.Field#getValue getValue()} method.
  612.      * If multiple fields exist with the same name they are returned as an array.
  613.      * @param {Boolean} dirtyOnly (optional) True to return only fields that are dirty.
  614.      * @return {Object} The values in the form
  615.      */
  616.     getFieldValues : function(dirtyOnly){
  617.         var o = {},
  618.             n,
  619.             key,
  620.             val;
  621.         this.items.each(function(f){
  622.             if(dirtyOnly !== true || f.isDirty()){
  623.                 n = f.getName();
  624.                 key = o[n];
  625.                 val = f.getValue();
  626.                 
  627.                 if(Ext.isDefined(key)){
  628.                     if(Ext.isArray(key)){
  629.                         o[n].push(val);
  630.                     }else{
  631.                         o[n] = [key, val];
  632.                     }
  633.                 }else{
  634.                     o[n] = val;
  635.                 }
  636.             }
  637.         });
  638.         return o;
  639.     },
  640.     /**
  641.      * Clears all invalid messages in this form.
  642.      * @return {BasicForm} this
  643.      */
  644.     clearInvalid : function(){
  645.         this.items.each(function(f){
  646.            f.clearInvalid();
  647.         });
  648.         return this;
  649.     },
  650.     /**
  651.      * Resets this form.
  652.      * @return {BasicForm} this
  653.      */
  654.     reset : function(){
  655.         this.items.each(function(f){
  656.             f.reset();
  657.         });
  658.         return this;
  659.     },
  660.     /**
  661.      * Add Ext.form Components to this form's Collection. This does not result in rendering of
  662.      * the passed Component, it just enables the form to validate Fields, and distribute values to
  663.      * Fields.
  664.      * <p><b>You will not usually call this function. In order to be rendered, a Field must be added
  665.      * to a {@link Ext.Container Container}, usually an {@link Ext.form.FormPanel FormPanel}.
  666.      * The FormPanel to which the field is added takes care of adding the Field to the BasicForm's
  667.      * collection.</b></p>
  668.      * @param {Field} field1
  669.      * @param {Field} field2 (optional)
  670.      * @param {Field} etc (optional)
  671.      * @return {BasicForm} this
  672.      */
  673.     add : function(){
  674.         this.items.addAll(Array.prototype.slice.call(arguments, 0));
  675.         return this;
  676.     },
  677.     /**
  678.      * Removes a field from the items collection (does NOT remove its markup).
  679.      * @param {Field} field
  680.      * @return {BasicForm} this
  681.      */
  682.     remove : function(field){
  683.         this.items.remove(field);
  684.         return this;
  685.     },
  686.     /**
  687.      * Iterates through the {@link Ext.form.Field Field}s which have been {@link #add add}ed to this BasicForm,
  688.      * checks them for an id attribute, and calls {@link Ext.form.Field#applyToMarkup} on the existing dom element with that id.
  689.      * @return {BasicForm} this
  690.      */
  691.     render : function(){
  692.         this.items.each(function(f){
  693.             if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
  694.                 f.applyToMarkup(f.id);
  695.             }
  696.         });
  697.         return this;
  698.     },
  699.     /**
  700.      * Calls {@link Ext#apply} for all fields in this form with the passed object.
  701.      * @param {Object} values
  702.      * @return {BasicForm} this
  703.      */
  704.     applyToFields : function(o){
  705.         this.items.each(function(f){
  706.            Ext.apply(f, o);
  707.         });
  708.         return this;
  709.     },
  710.     /**
  711.      * Calls {@link Ext#applyIf} for all field in this form with the passed object.
  712.      * @param {Object} values
  713.      * @return {BasicForm} this
  714.      */
  715.     applyIfToFields : function(o){
  716.         this.items.each(function(f){
  717.            Ext.applyIf(f, o);
  718.         });
  719.         return this;
  720.     },
  721.     callFieldMethod : function(fnName, args){
  722.         args = args || [];
  723.         this.items.each(function(f){
  724.             if(Ext.isFunction(f[fnName])){
  725.                 f[fnName].apply(f, args);
  726.             }
  727.         });
  728.         return this;
  729.     }
  730. });
  731. // back compat
  732. Ext.BasicForm = Ext.form.BasicForm;