fc009f3a3c089b68921be35fedbb986d7ed7f87e
[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' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
541             // on BS4 we do this only if not form 
542             cfg.cls += ' navbar-form';
543             cfg.tag = 'li';
544         }
545         
546         return cfg;
547         
548     },
549     /**
550      * return the real input element.
551      */
552     inputEl: function ()
553     {
554         return this.el.select('input.form-control',true).first();
555     },
556     
557     tooltipEl : function()
558     {
559         return this.inputEl();
560     },
561     
562     indicatorEl : function()
563     {
564         if (Roo.bootstrap.version == 4) {
565             return false; // not enabled in v4 yet.
566         }
567         
568         var indicator = this.el.select('i.roo-required-indicator',true).first();
569         
570         if(!indicator){
571             return false;
572         }
573         
574         return indicator;
575         
576     },
577     
578     setDisabled : function(v)
579     {
580         var i  = this.inputEl().dom;
581         if (!v) {
582             i.removeAttribute('disabled');
583             return;
584             
585         }
586         i.setAttribute('disabled','true');
587     },
588     initEvents : function()
589     {
590           
591         this.inputEl().on("keydown" , this.fireKey,  this);
592         this.inputEl().on("focus", this.onFocus,  this);
593         this.inputEl().on("blur", this.onBlur,  this);
594         
595         this.inputEl().relayEvent('keyup', this);
596         
597         this.indicator = this.indicatorEl();
598         
599         if(this.indicator){
600             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? - 
601         }
602  
603         // reference to original value for reset
604         this.originalValue = this.getValue();
605         //Roo.form.TextField.superclass.initEvents.call(this);
606         if(this.validationEvent == 'keyup'){
607             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
608             this.inputEl().on('keyup', this.filterValidation, this);
609         }
610         else if(this.validationEvent !== false){
611             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
612         }
613         
614         if(this.selectOnFocus){
615             this.on("focus", this.preFocus, this);
616             
617         }
618         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
619             this.inputEl().on("keypress", this.filterKeys, this);
620         } else {
621             this.inputEl().relayEvent('keypress', this);
622         }
623        /* if(this.grow){
624             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
625             this.el.on("click", this.autoSize,  this);
626         }
627         */
628         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
629             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
630         }
631         
632         if (typeof(this.before) == 'object') {
633             this.before.render(this.el.select('.roo-input-before',true).first());
634         }
635         if (typeof(this.after) == 'object') {
636             this.after.render(this.el.select('.roo-input-after',true).first());
637         }
638         
639         this.inputEl().on('change', this.onChange, this);
640         
641     },
642     filterValidation : function(e){
643         if(!e.isNavKeyPress()){
644             this.validationTask.delay(this.validationDelay);
645         }
646     },
647      /**
648      * Validates the field value
649      * @return {Boolean} True if the value is valid, else false
650      */
651     validate : function(){
652         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
653         if(this.disabled || this.validateValue(this.getRawValue())){
654             this.markValid();
655             return true;
656         }
657         
658         this.markInvalid();
659         return false;
660     },
661     
662     
663     /**
664      * Validates a value according to the field's validation rules and marks the field as invalid
665      * if the validation fails
666      * @param {Mixed} value The value to validate
667      * @return {Boolean} True if the value is valid, else false
668      */
669     validateValue : function(value)
670     {
671         if(this.getVisibilityEl().hasClass('hidden')){
672             return true;
673         }
674         
675         if(value.length < 1)  { // if it's blank
676             if(this.allowBlank){
677                 return true;
678             }
679             return false;
680         }
681         
682         if(value.length < this.minLength){
683             this.invalidText = String.format(this.minLengthText, this.minLength);
684             return false;
685         }
686         if(value.length > this.maxLength){
687             this.invalidText = String.format(this.maxLengthText, this.maxLength);
688             return false;
689         }
690         if(this.vtype){
691             var vt = Roo.form.VTypes;
692             if(!vt[this.vtype](value, this)){
693                 return false;
694             }
695         }
696         if(typeof this.validator == "function"){
697             var msg = this.validator(value);
698             if(msg !== true){
699                 return false;
700             }
701             if (typeof(msg) == 'string') {
702                 this.invalidText = msg;
703             }
704         }
705         
706         if(this.regex && !this.regex.test(value)){
707             return false;
708         }
709         
710         return true;
711     },
712     
713      // private
714     fireKey : function(e){
715         //Roo.log('field ' + e.getKey());
716         if(e.isNavKeyPress()){
717             this.fireEvent("specialkey", this, e);
718         }
719     },
720     focus : function (selectText){
721         if(this.rendered){
722             this.inputEl().focus();
723             if(selectText === true){
724                 this.inputEl().dom.select();
725             }
726         }
727         return this;
728     } ,
729     
730     onFocus : function(){
731         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
732            // this.el.addClass(this.focusClass);
733         }
734         if(!this.hasFocus){
735             this.hasFocus = true;
736             this.startValue = this.getValue();
737             this.fireEvent("focus", this);
738         }
739     },
740     
741     beforeBlur : Roo.emptyFn,
742
743     
744     // private
745     onBlur : function(){
746         this.beforeBlur();
747         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
748             //this.el.removeClass(this.focusClass);
749         }
750         this.hasFocus = false;
751         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
752             this.validate();
753         }
754         var v = this.getValue();
755         if(String(v) !== String(this.startValue)){
756             this.fireEvent('change', this, v, this.startValue);
757         }
758         this.fireEvent("blur", this);
759     },
760     
761     onChange : function(e)
762     {
763         var v = this.getValue();
764         if(String(v) !== String(this.startValue)){
765             this.fireEvent('change', this, v, this.startValue);
766         }
767         
768     },
769     
770     /**
771      * Resets the current field value to the originally loaded value and clears any validation messages
772      */
773     reset : function(){
774         this.setValue(this.originalValue);
775         this.validate();
776     },
777      /**
778      * Returns the name of the field
779      * @return {Mixed} name The name field
780      */
781     getName: function(){
782         return this.name;
783     },
784      /**
785      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
786      * @return {Mixed} value The field value
787      */
788     getValue : function(){
789         
790         var v = this.inputEl().getValue();
791         
792         return v;
793     },
794     /**
795      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
796      * @return {Mixed} value The field value
797      */
798     getRawValue : function(){
799         var v = this.inputEl().getValue();
800         
801         return v;
802     },
803     
804     /**
805      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
806      * @param {Mixed} value The value to set
807      */
808     setRawValue : function(v){
809         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
810     },
811     
812     selectText : function(start, end){
813         var v = this.getRawValue();
814         if(v.length > 0){
815             start = start === undefined ? 0 : start;
816             end = end === undefined ? v.length : end;
817             var d = this.inputEl().dom;
818             if(d.setSelectionRange){
819                 d.setSelectionRange(start, end);
820             }else if(d.createTextRange){
821                 var range = d.createTextRange();
822                 range.moveStart("character", start);
823                 range.moveEnd("character", v.length-end);
824                 range.select();
825             }
826         }
827     },
828     
829     /**
830      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
831      * @param {Mixed} value The value to set
832      */
833     setValue : function(v){
834         this.value = v;
835         if(this.rendered){
836             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
837             this.validate();
838         }
839     },
840     
841     /*
842     processValue : function(value){
843         if(this.stripCharsRe){
844             var newValue = value.replace(this.stripCharsRe, '');
845             if(newValue !== value){
846                 this.setRawValue(newValue);
847                 return newValue;
848             }
849         }
850         return value;
851     },
852   */
853     preFocus : function(){
854         
855         if(this.selectOnFocus){
856             this.inputEl().dom.select();
857         }
858     },
859     filterKeys : function(e){
860         var k = e.getKey();
861         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
862             return;
863         }
864         var c = e.getCharCode(), cc = String.fromCharCode(c);
865         if(Roo.isIE && (e.isSpecialKey() || !cc)){
866             return;
867         }
868         if(!this.maskRe.test(cc)){
869             e.stopEvent();
870         }
871     },
872      /**
873      * Clear any invalid styles/messages for this field
874      */
875     clearInvalid : function(){
876         
877         if(!this.el || this.preventMark){ // not rendered
878             return;
879         }
880         
881      
882         this.el.removeClass(this.invalidClass);
883         
884         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
885             
886             var feedback = this.el.select('.form-control-feedback', true).first();
887             
888             if(feedback){
889                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
890             }
891             
892         }
893         
894         if(this.indicator){
895             this.indicator.removeClass('visible');
896             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
897         }
898         
899         this.fireEvent('valid', this);
900     },
901     
902      /**
903      * Mark this field as valid
904      */
905     markValid : function()
906     {
907         if(!this.el  || this.preventMark){ // not rendered...
908             return;
909         }
910         
911         this.el.removeClass([this.invalidClass, this.validClass]);
912         
913         var feedback = this.el.select('.form-control-feedback', true).first();
914             
915         if(feedback){
916             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
917         }
918         
919         if(this.indicator){
920             this.indicator.removeClass('visible');
921             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
922         }
923         
924         if(this.disabled){
925             return;
926         }
927         
928         if(this.allowBlank && !this.getRawValue().length){
929             return;
930         }
931         
932         this.el.addClass(this.validClass);
933         
934         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
935             
936             var feedback = this.el.select('.form-control-feedback', true).first();
937             
938             if(feedback){
939                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
940                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
941             }
942             
943         }
944         
945         this.fireEvent('valid', this);
946     },
947     
948      /**
949      * Mark this field as invalid
950      * @param {String} msg The validation message
951      */
952     markInvalid : function(msg)
953     {
954         if(!this.el  || this.preventMark){ // not rendered
955             return;
956         }
957         
958         this.el.removeClass([this.invalidClass, this.validClass]);
959         
960         var feedback = this.el.select('.form-control-feedback', true).first();
961             
962         if(feedback){
963             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
964         }
965
966         if(this.disabled){
967             return;
968         }
969         
970         if(this.allowBlank && !this.getRawValue().length){
971             return;
972         }
973         
974         if(this.indicator){
975             this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
976             this.indicator.addClass('visible');
977         }
978         
979         this.el.addClass(this.invalidClass);
980         
981         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
982             
983             var feedback = this.el.select('.form-control-feedback', true).first();
984             
985             if(feedback){
986                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
987                 
988                 if(this.getValue().length || this.forceFeedback){
989                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
990                 }
991                 
992             }
993             
994         }
995         
996         this.fireEvent('invalid', this, msg);
997     },
998     // private
999     SafariOnKeyDown : function(event)
1000     {
1001         // this is a workaround for a password hang bug on chrome/ webkit.
1002         if (this.inputEl().dom.type != 'password') {
1003             return;
1004         }
1005         
1006         var isSelectAll = false;
1007         
1008         if(this.inputEl().dom.selectionEnd > 0){
1009             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
1010         }
1011         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
1012             event.preventDefault();
1013             this.setValue('');
1014             return;
1015         }
1016         
1017         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
1018             
1019             event.preventDefault();
1020             // this is very hacky as keydown always get's upper case.
1021             //
1022             var cc = String.fromCharCode(event.getCharCode());
1023             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
1024             
1025         }
1026     },
1027     adjustWidth : function(tag, w){
1028         tag = tag.toLowerCase();
1029         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
1030             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
1031                 if(tag == 'input'){
1032                     return w + 2;
1033                 }
1034                 if(tag == 'textarea'){
1035                     return w-2;
1036                 }
1037             }else if(Roo.isOpera){
1038                 if(tag == 'input'){
1039                     return w + 2;
1040                 }
1041                 if(tag == 'textarea'){
1042                     return w-2;
1043                 }
1044             }
1045         }
1046         return w;
1047     },
1048     
1049     setFieldLabel : function(v)
1050     {
1051         if(!this.rendered){
1052             return;
1053         }
1054         
1055         if(this.indicatorEl()){
1056             var ar = this.el.select('label > span',true);
1057             
1058             if (ar.elements.length) {
1059                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1060                 this.fieldLabel = v;
1061                 return;
1062             }
1063             
1064             var br = this.el.select('label',true);
1065             
1066             if(br.elements.length) {
1067                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1068                 this.fieldLabel = v;
1069                 return;
1070             }
1071             
1072             Roo.log('Cannot Found any of label > span || label in input');
1073             return;
1074         }
1075         
1076         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1077         this.fieldLabel = v;
1078         
1079         
1080     }
1081 });
1082
1083