/**
* @class Ext.form.action.Submit
* @extends Ext.form.action.Action
* <p>A class which handles submission of data from {@link Ext.form.Basic Form}s
* and processes the returned response.</p>
* <p>Instances of this class are only created by a {@link Ext.form.Basic Form} when
* {@link Ext.form.Basic#submit submit}ting.</p>
* <p><u><b>Response Packet Criteria</b></u></p>
* <p>A response packet may contain:
* <div class="mdetail-params"><ul>
* <li><b><code>success</code></b> property : Boolean
* <div class="sub-desc">The <code>success</code> property is required.</div></li>
* <li><b><code>errors</code></b> property : Object
* <div class="sub-desc"><div class="sub-desc">The <code>errors</code> property,
* which is optional, contains error messages for invalid fields.</div></li>
* </ul></div>
* <p><u><b>JSON Packets</b></u></p>
* <p>By default, response packets are assumed to be JSON, so a typical response
* packet may look like this:</p><pre><code>
{
success: false,
errors: {
clientCode: "Client not found",
portOfLoading: "This field must not be null"
}
}</code></pre>
* <p>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.</p>
* <p>Alternatively, if an {@link #errorReader} is specified as an {@link Ext.data.reader.Xml XmlReader}:</p><pre><code>
errorReader: new Ext.data.reader.Xml({
record : 'field',
success: '@success'
}, [
'id', 'msg'
]
)
</code></pre>
* <p>then the results may be sent back in XML format:</p><pre><code>
<?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>
</code></pre>
* <p>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 #errorReader}'s {@link Ext.data.reader.Xml#xmlData xmlData} property.</p>
*/
Ext.define('Ext.form.action.Submit', {
extend:'Ext.form.action.Action',
alternateClassName: 'Ext.form.Action.Submit',
alias: 'formaction.submit',
type: 'submit',
/**
* @cfg {boolean} clientValidation Determines whether a Form's fields are validated
* in a final call to {@link Ext.form.Basic#isValid isValid} prior to submission.
* Pass <tt>false</tt> in the Form's submit options to prevent this. Defaults to true.
*/
// inherit docs
run : function(){
var form = this.form;
if (this.clientValidation === false || form.isValid()) {
this.doSubmit();
} else {
// client validation failed
this.failureType = Ext.form.action.Action.CLIENT_INVALID;
form.afterAction(this, false);
}
},
/**
* @private
* Perform the submit of the form data.
*/
doSubmit: function() {
var formEl,
ajaxOptions = Ext.apply(this.createCallback(), {
url: this.getUrl(),
method: this.getMethod(),
headers: this.headers
});
// 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 (this.form.hasUpload()) {
formEl = ajaxOptions.form = this.buildForm();
ajaxOptions.isUpload = true;
} else {
ajaxOptions.params = this.getParams();
}
Ext.Ajax.request(ajaxOptions);
if (formEl) {
Ext.removeNode(formEl);
}
},
/**
* @private
* Build the full set of parameters from the field values plus any additional configured params.
*/
getParams: function() {
var nope = false,
configParams = this.callParent(),
fieldParams = this.form.getValues(nope, nope, this.submitEmptyText !== nope);
return Ext.apply({}, fieldParams, configParams);
},
/**
* @private
* Build 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 HTMLFormElement
*/
buildForm: function() {
var fieldsSpec = [],
formSpec,
formEl,
basicForm = this.form,
params = this.getParams(),
uploadFields = [];
basicForm.getFields().each(function(field) {
if (field.isFileUpload()) {
uploadFields.push(field);
}
});
function addField(name, val) {
fieldsSpec.push({
tag: 'input',
type: 'hidden',
name: name,
value: val
});
}
// Add the form field values
Ext.iterate(params, function(key, val) {
if (Ext.isArray(val)) {
Ext.each(val, function(v) {
addField(key, v);
});
} else {
addField(key, val);
}
});
formSpec = {
tag: 'form',
action: this.getUrl(),
method: this.getMethod(),
target: this.target || '_self',
style: 'display:none',
cn: fieldsSpec
};
// Set the proper encoding for file uploads
if (uploadFields.length) {
formSpec.encoding = formSpec.enctype = 'multipart/form-data';
}
// Create the form
formEl = Ext.core.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.
Ext.Array.each(uploadFields, function(field) {
if (field.rendered) { // can only have a selected file value after being rendered
formEl.appendChild(field.extractFileInput());
}
});
return formEl;
},
/**
* @private
*/
onSuccess: function(response) {
var form = this.form,
success = true,
result = this.processResponse(response);
if (result !== true && !result.success) {
if (result.errors) {
form.markInvalid(result.errors);
}
this.failureType = Ext.form.action.Action.SERVER_INVALID;
success = false;
}
form.afterAction(this, success);
},
/**
* @private
*/
handleResponse: function(response) {
var form = this.form,
errorReader = form.errorReader,
rs, errors, i, len, records;
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;
}
return {
success : rs.success,
errors : errors
};
}
return Ext.decode(response.responseText);
}
});