6b970c186044a73145d6fd9de23f12d43f60c7c4
[roojs1] / Roo / bootstrap / Input.js
1 /*
2  * - LGPL
3  *
4  * Input
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.Input
10  * @extends Roo.bootstrap.Component
11  * Bootstrap Input class
12  * @cfg {Boolean} disabled is it disabled
13  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
14  * @cfg {String} name name of the input
15  * @cfg {string} fieldLabel - the label associated
16  * @cfg {string} placeholder - placeholder to put in text.
17  * @cfg {string}  before - input group add on before
18  * @cfg {string} after - input group add on after
19  * @cfg {string} size - (lg|sm) or leave empty..
20  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
21  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
22  * @cfg {Number} md colspan out of 12 for computer-sized screens
23  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
24  * @cfg {string} value default value of the input
25  * @cfg {Number} labelWidth set the width of label 
26  * @cfg {Number} labellg set the width of label (1-12)
27  * @cfg {Number} labelmd set the width of label (1-12)
28  * @cfg {Number} labelsm set the width of label (1-12)
29  * @cfg {Number} labelxs set the width of label (1-12)
30  * @cfg {String} labelAlign (top|left)
31  * @cfg {Boolean} readOnly Specifies that the field should be read-only
32  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
33  * @cfg {String} indicatorpos (left|right) default left
34  * @cfg {String} capture (user|camera) use for file input only. (default empty)
35  * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
36
37  * @cfg {String} align (left|center|right) Default left
38  * @cfg {Boolean} forceFeedback (true|false) Default false
39  * 
40  * @constructor
41  * Create a new Input
42  * @param {Object} config The config object
43  */
44
45 Roo.bootstrap.Input = function(config){
46     
47     Roo.bootstrap.Input.superclass.constructor.call(this, config);
48     
49     this.addEvents({
50         /**
51          * @event focus
52          * Fires when this field receives input focus.
53          * @param {Roo.form.Field} this
54          */
55         focus : true,
56         /**
57          * @event blur
58          * Fires when this field loses input focus.
59          * @param {Roo.form.Field} this
60          */
61         blur : true,
62         /**
63          * @event specialkey
64          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
65          * {@link Roo.EventObject#getKey} to determine which key was pressed.
66          * @param {Roo.form.Field} this
67          * @param {Roo.EventObject} e The event object
68          */
69         specialkey : true,
70         /**
71          * @event change
72          * Fires just before the field blurs if the field value has changed.
73          * @param {Roo.form.Field} this
74          * @param {Mixed} newValue The new value
75          * @param {Mixed} oldValue The original value
76          */
77         change : true,
78         /**
79          * @event invalid
80          * Fires after the field has been marked as invalid.
81          * @param {Roo.form.Field} this
82          * @param {String} msg The validation message
83          */
84         invalid : true,
85         /**
86          * @event valid
87          * Fires after the field has been validated with no errors.
88          * @param {Roo.form.Field} this
89          */
90         valid : true,
91          /**
92          * @event keyup
93          * Fires after the key up
94          * @param {Roo.form.Field} this
95          * @param {Roo.EventObject}  e The event Object
96          */
97         keyup : true
98     });
99 };
100
101 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
102      /**
103      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
104       automatic validation (defaults to "keyup").
105      */
106     validationEvent : "keyup",
107      /**
108      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
109      */
110     validateOnBlur : true,
111     /**
112      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
113      */
114     validationDelay : 250,
115      /**
116      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
117      */
118     focusClass : "x-form-focus",  // not needed???
119     
120        
121     /**
122      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
123      */
124     invalidClass : "has-warning",
125     
126     /**
127      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
128      */
129     validClass : "has-success",
130     
131     /**
132      * @cfg {Boolean} hasFeedback (true|false) default true
133      */
134     hasFeedback : true,
135     
136     /**
137      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
138      */
139     invalidFeedbackClass : "glyphicon-warning-sign",
140     
141     /**
142      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
143      */
144     validFeedbackClass : "glyphicon-ok",
145     
146     /**
147      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
148      */
149     selectOnFocus : false,
150     
151      /**
152      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
153      */
154     maskRe : null,
155        /**
156      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
157      */
158     vtype : null,
159     
160       /**
161      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
162      */
163     disableKeyFilter : false,
164     
165        /**
166      * @cfg {Boolean} disabled True to disable the field (defaults to false).
167      */
168     disabled : false,
169      /**
170      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
171      */
172     allowBlank : true,
173     /**
174      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
175      */
176     blankText : "Please complete this mandatory field",
177     
178      /**
179      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
180      */
181     minLength : 0,
182     /**
183      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
184      */
185     maxLength : Number.MAX_VALUE,
186     /**
187      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
188      */
189     minLengthText : "The minimum length for this field is {0}",
190     /**
191      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
192      */
193     maxLengthText : "The maximum length for this field is {0}",
194   
195     
196     /**
197      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
198      * If available, this function will be called only after the basic validators all return true, and will be passed the
199      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
200      */
201     validator : null,
202     /**
203      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
204      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
205      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
206      */
207     regex : null,
208     /**
209      * @cfg {String} regexText -- Depricated - use Invalid Text
210      */
211     regexText : "",
212     
213     /**
214      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
215      */
216     invalidText : "",
217     
218     
219     
220     autocomplete: false,
221     
222     
223     fieldLabel : '',
224     inputType : 'text',
225     
226     name : false,
227     placeholder: false,
228     before : false,
229     after : false,
230     size : false,
231     hasFocus : false,
232     preventMark: false,
233     isFormField : true,
234     value : '',
235     labelWidth : 2,
236     labelAlign : false,
237     readOnly : false,
238     align : false,
239     formatedValue : false,
240     forceFeedback : false,
241     
242     indicatorpos : 'left',
243     
244     labellg : 0,
245     labelmd : 0,
246     labelsm : 0,
247     labelxs : 0,
248     
249     capture : '',
250     accept : '',
251     
252     parentLabelAlign : function()
253     {
254         var parent = this;
255         while (parent.parent()) {
256             parent = parent.parent();
257             if (typeof(parent.labelAlign) !='undefined') {
258                 return parent.labelAlign;
259             }
260         }
261         return 'left';
262         
263     },
264     
265     getAutoCreate : function()
266     {
267         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
268         
269         var id = Roo.id();
270         
271         var cfg = {};
272         
273         if(this.inputType != 'hidden'){
274             cfg.cls = 'form-group' //input-group
275         }
276         
277         var input =  {
278             tag: 'input',
279             id : id,
280             type : this.inputType,
281             value : this.value,
282             cls : 'form-control',
283             placeholder : this.placeholder || '',
284             autocomplete : this.autocomplete || 'new-password'
285         };
286         
287         if(this.capture.length){
288             input.capture = this.capture;
289         }
290         
291         if(this.accept.length){
292             input.accept = this.accept + "/*";
293         }
294         
295         if(this.align){
296             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
297         }
298         
299         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
300             input.maxLength = this.maxLength;
301         }
302         
303         if (this.disabled) {
304             input.disabled=true;
305         }
306         
307         if (this.readOnly) {
308             input.readonly=true;
309         }
310         
311         if (this.name) {
312             input.name = this.name;
313         }
314         
315         if (this.size) {
316             input.cls += ' input-' + this.size;
317         }
318         
319         var settings=this;
320         ['xs','sm','md','lg'].map(function(size){
321             if (settings[size]) {
322                 cfg.cls += ' col-' + size + '-' + settings[size];
323             }
324         });
325         
326         var inputblock = input;
327         
328         var feedback = {
329             tag: 'span',
330             cls: 'glyphicon form-control-feedback'
331         };
332             
333         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
334             
335             inputblock = {
336                 cls : 'has-feedback',
337                 cn :  [
338                     input,
339                     feedback
340                 ] 
341             };  
342         }
343         
344         if (this.before || this.after) {
345             
346             inputblock = {
347                 cls : 'input-group',
348                 cn :  [] 
349             };
350             
351             if (this.before && typeof(this.before) == 'string') {
352                 
353                 inputblock.cn.push({
354                     tag :'span',
355                     cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
356                     html : this.before
357                 });
358             }
359             if (this.before && typeof(this.before) == 'object') {
360                 this.before = Roo.factory(this.before);
361                 
362                 inputblock.cn.push({
363                     tag :'span',
364                     cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
365                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
366                 });
367             }
368             
369             inputblock.cn.push(input);
370             
371             if (this.after && typeof(this.after) == 'string') {
372                 inputblock.cn.push({
373                     tag :'span',
374                     cls : 'roo-input-after input-group-append input-group-text input-group-addon',
375                     html : this.after
376                 });
377             }
378             if (this.after && typeof(this.after) == 'object') {
379                 this.after = Roo.factory(this.after);
380                 
381                 inputblock.cn.push({
382                     tag :'span',
383                     cls : 'roo-input-after input-group-append input-group-text input-group-' +
384                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
385                 });
386             }
387             
388             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
389                 inputblock.cls += ' has-feedback';
390                 inputblock.cn.push(feedback);
391             }
392         };
393         var indicator = {
394             tag : 'i',
395             cls : 'roo-required-indicator ' + (this.indicatorpos == 'right'  ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
396             tooltip : 'This field is required'
397         };
398         if (Roo.bootstrap.version == 4) {
399             indicator = {
400                 tag : 'i',
401                 style : 'display-none'
402             };
403         }
404         if (align ==='left' && this.fieldLabel.length) {
405             
406             cfg.cls += ' roo-form-group-label-left'  + (Roo.bootstrap.version == 4 ? ' row' : '');
407             
408             cfg.cn = [
409                 indicator,
410                 {
411                     tag: 'label',
412                     'for' :  id,
413                     cls : 'control-label col-form-label',
414                     html : this.fieldLabel
415
416                 },
417                 {
418                     cls : "", 
419                     cn: [
420                         inputblock
421                     ]
422                 }
423             ];
424             
425             var labelCfg = cfg.cn[1];
426             var contentCfg = cfg.cn[2];
427             
428             if(this.indicatorpos == 'right'){
429                 cfg.cn = [
430                     {
431                         tag: 'label',
432                         'for' :  id,
433                         cls : 'control-label col-form-label',
434                         cn : [
435                             {
436                                 tag : 'span',
437                                 html : this.fieldLabel
438                             },
439                             indicator
440                         ]
441                     },
442                     {
443                         cls : "",
444                         cn: [
445                             inputblock
446                         ]
447                     }
448
449                 ];
450                 
451                 labelCfg = cfg.cn[0];
452                 contentCfg = cfg.cn[1];
453             
454             }
455             
456             if(this.labelWidth > 12){
457                 labelCfg.style = "width: " + this.labelWidth + 'px';
458             }
459             
460             if(this.labelWidth < 13 && this.labelmd == 0){
461                 this.labelmd = this.labelWidth;
462             }
463             
464             if(this.labellg > 0){
465                 labelCfg.cls += ' col-lg-' + this.labellg;
466                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
467             }
468             
469             if(this.labelmd > 0){
470                 labelCfg.cls += ' col-md-' + this.labelmd;
471                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
472             }
473             
474             if(this.labelsm > 0){
475                 labelCfg.cls += ' col-sm-' + this.labelsm;
476                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
477             }
478             
479             if(this.labelxs > 0){
480                 labelCfg.cls += ' col-xs-' + this.labelxs;
481                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
482             }
483             
484             
485         } else if ( this.fieldLabel.length) {
486                 
487             cfg.cn = [
488                 {
489                     tag : 'i',
490                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
491                     tooltip : 'This field is required'
492                 },
493                 {
494                     tag: 'label',
495                    //cls : 'input-group-addon',
496                     html : this.fieldLabel
497
498                 },
499
500                inputblock
501
502            ];
503            
504            if(this.indicatorpos == 'right'){
505                 
506                 cfg.cn = [
507                     {
508                         tag: 'label',
509                        //cls : 'input-group-addon',
510                         html : this.fieldLabel
511
512                     },
513                     {
514                         tag : 'i',
515                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
516                         tooltip : 'This field is required'
517                     },
518
519                    inputblock
520
521                ];
522
523             }
524
525         } else {
526             
527             cfg.cn = [
528
529                     inputblock
530
531             ];
532                 
533                 
534         };
535         
536         if (this.parentType === 'Navbar' &&  this.parent().bar) {
537            cfg.cls += ' navbar-form';
538         }
539         
540         if (this.parentType === 'NavGroup') {
541            cfg.cls += ' navbar-form';
542            cfg.tag = 'li';
543         }
544         
545         return cfg;
546         
547     },
548     /**
549      * return the real input element.
550      */
551     inputEl: function ()
552     {
553         return this.el.select('input.form-control',true).first();
554     },
555     
556     tooltipEl : function()
557     {
558         return this.inputEl();
559     },
560     
561     indicatorEl : function()
562     {
563         if (Roo.bootstrap.version == 4) {
564             return false; // not enabled in v4 yet.
565         }
566         
567         var indicator = this.el.select('i.roo-required-indicator',true).first();
568         
569         if(!indicator){
570             return false;
571         }
572         
573         return indicator;
574         
575     },
576     
577     setDisabled : function(v)
578     {
579         var i  = this.inputEl().dom;
580         if (!v) {
581             i.removeAttribute('disabled');
582             return;
583             
584         }
585         i.setAttribute('disabled','true');
586     },
587     initEvents : function()
588     {
589           
590         this.inputEl().on("keydown" , this.fireKey,  this);
591         this.inputEl().on("focus", this.onFocus,  this);
592         this.inputEl().on("blur", this.onBlur,  this);
593         
594         this.inputEl().relayEvent('keyup', this);
595         
596         this.indicator = this.indicatorEl();
597         
598         if(this.indicator){
599             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? - 
600         }
601  
602         // reference to original value for reset
603         this.originalValue = this.getValue();
604         //Roo.form.TextField.superclass.initEvents.call(this);
605         if(this.validationEvent == 'keyup'){
606             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
607             this.inputEl().on('keyup', this.filterValidation, this);
608         }
609         else if(this.validationEvent !== false){
610             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
611         }
612         
613         if(this.selectOnFocus){
614             this.on("focus", this.preFocus, this);
615             
616         }
617         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
618             this.inputEl().on("keypress", this.filterKeys, this);
619         } else {
620             this.inputEl().relayEvent('keypress', this);
621         }
622        /* if(this.grow){
623             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
624             this.el.on("click", this.autoSize,  this);
625         }
626         */
627         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
628             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
629         }
630         
631         if (typeof(this.before) == 'object') {
632             this.before.render(this.el.select('.roo-input-before',true).first());
633         }
634         if (typeof(this.after) == 'object') {
635             this.after.render(this.el.select('.roo-input-after',true).first());
636         }
637         
638         this.inputEl().on('change', this.onChange, this);
639         
640     },
641     filterValidation : function(e){
642         if(!e.isNavKeyPress()){
643             this.validationTask.delay(this.validationDelay);
644         }
645     },
646      /**
647      * Validates the field value
648      * @return {Boolean} True if the value is valid, else false
649      */
650     validate : function(){
651         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
652         if(this.disabled || this.validateValue(this.getRawValue())){
653             this.markValid();
654             return true;
655         }
656         
657         this.markInvalid();
658         return false;
659     },
660     
661     
662     /**
663      * Validates a value according to the field's validation rules and marks the field as invalid
664      * if the validation fails
665      * @param {Mixed} value The value to validate
666      * @return {Boolean} True if the value is valid, else false
667      */
668     validateValue : function(value)
669     {
670         if(this.getVisibilityEl().hasClass('hidden')){
671             return true;
672         }
673         
674         if(value.length < 1)  { // if it's blank
675             if(this.allowBlank){
676                 return true;
677             }
678             return false;
679         }
680         
681         if(value.length < this.minLength){
682             return false;
683         }
684         if(value.length > this.maxLength){
685             return false;
686         }
687         if(this.vtype){
688             var vt = Roo.form.VTypes;
689             if(!vt[this.vtype](value, this)){
690                 return false;
691             }
692         }
693         if(typeof this.validator == "function"){
694             var msg = this.validator(value);
695             if(msg !== true){
696                 return false;
697             }
698             if (typeof(msg) == 'string') {
699                 this.invalidText = msg;
700             }
701         }
702         
703         if(this.regex && !this.regex.test(value)){
704             return false;
705         }
706         
707         return true;
708     },
709     
710      // private
711     fireKey : function(e){
712         //Roo.log('field ' + e.getKey());
713         if(e.isNavKeyPress()){
714             this.fireEvent("specialkey", this, e);
715         }
716     },
717     focus : function (selectText){
718         if(this.rendered){
719             this.inputEl().focus();
720             if(selectText === true){
721                 this.inputEl().dom.select();
722             }
723         }
724         return this;
725     } ,
726     
727     onFocus : function(){
728         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
729            // this.el.addClass(this.focusClass);
730         }
731         if(!this.hasFocus){
732             this.hasFocus = true;
733             this.startValue = this.getValue();
734             this.fireEvent("focus", this);
735         }
736     },
737     
738     beforeBlur : Roo.emptyFn,
739
740     
741     // private
742     onBlur : function(){
743         this.beforeBlur();
744         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
745             //this.el.removeClass(this.focusClass);
746         }
747         this.hasFocus = false;
748         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
749             this.validate();
750         }
751         var v = this.getValue();
752         if(String(v) !== String(this.startValue)){
753             this.fireEvent('change', this, v, this.startValue);
754         }
755         this.fireEvent("blur", this);
756     },
757     
758     onChange : function(e)
759     {
760         var v = this.getValue();
761         if(String(v) !== String(this.startValue)){
762             this.fireEvent('change', this, v, this.startValue);
763         }
764         
765     },
766     
767     /**
768      * Resets the current field value to the originally loaded value and clears any validation messages
769      */
770     reset : function(){
771         this.setValue(this.originalValue);
772         this.validate();
773     },
774      /**
775      * Returns the name of the field
776      * @return {Mixed} name The name field
777      */
778     getName: function(){
779         return this.name;
780     },
781      /**
782      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
783      * @return {Mixed} value The field value
784      */
785     getValue : function(){
786         
787         var v = this.inputEl().getValue();
788         
789         return v;
790     },
791     /**
792      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
793      * @return {Mixed} value The field value
794      */
795     getRawValue : function(){
796         var v = this.inputEl().getValue();
797         
798         return v;
799     },
800     
801     /**
802      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
803      * @param {Mixed} value The value to set
804      */
805     setRawValue : function(v){
806         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
807     },
808     
809     selectText : function(start, end){
810         var v = this.getRawValue();
811         if(v.length > 0){
812             start = start === undefined ? 0 : start;
813             end = end === undefined ? v.length : end;
814             var d = this.inputEl().dom;
815             if(d.setSelectionRange){
816                 d.setSelectionRange(start, end);
817             }else if(d.createTextRange){
818                 var range = d.createTextRange();
819                 range.moveStart("character", start);
820                 range.moveEnd("character", v.length-end);
821                 range.select();
822             }
823         }
824     },
825     
826     /**
827      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
828      * @param {Mixed} value The value to set
829      */
830     setValue : function(v){
831         this.value = v;
832         if(this.rendered){
833             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
834             this.validate();
835         }
836     },
837     
838     /*
839     processValue : function(value){
840         if(this.stripCharsRe){
841             var newValue = value.replace(this.stripCharsRe, '');
842             if(newValue !== value){
843                 this.setRawValue(newValue);
844                 return newValue;
845             }
846         }
847         return value;
848     },
849   */
850     preFocus : function(){
851         
852         if(this.selectOnFocus){
853             this.inputEl().dom.select();
854         }
855     },
856     filterKeys : function(e){
857         var k = e.getKey();
858         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
859             return;
860         }
861         var c = e.getCharCode(), cc = String.fromCharCode(c);
862         if(Roo.isIE && (e.isSpecialKey() || !cc)){
863             return;
864         }
865         if(!this.maskRe.test(cc)){
866             e.stopEvent();
867         }
868     },
869      /**
870      * Clear any invalid styles/messages for this field
871      */
872     clearInvalid : function(){
873         
874         if(!this.el || this.preventMark){ // not rendered
875             return;
876         }
877         
878      
879         this.el.removeClass(this.invalidClass);
880         
881         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
882             
883             var feedback = this.el.select('.form-control-feedback', true).first();
884             
885             if(feedback){
886                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
887             }
888             
889         }
890         
891         if(this.indicator){
892             this.indicator.removeClass('visible');
893             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
894         }
895         
896         this.fireEvent('valid', this);
897     },
898     
899      /**
900      * Mark this field as valid
901      */
902     markValid : function()
903     {
904         if(!this.el  || this.preventMark){ // not rendered...
905             return;
906         }
907         
908         this.el.removeClass([this.invalidClass, this.validClass]);
909         
910         var feedback = this.el.select('.form-control-feedback', true).first();
911             
912         if(feedback){
913             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
914         }
915         
916         if(this.indicator){
917             this.indicator.removeClass('visible');
918             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
919         }
920         
921         if(this.disabled){
922             return;
923         }
924         
925         if(this.allowBlank && !this.getRawValue().length){
926             return;
927         }
928         
929         this.el.addClass(this.validClass);
930         
931         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
932             
933             var feedback = this.el.select('.form-control-feedback', true).first();
934             
935             if(feedback){
936                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
937                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
938             }
939             
940         }
941         
942         this.fireEvent('valid', this);
943     },
944     
945      /**
946      * Mark this field as invalid
947      * @param {String} msg The validation message
948      */
949     markInvalid : function(msg)
950     {
951         if(!this.el  || this.preventMark){ // not rendered
952             return;
953         }
954         
955         this.el.removeClass([this.invalidClass, this.validClass]);
956         
957         var feedback = this.el.select('.form-control-feedback', true).first();
958             
959         if(feedback){
960             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
961         }
962
963         if(this.disabled){
964             return;
965         }
966         
967         if(this.allowBlank && !this.getRawValue().length){
968             return;
969         }
970         
971         if(this.indicator){
972             this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
973             this.indicator.addClass('visible');
974         }
975         
976         this.el.addClass(this.invalidClass);
977         
978         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
979             
980             var feedback = this.el.select('.form-control-feedback', true).first();
981             
982             if(feedback){
983                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
984                 
985                 if(this.getValue().length || this.forceFeedback){
986                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
987                 }
988                 
989             }
990             
991         }
992         
993         this.fireEvent('invalid', this, msg);
994     },
995     // private
996     SafariOnKeyDown : function(event)
997     {
998         // this is a workaround for a password hang bug on chrome/ webkit.
999         if (this.inputEl().dom.type != 'password') {
1000             return;
1001         }
1002         
1003         var isSelectAll = false;
1004         
1005         if(this.inputEl().dom.selectionEnd > 0){
1006             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
1007         }
1008         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
1009             event.preventDefault();
1010             this.setValue('');
1011             return;
1012         }
1013         
1014         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
1015             
1016             event.preventDefault();
1017             // this is very hacky as keydown always get's upper case.
1018             //
1019             var cc = String.fromCharCode(event.getCharCode());
1020             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
1021             
1022         }
1023     },
1024     adjustWidth : function(tag, w){
1025         tag = tag.toLowerCase();
1026         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
1027             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
1028                 if(tag == 'input'){
1029                     return w + 2;
1030                 }
1031                 if(tag == 'textarea'){
1032                     return w-2;
1033                 }
1034             }else if(Roo.isOpera){
1035                 if(tag == 'input'){
1036                     return w + 2;
1037                 }
1038                 if(tag == 'textarea'){
1039                     return w-2;
1040                 }
1041             }
1042         }
1043         return w;
1044     },
1045     
1046     setFieldLabel : function(v)
1047     {
1048         if(!this.rendered){
1049             return;
1050         }
1051         
1052         if(this.indicatorEl()){
1053             var ar = this.el.select('label > span',true);
1054             
1055             if (ar.elements.length) {
1056                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1057                 this.fieldLabel = v;
1058                 return;
1059             }
1060             
1061             var br = this.el.select('label',true);
1062             
1063             if(br.elements.length) {
1064                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1065                 this.fieldLabel = v;
1066                 return;
1067             }
1068             
1069             Roo.log('Cannot Found any of label > span || label in input');
1070             return;
1071         }
1072         
1073         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1074         this.fieldLabel = v;
1075         
1076         
1077     }
1078 });
1079
1080