text: /**
   * A class which handles submission of data from {@link Ext.form.Basic Form}s and processes
   * the returned response.
   *
   * Instances of this class are only created by a {@link Ext.form.Basic Form} when
   * {@link Ext.form.Basic#submit submit}ting.
   *
   * # Response Packet Criteria
   *
   * A response packet may contain:
   *
   *   - **`success`** property : Boolean - required.
   *
   *   - **`errors`** property : Object - optional, contains error messages for invalid fields.
   *
   * # JSON Packets
   *
   * By default, response packets are assumed to be JSON, so a typical response packet may look
   * like this:
   *
   *     {
   *         success: false,
   *         errors: {
   *             clientCode: "Client not found",
   *             portOfLoading: "This field must not be null"
   *         }
   *     }
   *
   * Other data may be placed into the response for processing by the {@link Ext.form.Basic}'s
   * callback or event handler methods. The object decoded from this JSON is available in the
   * {@link Ext.form.action.Action#result result} property.
   *
   * Alternatively, if an {@link Ext.form.Basic#errorReader errorReader} is specified as an
   * {@link Ext.data.reader.Xml XmlReader}:
   *
   *     errorReader: new Ext.data.reader.Xml({
   *             record : 'field',
   *             success: '@success'
   *         }, [
   *             'id', 'msg'
   *         ]
   *     )
   *
   * then the results may be sent back in XML format:
   *
   *     <?xml version="1.0" encoding="UTF-8"?>
   *     <message success="false">
   *     <errors>
   *         <field>
   *             <id>clientCode</id>
   *             <msg>
   *                 <![CDATA[
   *                     Code not found. <br />
   *                     <i>This is a test validation message from the server </i>
   *                 ]]>
   *             </msg>
   *         </field>
   *         <field>
   *             <id>portOfLoading</id>
   *             <msg>
   *                 <![CDATA[
   *                     Port not found. <br />
   *                     <i>This is a test validation message from the server </i>
   *                 ]]>
   *             </msg>
   *         </field>
   *     </errors>
   *     </message>
   *
   * Other elements may be placed into the response XML for processing by the {@link Ext.form.Basic}'s
   * callback or event handler methods. The XML document is available in the
   * {@link Ext.form.Basic#errorReader errorReader}'s {@link Ext.data.reader.Xml#xmlData xmlData}
   * property.
   */
  Ext.define('Ext.form.action.Submit', {
      extend: 'Ext.form.action.Action',
      alternateClassName: 'Ext.form.Action.Submit',
      alias: 'formaction.submit',
  
      type: 'submit',
  
      /**
       * @cfg {Boolean} [clientValidation=true]
       * Determines whether a Form's fields are validated in a final call
       * to {@link Ext.form.Basic#isValid isValid} prior to submission. Pass false in the Form's
       * submit options to prevent this.
       */
  
      run: function() {
          var me = this,
              form = me.form;
  
          if (me.clientValidation === false || form.isValid()) {
              me.doSubmit();
          }
          else {
              // client validation failed
              me.failureType = Ext.form.action.Action.CLIENT_INVALID;
              form.afterAction(me, false);
          }
      },
  
      /**
       * @private
       * Performs the submit of the form data.
       */
      doSubmit: function() {
          var me = this,
              ajaxOptions = Ext.apply(me.createCallback(), {
                  url: me.getUrl(),
                  method: me.getMethod(),
                  headers: me.headers
              }),
              form = me.form,
              jsonSubmit = me.jsonSubmit || form.jsonSubmit,
              paramsProp = jsonSubmit ? 'jsonData' : 'params',
              formInfo;
  
          // For uploads we need to create an actual form that contains the file upload fields,
          // and pass that to the ajax call so it can do its iframe-based submit method.
          if (form.hasUpload()) {
              formInfo = me.buildForm();
              ajaxOptions.form = formInfo.formEl;
              ajaxOptions.isUpload = true;
          }
          else {
              ajaxOptions[paramsProp] = me.getParams(jsonSubmit);
          }
  
          Ext.Ajax.request(ajaxOptions);
  
          if (formInfo) {
              me.cleanup(formInfo);
          }
      },
  
      cleanup: function(formInfo) {
          var formEl = formInfo.formEl,
              uploadEls = formInfo.uploadEls,
              uploadFields = formInfo.uploadFields,
              len = uploadFields.length,
              i, field;
  
          for (i = 0; i < len; ++i) {
              field = uploadFields[i];
  
              if (!field.clearOnSubmit) {
                  field.restoreInput(uploadEls[i]);
              }
          }
  
          if (formEl) {
              Ext.removeNode(formEl);
          }
      },
  
      /**
       * @private
       * Builds the full set of parameters from the field values plus any additional
       * configured params.
       */
      getParams: function(useModelValues) {
          var falseVal = false,
              configParams = this.callParent(),
              fieldParams;
  
          fieldParams = this.form.getValues(
              falseVal, falseVal, this.submitEmptyText !== falseVal, useModelValues,
              /* isSubmitting */ true
          );
  
          return Ext.apply({}, fieldParams, configParams);
      },
  
      /**
       * @private
       * Builds a form element containing fields corresponding to all the parameters to be
       * submitted (everything returned by {@link #getParams}.
       *
       * NOTE: the form element is automatically added to the DOM, so any code that uses
       * it must remove it from the DOM after finishing with it.
       *
       * @return {HTMLElement}
       */
      buildForm: function() {
          var me = this,
              fieldsSpec = [],
              formSpec,
              formEl,
              basicForm = me.form,
              params = me.getParams(),
              uploadFields = [],
              uploadEls = [],
              fields = basicForm.getFields().items,
              i,
              len = fields.length,
              field, key, value, v, vLen,
              el;
  
          for (i = 0; i < len; ++i) {
              field = fields[i];
  
              if (field.isFileUpload()) {
                  uploadFields.push(field);
              }
          }
  
          for (key in params) {
              if (params.hasOwnProperty(key)) {
                  value = params[key];
  
                  if (Ext.isArray(value)) {
                      vLen = value.length;
  
                      for (v = 0; v < vLen; v++) {
                          fieldsSpec.push(me.getFieldConfig(key, value[v]));
                      }
                  }
                  else {
                      fieldsSpec.push(me.getFieldConfig(key, value));
                  }
              }
          }
  
          formSpec = {
              tag: 'form',
              role: 'presentation',
              action: me.getUrl(),
              method: me.getMethod(),
              target: me.target
                  ? (Ext.isString(me.target) ? me.target : Ext.fly(me.target).dom.name)
                  : '_self',
              style: 'display:none',
              cn: fieldsSpec
          };
  
          //<debug>
          if (!formSpec.target) {
              Ext.raise('Invalid form target.');
          }
          //</debug>
  
          // Set the proper encoding for file uploads
          if (uploadFields.length) {
              formSpec.encoding = formSpec.enctype = 'multipart/form-data';
          }
  
          // Create the form
          formEl = Ext.DomHelper.append(Ext.getBody(), formSpec);
  
          // Special handling for file upload fields: since browser security measures prevent setting
          // their values programatically, and prevent carrying their selected values over
          // when cloning, we have to move the actual field instances out of their components
          // and into the form.
          len = uploadFields.length;
  
          for (i = 0; i < len; ++i) {
              el = uploadFields[i].extractFileInput();
              formEl.appendChild(el);
              uploadEls.push(el);
          }
  
          return {
              formEl: formEl,
              uploadFields: uploadFields,
              uploadEls: uploadEls
          };
      },
  
      getFieldConfig: function(name, value) {
          return {
              tag: 'input',
              type: 'hidden',
              name: name,
              value: Ext.String.htmlEncode(value)
          };
      },
  
      /**
       * @private
       */
      onSuccess: function(response) {
          var form = this.form,
              formActive = form && !form.destroying && !form.destroyed,
              success = true,
              result = this.processResponse(response);
  
          if (result !== true && !result.success) {
              if (result.errors && formActive) {
                  form.markInvalid(result.errors);
              }
  
              this.failureType = Ext.form.action.Action.SERVER_INVALID;
              success = false;
          }
  
          if (formActive) {
              form.afterAction(this, success);
          }
      },
  
      /**
       * @private
       */
      handleResponse: function(response) {
          var form = this.form,
              errorReader = form.errorReader,
              rs, errors, i, len, records, result;
  
          if (errorReader) {
              rs = errorReader.read(response);
              records = rs.records;
              errors = [];
  
              if (records) {
                  for (i = 0, len = records.length; i < len; i++) {
                      errors[i] = records[i].data;
                  }
              }
  
              if (errors.length < 1) {
                  errors = null;
              }
  
              result = {
                  success: rs.success,
                  errors: errors
              };
          }
          else {
              try {
                  result = Ext.decode(response.responseText);
              }
              catch (e) {
                  result = {
                      success: false,
                      errors: []
                  };
              }
  
          }
  
          return result;
      }
  });
  