Roo/bootstrap/TextArea.js
[roojs1] / Roo / bootstrap / TextArea.js
index e16b41a..3eb51d9 100644 (file)
@@ -7,13 +7,13 @@
 
 /**
  * @class Roo.bootstrap.TextArea
- * @extends Roo.bootstrap.Component
+ * @extends Roo.bootstrap.Input
  * Bootstrap TextArea class
  * @cfg {Number} cols Specifies the visible width of a text area
  * @cfg {Number} rows Specifies the visible number of lines in a text area
- * @cfg {Number} readOnly Specifies that a text area should be read-only
  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
- * 
+ * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
+ * @cfg {string} html text
  * 
  * @constructor
  * Create a new TextArea
@@ -27,36 +27,60 @@ Roo.bootstrap.TextArea = function(config){
 
 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
      
-    cols : 20,
-    rows : 3,
+    cols : false,
+    rows : 5,
     readOnly : false,
     warp : 'soft',
+    resize : false,
+    value: false,
+    html: false,
     
     getAutoCreate : function(){
         
-        var parent = this.parent();
-        
-        var align = parent.labelAlign;
+        var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
         
         var id = Roo.id();
         
         var cfg = {};
         
+        if(this.inputType != 'hidden'){
+            cfg.cls = 'form-group' //input-group
+        }
+        
         var input =  {
             tag: 'textarea',
             id : id,
-            value : this.value,
+            warp : this.warp,
+            rows : this.rows,
+            value : this.value || '',
+            html: this.html || '',
             cls : 'form-control',
             placeholder : this.placeholder || '' 
             
         };
         
+        if(this.maxLength && this.maxLength != Number.MAX_VALUE){
+            input.maxLength = this.maxLength;
+        }
+        
+        if(this.resize){
+            input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
+        }
+        
+        if(this.cols){
+            input.cols = this.cols;
+        }
+        
+        if (this.readOnly) {
+            input.readonly = true;
+        }
+        
         if (this.name) {
             input.name = this.name;
         }
         
         if (this.size) {
-            input.cls += ' input-' + this.size;
+            input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
         }
         
         var settings=this;
@@ -68,6 +92,23 @@ Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
         
         var inputblock = input;
         
+        if(this.hasFeedback && !this.allowBlank){
+            
+            var feedback = {
+                tag: 'span',
+                cls: 'glyphicon form-control-feedback'
+            };
+
+            inputblock = {
+                cls : 'has-feedback',
+                cn :  [
+                    input,
+                    feedback
+                ] 
+            };  
+        }
+        
+        
         if (this.before || this.after) {
             
             inputblock = {
@@ -81,7 +122,14 @@ Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
                     html : this.before
                 });
             }
+            
             inputblock.cn.push(input);
+            
+            if(this.hasFeedback && !this.allowBlank){
+                inputblock.cls += ' has-feedback';
+                inputblock.cn.push(feedback);
+            }
+            
             if (this.after) {
                 inputblock.cn.push({
                     tag :'span',
@@ -93,440 +141,228 @@ Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
         }
         
         if (align ==='left' && this.fieldLabel.length) {
-                Roo.log("left and has label");
-                cfg.cn = [
-                    
-                    {
-                        tag: 'label',
-                        'for' :  id,
-                        cls : 'control-label col-sm-' + this.labelWidth,
-                        html : this.fieldLabel
-                        
-                    },
-                    {
-                        cls : "col-sm-" + (12 - this.labelWidth), 
-                        cn: [
-                            inputblock
-                        ]
-                    }
-                    
-                ];
+            cfg.cn = [
+                {
+                    tag: 'label',
+                    'for' :  id,
+                    cls : 'control-label',
+                    html : this.fieldLabel
+                },
+                {
+                    cls : "",
+                    cn: [
+                        inputblock
+                    ]
+                }
+
+            ];
+            
+            if(this.labelWidth > 12){
+                cfg.cn[0].style = "width: " + this.labelWidth + 'px';
+            }
+
+            if(this.labelWidth < 13 && this.labelmd == 0){
+                this.labelmd = this.labelWidth;
+            }
+
+            if(this.labellg > 0){
+                cfg.cn[0].cls += ' col-lg-' + this.labellg;
+                cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
+            }
+
+            if(this.labelmd > 0){
+                cfg.cn[0].cls += ' col-md-' + this.labelmd;
+                cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
+            }
+
+            if(this.labelsm > 0){
+                cfg.cn[0].cls += ' col-sm-' + this.labelsm;
+                cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
+            }
+
+            if(this.labelxs > 0){
+                cfg.cn[0].cls += ' col-xs-' + this.labelxs;
+                cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
+            }
+            
         } else if ( this.fieldLabel.length) {
-                Roo.log(" label");
-                 cfg.cn = [
-                   
-                    {
-                        tag: 'label',
-                        //cls : 'input-group-addon',
-                        html : this.fieldLabel
-                        
-                    },
-                    
-                    inputblock
-                    
-                ];
+            cfg.cn = [
+
+               {
+                   tag: 'label',
+                   //cls : 'input-group-addon',
+                   html : this.fieldLabel
+
+               },
+
+               inputblock
+
+           ];
 
         } else {
-            
-                   Roo.log(" no label && no align");
-                cfg.cn = [
-                    
-                        inputblock
-                    
-                ];
-                
+
+            cfg.cn = [
+
+                inputblock
+
+            ];
                 
         }
         
         if (this.disabled) {
             input.disabled=true;
         }
+        
         return cfg;
         
     },
     /**
-     * return the real input element.
+     * return the real textarea element.
      */
     inputEl: function ()
     {
-        return this.el.select('input.form-control',true).first();
-    },
-    setDisabled : function(v)
-    {
-        var i  = this.inputEl().dom;
-        if (v) {
-            i.removeAttribute('disabled');
-            return;
-            
-        }
-        i.setAttribute('disabled','true');
+        return this.el.select('textarea.form-control',true).first();
     },
-    initEvents : function()
+    
+    /**
+     * Clear any invalid styles/messages for this field
+     */
+    clearInvalid : function()
     {
         
-        this.inputEl().on("keydown" , this.fireKey,  this);
-        this.inputEl().on("focus", this.onFocus,  this);
-        this.inputEl().on("blur", this.onBlur,  this);
-        this.inputEl().relayEvent('keyup', this);
-
-        // reference to original value for reset
-        this.originalValue = this.getValue();
-        //Roo.form.TextField.superclass.initEvents.call(this);
-        if(this.validationEvent == 'keyup'){
-            this.validationTask = new Roo.util.DelayedTask(this.validate, this);
-            this.inputEl().on('keyup', this.filterValidation, this);
-        }
-        else if(this.validationEvent !== false){
-            this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
+        if(!this.el || this.preventMark){ // not rendered
+            return;
         }
         
-        if(this.selectOnFocus){
-            this.on("focus", this.preFocus, this);
-            
-        }
-        if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
-            this.inputEl().on("keypress", this.filterKeys, this);
-        }
-       /* if(this.grow){
-            this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
-            this.el.on("click", this.autoSize,  this);
-        }
-        */
-        if(this.inputEl().is('input[type=password]') && Roo.isSafari){
-            this.inputEl().on('keydown', this.SafariOnKeyDown, this);
-        }
+        var label = this.el.select('label', true).first();
+        var icon = this.el.select('i.fa-star', true).first();
         
-    },
-    filterValidation : function(e){
-        if(!e.isNavKeyPress()){
-            this.validationTask.delay(this.validationDelay);
+        if(label && icon){
+            icon.remove();
         }
-    },
-     /**
-     * Validates the field value
-     * @return {Boolean} True if the value is valid, else false
-     */
-    validate : function(){
-        //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
-        if(this.disabled || this.validateValue(this.getRawValue())){
-            this.clearInvalid();
-            return true;
-        }
-        return false;
-    },
-    
-    
-    /**
-     * Validates a value according to the field's validation rules and marks the field as invalid
-     * if the validation fails
-     * @param {Mixed} value The value to validate
-     * @return {Boolean} True if the value is valid, else false
-     */
-    validateValue : function(value){
-        if(value.length < 1)  { // if it's blank
-             if(this.allowBlank){
-                this.clearInvalid();
-                return true;
-             }else{
-                this.markInvalid(this.blankText);
-                return false;
-             }
-        }
-        if(value.length < this.minLength){
-            this.markInvalid(String.format(this.minLengthText, this.minLength));
-            return false;
-        }
-        if(value.length > this.maxLength){
-            this.markInvalid(String.format(this.maxLengthText, this.maxLength));
-            return false;
-        }
-        if(this.vtype){
-            var vt = Roo.form.VTypes;
-            if(!vt[this.vtype](value, this)){
-                this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
-                return false;
-            }
-        }
-        if(typeof this.validator == "function"){
-            var msg = this.validator(value);
-            if(msg !== true){
-                this.markInvalid(msg);
-                return false;
-            }
-        }
-        if(this.regex && !this.regex.test(value)){
-            this.markInvalid(this.regexText);
-            return false;
-        }
-        return true;
-    },
-
-    
-    
-     // private
-    fireKey : function(e){
-        //Roo.log('field ' + e.getKey());
-        if(e.isNavKeyPress()){
-            this.fireEvent("specialkey", this, e);
-        }
-    },
-    focus : function (selectText){
-        if(this.rendered){
-            this.inputEl().focus();
-            if(selectText === true){
-                this.inputEl().dom.select();
+        this.el.removeClass( this.validClass);
+        this.inputEl().removeClass('is-invalid');
+         
+        if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
+            
+            var feedback = this.el.select('.form-control-feedback', true).first();
+            
+            if(feedback){
+                this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
             }
+            
         }
-        return this;
-    } ,
-    
-    onFocus : function(){
-        if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
-           // this.el.addClass(this.focusClass);
-        }
-        if(!this.hasFocus){
-            this.hasFocus = true;
-            this.startValue = this.getValue();
-            this.fireEvent("focus", this);
-        }
-    },
-    
-    beforeBlur : Roo.emptyFn,
-
-    
-    // private
-    onBlur : function(){
-        this.beforeBlur();
-        if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
-            //this.el.removeClass(this.focusClass);
-        }
-        this.hasFocus = false;
-        if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
-            this.validate();
-        }
-        var v = this.getValue();
-        if(String(v) !== String(this.startValue)){
-            this.fireEvent('change', this, v, this.startValue);
-        }
-        this.fireEvent("blur", this);
-    },
-    
-    /**
-     * Resets the current field value to the originally loaded value and clears any validation messages
-     */
-    reset : function(){
-        this.setValue(this.originalValue);
-        this.clearInvalid();
-    },
-     /**
-     * Returns the name of the field
-     * @return {Mixed} name The name field
-     */
-    getName: function(){
-        return this.name;
-    },
-     /**
-     * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
-     * @return {Mixed} value The field value
-     */
-    getValue : function(){
-        var v = this.inputEl().getValue();
-        return v;
-    },
-    /**
-     * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
-     * @return {Mixed} value The field value
-     */
-    getRawValue : function(){
-        var v = this.inputEl().getValue();
         
-        return v;
-    },
-    
-    /**
-     * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
-     * @param {Mixed} value The value to set
-     */
-    setRawValue : function(v){
-        return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
-    },
-    
-    selectText : function(start, end){
-        var v = this.getRawValue();
-        if(v.length > 0){
-            start = start === undefined ? 0 : start;
-            end = end === undefined ? v.length : end;
-            var d = this.inputEl().dom;
-            if(d.setSelectionRange){
-                d.setSelectionRange(start, end);
-            }else if(d.createTextRange){
-                var range = d.createTextRange();
-                range.moveStart("character", start);
-                range.moveEnd("character", v.length-end);
-                range.select();
-            }
-        }
+        this.fireEvent('valid', this);
     },
     
-    /**
-     * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
-     * @param {Mixed} value The value to set
+     /**
+     * Mark this field as valid
      */
-    setValue : function(v){
-        this.value = v;
-        if(this.rendered){
-            this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
-            this.validate();
-        }
-    },
-    
-    /*
-    processValue : function(value){
-        if(this.stripCharsRe){
-            var newValue = value.replace(this.stripCharsRe, '');
-            if(newValue !== value){
-                this.setRawValue(newValue);
-                return newValue;
-            }
+    markValid : function()
+    {
+        if(!this.el  || this.preventMark){ // not rendered
+            return;
         }
-        return value;
-    },
-  */
-    preFocus : function(){
         
-        if(this.selectOnFocus){
-            this.inputEl().dom.select();
+        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]);
         }
-    },
-    filterKeys : function(e){
-        var k = e.getKey();
-        if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
+
+        if(this.disabled || this.allowBlank){
             return;
         }
-        var c = e.getCharCode(), cc = String.fromCharCode(c);
-        if(Roo.isIE && (e.isSpecialKey() || !cc)){
-            return;
+        
+        var label = this.el.select('label', true).first();
+        var icon = this.el.select('i.fa-star', true).first();
+        
+        if(label && icon){
+            icon.remove();
         }
-        if(!this.maskRe.test(cc)){
-            e.stopEvent();
+        if (Roo.bootstrap.version == 3) {
+            this.el.addClass(this.validClass);
+        } else {
+            this.inputEl().addClass('is-valid');
         }
-    },
-     /**
-     * Clear any invalid styles/messages for this field
-     */
-    clearInvalid : function(){
         
-        if(!this.el || this.preventMark){ // not rendered
-            return;
-        }
-        this.el.removeClass(this.invalidClass);
-        /*
-        switch(this.msgTarget){
-            case 'qtip':
-                this.el.dom.qtip = '';
-                break;
-            case 'title':
-                this.el.dom.title = '';
-                break;
-            case 'under':
-                if(this.errorEl){
-                    Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
-                }
-                break;
-            case 'side':
-                if(this.errorIcon){
-                    this.errorIcon.dom.qtip = '';
-                    this.errorIcon.hide();
-                    this.un('resize', this.alignErrorIcon, this);
-                }
-                break;
-            default:
-                var t = Roo.getDom(this.msgTarget);
-                t.innerHTML = '';
-                t.style.display = 'none';
-                break;
+        
+        if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
+            
+            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().addClass([this.validFeedbackClass]);
+            }
+            
         }
-        */
+        
         this.fireEvent('valid', this);
     },
+    
      /**
      * Mark this field as invalid
      * @param {String} msg The validation message
      */
-    markInvalid : function(msg){
+    markInvalid : function(msg)
+    {
         if(!this.el  || this.preventMark){ // not rendered
             return;
         }
-        this.el.addClass(this.invalidClass);
-        /*
-        msg = msg || this.invalidText;
-        switch(this.msgTarget){
-            case 'qtip':
-                this.el.dom.qtip = msg;
-                this.el.dom.qclass = 'x-form-invalid-tip';
-                if(Roo.QuickTips){ // fix for floating editors interacting with DND
-                    Roo.QuickTips.enable();
-                }
-                break;
-            case 'title':
-                this.el.dom.title = msg;
-                break;
-            case 'under':
-                if(!this.errorEl){
-                    var elp = this.el.findParent('.x-form-element', 5, true);
-                    this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
-                    this.errorEl.setWidth(elp.getWidth(true)-20);
-                }
-                this.errorEl.update(msg);
-                Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
-                break;
-            case 'side':
-                if(!this.errorIcon){
-                    var elp = this.el.findParent('.x-form-element', 5, true);
-                    this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
-                }
-                this.alignErrorIcon();
-                this.errorIcon.dom.qtip = msg;
-                this.errorIcon.dom.qclass = 'x-form-invalid-tip';
-                this.errorIcon.show();
-                this.on('resize', this.alignErrorIcon, this);
-                break;
-            default:
-                var t = Roo.getDom(this.msgTarget);
-                t.innerHTML = msg;
-                t.style.display = this.msgDisplay;
-                break;
-        }
-        */
-        this.fireEvent('invalid', this, msg);
-    },
-    // private
-    SafariOnKeyDown : function(event)
-    {
-        // this is a workaround for a password hang bug on chrome/ webkit.
         
-        var isSelectAll = false;
+        this.el.removeClass([this.invalidClass, this.validClass]);
+        this.inputEl().removeClass(['is-valid', 'is-invalid']);
         
-        if(this.inputEl().dom.selectionEnd > 0){
-            isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
+        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(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
-            event.preventDefault();
-            this.setValue('');
+
+        if(this.disabled || this.allowBlank){
             return;
         }
         
-        if(isSelectAll){ // backspace and delete key
+        var label = this.el.select('label', true).first();
+        var icon = this.el.select('i.fa-star', true).first();
+        
+        if(!this.getValue().length && label && !icon){
+            this.el.createChild({
+                tag : 'i',
+                cls : 'text-danger fa fa-lg fa-star',
+                tooltip : 'This field is required',
+                style : 'margin-right:5px;'
+            }, label, true);
+        }
+        
+        if (Roo.bootstrap.version == 3) {
+            this.el.addClass(this.invalidClass);
+        } else {
+            this.inputEl().addClass('is-invalid');
+        }
+        
+        // fixme ... this may be depricated need to test..
+        if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
             
-            event.preventDefault();
-            // this is very hacky as keydown always get's upper case.
-            //
-            var cc = String.fromCharCode(event.getCharCode());
-            this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
+            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.getValue().length || this.forceFeedback){
+                    this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
+                }
+                
+            }
             
         }
         
-        
+        this.fireEvent('invalid', this, msg);
     }
 });