/**
* @class Ext.form.field.File
* @extends Ext.form.field.Text
A file upload field which has custom styling and allows control over the button text and other
features of {@link Ext.form.field.Text text fields} like {@link Ext.form.field.Text#emptyText empty text}.
It uses a hidden file input element behind the scenes to allow user selection of a file and to
perform the actual upload during {@link Ext.form.Basic#submit form submit}.
Because there is no secure cross-browser way to programmatically set the value of a file input,
the standard Field `setValue` method is not implemented. The `{@link #getValue}` method will return
a value that is browser-dependent; some have just the file name, some have a full path, some use
a fake path.
{@img Ext.form.File/Ext.form.File.png Ext.form.File component}
#Example Usage:#
Ext.create('Ext.form.Panel', {
title: 'Upload a Photo',
width: 400,
bodyPadding: 10,
frame: true,
renderTo: Ext.getBody(),
items: [{
xtype: 'filefield',
name: 'photo',
fieldLabel: 'Photo',
labelWidth: 50,
msgTarget: 'side',
allowBlank: false,
anchor: '100%',
buttonText: 'Select Photo...'
}],
buttons: [{
text: 'Upload',
handler: function() {
var form = this.up('form').getForm();
if(form.isValid()){
form.submit({
url: 'photo-upload.php',
waitMsg: 'Uploading your photo...',
success: function(fp, o) {
Ext.Msg.alert('Success', 'Your photo "' + o.result.file + '" has been uploaded.');
}
});
}
}
}]
});
* @constructor
* Create a new File field
* @param {Object} config Configuration options
* @xtype filefield
* @markdown
* @docauthor Jason Johnston <jason@sencha.com>
*/
Ext.define("Ext.form.field.File", {
extend: 'Ext.form.field.Text',
alias: ['widget.filefield', 'widget.fileuploadfield'],
alternateClassName: ['Ext.form.FileUploadField', 'Ext.ux.form.FileUploadField', 'Ext.form.File'],
uses: ['Ext.button.Button', 'Ext.layout.component.field.File'],
/**
* @cfg {String} buttonText The button text to display on the upload button (defaults to
* 'Browse...'). Note that if you supply a value for {@link #buttonConfig}, the buttonConfig.text
* value will be used instead if available.
*/
buttonText: 'Browse...',
/**
* @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible
* text field (defaults to false). If true, all inherited Text members will still be available.
*/
buttonOnly: false,
/**
* @cfg {Number} buttonMargin The number of pixels of space reserved between the button and the text field
* (defaults to 3). Note that this only applies if {@link #buttonOnly} = false.
*/
buttonMargin: 3,
/**
* @cfg {Object} buttonConfig A standard {@link Ext.button.Button} config object.
*/
/**
* @event change
* Fires when the underlying file input field's value has changed from the user
* selecting a new file from the system file selection dialog.
* @param {Ext.ux.form.FileUploadField} this
* @param {String} value The file value returned by the underlying file input field
*/
/**
* @property fileInputEl
* @type {Ext.core.Element}
* A reference to the invisible file input element created for this upload field. Only
* populated after this component is rendered.
*/
/**
* @property button
* @type {Ext.button.Button}
* A reference to the trigger Button component created for this upload field. Only
* populated after this component is rendered.
*/
/**
* @cfg {String} fieldBodyCls
* An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
* Defaults to 'x-form-file-wrap' for file upload field.
*/
fieldBodyCls: Ext.baseCSSPrefix + 'form-file-wrap',
// private
readOnly: true,
componentLayout: 'filefield',
// private
onRender: function() {
var me = this,
inputEl;
me.callParent(arguments);
me.createButton();
me.createFileInput();
// we don't create the file/button til after onRender, the initial disable() is
// called in the onRender of the component.
if (me.disabled) {
me.disableItems();
}
inputEl = me.inputEl;
inputEl.dom.removeAttribute('name'); //name goes on the fileInput, not the text input
if (me.buttonOnly) {
inputEl.setDisplayed(false);
}
},
/**
* @private
* Creates the custom trigger Button component. The fileInput will be inserted into this.
*/
createButton: function() {
var me = this;
me.button = Ext.widget('button', Ext.apply({
renderTo: me.bodyEl,
text: me.buttonText,
cls: Ext.baseCSSPrefix + 'form-file-btn',
preventDefault: false,
style: me.buttonOnly ? '' : 'margin-left:' + me.buttonMargin + 'px'
}, me.buttonConfig));
},
/**
* @private
* Creates the file input element. It is inserted into the trigger button component, made
* invisible, and floated on top of the button's other content so that it will receive the
* button's clicks.
*/
createFileInput : function() {
var me = this;
me.fileInputEl = me.button.el.createChild({
name: me.getName(),
cls: Ext.baseCSSPrefix + 'form-file-input',
tag: 'input',
type: 'file',
size: 1
}).on('change', me.onFileChange, me);
},
/**
* @private Event handler fired when the user selects a file.
*/
onFileChange: function() {
this.lastValue = null; // force change event to get fired even if the user selects a file with the same name
Ext.form.field.File.superclass.setValue.call(this, this.fileInputEl.dom.value);
},
/**
* Overridden to do nothing
* @hide
*/
setValue: Ext.emptyFn,
reset : function(){
this.fileInputEl.remove();
this.createFileInput();
this.callParent();
},
onDisable: function(){
this.callParent();
this.disableItems();
},
disableItems: function(){
var file = this.fileInputEl,
button = this.button;
if (file) {
file.dom.disabled = true;
}
if (button) {
button.disable();
}
},
onEnable: function(){
var me = this;
me.callParent();
me.fileInputEl.dom.disabled = false;
me.button.enable();
},
isFileUpload: function() {
return true;
},
extractFileInput: function() {
var fileInput = this.fileInputEl.dom;
this.reset();
return fileInput;
},
onDestroy: function(){
Ext.destroyMembers(this, 'fileInputEl', 'button');
this.callParent();
}
});