35b33161027fdc1ec3109414923aeac2ce33a946
[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 DEPRICATED - code uses BS4 - is-valid / is-invalid
123      */
124     invalidClass : "has-warning",
125     
126     /**
127      * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-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             return false;
684         }
685         if(value.length > this.maxLength){
686             return false;
687         }
688         if(this.vtype){
689             var vt = Roo.form.VTypes;
690             if(!vt[this.vtype](value, this)){
691                 return false;
692             }
693         }
694         if(typeof this.validator == "function"){
695             var msg = this.validator(value);
696             if(msg !== true){
697                 return false;
698             }
699             if (typeof(msg) == 'string') {
700                 this.invalidText = msg;
701             }
702         }
703         
704         if(this.regex && !this.regex.test(value)){
705             return false;
706         }
707         
708         return true;
709     },
710     
711      // private
712     fireKey : function(e){
713         //Roo.log('field ' + e.getKey());
714         if(e.isNavKeyPress()){
715             this.fireEvent("specialkey", this, e);
716         }
717     },
718     focus : function (selectText){
719         if(this.rendered){
720             this.inputEl().focus();
721             if(selectText === true){
722                 this.inputEl().dom.select();
723             }
724         }
725         return this;
726     } ,
727     
728     onFocus : function(){
729         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
730            // this.el.addClass(this.focusClass);
731         }
732         if(!this.hasFocus){
733             this.hasFocus = true;
734             this.startValue = this.getValue();
735             this.fireEvent("focus", this);
736         }
737     },
738     
739     beforeBlur : Roo.emptyFn,
740
741     
742     // private
743     onBlur : function(){
744         this.beforeBlur();
745         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
746             //this.el.removeClass(this.focusClass);
747         }
748         this.hasFocus = false;
749         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
750             this.validate();
751         }
752         var v = this.getValue();
753         if(String(v) !== String(this.startValue)){
754             this.fireEvent('change', this, v, this.startValue);
755         }
756         this.fireEvent("blur", this);
757     },
758     
759     onChange : function(e)
760     {
761         var v = this.getValue();
762         if(String(v) !== String(this.startValue)){
763             this.fireEvent('change', this, v, this.startValue);
764         }
765         
766     },
767     
768     /**
769      * Resets the current field value to the originally loaded value and clears any validation messages
770      */
771     reset : function(){
772         this.setValue(this.originalValue);
773         this.validate();
774     },
775      /**
776      * Returns the name of the field
777      * @return {Mixed} name The name field
778      */
779     getName: function(){
780         return this.name;
781     },
782      /**
783      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
784      * @return {Mixed} value The field value
785      */
786     getValue : function(){
787         
788         var v = this.inputEl().getValue();
789         
790         return v;
791     },
792     /**
793      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
794      * @return {Mixed} value The field value
795      */
796     getRawValue : function(){
797         var v = this.inputEl().getValue();
798         
799         return v;
800     },
801     
802     /**
803      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
804      * @param {Mixed} value The value to set
805      */
806     setRawValue : function(v){
807         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
808     },
809     
810     selectText : function(start, end){
811         var v = this.getRawValue();
812         if(v.length > 0){
813             start = start === undefined ? 0 : start;
814             end = end === undefined ? v.length : end;
815             var d = this.inputEl().dom;
816             if(d.setSelectionRange){
817                 d.setSelectionRange(start, end);
818             }else if(d.createTextRange){
819                 var range = d.createTextRange();
820                 range.moveStart("character", start);
821                 range.moveEnd("character", v.length-end);
822                 range.select();
823             }
824         }
825     },
826     
827     /**
828      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
829      * @param {Mixed} value The value to set
830      */
831     setValue : function(v){
832         this.value = v;
833         if(this.rendered){
834             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
835             this.validate();
836         }
837     },
838     
839     /*
840     processValue : function(value){
841         if(this.stripCharsRe){
842             var newValue = value.replace(this.stripCharsRe, '');
843             if(newValue !== value){
844                 this.setRawValue(newValue);
845                 return newValue;
846             }
847         }
848         return value;
849     },
850   */
851     preFocus : function(){
852         
853         if(this.selectOnFocus){
854             this.inputEl().dom.select();
855         }
856     },
857     filterKeys : function(e){
858         var k = e.getKey();
859         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
860             return;
861         }
862         var c = e.getCharCode(), cc = String.fromCharCode(c);
863         if(Roo.isIE && (e.isSpecialKey() || !cc)){
864             return;
865         }
866         if(!this.maskRe.test(cc)){
867             e.stopEvent();
868         }
869     },
870      /**
871      * Clear any invalid styles/messages for this field
872      */
873     clearInvalid : function(){
874         
875         if(!this.el || this.preventMark){ // not rendered
876             return;
877         }
878         
879         
880         this.el.removeClass([this.invalidClass, 'is-invalid']);
881         
882         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
883             
884             var feedback = this.el.select('.form-control-feedback', true).first();
885             
886             if(feedback){
887                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
888             }
889             
890         }
891         
892         if(this.indicator){
893             this.indicator.removeClass('visible');
894             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
895         }
896         
897         this.fireEvent('valid', this);
898     },
899     
900      /**
901      * Mark this field as valid
902      */
903     markValid : function()
904     {
905         if(!this.el  || this.preventMark){ // not rendered...
906             return;
907         }
908         
909         this.el.removeClass([this.invalidClass, this.validClass]);
910         this.inputEl().removeClass(['is-valid', 'is-invalid']);
911
912         var feedback = this.el.select('.form-control-feedback', true).first();
913             
914         if(feedback){
915             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
916         }
917         
918         if(this.indicator){
919             this.indicator.removeClass('visible');
920             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
921         }
922         
923         if(this.disabled){
924             return;
925         }
926         
927         if(this.allowBlank && !this.getRawValue().length){
928             return;
929         }
930         if (Roo.bootstrap.version == 3) {
931             this.el.addClass(this.validClass);
932         } else {
933             this.inputEl().addClass('is-valid');
934         }
935
936         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
937             
938             var feedback = this.el.select('.form-control-feedback', true).first();
939             
940             if(feedback){
941                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
942                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
943             }
944             
945         }
946         
947         this.fireEvent('valid', this);
948     },
949     
950      /**
951      * Mark this field as invalid
952      * @param {String} msg The validation message
953      */
954     markInvalid : function(msg)
955     {
956         if(!this.el  || this.preventMark){ // not rendered
957             return;
958         }
959         
960         this.el.removeClass([this.invalidClass, this.validClass]);
961         this.inputEl().removeClass(['is-valid', 'is-invalid']);
962         
963         var feedback = this.el.select('.form-control-feedback', true).first();
964             
965         if(feedback){
966             this.el.select('.form-control-feedback', true).first().removeClass(
967                     [this.invalidFeedbackClass, this.validFeedbackClass]);
968         }
969
970         if(this.disabled){
971             return;
972         }
973         
974         if(this.allowBlank && !this.getRawValue().length){
975             return;
976         }
977         
978         if(this.indicator){
979             this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
980             this.indicator.addClass('visible');
981         }
982         if (Roo.bootstrap.version == 3) {
983             this.el.addClass(this.invalidClass);
984         } else {
985             this.inputEl().addClass('is-invalid');
986         }
987         
988         
989         
990         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
991             
992             var feedback = this.el.select('.form-control-feedback', true).first();
993             
994             if(feedback){
995                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
996                 
997                 if(this.getValue().length || this.forceFeedback){
998                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
999                 }
1000                 
1001             }
1002             
1003         }
1004         
1005         this.fireEvent('invalid', this, msg);
1006     },
1007     // private
1008     SafariOnKeyDown : function(event)
1009     {
1010         // this is a workaround for a password hang bug on chrome/ webkit.
1011         if (this.inputEl().dom.type != 'password') {
1012             return;
1013         }
1014         
1015         var isSelectAll = false;
1016         
1017         if(this.inputEl().dom.selectionEnd > 0){
1018             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
1019         }
1020         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
1021             event.preventDefault();
1022             this.setValue('');
1023             return;
1024         }
1025         
1026         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
1027             
1028             event.preventDefault();
1029             // this is very hacky as keydown always get's upper case.
1030             //
1031             var cc = String.fromCharCode(event.getCharCode());
1032             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
1033             
1034         }
1035     },
1036     adjustWidth : function(tag, w){
1037         tag = tag.toLowerCase();
1038         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
1039             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
1040                 if(tag == 'input'){
1041                     return w + 2;
1042                 }
1043                 if(tag == 'textarea'){
1044                     return w-2;
1045                 }
1046             }else if(Roo.isOpera){
1047                 if(tag == 'input'){
1048                     return w + 2;
1049                 }
1050                 if(tag == 'textarea'){
1051                     return w-2;
1052                 }
1053             }
1054         }
1055         return w;
1056     },
1057     
1058     setFieldLabel : function(v)
1059     {
1060         if(!this.rendered){
1061             return;
1062         }
1063         
1064         if(this.indicatorEl()){
1065             var ar = this.el.select('label > span',true);
1066             
1067             if (ar.elements.length) {
1068                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1069                 this.fieldLabel = v;
1070                 return;
1071             }
1072             
1073             var br = this.el.select('label',true);
1074             
1075             if(br.elements.length) {
1076                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1077                 this.fieldLabel = v;
1078                 return;
1079             }
1080             
1081             Roo.log('Cannot Found any of label > span || label in input');
1082             return;
1083         }
1084         
1085         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
1086         this.fieldLabel = v;
1087         
1088         
1089     }
1090 });
1091
1092