3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
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.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.form.field.Text
17 * @extends Ext.form.field.Base
19 A basic text field. Can be used as a direct replacement for traditional text inputs,
20 or as the base class for more sophisticated input controls (like {@link Ext.form.field.TextArea}
21 and {@link Ext.form.field.ComboBox}). Has support for empty-field placeholder values (see {@link #emptyText}).
25 The Text field has a useful set of validations built in:
27 - {@link #allowBlank} for making the field required
28 - {@link #minLength} for requiring a minimum value length
29 - {@link #maxLength} for setting a maximum value length (with {@link #enforceMaxLength} to add it
30 as the `maxlength` attribute on the input element)
31 - {@link #regex} to specify a custom regular expression for validation
33 In addition, custom validations may be added:
35 - {@link #vtype} specifies a virtual type implementation from {@link Ext.form.field.VTypes} which can contain
36 custom validation logic
37 - {@link #validator} allows a custom arbitrary function to be called during validation
39 The details around how and when each of these validation options get used are described in the
40 documentation for {@link #getErrors}.
42 By default, the field value is checked for validity immediately while the user is typing in the
43 field. This can be controlled with the {@link #validateOnChange}, {@link #checkChangeEvents}, and
44 {@link #checkChangeBugger} configurations. Also see the details on Form Validation in the
45 {@link Ext.form.Panel} class documentation.
47 #Masking and Character Stripping#
49 Text fields can be configured with custom regular expressions to be applied to entered values before
50 validation: see {@link #maskRe} and {@link #stripCharsRe} for details.
51 {@img Ext.form.Text/Ext.form.Text.png Ext.form.Text component}
54 Ext.create('Ext.form.Panel', {
55 title: 'Contact Info',
58 renderTo: Ext.getBody(),
63 allowBlank: false // requires a non-empty value
67 fieldLabel: 'Email Address',
68 vtype: 'email' // requires value to be a valid email address format
74 * @docauthor Jason Johnston <jason@sencha.com>
76 Ext.define('Ext.form.field.Text', {
77 extend:'Ext.form.field.Base',
78 alias: 'widget.textfield',
79 requires: ['Ext.form.field.VTypes', 'Ext.layout.component.field.Text'],
80 alternateClassName: ['Ext.form.TextField', 'Ext.form.Text'],
83 * @cfg {String} vtypeText A custom error message to display in place of the default message provided
84 * for the <b><code>{@link #vtype}</code></b> currently set for this field (defaults to <tt>undefined</tt>).
85 * <b>Note</b>: only applies if <b><code>{@link #vtype}</code></b> is set, else ignored.
89 * @cfg {RegExp} stripCharsRe A JavaScript RegExp object used to strip unwanted content from the value
90 * before validation (defaults to <tt>undefined</tt>).
94 * @cfg {Number} size An initial value for the 'size' attribute on the text input element. This is only
95 * used if the field has no configured {@link #width} and is not given a width by its container's layout.
96 * Defaults to <tt>20</tt>.
101 * @cfg {Boolean} grow <tt>true</tt> if this field should automatically grow and shrink to its content
102 * (defaults to <tt>false</tt>)
106 * @cfg {Number} growMin The minimum width to allow when <code><b>{@link #grow}</b> = true</code> (defaults
112 * @cfg {Number} growMax The maximum width to allow when <code><b>{@link #grow}</b> = true</code> (defaults
118 * @cfg {String} growAppend
119 * A string that will be appended to the field's current value for the purposes of calculating the target
120 * field size. Only used when the {@link #grow} config is <tt>true</tt>. Defaults to a single capital "W"
121 * (the widest character in common fonts) to leave enough space for the next typed character and avoid the
122 * field value shifting before the width is adjusted.
127 * @cfg {String} vtype A validation type name as defined in {@link Ext.form.field.VTypes} (defaults to <tt>undefined</tt>)
131 * @cfg {RegExp} maskRe An input mask regular expression that will be used to filter keystrokes that do
132 * not match (defaults to <tt>undefined</tt>)
136 * @cfg {Boolean} disableKeyFilter Specify <tt>true</tt> to disable input keystroke filtering (defaults
141 * @cfg {Boolean} allowBlank Specify <tt>false</tt> to validate that the value's length is > 0 (defaults to
147 * @cfg {Number} minLength Minimum input field length required (defaults to <tt>0</tt>)
152 * @cfg {Number} maxLength Maximum input field length allowed by validation (defaults to Number.MAX_VALUE).
153 * This behavior is intended to provide instant feedback to the user by improving usability to allow pasting
154 * and editing or overtyping and back tracking. To restrict the maximum number of characters that can be
155 * entered into the field use the <tt><b>{@link Ext.form.field.Text#enforceMaxLength enforceMaxLength}</b></tt> option.
157 maxLength : Number.MAX_VALUE,
160 * @cfg {Boolean} enforceMaxLength True to set the maxLength property on the underlying input field. Defaults to <tt>false</tt>
164 * @cfg {String} minLengthText Error text to display if the <b><tt>{@link #minLength minimum length}</tt></b>
165 * validation fails (defaults to <tt>'The minimum length for this field is {minLength}'</tt>)
167 minLengthText : 'The minimum length for this field is {0}',
170 * @cfg {String} maxLengthText Error text to display if the <b><tt>{@link #maxLength maximum length}</tt></b>
171 * validation fails (defaults to <tt>'The maximum length for this field is {maxLength}'</tt>)
173 maxLengthText : 'The maximum length for this field is {0}',
176 * @cfg {Boolean} selectOnFocus <tt>true</tt> to automatically select any existing field text when the field
177 * receives input focus (defaults to <tt>false</tt>)
181 * @cfg {String} blankText The error text to display if the <b><tt>{@link #allowBlank}</tt></b> validation
182 * fails (defaults to <tt>'This field is required'</tt>)
184 blankText : 'This field is required',
187 * @cfg {Function} validator
188 * <p>A custom validation function to be called during field validation ({@link #getErrors})
189 * (defaults to <tt>undefined</tt>). If specified, this function will be called first, allowing the
190 * developer to override the default validation process.</p>
191 * <br><p>This function will be passed the following Parameters:</p>
192 * <div class="mdetail-params"><ul>
193 * <li><code>value</code>: <i>Mixed</i>
194 * <div class="sub-desc">The current field value</div></li>
196 * <br><p>This function is to Return:</p>
197 * <div class="mdetail-params"><ul>
198 * <li><code>true</code>: <i>Boolean</i>
199 * <div class="sub-desc"><code>true</code> if the value is valid</div></li>
200 * <li><code>msg</code>: <i>String</i>
201 * <div class="sub-desc">An error message if the value is invalid</div></li>
206 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation
207 * (defaults to <tt>undefined</tt>). If the test fails, the field will be marked invalid using
208 * <b><tt>{@link #regexText}</tt></b>.
212 * @cfg {String} regexText The error text to display if <b><tt>{@link #regex}</tt></b> is used and the
213 * test fails during validation (defaults to <tt>''</tt>)
218 * @cfg {String} emptyText
219 * <p>The default text to place into an empty field (defaults to <tt>undefined</tt>).</p>
220 * <p>Note that normally this value will be submitted to the server if this field is enabled; to prevent this
221 * you can set the {@link Ext.form.action.Action#submitEmptyText submitEmptyText} option of
222 * {@link Ext.form.Basic#submit} to <tt>false</tt>.</p>
223 * <p>Also note that if you use <tt>{@link #inputType inputType}:'file'</tt>, {@link #emptyText} is not
224 * supported and should be avoided.</p>
228 * @cfg {String} emptyCls The CSS class to apply to an empty field to style the <b><tt>{@link #emptyText}</tt></b>
229 * (defaults to <tt>'x-form-empty-field'</tt>). This class is automatically added and removed as needed
230 * depending on the current field value.
232 emptyCls : Ext.baseCSSPrefix + 'form-empty-field',
237 * @cfg {Boolean} enableKeyEvents <tt>true</tt> to enable the proxying of key events for the HTML input field (defaults to <tt>false</tt>)
240 componentLayout: 'textfield',
242 initComponent : function(){
247 * Fires when the <tt><b>{@link #autoSize}</b></tt> function is triggered and the field is
248 * resized according to the {@link #grow}/{@link #growMin}/{@link #growMax} configs as a result.
249 * This event provides a hook for the developer to apply additional logic at runtime to resize the
251 * @param {Ext.form.field.Text} this This text field
252 * @param {Number} width The new field width
258 * Keydown input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
260 * @param {Ext.form.field.Text} this This text field
261 * @param {Ext.EventObject} e
266 * Keyup input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
268 * @param {Ext.form.field.Text} this This text field
269 * @param {Ext.EventObject} e
274 * Keypress input field event. This event only fires if <tt><b>{@link #enableKeyEvents}</b></tt>
276 * @param {Ext.form.field.Text} this This text field
277 * @param {Ext.EventObject} e
284 initEvents : function(){
289 if(me.selectOnFocus || me.emptyText){
290 me.mon(el, 'mousedown', me.onMouseDown, me);
292 if(me.maskRe || (me.vtype && me.disableKeyFilter !== true && (me.maskRe = Ext.form.field.VTypes[me.vtype+'Mask']))){
293 me.mon(el, 'keypress', me.filterKeys, me);
296 if (me.enableKeyEvents) {
300 keydown: me.onKeyDown,
301 keypress: me.onKeyPress
307 * @private override - treat undefined and null values as equal to an empty string value
309 isEqual: function(value1, value2) {
310 return String(Ext.value(value1, '')) === String(Ext.value(value2, ''));
315 * If grow=true, invoke the autoSize method when the field's value is changed.
317 onChange: function() {
322 afterRender: function(){
324 if (me.enforceMaxLength) {
325 me.inputEl.dom.maxLength = me.maxLength;
332 onMouseDown: function(e){
335 me.mon(me.inputEl, 'mouseup', Ext.emptyFn, me, { single: true, preventDefault: true });
340 * Performs any necessary manipulation of a raw String value to prepare it for {@link #stringToValue conversion}
341 * and/or {@link #validate validation}. For text fields this applies the configured {@link #stripCharsRe} to the
343 * @param {String} value The unprocessed string value
344 * @return {String} The processed string value
346 processRawValue: function(value) {
348 stripRe = me.stripCharsRe,
352 newValue = value.replace(stripRe, '');
353 if (newValue !== value) {
354 me.setRawValue(newValue);
362 onDisable: function(){
365 this.inputEl.dom.unselectable = 'on';
370 onEnable: function(){
373 this.inputEl.dom.unselectable = '';
377 onKeyDown: function(e) {
378 this.fireEvent('keydown', this, e);
381 onKeyUp: function(e) {
382 this.fireEvent('keyup', this, e);
385 onKeyPress: function(e) {
386 this.fireEvent('keypress', this, e);
390 * Resets the current field value to the originally-loaded value and clears any validation messages.
391 * Also adds <tt><b>{@link #emptyText}</b></tt> and <tt><b>{@link #emptyCls}</b></tt> if the
392 * original value was blank.
396 this.applyEmptyText();
399 applyEmptyText : function(){
401 emptyText = me.emptyText,
404 if (me.rendered && emptyText) {
405 isEmpty = me.getRawValue().length < 1 && !me.hasFocus;
407 if (Ext.supports.Placeholder) {
408 me.inputEl.dom.placeholder = emptyText;
409 } else if (isEmpty) {
410 me.setRawValue(emptyText);
413 //all browsers need this because of a styling issue with chrome + placeholders.
414 //the text isnt vertically aligned when empty (and using the placeholder)
416 me.inputEl.addCls(me.emptyCls);
424 preFocus : function(){
426 inputEl = me.inputEl,
427 emptyText = me.emptyText,
430 if (emptyText && !Ext.supports.Placeholder && inputEl.dom.value === emptyText) {
433 inputEl.removeCls(me.emptyCls);
434 } else if (Ext.supports.Placeholder) {
435 me.inputEl.removeCls(me.emptyCls);
437 if (me.selectOnFocus || isEmpty) {
438 inputEl.dom.select();
442 onFocus: function() {
444 me.callParent(arguments);
451 postBlur : function(){
452 this.applyEmptyText();
456 filterKeys : function(e){
460 var key = e.getKey(),
461 charCode = String.fromCharCode(e.getCharCode());
463 if(Ext.isGecko && (e.isNavKeyPress() || key === e.BACKSPACE || (key === e.DELETE && e.button === -1))){
467 if(!Ext.isGecko && e.isSpecialKey() && !charCode){
470 if(!this.maskRe.test(charCode)){
476 * Returns the raw String value of the field, without performing any normalization, conversion, or validation.
477 * Gets the current value of the input element if the field has been rendered, ignoring the value if it is the
478 * {@link #emptyText}. To get a normalized and converted value see {@link #getValue}.
479 * @return {String} value The raw String value of the field
481 getRawValue: function() {
484 if (v === me.emptyText) {
491 * Sets a data value into the field and runs the change detection and validation. Also applies any configured
492 * {@link #emptyText} for text fields. To set the value directly without these inspections see {@link #setRawValue}.
493 * @param {Mixed} value The value to set
494 * @return {Ext.form.field.Text} this
496 setValue: function(value) {
498 inputEl = me.inputEl;
500 if (inputEl && me.emptyText && !Ext.isEmpty(value)) {
501 inputEl.removeCls(me.emptyCls);
504 me.callParent(arguments);
511 Validates a value according to the field's validation rules and returns an array of errors
512 for any failing validations. Validation rules are processed in the following order:
514 1. **Field specific validator**
516 A validator offers a way to customize and reuse a validation specification.
517 If a field is configured with a `{@link #validator}`
518 function, it will be passed the current field value. The `{@link #validator}`
519 function is expected to return either:
521 - Boolean `true` if the value is valid (validation continues).
522 - a String to represent the invalid message if invalid (validation halts).
524 2. **Basic Validation**
526 If the `{@link #validator}` has not halted validation,
527 basic validation proceeds as follows:
529 - `{@link #allowBlank}` : (Invalid message = `{@link #emptyText}`)
531 Depending on the configuration of <code>{@link #allowBlank}</code>, a
532 blank field will cause validation to halt at this step and return
533 Boolean true or false accordingly.
535 - `{@link #minLength}` : (Invalid message = `{@link #minLengthText}`)
537 If the passed value does not satisfy the `{@link #minLength}`
538 specified, validation halts.
540 - `{@link #maxLength}` : (Invalid message = `{@link #maxLengthText}`)
542 If the passed value does not satisfy the `{@link #maxLength}`
543 specified, validation halts.
545 3. **Preconfigured Validation Types (VTypes)**
547 If none of the prior validation steps halts validation, a field
548 configured with a `{@link #vtype}` will utilize the
549 corresponding {@link Ext.form.field.VTypes VTypes} validation function.
550 If invalid, either the field's `{@link #vtypeText}` or
551 the VTypes vtype Text property will be used for the invalid message.
552 Keystrokes on the field will be filtered according to the VTypes
555 4. **Field specific regex test**
557 If none of the prior validation steps halts validation, a field's
558 configured <code>{@link #regex}</code> test will be processed.
559 The invalid message for this test is configured with `{@link #regexText}`
561 * @param {Mixed} value The value to validate. The processed raw value will be used if nothing is passed
562 * @return {Array} Array of any validation errors
565 getErrors: function(value) {
567 errors = me.callParent(arguments),
568 validator = me.validator,
569 emptyText = me.emptyText,
570 allowBlank = me.allowBlank,
572 vtypes = Ext.form.field.VTypes,
574 format = Ext.String.format,
577 value = value || me.processRawValue(me.getRawValue());
579 if (Ext.isFunction(validator)) {
580 msg = validator.call(me, value);
586 if (value.length < 1 || value === emptyText) {
588 errors.push(me.blankText);
590 //if value is blank, there cannot be any additional errors
594 if (value.length < me.minLength) {
595 errors.push(format(me.minLengthText, me.minLength));
598 if (value.length > me.maxLength) {
599 errors.push(format(me.maxLengthText, me.maxLength));
603 if(!vtypes[vtype](value, me)){
604 errors.push(me.vtypeText || vtypes[vtype +'Text']);
608 if (regex && !regex.test(value)) {
609 errors.push(me.regexText || me.invalidText);
616 * Selects text in this field
617 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
618 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
620 selectText : function(start, end){
622 v = me.getRawValue(),
629 start = start === undef ? 0 : start;
630 end = end === undef ? v.length : end;
631 if (el.setSelectionRange) {
632 el.setSelectionRange(start, end);
634 else if(el.createTextRange) {
635 range = el.createTextRange();
636 range.moveStart('character', start);
637 range.moveEnd('character', end - v.length);
640 doFocus = Ext.isGecko || Ext.isOpera;
648 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
649 * This only takes effect if <tt>{@link #grow} = true</tt>, and fires the {@link #autosize} event if the
652 autoSize: function() {
655 if (me.grow && me.rendered) {
656 me.doComponentLayout();
657 width = me.inputEl.getWidth();
658 if (width !== me.lastInputWidth) {
659 me.fireEvent('autosize', width);
660 me.lastInputWidth = width;
665 initAria: function() {
667 this.getActionEl().dom.setAttribute('aria-required', this.allowBlank === false);
671 * @protected override
672 * To get the natural width of the inputEl, we do a simple calculation based on the
673 * 'size' config. We use hard-coded numbers to approximate what browsers do natively,
674 * to avoid having to read any styles which would hurt performance.
676 getBodyNaturalWidth: function() {
677 return Math.round(this.size * 6.5) + 20;