support paste event
[roojs1] / Roo / bootstrap / Input.js
index 4e0ca54..6ff1d93 100644 (file)
@@ -10,7 +10,7 @@
  * @extends Roo.bootstrap.Component
  * Bootstrap Input class
  * @cfg {Boolean} disabled is it disabled
- * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
+ * @cfg {String} (button|checkbox|email|file|hidden|image|number|password|radio|range|reset|search|submit|text) inputType 
  * @cfg {String} name name of the input
  * @cfg {string} fieldLabel - the label associated
  * @cfg {string} placeholder - placeholder to put in text.
  * @cfg {Boolean} readOnly Specifies that the field should be read-only
  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
  * @cfg {String} indicatorpos (left|right) default left
+ * @cfg {String} capture (user|camera) use for file input only. (default empty)
+ * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
+ * @cfg {Boolean} preventMark Do not show tick or cross if error/success
 
  * @cfg {String} align (left|center|right) Default left
  * @cfg {Boolean} forceFeedback (true|false) Default false
  * 
- * 
- * 
- * 
  * @constructor
  * Create a new Input
  * @param {Object} config The config object
@@ -95,7 +95,14 @@ Roo.bootstrap.Input = function(config){
          * @param {Roo.form.Field} this
          * @param {Roo.EventObject}  e The event Object
          */
-        keyup : true
+        keyup : true,
+        /**
+         * @event paste
+         * Fires after the user pastes into input
+         * @param {Roo.form.Field} this
+         * @param {Roo.EventObject}  e The event Object
+         */
+        paste : true
     });
 };
 
@@ -120,12 +127,12 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
     
        
     /**
-     * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
+     * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
      */
     invalidClass : "has-warning",
     
     /**
-     * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
+     * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
      */
     validClass : "has-success",
     
@@ -207,10 +214,17 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
      */
     regex : null,
     /**
-     * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
+     * @cfg {String} regexText -- Depricated - use Invalid Text
      */
     regexText : "",
     
+    /**
+     * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
+     */
+    invalidText : "",
+    
+    
+    
     autocomplete: false,
     
     
@@ -240,6 +254,9 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
     labelsm : 0,
     labelxs : 0,
     
+    capture : '',
+    accept : '',
+    
     parentLabelAlign : function()
     {
         var parent = this;
@@ -274,6 +291,17 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             placeholder : this.placeholder || '',
             autocomplete : this.autocomplete || 'new-password'
         };
+        if (this.inputType == 'file') {
+            input.style = 'overflow:hidden'; // why not in CSS?
+        }
+        
+        if(this.capture.length){
+            input.capture = this.capture;
+        }
+        
+        if(this.accept.length){
+            input.accept = this.accept + "/*";
+        }
         
         if(this.align){
             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
@@ -335,7 +363,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
                 
                 inputblock.cn.push({
                     tag :'span',
-                    cls : 'roo-input-before input-group-addon',
+                    cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
                     html : this.before
                 });
             }
@@ -344,7 +372,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
                 
                 inputblock.cn.push({
                     tag :'span',
-                    cls : 'roo-input-before input-group-' +
+                    cls : 'roo-input-before input-group-prepend   input-group-' +
                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
                 });
             }
@@ -354,7 +382,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             if (this.after && typeof(this.after) == 'string') {
                 inputblock.cn.push({
                     tag :'span',
-                    cls : 'roo-input-after input-group-addon',
+                    cls : 'roo-input-after input-group-append input-group-text input-group-addon',
                     html : this.after
                 });
             }
@@ -363,7 +391,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
                 
                 inputblock.cn.push({
                     tag :'span',
-                    cls : 'roo-input-after input-group-' +
+                    cls : 'roo-input-after input-group-append  input-group-' +
                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
                 });
             }
@@ -373,21 +401,24 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
                 inputblock.cn.push(feedback);
             }
         };
-        
+        var indicator = {
+            tag : 'i',
+            cls : 'roo-required-indicator ' + (this.indicatorpos == 'right'  ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
+            tooltip : 'This field is required'
+        };
+        if (this.allowBlank ) {
+            indicator.style = this.allowBlank ? ' display:none' : '';
+        }
         if (align ==='left' && this.fieldLabel.length) {
             
-            cfg.cls += ' roo-form-group-label-left';
+            cfg.cls += ' roo-form-group-label-left'  + (Roo.bootstrap.version == 4 ? ' row' : '');
             
             cfg.cn = [
-                {
-                    tag : 'i',
-                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
-                    tooltip : 'This field is required'
-                },
+                indicator,
                 {
                     tag: 'label',
                     'for' :  id,
-                    cls : 'control-label',
+                    cls : 'control-label col-form-label',
                     html : this.fieldLabel
 
                 },
@@ -407,14 +438,14 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
                     {
                         tag: 'label',
                         'for' :  id,
-                        cls : 'control-label',
-                        html : this.fieldLabel
-
-                    },
-                    {
-                        tag : 'i',
-                        cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
-                        tooltip : 'This field is required'
+                        cls : 'control-label col-form-label',
+                        cn : [
+                            {
+                                tag : 'span',
+                                html : this.fieldLabel
+                            },
+                            indicator
+                        ]
                     },
                     {
                         cls : "",
@@ -426,7 +457,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
                 ];
                 
                 labelCfg = cfg.cn[0];
-                contentCfg = cfg.cn[2];
+                contentCfg = cfg.cn[1];
             
             }
             
@@ -461,11 +492,14 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             
         } else if ( this.fieldLabel.length) {
                 
+            
+            
             cfg.cn = [
                 {
                     tag : 'i',
                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
-                    tooltip : 'This field is required'
+                    tooltip : 'This field is required',
+                    style : this.allowBlank ? ' display:none' : '' 
                 },
                 {
                     tag: 'label',
@@ -479,7 +513,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
            ];
            
            if(this.indicatorpos == 'right'){
-                
+       
                 cfg.cn = [
                     {
                         tag: 'label',
@@ -490,7 +524,8 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
                     {
                         tag : 'i',
                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
-                        tooltip : 'This field is required'
+                        tooltip : 'This field is required',
+                        style : this.allowBlank ? ' display:none' : '' 
                     },
 
                    inputblock
@@ -514,9 +549,10 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
            cfg.cls += ' navbar-form';
         }
         
-        if (this.parentType === 'NavGroup') {
-           cfg.cls += ' navbar-form';
-           cfg.tag = 'li';
+        if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
+            // on BS4 we do this only if not form 
+            cfg.cls += ' navbar-form';
+            cfg.tag = 'li';
         }
         
         return cfg;
@@ -537,6 +573,10 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
     
     indicatorEl : function()
     {
+        if (Roo.bootstrap.version == 4) {
+            return false; // not enabled in v4 yet.
+        }
+        
         var indicator = this.el.select('i.roo-required-indicator',true).first();
         
         if(!indicator){
@@ -565,12 +605,12 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
         this.inputEl().on("blur", this.onBlur,  this);
         
         this.inputEl().relayEvent('keyup', this);
+        this.inputEl().relayEvent('paste', this);
         
         this.indicator = this.indicatorEl();
         
         if(this.indicator){
-            this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
-            this.indicator.hide();
+            this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? - 
         }
  
         // reference to original value for reset
@@ -609,6 +649,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             this.after.render(this.el.select('.roo-input-after',true).first());
         }
         
+        this.inputEl().on('change', this.onChange, this);
         
     },
     filterValidation : function(e){
@@ -638,7 +679,12 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
      * @param {Mixed} value The value to validate
      * @return {Boolean} True if the value is valid, else false
      */
-    validateValue : function(value){
+    validateValue : function(value)
+    {
+        if(this.getVisibilityEl().hasClass('hidden')){
+            return true;
+        }
+        
         if(value.length < 1)  { // if it's blank
             if(this.allowBlank){
                 return true;
@@ -663,6 +709,9 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             if(msg !== true){
                 return false;
             }
+            if (typeof(msg) == 'string') {
+                this.invalidText = msg;
+            }
         }
         
         if(this.regex && !this.regex.test(value)){
@@ -671,8 +720,6 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
         
         return true;
     },
-
-    
     
      // private
     fireKey : function(e){
@@ -722,6 +769,15 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
         this.fireEvent("blur", this);
     },
     
+    onChange : function(e)
+    {
+        var v = this.getValue();
+        if(String(v) !== String(this.startValue)){
+            this.fireEvent('change', this, v, this.startValue);
+        }
+        
+    },
+    
     /**
      * Resets the current field value to the originally loaded value and clears any validation messages
      */
@@ -833,11 +889,8 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             return;
         }
         
-        if(this.indicator){
-            this.indicator.hide();
-        }
         
-        this.el.removeClass(this.invalidClass);
+        this.el.removeClass([this.invalidClass, 'is-invalid']);
         
         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
             
@@ -849,6 +902,11 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             
         }
         
+        if(this.indicator){
+            this.indicator.removeClass('visible');
+            this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
+        }
+        
         this.fireEvent('valid', this);
     },
     
@@ -862,27 +920,33 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
         }
         
         this.el.removeClass([this.invalidClass, this.validClass]);
-        
+        this.inputEl().removeClass(['is-valid', 'is-invalid']);
+
         var feedback = this.el.select('.form-control-feedback', true).first();
             
         if(feedback){
             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
         }
-
+        
+        if(this.indicator){
+            this.indicator.removeClass('visible');
+            this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
+        }
+        
         if(this.disabled){
             return;
         }
         
+           
         if(this.allowBlank && !this.getRawValue().length){
             return;
         }
-        
-        if(this.indicator){
-            this.indicator.hide();
+        if (Roo.bootstrap.version == 3) {
+            this.el.addClass(this.validClass);
+        } else {
+            this.inputEl().addClass('is-valid');
         }
-        
-        this.el.addClass(this.validClass);
-        
+
         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
             
             var feedback = this.el.select('.form-control-feedback', true).first();
@@ -903,16 +967,18 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
      */
     markInvalid : function(msg)
     {
-        if(!this.el  || this.preventMark){ // not rendered...
+        if(!this.el  || this.preventMark){ // not rendered
             return;
         }
         
         this.el.removeClass([this.invalidClass, this.validClass]);
+        this.inputEl().removeClass(['is-valid', 'is-invalid']);
         
         var feedback = this.el.select('.form-control-feedback', true).first();
             
         if(feedback){
-            this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
+            this.el.select('.form-control-feedback', true).first().removeClass(
+                    [this.invalidFeedbackClass, this.validFeedbackClass]);
         }
 
         if(this.disabled){
@@ -924,10 +990,16 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
         }
         
         if(this.indicator){
-            this.indicator.show();
+            this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
+            this.indicator.addClass('visible');
         }
+        if (Roo.bootstrap.version == 3) {
+            this.el.addClass(this.invalidClass);
+        } else {
+            this.inputEl().addClass('is-invalid');
+        }
+        
         
-        this.el.addClass(this.invalidClass);
         
         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
             
@@ -995,8 +1067,40 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             }
         }
         return w;
-    }
+    },
     
+    setFieldLabel : function(v)
+    {
+        if(!this.rendered){
+            return;
+        }
+        
+        if(this.indicatorEl()){
+            var ar = this.el.select('label > span',true);
+            
+            if (ar.elements.length) {
+                this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
+                this.fieldLabel = v;
+                return;
+            }
+            
+            var br = this.el.select('label',true);
+            
+            if(br.elements.length) {
+                this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
+                this.fieldLabel = v;
+                return;
+            }
+            
+            Roo.log('Cannot Found any of label > span || label in input');
+            return;
+        }
+        
+        this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
+        this.fieldLabel = v;
+        
+        
+    }
 });