]> git.proxmox.com Git - sencha-touch.git/blob - src/src/field/Text.js
import Sencha Touch 2.4.2 source
[sencha-touch.git] / src / src / field / Text.js
1 /**
2 * The text field is the basis for most of the input fields in Sencha Touch. It provides a baseline of shared
3 * functionality such as input validation, standard events, state management and look and feel. Typically we create
4 * text fields inside a form, like this:
5 *
6 * @example
7 * Ext.create('Ext.form.Panel', {
8 * fullscreen: true,
9 * items: [
10 * {
11 * xtype: 'fieldset',
12 * title: 'Enter your name',
13 * items: [
14 * {
15 * xtype: 'textfield',
16 * label: 'First Name',
17 * name: 'firstName'
18 * },
19 * {
20 * xtype: 'textfield',
21 * label: 'Last Name',
22 * name: 'lastName'
23 * }
24 * ]
25 * }
26 * ]
27 * });
28 *
29 * This creates two text fields inside a form. Text Fields can also be created outside of a Form, like this:
30 *
31 * Ext.create('Ext.field.Text', {
32 * label: 'Your Name',
33 * value: 'Ed Spencer'
34 * });
35 *
36 * ## Configuring
37 *
38 * Text field offers several configuration options, including {@link #placeHolder}, {@link #maxLength},
39 * {@link #autoComplete}, {@link #autoCapitalize} and {@link #autoCorrect}. For example, here is how we would configure
40 * a text field to have a maximum length of 10 characters, with placeholder text that disappears when the field is
41 * focused:
42 *
43 * Ext.create('Ext.field.Text', {
44 * label: 'Username',
45 * maxLength: 10,
46 * placeHolder: 'Enter your username'
47 * });
48 *
49 * The autoComplete, autoCapitalize and autoCorrect configs simply set those attributes on the text field and allow the
50 * native browser to provide those capabilities. For example, to enable auto complete and auto correct, simply
51 * configure your text field like this:
52 *
53 * Ext.create('Ext.field.Text', {
54 * label: 'Username',
55 * autoComplete: true,
56 * autoCorrect: true
57 * });
58 *
59 * These configurations will be picked up by the native browser, which will enable the options at the OS level.
60 *
61 * Text field inherits from {@link Ext.field.Field}, which is the base class for all fields in Sencha Touch and provides
62 * a lot of shared functionality for all fields, including setting values, clearing and basic validation. See the
63 * {@link Ext.field.Field} documentation to see how to leverage its capabilities.
64 *
65 * For more information regarding forms and fields, please review [Using Forms in Sencha Touch Guide](../../../components/forms.html)
66 */
67 Ext.define('Ext.field.Text', {
68 extend: 'Ext.field.Field',
69 xtype: 'textfield',
70 alternateClassName: 'Ext.form.Text',
71
72 /**
73 * @event focus
74 * Fires when this field receives input focus
75 * @param {Ext.field.Text} this This field
76 * @param {Ext.event.Event} e
77 */
78
79 /**
80 * @event blur
81 * Fires when this field loses input focus
82 * @param {Ext.field.Text} this This field
83 * @param {Ext.event.Event} e
84 */
85
86 /**
87 * @event paste
88 * Fires when this field is pasted.
89 * @param {Ext.field.Text} this This field
90 * @param {Ext.event.Event} e
91 */
92
93 /**
94 * @event mousedown
95 * Fires when this field receives a mousedown
96 * @param {Ext.field.Text} this This field
97 * @param {Ext.event.Event} e
98 */
99
100 /**
101 * @event keyup
102 * @preventable doKeyUp
103 * Fires when a key is released on the input element
104 * @param {Ext.field.Text} this This field
105 * @param {Ext.event.Event} e
106 */
107
108 /**
109 * @event clearicontap
110 * @preventable doClearIconTap
111 * Fires when the clear icon is tapped
112 * @param {Ext.field.Text} this This field
113 * @param {Ext.field.Input} input The field's input component.
114 * @param {Ext.event.Event} e
115 */
116
117 /**
118 * @event change
119 * Fires just before the field blurs if the field value has changed
120 * @param {Ext.field.Text} this This field
121 * @param {Mixed} newValue The new value
122 * @param {Mixed} oldValue The original value
123 */
124
125 /**
126 * @event action
127 * @preventable doAction
128 * Fires whenever the return key or go is pressed. FormPanel listeners
129 * for this event, and submits itself whenever it fires. Also note
130 * that this event bubbles up to parent containers.
131 * @param {Ext.field.Text} this This field
132 * @param {Mixed} e The key event object
133 */
134
135 config: {
136 /**
137 * @cfg
138 * @inheritdoc
139 */
140 ui: 'text',
141
142 /**
143 * @cfg
144 * @inheritdoc
145 */
146 clearIcon: true,
147
148 /**
149 * @cfg {String} placeHolder A string value displayed in the input (if supported) when the control is empty.
150 * @accessor
151 */
152 placeHolder: null,
153
154 /**
155 * @cfg {Number} maxLength The maximum number of permitted input characters.
156 * @accessor
157 */
158 maxLength: null,
159
160 /**
161 * True to set the field's DOM element autocomplete attribute to "on", false to set to "off".
162 * @cfg {Boolean} autoComplete
163 * @accessor
164 */
165 autoComplete: null,
166
167 /**
168 * True to set the field's DOM element autocapitalize attribute to "on", false to set to "off".
169 * @cfg {Boolean} autoCapitalize
170 * @accessor
171 */
172 autoCapitalize: null,
173
174 /**
175 * True to set the field DOM element autocorrect attribute to "on", false to set to "off".
176 * @cfg {Boolean} autoCorrect
177 * @accessor
178 */
179 autoCorrect: null,
180
181 /**
182 * True to set the field DOM element readonly attribute to true.
183 * @cfg {Boolean} readOnly
184 * @accessor
185 */
186 readOnly: null,
187
188 /**
189 * @cfg {Object} component The inner component for this field, which defaults to an input text.
190 * @accessor
191 */
192 component: {
193 xtype: 'input',
194 type: 'text',
195 fastFocus: true
196 },
197
198 bubbleEvents: ['action']
199 },
200
201 // @private
202 initialize: function() {
203 var me = this;
204
205 me.callParent();
206
207 me.getComponent().on({
208 scope: this,
209
210 keyup : 'onKeyUp',
211 change : 'onChange',
212 focus : 'onFocus',
213 blur : 'onBlur',
214 paste : 'onPaste',
215 mousedown : 'onMouseDown',
216 clearicontap: 'onClearIconTap'
217 });
218
219 // set the originalValue of the textfield, if one exists
220 me.originalValue = me.getValue() || "";
221 me.getComponent().originalValue = me.originalValue;
222
223 me.syncEmptyCls();
224 },
225
226 syncEmptyCls: function() {
227 var empty = (this._value) ? this._value.length : false,
228 cls = Ext.baseCSSPrefix + 'empty';
229
230 if (empty) {
231 this.removeCls(cls);
232 } else {
233 this.addCls(cls);
234 }
235 },
236
237 // @private
238 updateValue: function(newValue) {
239 var component = this.getComponent(),
240 // allows newValue to be zero but not undefined or null (other falsey values)
241 valueValid = newValue !== undefined && newValue !== null && newValue !== "";
242
243 if (component) {
244 component.setValue(newValue);
245 }
246
247 this[valueValid && this.isDirty() ? 'showClearIcon' : 'hideClearIcon']();
248
249 this.syncEmptyCls();
250 },
251
252 getValue: function() {
253 var me = this;
254
255 me._value = me.getComponent().getValue();
256
257 me.syncEmptyCls();
258
259 return me._value;
260 },
261
262 // @private
263 updatePlaceHolder: function(newPlaceHolder) {
264 this.getComponent().setPlaceHolder(newPlaceHolder);
265 },
266
267 // @private
268 updateMaxLength: function(newMaxLength) {
269 this.getComponent().setMaxLength(newMaxLength);
270 },
271
272 // @private
273 updateAutoComplete: function(newAutoComplete) {
274 this.getComponent().setAutoComplete(newAutoComplete);
275 },
276
277 // @private
278 updateAutoCapitalize: function(newAutoCapitalize) {
279 this.getComponent().setAutoCapitalize(newAutoCapitalize);
280 },
281
282 // @private
283 updateAutoCorrect: function(newAutoCorrect) {
284 this.getComponent().setAutoCorrect(newAutoCorrect);
285 },
286
287 // @private
288 updateReadOnly: function(newReadOnly) {
289 if (newReadOnly) {
290 this.hideClearIcon();
291 } else {
292 this.showClearIcon();
293 }
294
295 this.getComponent().setReadOnly(newReadOnly);
296 },
297
298 // @private
299 updateInputType: function(newInputType) {
300 var component = this.getComponent();
301 if (component) {
302 component.setType(newInputType);
303 }
304 },
305
306 // @private
307 updateName: function(newName) {
308 var component = this.getComponent();
309 if (component) {
310 component.setName(newName);
311 }
312 },
313
314 // @private
315 updateTabIndex: function(newTabIndex) {
316 var component = this.getComponent();
317 if (component) {
318 component.setTabIndex(newTabIndex);
319 }
320 },
321
322 /**
323 * Updates the {@link #inputCls} configuration on this fields {@link #component}
324 * @private
325 */
326 updateInputCls: function(newInputCls, oldInputCls) {
327 var component = this.getComponent();
328 if (component) {
329 component.replaceCls(oldInputCls, newInputCls);
330 }
331 },
332
333 doSetDisabled: function(disabled) {
334 var me = this;
335
336 me.callParent(arguments);
337
338 var component = me.getComponent();
339 if (component) {
340 component.setDisabled(disabled);
341 }
342
343 if (disabled) {
344 me.hideClearIcon();
345 } else {
346 me.showClearIcon();
347 }
348 },
349
350 // @private
351 showClearIcon: function() {
352 var me = this,
353 value = me.getValue(),
354 // allows value to be zero but not undefined or null (other falsey values)
355 valueValid = value !== undefined && value !== null && value !== "";
356
357 if (me.getClearIcon() && !me.getDisabled() && !me.getReadOnly() && valueValid) {
358 me.element.addCls(Ext.baseCSSPrefix + 'field-clearable');
359 }
360
361 return me;
362 },
363
364 // @private
365 hideClearIcon: function() {
366 if (this.getClearIcon()) {
367 this.element.removeCls(Ext.baseCSSPrefix + 'field-clearable');
368 }
369 },
370
371 onKeyUp: function(e) {
372 this.fireAction('keyup', [this, e], 'doKeyUp');
373 },
374
375 /**
376 * Called when a key has been pressed in the `<input>`
377 * @private
378 */
379 doKeyUp: function(me, e) {
380 // getValue to ensure that we are in sync with the dom
381 var value = me.getValue(),
382 // allows value to be zero but not undefined or null (other falsey values)
383 valueValid = value !== undefined && value !== null && value !== "";
384
385 this[valueValid ? 'showClearIcon' : 'hideClearIcon']();
386
387 if (e.browserEvent.keyCode === 13) {
388 me.fireAction('action', [me, e], 'doAction');
389 }
390 },
391
392 doAction: function() {
393 this.blur();
394 },
395
396 onClearIconTap: function(input, e) {
397 this.fireAction('clearicontap', [this, input, e], 'doClearIconTap');
398 },
399
400 // @private
401 doClearIconTap: function(me, e) {
402 me.setValue('');
403
404 //sync with the input
405 me.getValue();
406 },
407
408 onChange: function(me, value, startValue) {
409 me.fireEvent('change', this, value, startValue);
410 },
411
412 onFocus: function(e) {
413 this.addCls(Ext.baseCSSPrefix + 'field-focused');
414 this.isFocused = true;
415 this.fireEvent('focus', this, e);
416 },
417
418 onBlur: function(e) {
419 var me = this;
420
421 this.removeCls(Ext.baseCSSPrefix + 'field-focused');
422 this.isFocused = false;
423
424 me.fireEvent('blur', me, e);
425
426 setTimeout(function() {
427 me.isFocused = false;
428 }, 50);
429 },
430
431 onPaste: function(e) {
432 this.fireEvent('paste', this, e);
433 },
434
435 onMouseDown: function(e) {
436 this.fireEvent('mousedown', this, e);
437 },
438
439 /**
440 * Attempts to set the field as the active input focus.
441 * @return {Ext.field.Text} This field
442 */
443 focus: function() {
444 this.getComponent().focus();
445 return this;
446 },
447
448 /**
449 * Attempts to forcefully blur input focus for the field.
450 * @return {Ext.field.Text} This field
451 */
452 blur: function() {
453 this.getComponent().blur();
454 return this;
455 },
456
457 /**
458 * Attempts to forcefully select all the contents of the input field.
459 * @return {Ext.field.Text} this
460 */
461 select: function() {
462 this.getComponent().select();
463 return this;
464 },
465
466 resetOriginalValue: function() {
467 this.callParent();
468 var component = this.getComponent();
469 if(component && component.hasOwnProperty("originalValue")) {
470 this.getComponent().originalValue = this.originalValue;
471 }
472 this.reset();
473 },
474
475 reset: function() {
476 this.getComponent().reset();
477
478 //we need to call this to sync the input with this field
479 this.getValue();
480
481 this[this.isDirty() ? 'showClearIcon' : 'hideClearIcon']();
482 },
483
484 isDirty: function() {
485 var component = this.getComponent();
486 if (component) {
487 return component.isDirty();
488 }
489 return false;
490 }
491 });
492
493 //<deprecated product=touch since=2.0>
494 /**
495 * @property startValue
496 * @type String/Number
497 * Used to contain the previous value of the field before the edit
498 * @removed 2.0.0
499 * @member Ext.field.Text
500 */
501 //</deprecated>