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