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