Roo/bootstrap/Input.js
[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',
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-' +
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-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-' +
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         
394         if (align ==='left' && this.fieldLabel.length) {
395             
396             cfg.cls += ' roo-form-group-label-left';
397             
398             cfg.cn = [
399                 {
400                     tag : 'i',
401                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
402                     tooltip : 'This field is required'
403                 },
404                 {
405                     tag: 'label',
406                     'for' :  id,
407                     cls : 'control-label',
408                     html : this.fieldLabel
409
410                 },
411                 {
412                     cls : "", 
413                     cn: [
414                         inputblock
415                     ]
416                 }
417             ];
418             
419             var labelCfg = cfg.cn[1];
420             var contentCfg = cfg.cn[2];
421             
422             if(this.indicatorpos == 'right'){
423                 cfg.cn = [
424                     {
425                         tag: 'label',
426                         'for' :  id,
427                         cls : 'control-label',
428                         cn : [
429                             {
430                                 tag : 'span',
431                                 html : this.fieldLabel
432                             },
433                             {
434                                 tag : 'i',
435                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
436                                 tooltip : 'This field is required'
437                             }
438                         ]
439                     },
440                     {
441                         cls : "",
442                         cn: [
443                             inputblock
444                         ]
445                     }
446
447                 ];
448                 
449                 labelCfg = cfg.cn[0];
450                 contentCfg = cfg.cn[1];
451             
452             }
453             
454             if(this.labelWidth > 12){
455                 labelCfg.style = "width: " + this.labelWidth + 'px';
456             }
457             
458             if(this.labelWidth < 13 && this.labelmd == 0){
459                 this.labelmd = this.labelWidth;
460             }
461             
462             if(this.labellg > 0){
463                 labelCfg.cls += ' col-lg-' + this.labellg;
464                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
465             }
466             
467             if(this.labelmd > 0){
468                 labelCfg.cls += ' col-md-' + this.labelmd;
469                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
470             }
471             
472             if(this.labelsm > 0){
473                 labelCfg.cls += ' col-sm-' + this.labelsm;
474                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
475             }
476             
477             if(this.labelxs > 0){
478                 labelCfg.cls += ' col-xs-' + this.labelxs;
479                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
480             }
481             
482             
483         } else if ( this.fieldLabel.length) {
484                 
485             cfg.cn = [
486                 {
487                     tag : 'i',
488                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
489                     tooltip : 'This field is required'
490                 },
491                 {
492                     tag: 'label',
493                    //cls : 'input-group-addon',
494                     html : this.fieldLabel
495
496                 },
497
498                inputblock
499
500            ];
501            
502            if(this.indicatorpos == 'right'){
503                 
504                 cfg.cn = [
505                     {
506                         tag: 'label',
507                        //cls : 'input-group-addon',
508                         html : this.fieldLabel
509
510                     },
511                     {
512                         tag : 'i',
513                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
514                         tooltip : 'This field is required'
515                     },
516
517                    inputblock
518
519                ];
520
521             }
522
523         } else {
524             
525             cfg.cn = [
526
527                     inputblock
528
529             ];
530                 
531                 
532         };
533         
534         if (this.parentType === 'Navbar' &&  this.parent().bar) {
535            cfg.cls += ' navbar-form';
536         }
537         
538         if (this.parentType === 'NavGroup') {
539            cfg.cls += ' navbar-form';
540            cfg.tag = 'li';
541         }
542         
543         return cfg;
544         
545     },
546     /**
547      * return the real input element.
548      */
549     inputEl: function ()
550     {
551         return this.el.select('input.form-control',true).first();
552     },
553     
554     tooltipEl : function()
555     {
556         return this.inputEl();
557     },
558     
559     indicatorEl : function()
560     {
561         var indicator = this.el.select('i.roo-required-indicator',true).first();
562         
563         if(!indicator){
564             return false;
565         }
566         
567         return indicator;
568         
569     },
570     
571     setDisabled : function(v)
572     {
573         var i  = this.inputEl().dom;
574         if (!v) {
575             i.removeAttribute('disabled');
576             return;
577             
578         }
579         i.setAttribute('disabled','true');
580     },
581     initEvents : function()
582     {
583           
584         this.inputEl().on("keydown" , this.fireKey,  this);
585         this.inputEl().on("focus", this.onFocus,  this);
586         this.inputEl().on("blur", this.onBlur,  this);
587         
588         this.inputEl().relayEvent('keyup', this);
589         
590         this.indicator = this.indicatorEl();
591         
592         if(this.indicator){
593             this.indicator.addClass('invisible');
594         }
595  
596         // reference to original value for reset
597         this.originalValue = this.getValue();
598         //Roo.form.TextField.superclass.initEvents.call(this);
599         if(this.validationEvent == 'keyup'){
600             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
601             this.inputEl().on('keyup', this.filterValidation, this);
602         }
603         else if(this.validationEvent !== false){
604             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
605         }
606         
607         if(this.selectOnFocus){
608             this.on("focus", this.preFocus, this);
609             
610         }
611         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
612             this.inputEl().on("keypress", this.filterKeys, this);
613         } else {
614             this.inputEl().relayEvent('keypress', this);
615         }
616        /* if(this.grow){
617             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
618             this.el.on("click", this.autoSize,  this);
619         }
620         */
621         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
622             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
623         }
624         
625         if (typeof(this.before) == 'object') {
626             this.before.render(this.el.select('.roo-input-before',true).first());
627         }
628         if (typeof(this.after) == 'object') {
629             this.after.render(this.el.select('.roo-input-after',true).first());
630         }
631         
632         this.inputEl().on('change', this.onChange, this);
633         
634     },
635     filterValidation : function(e){
636         if(!e.isNavKeyPress()){
637             this.validationTask.delay(this.validationDelay);
638         }
639     },
640      /**
641      * Validates the field value
642      * @return {Boolean} True if the value is valid, else false
643      */
644     validate : function(){
645         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
646         if(this.disabled || this.validateValue(this.getRawValue())){
647             this.markValid();
648             return true;
649         }
650         
651         this.markInvalid();
652         return false;
653     },
654     
655     
656     /**
657      * Validates a value according to the field's validation rules and marks the field as invalid
658      * if the validation fails
659      * @param {Mixed} value The value to validate
660      * @return {Boolean} True if the value is valid, else false
661      */
662     validateValue : function(value)
663     {
664         if(this.getVisibilityEl().hasClass('hidden')){
665             return true;
666         }
667         
668         if(value.length < 1)  { // if it's blank
669             if(this.allowBlank){
670                 return true;
671             }
672             return false;
673         }
674         
675         if(value.length < this.minLength){
676             return false;
677         }
678         if(value.length > this.maxLength){
679             return false;
680         }
681         if(this.vtype){
682             var vt = Roo.form.VTypes;
683             if(!vt[this.vtype](value, this)){
684                 return false;
685             }
686         }
687         if(typeof this.validator == "function"){
688             var msg = this.validator(value);
689             if(msg !== true){
690                 return false;
691             }
692             if (typeof(msg) == 'string') {
693                 this.invalidText = msg;
694             }
695         }
696         
697         if(this.regex && !this.regex.test(value)){
698             return false;
699         }
700         
701         return true;
702     },
703     
704      // private
705     fireKey : function(e){
706         //Roo.log('field ' + e.getKey());
707         if(e.isNavKeyPress()){
708             this.fireEvent("specialkey", this, e);
709         }
710     },
711     focus : function (selectText){
712         if(this.rendered){
713             this.inputEl().focus();
714             if(selectText === true){
715                 this.inputEl().dom.select();
716             }
717         }
718         return this;
719     } ,
720     
721     onFocus : function(){
722         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
723            // this.el.addClass(this.focusClass);
724         }
725         if(!this.hasFocus){
726             this.hasFocus = true;
727             this.startValue = this.getValue();
728             this.fireEvent("focus", this);
729         }
730     },
731     
732     beforeBlur : Roo.emptyFn,
733
734     
735     // private
736     onBlur : function(){
737         this.beforeBlur();
738         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
739             //this.el.removeClass(this.focusClass);
740         }
741         this.hasFocus = false;
742         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
743             this.validate();
744         }
745         var v = this.getValue();
746         if(String(v) !== String(this.startValue)){
747             this.fireEvent('change', this, v, this.startValue);
748         }
749         this.fireEvent("blur", this);
750     },
751     
752     onChange : function(e)
753     {
754         var v = this.getValue();
755         if(String(v) !== String(this.startValue)){
756             this.fireEvent('change', this, v, this.startValue);
757         }
758         
759     },
760     
761     /**
762      * Resets the current field value to the originally loaded value and clears any validation messages
763      */
764     reset : function(){
765         this.setValue(this.originalValue);
766         this.validate();
767     },
768      /**
769      * Returns the name of the field
770      * @return {Mixed} name The name field
771      */
772     getName: function(){
773         return this.name;
774     },
775      /**
776      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
777      * @return {Mixed} value The field value
778      */
779     getValue : function(){
780         
781         var v = this.inputEl().getValue();
782         
783         return v;
784     },
785     /**
786      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
787      * @return {Mixed} value The field value
788      */
789     getRawValue : function(){
790         var v = this.inputEl().getValue();
791         
792         return v;
793     },
794     
795     /**
796      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
797      * @param {Mixed} value The value to set
798      */
799     setRawValue : function(v){
800         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
801     },
802     
803     selectText : function(start, end){
804         var v = this.getRawValue();
805         if(v.length > 0){
806             start = start === undefined ? 0 : start;
807             end = end === undefined ? v.length : end;
808             var d = this.inputEl().dom;
809             if(d.setSelectionRange){
810                 d.setSelectionRange(start, end);
811             }else if(d.createTextRange){
812                 var range = d.createTextRange();
813                 range.moveStart("character", start);
814                 range.moveEnd("character", v.length-end);
815                 range.select();
816             }
817         }
818     },
819     
820     /**
821      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
822      * @param {Mixed} value The value to set
823      */
824     setValue : function(v){
825         this.value = v;
826         if(this.rendered){
827             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
828             this.validate();
829         }
830     },
831     
832     /*
833     processValue : function(value){
834         if(this.stripCharsRe){
835             var newValue = value.replace(this.stripCharsRe, '');
836             if(newValue !== value){
837                 this.setRawValue(newValue);
838                 return newValue;
839             }
840         }
841         return value;
842     },
843   */
844     preFocus : function(){
845         
846         if(this.selectOnFocus){
847             this.inputEl().dom.select();
848         }
849     },
850     filterKeys : function(e){
851         var k = e.getKey();
852         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
853             return;
854         }
855         var c = e.getCharCode(), cc = String.fromCharCode(c);
856         if(Roo.isIE && (e.isSpecialKey() || !cc)){
857             return;
858         }
859         if(!this.maskRe.test(cc)){
860             e.stopEvent();
861         }
862     },
863      /**
864      * Clear any invalid styles/messages for this field
865      */
866     clearInvalid : function(){
867         
868         if(!this.el || this.preventMark){ // not rendered
869             return;
870         }
871         
872      
873         this.el.removeClass(this.invalidClass);
874         
875         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
876             
877             var feedback = this.el.select('.form-control-feedback', true).first();
878             
879             if(feedback){
880                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
881             }
882             
883         }
884         
885         this.fireEvent('valid', this);
886     },
887     
888      /**
889      * Mark this field as valid
890      */
891     markValid : function()
892     {
893         if(!this.el  || this.preventMark){ // not rendered...
894             return;
895         }
896         
897         this.el.removeClass([this.invalidClass, this.validClass]);
898         
899         var feedback = this.el.select('.form-control-feedback', true).first();
900             
901         if(feedback){
902             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
903         }
904         
905         if(this.indicator){
906             this.indicator.removeClass('visible');
907             this.indicator.addClass('invisible');
908         }
909         
910         if(this.disabled){
911             return;
912         }
913         
914         if(this.allowBlank && !this.getRawValue().length){
915             return;
916         }
917         
918         this.el.addClass(this.validClass);
919         
920         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
921             
922             var feedback = this.el.select('.form-control-feedback', true).first();
923             
924             if(feedback){
925                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
926                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
927             }
928             
929         }
930         
931         this.fireEvent('valid', this);
932     },
933     
934      /**
935      * Mark this field as invalid
936      * @param {String} msg The validation message
937      */
938     markInvalid : function(msg)
939     {
940         if(!this.el  || this.preventMark){ // not rendered
941             return;
942         }
943         
944         this.el.removeClass([this.invalidClass, this.validClass]);
945         
946         var feedback = this.el.select('.form-control-feedback', true).first();
947             
948         if(feedback){
949             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
950         }
951
952         if(this.disabled){
953             return;
954         }
955         
956         if(this.allowBlank && !this.getRawValue().length){
957             return;
958         }
959         
960         if(this.indicator){
961             this.indicator.removeClass('invisible');
962             this.indicator.addClass('visible');
963         }
964         
965         this.el.addClass(this.invalidClass);
966         
967         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
968             
969             var feedback = this.el.select('.form-control-feedback', true).first();
970             
971             if(feedback){
972                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
973                 
974                 if(this.getValue().length || this.forceFeedback){
975                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
976                 }
977                 
978             }
979             
980         }
981         
982         this.fireEvent('invalid', this, msg);
983     },
984     // private
985     SafariOnKeyDown : function(event)
986     {
987         // this is a workaround for a password hang bug on chrome/ webkit.
988         if (this.inputEl().dom.type != 'password') {
989             return;
990         }
991         
992         var isSelectAll = false;
993         
994         if(this.inputEl().dom.selectionEnd > 0){
995             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
996         }
997         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
998             event.preventDefault();
999             this.setValue('');
1000             return;
1001         }
1002         
1003         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
1004             
1005             event.preventDefault();
1006             // this is very hacky as keydown always get's upper case.
1007             //
1008             var cc = String.fromCharCode(event.getCharCode());
1009             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
1010             
1011         }
1012     },
1013     adjustWidth : function(tag, w){
1014         tag = tag.toLowerCase();
1015         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
1016             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
1017                 if(tag == 'input'){
1018                     return w + 2;
1019                 }
1020                 if(tag == 'textarea'){
1021                     return w-2;
1022                 }
1023             }else if(Roo.isOpera){
1024                 if(tag == 'input'){
1025                     return w + 2;
1026                 }
1027                 if(tag == 'textarea'){
1028                     return w-2;
1029                 }
1030             }
1031         }
1032         return w;
1033     },
1034     
1035     setFieldLabel : function(v)
1036     {
1037         if(!this.rendered){
1038             return;
1039         }
1040         
1041         if(this.indicator){
1042             var ar = this.el.select('label > span',true);
1043             
1044             if (ar.elements.length) {
1045                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1046                 this.fieldLabel = v;
1047                 return;
1048             }
1049             
1050             var br = this.el.select('label',true);
1051             
1052             if(br.elements.length) {
1053                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1054                 this.fieldLabel = v;
1055                 return;
1056             }
1057             
1058             Roo.log('Cannot Found any of label > span || label in input');
1059             return;
1060         }
1061         
1062         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1063         this.fieldLabel = v;
1064         
1065         
1066     }
1067 });
1068
1069