Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / form / field / File.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.form.field.File
17  * @extends Ext.form.field.Text
18
19 A file upload field which has custom styling and allows control over the button text and other
20 features of {@link Ext.form.field.Text text fields} like {@link Ext.form.field.Text#emptyText empty text}.
21 It uses a hidden file input element behind the scenes to allow user selection of a file and to
22 perform the actual upload during {@link Ext.form.Basic#submit form submit}.
23
24 Because there is no secure cross-browser way to programmatically set the value of a file input,
25 the standard Field `setValue` method is not implemented. The `{@link #getValue}` method will return
26 a value that is browser-dependent; some have just the file name, some have a full path, some use
27 a fake path.
28 {@img Ext.form.File/Ext.form.File.png Ext.form.File component}
29 #Example Usage:#
30
31     Ext.create('Ext.form.Panel', {
32         title: 'Upload a Photo',
33         width: 400,
34         bodyPadding: 10,
35         frame: true,
36         renderTo: Ext.getBody(),    
37         items: [{
38             xtype: 'filefield',
39             name: 'photo',
40             fieldLabel: 'Photo',
41             labelWidth: 50,
42             msgTarget: 'side',
43             allowBlank: false,
44             anchor: '100%',
45             buttonText: 'Select Photo...'
46         }],
47     
48         buttons: [{
49             text: 'Upload',
50             handler: function() {
51                 var form = this.up('form').getForm();
52                 if(form.isValid()){
53                     form.submit({
54                         url: 'photo-upload.php',
55                         waitMsg: 'Uploading your photo...',
56                         success: function(fp, o) {
57                             Ext.Msg.alert('Success', 'Your photo "' + o.result.file + '" has been uploaded.');
58                         }
59                     });
60                 }
61             }
62         }]
63     });
64
65  * @markdown
66  * @docauthor Jason Johnston <jason@sencha.com>
67  */
68 Ext.define("Ext.form.field.File", {
69     extend: 'Ext.form.field.Text',
70     alias: ['widget.filefield', 'widget.fileuploadfield'],
71     alternateClassName: ['Ext.form.FileUploadField', 'Ext.ux.form.FileUploadField', 'Ext.form.File'],
72     uses: ['Ext.button.Button', 'Ext.layout.component.field.File'],
73
74     /**
75      * @cfg {String} buttonText The button text to display on the upload button (defaults to
76      * 'Browse...').  Note that if you supply a value for {@link #buttonConfig}, the buttonConfig.text
77      * value will be used instead if available.
78      */
79     buttonText: 'Browse...',
80
81     /**
82      * @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible
83      * text field (defaults to false).  If true, all inherited Text members will still be available.
84      */
85     buttonOnly: false,
86
87     /**
88      * @cfg {Number} buttonMargin The number of pixels of space reserved between the button and the text field
89      * (defaults to 3).  Note that this only applies if {@link #buttonOnly} = false.
90      */
91     buttonMargin: 3,
92
93     /**
94      * @cfg {Object} buttonConfig A standard {@link Ext.button.Button} config object.
95      */
96
97     /**
98      * @event change
99      * Fires when the underlying file input field's value has changed from the user
100      * selecting a new file from the system file selection dialog.
101      * @param {Ext.ux.form.FileUploadField} this
102      * @param {String} value The file value returned by the underlying file input field
103      */
104
105     /**
106      * @property fileInputEl
107      * @type {Ext.core.Element}
108      * A reference to the invisible file input element created for this upload field. Only
109      * populated after this component is rendered.
110      */
111
112     /**
113      * @property button
114      * @type {Ext.button.Button}
115      * A reference to the trigger Button component created for this upload field. Only
116      * populated after this component is rendered.
117      */
118
119     /**
120      * @cfg {String} fieldBodyCls
121      * An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
122      * Defaults to 'x-form-file-wrap' for file upload field.
123      */
124     fieldBodyCls: Ext.baseCSSPrefix + 'form-file-wrap',
125
126
127     // private
128     readOnly: true,
129     componentLayout: 'filefield',
130
131     // private
132     onRender: function() {
133         var me = this,
134             inputEl;
135
136         me.callParent(arguments);
137
138         me.createButton();
139         me.createFileInput();
140         
141         // we don't create the file/button til after onRender, the initial disable() is
142         // called in the onRender of the component.
143         if (me.disabled) {
144             me.disableItems();
145         }
146
147         inputEl = me.inputEl;
148         inputEl.dom.removeAttribute('name'); //name goes on the fileInput, not the text input
149         if (me.buttonOnly) {
150             inputEl.setDisplayed(false);
151         }
152     },
153
154     /**
155      * @private
156      * Creates the custom trigger Button component. The fileInput will be inserted into this.
157      */
158     createButton: function() {
159         var me = this;
160         me.button = Ext.widget('button', Ext.apply({
161             renderTo: me.bodyEl,
162             text: me.buttonText,
163             cls: Ext.baseCSSPrefix + 'form-file-btn',
164             preventDefault: false,
165             style: me.buttonOnly ? '' : 'margin-left:' + me.buttonMargin + 'px'
166         }, me.buttonConfig));
167     },
168
169     /**
170      * @private
171      * Creates the file input element. It is inserted into the trigger button component, made
172      * invisible, and floated on top of the button's other content so that it will receive the
173      * button's clicks.
174      */
175     createFileInput : function() {
176         var me = this;
177         me.fileInputEl = me.button.el.createChild({
178             name: me.getName(),
179             cls: Ext.baseCSSPrefix + 'form-file-input',
180             tag: 'input',
181             type: 'file',
182             size: 1
183         }).on('change', me.onFileChange, me);
184     },
185
186     /**
187      * @private Event handler fired when the user selects a file.
188      */
189     onFileChange: function() {
190         this.lastValue = null; // force change event to get fired even if the user selects a file with the same name
191         Ext.form.field.File.superclass.setValue.call(this, this.fileInputEl.dom.value);
192     },
193
194     /**
195      * Overridden to do nothing
196      * @hide
197      */
198     setValue: Ext.emptyFn,
199
200     reset : function(){
201         this.fileInputEl.remove();
202         this.createFileInput();
203         this.callParent();
204     },
205
206     onDisable: function(){
207         this.callParent();
208         this.disableItems();
209     },
210     
211     disableItems: function(){
212         var file = this.fileInputEl,
213             button = this.button;
214              
215         if (file) {
216             file.dom.disabled = true;
217         }
218         if (button) {
219             button.disable();
220         }    
221     },
222
223     onEnable: function(){
224         var me = this;
225         me.callParent();
226         me.fileInputEl.dom.disabled = false;
227         me.button.enable();
228     },
229
230     isFileUpload: function() {
231         return true;
232     },
233
234     extractFileInput: function() {
235         var fileInput = this.fileInputEl.dom;
236         this.reset();
237         return fileInput;
238     },
239
240     onDestroy: function(){
241         Ext.destroyMembers(this, 'fileInputEl', 'button');
242         this.callParent();
243     }
244
245
246 });
247