sync
[roojs1] / roojs-bootstrap-debug.js
index 92cdce6..c421bb9 100644 (file)
@@ -95,6 +95,7 @@ Roo.Shadow.prototype = {
      * frame: Shadow displays equally on all four sides<br />
      * drop: Traditional bottom-right drop shadow (default)
      */
+    mode: false,
     /**
      * @cfg {String} offset
      * The number of pixels to offset the shadow from the element (defaults to 4)
@@ -330,11 +331,11 @@ Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
         }
         
         if (this.cls) {
-            cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
+            cfg.cls = (typeof(cfg.cls) == 'undefined' ? this.cls : cfg.cls) + ' ' + this.cls;
         }
         
         if (this.style) { // fixme needs to support more complex style data.
-            cfg.style = this.style;
+            cfg.style = (typeof(cfg.style) == 'undefined' ? this.style : cfg.style) + '; ' + this.style;
         }
         
         if(this.name){
@@ -362,6 +363,11 @@ Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
     {
         return this.el;
     },
+    getDocumentBody : function() // used by menus - as they are attached to the body so zIndexes work
+    {
+        return Roo.get(document.body);
+    },
+    
     /**
      * Fetch the element to display the tooltip on.
      * @return {Roo.Element} defaults to this.el
@@ -650,6 +656,8 @@ Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
  * @cfg {String} cls class of the element
  * @cfg {Boolean} preventDefault (true|false) default false
  * @cfg {Boolean} clickable (true|false) default false
+ * @cfg {String} role default blank - set to button to force cursor pointer
  * 
  * @constructor
  * Create a new Element
@@ -667,7 +675,9 @@ Roo.bootstrap.Element = function(config){
          * @param {Roo.bootstrap.Element} this
          * @param {Roo.EventObject} e
          */
-        "click" : true
+        "click" : true 
+        
+      
     });
 };
 
@@ -678,6 +688,8 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
     html: '',
     preventDefault: false, 
     clickable: false,
+    tapedTwice : false,
+    role : false,
     
     getAutoCreate : function(){
         
@@ -686,6 +698,9 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
             // cls: this.cls, double assign in parent class Component.js :: onRender
             html: this.html
         };
+        if (this.role !== false) {
+            cfg.role = this.role;
+        }
         
         return cfg;
     },
@@ -698,6 +713,7 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
             this.el.on('click', this.onClick, this);
         }
         
+        
     },
     
     onClick : function(e)
@@ -706,9 +722,14 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
             e.preventDefault();
         }
         
-        this.fireEvent('click', this, e);
+        this.fireEvent('click', this, e); // why was this double click before?
     },
     
+    
+    
+
+    
+    
     getValue : function()
     {
         return this.el.dom.innerHTML;
@@ -1354,6 +1375,7 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
     {
         this.disabled = false;
         this.el.removeClass('disabled');
+        this.el.dom.removeAttribute("disabled");
     },
     
     /**
@@ -1363,6 +1385,7 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
     {
         this.disabled = true;
         this.el.addClass('disabled');
+        this.el.attr("disabled", "disabled")
     },
      /**
      * sets the active state on/off, 
@@ -2015,12 +2038,19 @@ Roo.bootstrap.Card = function(config){
          /**
          * @event rotate
          * When a element a card is rotate
-         * @param {Roo.bootstrap.Element} this
+         * @param {Roo.bootstrap.Card} this
          * @param {Roo.Element} n the node being dropped?
          * @param {Boolean} rotate status
          */
-        'rotate' : true
-        
+        'rotate' : true,
+        /**
+         * @event cardover
+         * When a card element is dragged over ready to drop (return false to block dropable)
+         * @param {Roo.bootstrap.Card} this
+         * @param {Object} data from dragdrop 
+         */
+         'cardover' : true
+         
     });
 };
 
@@ -2075,6 +2105,8 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     bodyEl: false, // card-body
     headerContainerEl : false, //
     headerEl : false,
+    header_imageEl : false,
+    
     
     layoutCls : function()
     {
@@ -2285,7 +2317,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     },
     getCardImageTop : function()
     {
-        var  ret = this.el.select('.card-img-top',true).first();
+        var  ret = this.header_imageEl;
         if (ret.hasClass('d-none')) {
             ret.removeClass('d-none');
         }
@@ -2331,17 +2363,19 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         if (this.rotateable) {
             this.el.select('.card-header',true).on('click', this.onToggleRotate, this);
         }
-        this.collapsableEl = this.el.select('.roo-collapsable').first();
+        this.collapsableEl = this.el.select('.roo-collapsable',true).first();
          
-        this.footerEl = this.el.select('.card-footer').first();
-        this.collapsableToggleEl = this.el.select('.roo-collapse-toggle');
-        this.headerContainerEl = this.el.select('.roo-card-header-ctr').first();
+        this.footerEl = this.el.select('.card-footer',true).first();
+        this.collapsableToggleEl = this.el.select('.roo-collapse-toggle',true).first();
+        this.headerContainerEl = this.el.select('.roo-card-header-ctr',true).first();
         this.headerEl = this.el.select('.card-header',true).first();
         
         if (this.rotated) {
             this.el.addClass('roo-card-rotated');
             this.fireEvent('rotate', this, true);
         }
+        this.header_imageEl = this.el.select('.card-img-top',true).first(); 
+        this.header_imageEl.on('load', this.onHeaderImageLoad, this );
         
     },
     getDragData : function(e)
@@ -2369,6 +2403,17 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     /**
     *    Part of the Roo.dd.DropZone interface. If no target node is found, the
     *    whole Element becomes the target, and this causes the drop gesture to append.
+    *
+    *    Returns an object:
+    *     {
+           
+           position : 'below' or 'above'
+           card  : relateive to card OBJECT (or true for no cards listed)
+           items_n : relative to nth item in list
+           card_n : relative to  nth card in list
+    }
+    *
+    *    
     */
     getTargetFromEvent : function(e, dragged_card_el)
     {
@@ -2462,7 +2507,11 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         }
         Roo.log(['getTargetFromEvent', target_info ]);
         
-         
+        
+        if (this.fireEvent('cardover', this, [ data ]) === false) {
+            return false;
+        }
+        
         this.dropPlaceHolder('show', target_info,data);
         
         return false; 
@@ -2487,9 +2536,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         }
         this.dropPlaceHolder('hide');
   
-         
-    
-    
+          
     
         this.acceptCard(data.source, info.position, info.card, info.items_n);
         return true;
@@ -2679,7 +2726,31 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     },
     setHeaderText: function(html)
     {
-        this.headerContainerEl.dom.innerHTML = html;
+        this.header = html;
+        if (this.headerContainerEl) {
+            this.headerContainerEl.dom.innerHTML = html;
+        }
+    },
+    onHeaderImageLoad : function(ev, he)
+    {
+        if (!this.header_image_fit_square) {
+            return;
+        }
+        
+        var hw = he.naturalHeight / he.naturalWidth;
+        // wide image = < 0
+        // tall image = > 1
+        //var w = he.dom.naturalWidth;
+        var ww = he.width;
+        he.style.left =  0;
+        he.style.position =  'relative';
+        if (hw > 1) {
+            var nw = (ww * (1/hw));
+            Roo.get(he).setSize( ww * (1/hw),  ww);
+            he.style.left =  ((ww - nw)/ 2) + 'px';
+            he.style.position =  'relative';
+        }
+
     }
 
     
@@ -2783,6 +2854,174 @@ Roo.extend(Roo.bootstrap.CardImageTop, Roo.bootstrap.Element,  {
 
  
 
+/*
+* Licence: LGPL
+*/
+
+/**
+ * @class Roo.bootstrap.ButtonUploader
+ * @extends Roo.bootstrap.Button
+ * Bootstrap Button Uploader class - it's a button which when you add files to it
+ *
+ * 
+ * @cfg {Number} errorTimeout default 3000
+ * @cfg {Array}  images  an array of ?? Img objects ??? when loading existing files..
+ * @cfg {Array}  html The button text.
+ * @cfg {Boolean}  multiple (default true) Should the upload allow multiple files to be uploaded.
+ *
+ * @constructor
+ * Create a new CardUploader
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.ButtonUploader = function(config){
+    
+    
+    Roo.bootstrap.ButtonUploader.superclass.constructor.call(this, config);
+    
+     
+     this.addEvents({
+         // raw events
+        /**
+         * @event beforeselect
+         * When button is pressed, before show upload files dialog is shown
+         * @param {Roo.bootstrap.UploaderButton} this
+         *
+         */
+        'beforeselect' : true,
+         /**
+         * @event fired when files have been selected, 
+         * When a the download link is clicked
+         * @param {Roo.bootstrap.UploaderButton} this
+         * @param {Array} Array of files that have been uploaded
+         */
+        'uploaded' : true
+        
+    });
+};
+Roo.extend(Roo.bootstrap.ButtonUploader, Roo.bootstrap.Button,  {
+    
+     
+    errorTimeout : 3000,
+     
+    images : false,
+   
+    fileCollection : false,
+    allowBlank : true,
+    
+    multiple : true,
+    
+    getAutoCreate : function()
+    {
+        var im = {
+            tag: 'input',
+            type : 'file',
+            cls : 'd-none  roo-card-upload-selector' 
+          
+        };
+        if (this.multiple) {
+            im.multiple = 'multiple';
+        }
+        
+        return  {
+            cls :'div' ,
+            cn : [
+                Roo.bootstrap.Button.prototype.getAutoCreate.call(this),
+                im
+
+            ]
+        };
+           
+         
+    },
+     
+   
+    initEvents : function()
+    {
+        
+        Roo.bootstrap.Button.prototype.initEvents.call(this);
+        
+        
+        
+        
+        
+        this.urlAPI = (window.createObjectURL && window) || 
+                                (window.URL && URL.revokeObjectURL && URL) || 
+                                (window.webkitURL && webkitURL);
+                        
+         
+         
+         
+        this.selectorEl = this.el.select('.roo-card-upload-selector', true).first();
+        
+        this.selectorEl.on('change', this.onFileSelected, this);
+         
+         
+       
+    },
+    
+   
+    onClick : function(e)
+    {
+        e.preventDefault();
+        
+        if ( this.fireEvent('beforeselect', this) === false) {
+            return;
+        }
+         
+        this.selectorEl.dom.click();
+         
+    },
+    
+    onFileSelected : function(e)
+    {
+        e.preventDefault();
+        
+        if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
+            return;
+        }
+        var files = Array.prototype.slice.call(this.selectorEl.dom.files);
+        this.selectorEl.dom.value  = '';// hopefully reset..
+        
+        this.fireEvent('uploaded', this,  files );
+        
+    },
+    
+       
+   
+    
+    /**
+     * addCard - add an Attachment to the uploader
+     * @param data - the data about the image to upload
+     *
+     * {
+          id : 123
+          title : "Title of file",
+          is_uploaded : false,
+          src : "http://.....",
+          srcfile : { the File upload object },
+          mimetype : file.type,
+          preview : false,
+          is_deleted : 0
+          .. any other data...
+        }
+     *
+     * 
+    */
+     
+    reset: function()
+    {
+         
+         this.selectorEl
+    } 
+    
+    
+    
+    
+});
  /*
  * - LGPL
  *
@@ -2805,6 +3044,7 @@ Roo.extend(Roo.bootstrap.CardImageTop, Roo.bootstrap.Element,  {
  * @cfg {String} smUrl sm image source
  * @cfg {String} mdUrl md image source
  * @cfg {String} lgUrl lg image source
+ * @cfg {Boolean} backgroundContain (use style background and contain image in content)
  * 
  * @constructor
  * Create a new Input
@@ -2821,7 +3061,13 @@ Roo.bootstrap.Img = function(config){
          * The img click event for the img.
          * @param {Roo.EventObject} e
          */
-        "click" : true
+        "click" : true,
+        /**
+         * @event load
+         * The when any image loads
+         * @param {Roo.EventObject} e
+         */
+        "load" : true
     });
 };
 
@@ -2836,6 +3082,7 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
     smUrl: '',
     mdUrl: '',
     lgUrl: '',
+    backgroundContain : false,
 
     getAutoCreate : function()
     {   
@@ -2908,12 +3155,20 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
             tag: 'img',
             cls: (this.imgResponsive) ? 'img-responsive' : '',
             html : null,
-            src : 'about:blank'  // just incase src get's set to undefined?!?
+            src : Roo.BLANK_IMAGE_URL  // just incase src get's set to undefined?!?
         };
         
+        if (this.backgroundContain) {
+            cfg.cls += ' background-contain';
+        }
+        
         cfg.html = this.html || cfg.html;
         
-        cfg.src = this.src || cfg.src;
+        if (this.backgroundContain) {
+            cfg.style="background-image: url(" + this.src + ')';
+        } else {
+            cfg.src = this.src || cfg.src;
+        }
         
         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
             cfg.cls += ' img-' + this.border;
@@ -2946,6 +3201,12 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
         if(!this.href){
             this.el.on('click', this.onClick, this);
         }
+        if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
+            this.el.on('load', this.onImageLoad, this);
+        } else {
+            // not sure if this works.. not tested
+            this.el.select('img', true).on('load', this.onImageLoad, this);
+        }
         
     },
     
@@ -2954,6 +3215,12 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
         Roo.log('img onclick');
         this.fireEvent('click', this, e);
     },
+    onImageLoad: function(e)
+    {
+        Roo.log('img load');
+        this.fireEvent('load', this, e);
+    },
+    
     /**
      * Sets the url of the image - used to update it
      * @param {String} url the url of the image
@@ -2964,7 +3231,11 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
         this.src =  url;
         
         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
-            this.el.dom.src =  url;
+            if (this.backgroundContain) {
+                this.el.dom.style.backgroundImage =  'url(' + url + ')';
+            } else {
+                this.el.dom.src =  url;
+            }
             return;
         }
         
@@ -3341,7 +3612,9 @@ Roo.bootstrap.MenuMgr = function(){
  * @cfg {bool} hidden  if the menu should be hidden when rendered.
  * @cfg {bool} stopEvent (true|false)  Stop event after trigger press (default true)
  * @cfg {bool} isLink (true|false)  the menu has link disable auto expand and collaspe (default false)
- * 
+  * @cfg {bool} hideTrigger (true|false)  default false - hide the carret for trigger.
+  * @cfg {String} align  default tl-bl? == below  - how the menu should be aligned. 
  * @constructor
  * Create a new Menu
  * @param {Object} config The config object
@@ -3349,6 +3622,13 @@ Roo.bootstrap.MenuMgr = function(){
 
 
 Roo.bootstrap.Menu = function(config){
+    
+    if (config.type == 'treeview') {
+       // normally menu's are drawn attached to the document to handle layering etc..
+       // however treeview (used by the docs menu is drawn into the parent element)
+       this.container_method = 'getChildContainer'; 
+    }
+    
     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
     if (this.registerMenu && this.type != 'treeview')  {
         Roo.bootstrap.MenuMgr.register(this);
@@ -3418,7 +3698,7 @@ Roo.bootstrap.Menu = function(config){
 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
     
    /// html : false,
-    //align : '',
+   
     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
     type: false,
     /**
@@ -3436,6 +3716,13 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
     
     isLink : false,
     
+    container_method : 'getDocumentBody', // so the menu is rendered on the body and zIndex works.
+    
+    hideTrigger : false,
+    
+    align : 'tl-bl?',
+    
+    
     getChildContainer : function() {
         return this.el;  
     },
@@ -3445,11 +3732,10 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
         //if (['right'].indexOf(this.align)!==-1) {
         //    cfg.cn[1].cls += ' pull-right'
         //}
-        
-        
+         
         var cfg = {
             tag : 'ul',
-            cls : 'dropdown-menu' ,
+            cls : 'dropdown-menu shadow' ,
             style : 'z-index:1000'
             
         };
@@ -3467,18 +3753,22 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
         
        // Roo.log("ADD event");
        // Roo.log(this.triggerEl.dom);
+        if (this.triggerEl) {
+            
+            this.triggerEl.on('click', this.onTriggerClick, this);
+            
+            this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
+            
+            if (!this.hideTrigger) {
+                if (this.triggerEl.hasClass('nav-item') && this.triggerEl.select('.nav-link',true).length) {
+                    // dropdown toggle on the 'a' in BS4?
+                    this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
+                } else {
+                    this.triggerEl.addClass('dropdown-toggle');
+                }
+            }
+        }
         
-        this.triggerEl.on('click', this.onTriggerClick, this);
-        
-        this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
-        
-       
-       if (this.triggerEl.hasClass('nav-item')) {
-           // dropdown toggle on the 'a' in BS4?
-           this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
-       } else {
-           this.triggerEl.addClass('dropdown-toggle');
-       }
         if (Roo.isTouch) {
             this.el.on('touchstart'  , this.onTouch, this);
         }
@@ -3596,8 +3886,31 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
         if(!this.el){
             this.render();
         }
+        this.el.addClass('show'); // show otherwise we do not know how big we are..
+        
+       var xy = this.el.getAlignToXY(el, pos);
+       
+       // bl-tl << left align  below
+       // tl-bl << left align 
+       
+       if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
+           // if it goes to far to the right.. -> align left.
+           xy = this.el.getAlignToXY(el, this.align.replace('/l/g', 'r'))
+        }
+       if(xy[0] < 0){
+           // was left align - go right?
+           xy = this.el.getAlignToXY(el, this.align.replace('/r/g', 'l'))
+        }
+       
+       // goes down the bottom
+        if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight() ||
+          xy[1]  < 0 ){
+           var a = this.align.replace('?', '').split('-');
+           xy = this.el.getAlignToXY(el, a[1]  + '-' + a[0] + '?')
+           
+        }
         
-        this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
+        this.showAt(  xy , parentMenu, false);
     },
      /**
      * Displays this menu at a specific xy position
@@ -3617,18 +3930,17 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
         //this.el.show();
         this.hideMenuItems();
         this.hidden = false;
-        this.triggerEl.addClass('open');
+       if (this.triggerEl) {
+           this.triggerEl.addClass('open');
+       }
+        
        this.el.addClass('show');
         
+       
+       
         // reassign x when hitting right
-        if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
-            xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
-        }
         
         // reassign y when hitting bottom
-        if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
-            xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
-        }
         
         // but the list may align on trigger left or trigger top... should it be a properity?
         
@@ -3660,9 +3972,9 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
     hide : function(deep)
     {
         if (false === this.fireEvent("beforehide", this)) {
-           Roo.log("hide canceled");
-           return;
-       }
+            Roo.log("hide canceled");
+            return;
+        }
         this.hideMenuItems();
         if(this.el && this.isVisible()){
            
@@ -3670,8 +3982,11 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
                 this.activeItem.deactivate();
                 this.activeItem = null;
             }
-            this.triggerEl.removeClass('open');;
-           this.el.removeClass('show');
+            if (this.triggerEl) {
+                this.triggerEl.removeClass('open');
+            }
+            
+            this.el.removeClass('show');
             this.hidden = true;
             this.fireEvent("hide", this);
         }
@@ -3716,7 +4031,8 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
             this.hide();
         } else {
             Roo.log('show');
-            this.show(this.triggerEl, '?', false);
+            
+            this.show(this.triggerEl, this.align, false);
         }
         
         if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
@@ -6125,8 +6441,10 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
                cfg.href = this.href;
            }
            if (this.fa) {
-                cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
-            }
+                cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span class="nav-html">' + this.html + '</span>';
+            } else {
+               cfg.cls += " nav-html";
+           }
            
            // menu .. should add dropdown-menu class - so no need for carat..
            
@@ -6142,7 +6460,8 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
                 {
                     tag: this.tagtype,
                     href : this.href || "#",
-                    html: this.html || ''
+                    html: this.html || '',
+                   cls : ''
                 }
             ];
             if (this.tagtype == 'a') {
@@ -6150,23 +6469,21 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
         
            }
             if (this.icon) {
-                cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
-            }
-           if (this.fa) {
-                cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
-            }
-            if(this.glyphicon) {
+                cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span class="nav-html">' + cfg.cn[0].html + '</span>';
+            } else  if (this.fa) {
+                cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span class="nav-html">' + cfg.cn[0].html + '</span>';
+            } else if(this.glyphicon) {
                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
-            }
+            } else {
+               cfg.cn[0].cls += " nav-html";
+           }
             
             if (this.menu) {
-                
                 cfg.cn[0].html += " <span class='caret'></span>";
              
             }
             
             if (this.badge !== '') {
-                 
                 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
             }
         }
@@ -6184,6 +6501,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
        
         var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
        this.navLink = this.el.select('.nav-link',true).first();
+       this.htmlEl = this.el.hasClass('nav-html') ? this.el : this.el.select('.nav-html',true).first();
        return ret;
     },
       
@@ -6381,7 +6699,17 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
         Roo.get(c).scrollTo('top', options.value, true);
         
         return;
-    }
+    },
+    /**
+     * Set the HTML (text content) of the item
+     * @param {string} html  content for the nav item
+     */
+    setHtml : function(html)
+    {
+       this.html = html;
+       this.htmlEl.dom.innerHTML = html;
+       
+    } 
 });
  
 
@@ -6980,6 +7308,631 @@ Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
  * Fork - LGPL
  * <script type="text/javascript">
  */
+ /**
+ * @extends Roo.dd.DDProxy
+ * @class Roo.grid.SplitDragZone
+ * Support for Column Header resizing
+ * @constructor
+ * @param {Object} config
+ */
+// private
+// This is a support class used internally by the Grid components
+Roo.grid.SplitDragZone = function(grid, hd, hd2){
+    this.grid = grid;
+    this.view = grid.getView();
+    this.proxy = this.view.resizeProxy;
+    Roo.grid.SplitDragZone.superclass.constructor.call(
+        this,
+        hd, // ID
+        "gridSplitters" + this.grid.getGridEl().id, // SGROUP
+        {  // CONFIG
+            dragElId : Roo.id(this.proxy.dom),
+            resizeFrame:false
+        }
+    );
+    
+    this.setHandleElId(Roo.id(hd));
+    if (hd2 !== false) {
+        this.setOuterHandleElId(Roo.id(hd2));
+    }
+    
+    this.scroll = false;
+};
+Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
+    fly: Roo.Element.fly,
+
+    b4StartDrag : function(x, y){
+        this.view.headersDisabled = true;
+        var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
+                    this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
+        );
+        this.proxy.setHeight(h);
+        
+        // for old system colWidth really stored the actual width?
+        // in bootstrap we tried using xs/ms/etc.. to do % sizing?
+        // which in reality did not work.. - it worked only for fixed sizes
+        // for resizable we need to use actual sizes.
+        var w = this.cm.getColumnWidth(this.cellIndex);
+        if (!this.view.mainWrap) {
+            // bootstrap.
+            w = this.view.getHeaderIndex(this.cellIndex).getWidth();
+        }
+        
+        
+        
+        // this was w-this.grid.minColumnWidth;
+        // doesnt really make sense? - w = thie curren width or the rendered one?
+        var minw = Math.max(w-this.grid.minColumnWidth, 0);
+        this.resetConstraints();
+        this.setXConstraint(minw, 1000);
+        this.setYConstraint(0, 0);
+        this.minX = x - minw;
+        this.maxX = x + 1000;
+        this.startPos = x;
+        if (!this.view.mainWrap) { // this is Bootstrap code..
+            this.getDragEl().style.display='block';
+        }
+        
+        Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
+    },
+
+
+    handleMouseDown : function(e){
+        ev = Roo.EventObject.setEvent(e);
+        var t = this.fly(ev.getTarget());
+        if(t.hasClass("x-grid-split")){
+            this.cellIndex = this.view.getCellIndex(t.dom);
+            this.split = t.dom;
+            this.cm = this.grid.colModel;
+            if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
+                Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
+            }
+        }
+    },
+
+    endDrag : function(e){
+        this.view.headersDisabled = false;
+        var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
+        var diff = endX - this.startPos;
+        // 
+        var w = this.cm.getColumnWidth(this.cellIndex);
+        if (!this.view.mainWrap) {
+            w = 0;
+        }
+        this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
+    },
+
+    autoOffset : function(){
+        this.setDelta(0,0);
+    }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+
+/**
+ * @class Roo.grid.AbstractSelectionModel
+ * @extends Roo.util.Observable
+ * Abstract base class for grid SelectionModels.  It provides the interface that should be
+ * implemented by descendant classes.  This class should not be directly instantiated.
+ * @constructor
+ */
+Roo.grid.AbstractSelectionModel = function(){
+    this.locked = false;
+    Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
+};
+
+Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable,  {
+    /** @ignore Called by the grid automatically. Do not call directly. */
+    init : function(grid){
+        this.grid = grid;
+        this.initEvents();
+    },
+
+    /**
+     * Locks the selections.
+     */
+    lock : function(){
+        this.locked = true;
+    },
+
+    /**
+     * Unlocks the selections.
+     */
+    unlock : function(){
+        this.locked = false;
+    },
+
+    /**
+     * Returns true if the selections are locked.
+     * @return {Boolean}
+     */
+    isLocked : function(){
+        return this.locked;
+    }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
+/**
+ * @extends Roo.grid.AbstractSelectionModel
+ * @class Roo.grid.RowSelectionModel
+ * The default SelectionModel used by {@link Roo.grid.Grid}.
+ * It supports multiple selections and keyboard selection/navigation. 
+ * @constructor
+ * @param {Object} config
+ */
+Roo.grid.RowSelectionModel = function(config){
+    Roo.apply(this, config);
+    this.selections = new Roo.util.MixedCollection(false, function(o){
+        return o.id;
+    });
+
+    this.last = false;
+    this.lastActive = false;
+
+    this.addEvents({
+        /**
+        * @event selectionchange
+        * Fires when the selection changes
+        * @param {SelectionModel} this
+        */
+       "selectionchange" : true,
+       /**
+        * @event afterselectionchange
+        * Fires after the selection changes (eg. by key press or clicking)
+        * @param {SelectionModel} this
+        */
+       "afterselectionchange" : true,
+       /**
+        * @event beforerowselect
+        * Fires when a row is selected being selected, return false to cancel.
+        * @param {SelectionModel} this
+        * @param {Number} rowIndex The selected index
+        * @param {Boolean} keepExisting False if other selections will be cleared
+        */
+       "beforerowselect" : true,
+       /**
+        * @event rowselect
+        * Fires when a row is selected.
+        * @param {SelectionModel} this
+        * @param {Number} rowIndex The selected index
+        * @param {Roo.data.Record} r The record
+        */
+       "rowselect" : true,
+       /**
+        * @event rowdeselect
+        * Fires when a row is deselected.
+        * @param {SelectionModel} this
+        * @param {Number} rowIndex The selected index
+        */
+        "rowdeselect" : true
+    });
+    Roo.grid.RowSelectionModel.superclass.constructor.call(this);
+    this.locked = false;
+};
+
+Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel,  {
+    /**
+     * @cfg {Boolean} singleSelect
+     * True to allow selection of only one row at a time (defaults to false)
+     */
+    singleSelect : false,
+
+    // private
+    initEvents : function(){
+
+        if(!this.grid.enableDragDrop && !this.grid.enableDrag){
+            this.grid.on("mousedown", this.handleMouseDown, this);
+        }else{ // allow click to work like normal
+            this.grid.on("rowclick", this.handleDragableRowClick, this);
+        }
+        // bootstrap does not have a view..
+        var view = this.grid.view ? this.grid.view : this.grid;
+        this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
+            "up" : function(e){
+                if(!e.shiftKey){
+                    this.selectPrevious(e.shiftKey);
+                }else if(this.last !== false && this.lastActive !== false){
+                    var last = this.last;
+                    this.selectRange(this.last,  this.lastActive-1);
+                    view.focusRow(this.lastActive);
+                    if(last !== false){
+                        this.last = last;
+                    }
+                }else{
+                    this.selectFirstRow();
+                }
+                this.fireEvent("afterselectionchange", this);
+            },
+            "down" : function(e){
+                if(!e.shiftKey){
+                    this.selectNext(e.shiftKey);
+                }else if(this.last !== false && this.lastActive !== false){
+                    var last = this.last;
+                    this.selectRange(this.last,  this.lastActive+1);
+                    view.focusRow(this.lastActive);
+                    if(last !== false){
+                        this.last = last;
+                    }
+                }else{
+                    this.selectFirstRow();
+                }
+                this.fireEvent("afterselectionchange", this);
+            },
+            scope: this
+        });
+
+         
+        view.on("refresh", this.onRefresh, this);
+        view.on("rowupdated", this.onRowUpdated, this);
+        view.on("rowremoved", this.onRemove, this);
+    },
+
+    // private
+    onRefresh : function(){
+        var ds = this.grid.ds, i, v = this.grid.view;
+        var s = this.selections;
+        s.each(function(r){
+            if((i = ds.indexOfId(r.id)) != -1){
+                v.onRowSelect(i);
+                s.add(ds.getAt(i)); // updating the selection relate data
+            }else{
+                s.remove(r);
+            }
+        });
+    },
+
+    // private
+    onRemove : function(v, index, r){
+        this.selections.remove(r);
+    },
+
+    // private
+    onRowUpdated : function(v, index, r){
+        if(this.isSelected(r)){
+            v.onRowSelect(index);
+        }
+    },
+
+    /**
+     * Select records.
+     * @param {Array} records The records to select
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectRecords : function(records, keepExisting){
+        if(!keepExisting){
+            this.clearSelections();
+        }
+        var ds = this.grid.ds;
+        for(var i = 0, len = records.length; i < len; i++){
+            this.selectRow(ds.indexOf(records[i]), true);
+        }
+    },
+
+    /**
+     * Gets the number of selected rows.
+     * @return {Number}
+     */
+    getCount : function(){
+        return this.selections.length;
+    },
+
+    /**
+     * Selects the first row in the grid.
+     */
+    selectFirstRow : function(){
+        this.selectRow(0);
+    },
+
+    /**
+     * Select the last row.
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectLastRow : function(keepExisting){
+        this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
+    },
+
+    /**
+     * Selects the row immediately following the last selected row.
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectNext : function(keepExisting){
+        if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
+            this.selectRow(this.last+1, keepExisting);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(this.last);
+        }
+    },
+
+    /**
+     * Selects the row that precedes the last selected row.
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectPrevious : function(keepExisting){
+        if(this.last){
+            this.selectRow(this.last-1, keepExisting);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(this.last);
+        }
+    },
+
+    /**
+     * Returns the selected records
+     * @return {Array} Array of selected records
+     */
+    getSelections : function(){
+        return [].concat(this.selections.items);
+    },
+
+    /**
+     * Returns the first selected record.
+     * @return {Record}
+     */
+    getSelected : function(){
+        return this.selections.itemAt(0);
+    },
+
+
+    /**
+     * Clears all selections.
+     */
+    clearSelections : function(fast){
+        if(this.locked) {
+            return;
+        }
+        if(fast !== true){
+            var ds = this.grid.ds;
+            var s = this.selections;
+            s.each(function(r){
+                this.deselectRow(ds.indexOfId(r.id));
+            }, this);
+            s.clear();
+        }else{
+            this.selections.clear();
+        }
+        this.last = false;
+    },
+
+
+    /**
+     * Selects all rows.
+     */
+    selectAll : function(){
+        if(this.locked) {
+            return;
+        }
+        this.selections.clear();
+        for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
+            this.selectRow(i, true);
+        }
+    },
+
+    /**
+     * Returns True if there is a selection.
+     * @return {Boolean}
+     */
+    hasSelection : function(){
+        return this.selections.length > 0;
+    },
+
+    /**
+     * Returns True if the specified row is selected.
+     * @param {Number/Record} record The record or index of the record to check
+     * @return {Boolean}
+     */
+    isSelected : function(index){
+        var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
+        return (r && this.selections.key(r.id) ? true : false);
+    },
+
+    /**
+     * Returns True if the specified record id is selected.
+     * @param {String} id The id of record to check
+     * @return {Boolean}
+     */
+    isIdSelected : function(id){
+        return (this.selections.key(id) ? true : false);
+    },
+
+    // private
+    handleMouseDown : function(e, t)
+    {
+        var view = this.grid.view ? this.grid.view : this.grid;
+        var rowIndex;
+        if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
+            return;
+        };
+        if(e.shiftKey && this.last !== false){
+            var last = this.last;
+            this.selectRange(last, rowIndex, e.ctrlKey);
+            this.last = last; // reset the last
+            view.focusRow(rowIndex);
+        }else{
+            var isSelected = this.isSelected(rowIndex);
+            if(e.button !== 0 && isSelected){
+                view.focusRow(rowIndex);
+            }else if(e.ctrlKey && isSelected){
+                this.deselectRow(rowIndex);
+            }else if(!isSelected){
+                this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
+                view.focusRow(rowIndex);
+            }
+        }
+        this.fireEvent("afterselectionchange", this);
+    },
+    // private
+    handleDragableRowClick :  function(grid, rowIndex, e) 
+    {
+        if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
+            this.selectRow(rowIndex, false);
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.focusRow(rowIndex);
+             this.fireEvent("afterselectionchange", this);
+        }
+    },
+    
+    /**
+     * Selects multiple rows.
+     * @param {Array} rows Array of the indexes of the row to select
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectRows : function(rows, keepExisting){
+        if(!keepExisting){
+            this.clearSelections();
+        }
+        for(var i = 0, len = rows.length; i < len; i++){
+            this.selectRow(rows[i], true);
+        }
+    },
+
+    /**
+     * Selects a range of rows. All rows in between startRow and endRow are also selected.
+     * @param {Number} startRow The index of the first row in the range
+     * @param {Number} endRow The index of the last row in the range
+     * @param {Boolean} keepExisting (optional) True to retain existing selections
+     */
+    selectRange : function(startRow, endRow, keepExisting){
+        if(this.locked) {
+            return;
+        }
+        if(!keepExisting){
+            this.clearSelections();
+        }
+        if(startRow <= endRow){
+            for(var i = startRow; i <= endRow; i++){
+                this.selectRow(i, true);
+            }
+        }else{
+            for(var i = startRow; i >= endRow; i--){
+                this.selectRow(i, true);
+            }
+        }
+    },
+
+    /**
+     * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
+     * @param {Number} startRow The index of the first row in the range
+     * @param {Number} endRow The index of the last row in the range
+     */
+    deselectRange : function(startRow, endRow, preventViewNotify){
+        if(this.locked) {
+            return;
+        }
+        for(var i = startRow; i <= endRow; i++){
+            this.deselectRow(i, preventViewNotify);
+        }
+    },
+
+    /**
+     * Selects a row.
+     * @param {Number} row The index of the row to select
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
+     */
+    selectRow : function(index, keepExisting, preventViewNotify){
+        if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
+            return;
+        }
+        if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
+            if(!keepExisting || this.singleSelect){
+                this.clearSelections();
+            }
+            var r = this.grid.ds.getAt(index);
+            this.selections.add(r);
+            this.last = this.lastActive = index;
+            if(!preventViewNotify){
+                var view = this.grid.view ? this.grid.view : this.grid;
+                view.onRowSelect(index);
+            }
+            this.fireEvent("rowselect", this, index, r);
+            this.fireEvent("selectionchange", this);
+        }
+    },
+
+    /**
+     * Deselects a row.
+     * @param {Number} row The index of the row to deselect
+     */
+    deselectRow : function(index, preventViewNotify){
+        if(this.locked) {
+            return;
+        }
+        if(this.last == index){
+            this.last = false;
+        }
+        if(this.lastActive == index){
+            this.lastActive = false;
+        }
+        var r = this.grid.ds.getAt(index);
+        this.selections.remove(r);
+        if(!preventViewNotify){
+            var view = this.grid.view ? this.grid.view : this.grid;
+            view.onRowDeselect(index);
+        }
+        this.fireEvent("rowdeselect", this, index);
+        this.fireEvent("selectionchange", this);
+    },
+
+    // private
+    restoreLast : function(){
+        if(this._last){
+            this.last = this._last;
+        }
+    },
+
+    // private
+    acceptsNav : function(row, col, cm){
+        return !cm.isHidden(col) && cm.isCellEditable(col, row);
+    },
+
+    // private
+    onEditorKey : function(field, e){
+        var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
+        if(k == e.TAB){
+            e.stopEvent();
+            ed.completeEdit();
+            if(e.shiftKey){
+                newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
+            }else{
+                newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
+            }
+        }else if(k == e.ENTER && !e.ctrlKey){
+            e.stopEvent();
+            ed.completeEdit();
+            if(e.shiftKey){
+                newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
+            }else{
+                newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
+            }
+        }else if(k == e.ESC){
+            ed.cancelEdit();
+        }
+        if(newCell){
+            g.startEditing(newCell[0], newCell[1]);
+        }
+    }
+});/*
+ * Based on:
+ * Ext JS Library 1.1.1
+ * Copyright(c) 2006-2007, Ext JS, LLC.
+ *
+ * Originally Released Under LGPL - original licence link has changed is not relivant.
+ *
+ * Fork - LGPL
+ * <script type="text/javascript">
+ */
  
 
 /**
@@ -7010,30 +7963,15 @@ Roo.grid.ColumnModel = function(config){
        /**
      * The config passed into the constructor
      */
-    this.config = config;
+    this.config = []; //config;
     this.lookup = {};
 
     // if no id, create one
     // if the column does not have a dataIndex mapping,
     // map it to the order it is in the config
     for(var i = 0, len = config.length; i < len; i++){
-        var c = config[i];
-        if(typeof c.dataIndex == "undefined"){
-            c.dataIndex = i;
-        }
-        if(typeof c.renderer == "string"){
-            c.renderer = Roo.util.Format[c.renderer];
-        }
-        if(typeof c.id == "undefined"){
-            c.id = Roo.id();
-        }
-        if(c.editor && c.editor.xtype){
-            c.editor  = Roo.factory(c.editor, Roo.grid);
-        }
-        if(c.editor && c.editor.isFormField){
-            c.editor = new Roo.grid.GridEditor(c.editor);
-        }
-        this.lookup[c.id] = c;
+       this.addColumn(config[i]);
+       
     }
 
     /**
@@ -7095,6 +8033,21 @@ Roo.grid.ColumnModel = function(config){
 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @cfg {String} header The header text to display in the Grid view.
+     */
+       /**
+     * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
+     */
+       /**
+     * @cfg {String} smHeader Header at Bootsrap Small width
+     */
+       /**
+     * @cfg {String} mdHeader Header at Bootsrap Medium width
+     */
+       /**
+     * @cfg {String} lgHeader Header at Bootsrap Large width
+     */
+       /**
+     * @cfg {String} xlHeader Header at Bootsrap extra Large width
      */
     /**
      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
@@ -7144,16 +8097,19 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
      * @cfg {String} tooltip (Optional)
      */
     /**
-     * @cfg {Number} xs (Optional)
+     * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
      */
     /**
-     * @cfg {Number} sm (Optional)
+     * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
      */
     /**
-     * @cfg {Number} md (Optional)
+     * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
      */
     /**
-     * @cfg {Number} lg (Optional)
+     * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
+     */
+       /**
+     * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
      */
     /**
      * Returns the id of the column at the specified index.
@@ -7175,7 +8131,7 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
 
     
     /**
-     * Returns the column for a specified dataIndex.
+     * Returns the column Object for a specified dataIndex.
      * @param {String} dataIndex The column dataIndex
      * @return {Object|Boolean} the column or false if not found
      */
@@ -7336,10 +8292,29 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * Returns the width for the specified column.
      * @param {Number} col The column index
+     * @param (optional) {String} gridSize bootstrap width size.
      * @return {Number}
      */
-    getColumnWidth : function(col){
-        return this.config[col].width * 1 || this.defaultWidth;
+    getColumnWidth : function(col, gridSize)
+       {
+               var cfg = this.config[col];
+               
+               if (typeof(gridSize) == 'undefined') {
+                       return cfg.width * 1 || this.defaultWidth;
+               }
+               if (gridSize === false) { // if we set it..
+                       return cfg.width || false;
+               }
+               var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
+               
+               for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
+                       if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
+                               continue;
+                       }
+                       return cfg[ sizes[i] ];
+               }
+               return 1;
+               
     },
 
     /**
@@ -7501,7 +8476,35 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
      */
     setEditor : function(col, editor){
         this.config[col].editor = editor;
+    },
+    /**
+     * Add a column (experimental...) - defaults to adding to the end..
+     * @param {Object} config 
+    */
+    addColumn : function(c)
+    {
+    
+       var i = this.config.length;
+       this.config[i] = c;
+       
+       if(typeof c.dataIndex == "undefined"){
+            c.dataIndex = i;
+        }
+        if(typeof c.renderer == "string"){
+            c.renderer = Roo.util.Format[c.renderer];
+        }
+        if(typeof c.id == "undefined"){
+            c.id = Roo.id();
+        }
+        if(c.editor && c.editor.xtype){
+            c.editor  = Roo.factory(c.editor, Roo.grid);
+        }
+        if(c.editor && c.editor.isFormField){
+            c.editor = new Roo.grid.GridEditor(c.editor);
+        }
+        this.lookup[c.id] = c;
     }
+    
 });
 
 Roo.grid.ColumnModel.defaultRenderer = function(value)
@@ -7564,6 +8567,7 @@ Roo.LoadMask.prototype = {
      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
      */
+    removeMask : false,
     /**
      * @cfg {String} msg
      * The text to display in a centered loading message box (defaults to 'Loading...')
@@ -7640,35 +8644,84 @@ Roo.LoadMask.prototype = {
             um.un('failure', this.onLoad, this);
         }
     }
-};/*
- * - LGPL
- *
- * table
- * 
- */
-
-/**
+};/**
  * @class Roo.bootstrap.Table
+ * @licence LGBL
  * @extends Roo.bootstrap.Component
- * Bootstrap Table class
+ * Bootstrap Table class.  This class represents the primary interface of a component based grid control.
+ * Similar to Roo.grid.Grid
+ * <pre><code>
+ var table = Roo.factory({
+    xtype : 'Table',
+    xns : Roo.bootstrap,
+    autoSizeColumns: true,
+    
+    
+    store : {
+        xtype : 'Store',
+        xns : Roo.data,
+        remoteSort : true,
+        sortInfo : { direction : 'ASC', field: 'name' },
+        proxy : {
+           xtype : 'HttpProxy',
+           xns : Roo.data,
+           method : 'GET',
+           url : 'https://example.com/some.data.url.json'
+        },
+        reader : {
+           xtype : 'JsonReader',
+           xns : Roo.data,
+           fields : [ 'id', 'name', whatever' ],
+           id : 'id',
+           root : 'data'
+        }
+    },
+    cm : [
+        {
+            xtype : 'ColumnModel',
+            xns : Roo.grid,
+            align : 'center',
+            cursor : 'pointer',
+            dataIndex : 'is_in_group',
+            header : "Name",
+            sortable : true,
+            renderer : function(v, x , r) {  
+            
+                return String.format("{0}", v)
+            }
+            width : 3
+        } // more columns..
+    ],
+    selModel : {
+        xtype : 'RowSelectionModel',
+        xns : Roo.bootstrap.Table
+        // you can add listeners to catch selection change here....
+    }
+     
+
+ });
+ // set any options
+ grid.render(Roo.get("some-div"));
+</code></pre>
+
+Currently the Table  uses multiple headers to try and handle XL / Medium etc... styling
+
+
+
+ *
+ * @cfg {Roo.grid.RowSelectionModel|Roo.grid.CellSelectionModel} sm The selection model to use (cell selection is not supported yet)
+ * @cfg {Roo.data.Store|Roo.data.SimpleStore} store The data store to use
+ * @cfg {Roo.grid.ColumnModel} cm[] A column for th grid.
+ * 
  * @cfg {String} cls table class
- * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
- * @cfg {String} bgcolor Specifies the background color for a table
- * @cfg {Number} border Specifies whether the table cells should have borders or not
- * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
- * @cfg {Number} cellspacing Specifies the space between cells
- * @cfg {String} frame Specifies which parts of the outside borders that should be visible
- * @cfg {String} rules Specifies which parts of the inside borders that should be visible
- * @cfg {String} sortable Specifies that the table should be sortable
- * @cfg {String} summary Specifies a summary of the content of a table
- * @cfg {Number} width Specifies the width of a table
- * @cfg {String} layout table layout (auto | fixed | initial | inherit)
+ *
  * 
  * @cfg {boolean} striped Should the rows be alternative striped
  * @cfg {boolean} bordered Add borders to the table
  * @cfg {boolean} hover Add hover highlighting
  * @cfg {boolean} condensed Format condensed
- * @cfg {boolean} responsive Format condensed
+ * @cfg {boolean} responsive default false - if this is on, columns are rendered with col-xs-4 etc. classes, otherwise columns will be sized by CSS,
+ *                also adds table-responsive (see bootstrap docs for details)
  * @cfg {Boolean} loadMask (true|false) default false
  * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
  * @cfg {Boolean} headerShow (true|false) generate thead, default true
@@ -7678,28 +8731,30 @@ Roo.LoadMask.prototype = {
  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
  * @cfg {Boolean} lazyLoad  auto load data while scrolling to the end (default false)
  * @cfg {Boolean} auto_hide_footer  auto hide footer if only one page (default false)
+ * @cfg {Boolean} enableColumnResize default true if columns can be resized (drag/drop)
+ * @cfg {Number} minColumnWidth default 50 pixels minimum column width 
  * 
  * @constructor
  * Create a new Table
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.Table = function(config){
+Roo.bootstrap.Table = function(config)
+{
     Roo.bootstrap.Table.superclass.constructor.call(this, config);
-    
-  
-    
+     
     // BC...
     this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
     this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
     this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
     this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
     
+    this.view = this; // compat with grid.
+    
     this.sm = this.sm || {xtype: 'RowSelectionModel'};
     if (this.sm) {
         this.sm.grid = this;
-        this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
+        this.selModel = Roo.factory(this.sm, Roo.grid);
         this.sm = this.selModel;
         this.sm.xmodule = this.xmodule || false;
     }
@@ -7823,23 +8878,21 @@ Roo.bootstrap.Table = function(config){
          * @param {Number} columnIndex
          * @param {Roo.EventObject} e
          */
-        "headercontextmenu" : true
+        "headercontextmenu" : true,
+        /**
+         * @event mousedown
+         * The raw mousedown event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mousedown" : true
+        
     });
 };
 
 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     
     cls: false,
-    align: false,
-    bgcolor: false,
-    border: false,
-    cellpadding: false,
-    cellspacing: false,
-    frame: false,
-    rules: false,
-    sortable: false,
-    summary: false,
-    width: false,
+    
     striped : false,
     scrollBody : false,
     bordered: false,
@@ -7852,15 +8905,20 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     loadMask : false,
     footerShow : true,
     headerShow : true,
+    enableColumnResize: true,
   
     rowSelection : false,
     cellSelection : false,
     layout : false,
+
+    minColumnWidth : 50,
     
     // Roo.Element - the tbody
-    mainBody: false,
-    // Roo.Element - thead element
-    mainHead: false,
+    bodyEl: false,  // <tbody> Roo.Element - thead element    
+    headEl: false,  // <thead> Roo.Element - thead element
+    resizeProxy : false, // proxy element for dragging?
+
+
     
     container: false, // used by gridpanel...
     
@@ -7870,15 +8928,18 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     
     auto_hide_footer : false,
     
+    view: false, // actually points to this..
+    
     getAutoCreate : function()
     {
         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
         
         cfg = {
             tag: 'table',
-            cls : 'table',
+            cls : 'table', 
             cn : []
         };
+        // this get's auto added by panel.Grid
         if (this.scrollBody) {
             cfg.cls += ' table-body-fixed';
         }    
@@ -7895,6 +8956,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         if (this.condensed) {
             cfg.cls += ' table-condensed';
         }
+        
         if (this.responsive) {
             cfg.cls += ' table-responsive';
         }
@@ -7903,24 +8965,6 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             cfg.cls+=  ' ' +this.cls;
         }
         
-        // this lot should be simplifed...
-        var _t = this;
-        var cp = [
-            'align',
-            'bgcolor',
-            'border',
-            'cellpadding',
-            'cellspacing',
-            'frame',
-            'rules',
-            'sortable',
-            'summary',
-            'width'
-        ].forEach(function(k) {
-            if (_t[k]) {
-                cfg[k] = _t[k];
-            }
-        });
         
         
         if (this.layout) {
@@ -7956,20 +9000,17 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         
         //Roo.log('initEvents with ds!!!!');
         
-        this.mainBody = this.el.select('tbody', true).first();
-        this.mainHead = this.el.select('thead', true).first();
+        this.bodyEl = this.el.select('tbody', true).first();
+        this.headEl = this.el.select('thead', true).first();
         this.mainFoot = this.el.select('tfoot', true).first();
         
         
         
-        var _this = this;
         
         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
-            e.on('click', _this.sort, _this);
-        });
+            e.on('click', this.sort, this);
+        }, this);
         
-        this.mainBody.on("click", this.onClick, this);
-        this.mainBody.on("dblclick", this.onDblClick, this);
         
         // why is this done????? = it breaks dialogs??
         //this.parent().el.setStyle('position', 'relative');
@@ -7996,14 +9037,125 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         
         this.el.on("contextmenu", this.onContextMenu, this);
         
-        this.mainBody.on('scroll', this.onBodyScroll, this);
         
         this.cm.on("headerchange", this.onHeaderChange, this);
-        
         this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
+
+ //?? does bodyEl get replaced on render?
+        this.bodyEl.on("click", this.onClick, this);
+        this.bodyEl.on("dblclick", this.onDblClick, this);        
+        this.bodyEl.on('scroll', this.onBodyScroll, this);
+
+        // guessing mainbody will work - this relays usually caught by selmodel at present.
+        this.relayEvents(this.bodyEl, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
+  
+  
+        this.resizeProxy = Roo.get(document.body).createChild({ cls:"x-grid-resize-proxy", html: '&#160;' });
         
+  
+        if(this.headEl && this.enableColumnResize !== false && Roo.grid.SplitDragZone){
+            new Roo.grid.SplitDragZone(this, this.headEl.dom, false); // not sure what 'lockedHd is for this implementation..)
+        }
+        
+        this.initCSS();
+    },
+    // Compatibility with grid - we implement all the view features at present.
+    getView : function()
+    {
+        return this;
     },
     
+    initCSS : function()
+    {
+        
+        
+        var cm = this.cm, styles = [];
+        this.CSS.removeStyleSheet(this.id + '-cssrules');
+        var headHeight = this.headEl ? this.headEl.dom.clientHeight : 0;
+        // we can honour xs/sm/md/xl  as widths...
+        // we first have to decide what widht we are currently at...
+        var sz = Roo.getGridSize();
+        
+        var total = 0;
+        var last = -1;
+        var cols = []; // visable cols.
+        var total_abs = 0;
+        for(var i = 0, len = cm.getColumnCount(); i < len; i++) {
+            var w = cm.getColumnWidth(i, false);
+            if(cm.isHidden(i)){
+                cols.push( { rel : false, abs : 0 });
+                continue;
+            }
+            if (w !== false) {
+                cols.push( { rel : false, abs : w });
+                total_abs += w;
+                last = i; // not really..
+                continue;
+            }
+            var w = cm.getColumnWidth(i, sz);
+            if (w > 0) {
+                last = i
+            }
+            total += w;
+            cols.push( { rel : w, abs : false });
+        }
+        
+        var avail = this.bodyEl.dom.clientWidth - total_abs;
+        
+        var unitWidth = Math.floor(avail / total);
+        var rem = avail - (unitWidth * total);
+        
+        var hidden, width, pos = 0 , splithide , left;
+        for(var i = 0, len = cm.getColumnCount(); i < len; i++) {
+            
+            hidden = 'display:none;';
+            left = '';
+            width  = 'width:0px;';
+            splithide = '';
+            if(!cm.isHidden(i)){
+                hidden = '';
+                
+                
+                // we can honour xs/sm/md/xl ?
+                var w = cols[i].rel == false ? cols[i].abs : (cols[i].rel * unitWidth);
+                if (w===0) {
+                    hidden = 'display:none;';
+                }
+                // width should return a small number...
+                if (i == last) {
+                    w+=rem; // add the remaining with..
+                }
+                pos += w;
+                left = "left:" + (pos -4) + "px;";
+                width = "width:" + w+ "px;";
+                
+            }
+            if (this.responsive) {
+                width = '';
+                left = '';
+                hidden = cm.isHidden(i) ? 'display:none' : '';
+                splithide = 'display: none';
+            }
+            
+            styles.push( '#' , this.id , ' .x-col-' , i, " {", cm.config[i].css, width, hidden, "}\n" );
+            if (this.headEl) {
+                if (i == last) {
+                    splithide = 'display:none;';
+                }
+                
+                styles.push('#' , this.id , ' .x-hcol-' , i, " { ", width, hidden," }\n",
+                            '#' , this.id , ' .x-grid-split-' , i, " { ", left, splithide,'height:', (headHeight - 4), "px;}\n"
+                );
+            }
+            
+        }
+        //Roo.log(styles.join(''));
+        this.CSS.createStyleSheet( styles.join(''), this.id + '-cssrules');
+        
+    },
+    
+    
+    
     onContextMenu : function(e, t)
     {
         this.processEvent("contextmenu", e);
@@ -8137,15 +9289,14 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         var rowIndex = this.getRowIndex(row);
         
         // why??? - should these not be based on SelectionModel?
-        if(this.cellSelection){
+        //if(this.cellSelection){
             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
-        }
+        //}
         
-        if(this.rowSelection){
+        //if(this.rowSelection){
             this.fireEvent('rowclick', this, row, rowIndex, e);
-        }
-        
-        
+        //}
+         
     },
         
     onDblClick : function(e,el)
@@ -8181,7 +9332,19 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             this.fireEvent('rowdblclick', this, row, rowIndex, e);
         }
     },
-    
+    findRowIndex : function(el)
+    {
+        var cell = Roo.get(el);
+        if(!cell) {
+            return false;
+        }
+        var row = cell.findParent('tr', false, true);
+        
+        if(!row || typeof(row) == 'undefined'){
+            return false;
+        }
+        return this.getRowIndex(row);
+    },
     sort : function(e,el)
     {
         var col = Roo.get(el);
@@ -8193,7 +9356,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         var sort = col.attr('sort');
         var dir = 'ASC';
         
-        if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
+        if(col.select('i', true).first().hasClass('fa-arrow-up')){
             dir = 'DESC';
         }
         
@@ -8226,14 +9389,21 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
                 tag: 'th',
                 cls : 'x-hcol-' + i,
                 style : '',
+                
                 html: cm.getColumnHeader(i)
             };
             
+            var tooltip = cm.getColumnTooltip(i);
+            if (tooltip) {
+                c.tooltip = tooltip;
+            }
+            
+            
             var hh = '';
             
             if(typeof(config.sortable) != 'undefined' && config.sortable){
-                c.cls = 'sortable';
-                c.html = '<i class="glyphicon"></i>' + c.html;
+                c.cls += ' sortable';
+                c.html = '<i class="fa"></i>' + c.html;
             }
             
             // could use BS4 hidden-..-down 
@@ -8266,9 +9436,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
                 c.colspan = config.colspan;
             }
             
-            if(typeof(config.hidden) != 'undefined' && config.hidden){
-                c.style += ' display:none;';
-            }
+            // hidden is handled by CSS now
             
             if(typeof(config.dataIndex) != 'undefined'){
                 c.sort = config.dataIndex;
@@ -8280,35 +9448,48 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
                 c.style += ' text-align:' + config.align + ';';
             }
             
-            if(typeof(config.width) != 'undefined'){
+            /* width is done in CSS
+             *if(typeof(config.width) != 'undefined'){
                 c.style += ' width:' + config.width + 'px;';
                 this.totalWidth += config.width;
             } else {
                 this.totalWidth += 100; // assume minimum of 100 per column?
             }
+            */
             
             if(typeof(config.cls) != 'undefined'){
                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
             }
+            // this is the bit that doesnt reall work at all...
             
-            ['xs','sm','md','lg'].map(function(size){
-                
-                if(typeof(config[size]) == 'undefined'){
-                    return;
-                }
+            if (this.responsive) {
                  
-                if (!config[size]) { // 0 = hidden
-                    // BS 4 '0' is treated as hide that column and below.
-                    c.cls += ' hidden-' + size + ' hidden' + size + '-down';
-                    return;
-                }
-                
-                c.cls += ' col-' + size + '-' + config[size] + (
-                    size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
-                );
-                
-                
-            });
+            
+                ['xs','sm','md','lg'].map(function(size){
+                    
+                    if(typeof(config[size]) == 'undefined'){
+                        return;
+                    }
+                     
+                    if (!config[size]) { // 0 = hidden
+                        // BS 4 '0' is treated as hide that column and below.
+                        c.cls += ' hidden-' + size + ' hidden' + size + '-down';
+                        return;
+                    }
+                    
+                    c.cls += ' col-' + size + '-' + config[size] + (
+                        size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
+                    );
+                    
+                    
+                });
+            }
+            // at the end?
+            
+            c.html +=' <span class="x-grid-split x-grid-split-' + i + '"></span>';
+            
+            
+            
             
             header.cn.push(c)
         }
@@ -8368,20 +9549,20 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         var ds = this.store;
         
         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
-            e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
+            e.select('i', true).removeClass(['fa-arrow-up', 'fa-arrow-down']);
             if (_this.store.sortInfo) {
                     
                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
-                    e.select('i', true).addClass(['glyphicon-arrow-up']);
+                    e.select('i', true).addClass(['fa-arrow-up']);
                 }
                 
                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
-                    e.select('i', true).addClass(['glyphicon-arrow-down']);
+                    e.select('i', true).addClass(['fa-arrow-down']);
                 }
             }
         });
         
-        var tbody =  this.mainBody;
+        var tbody =  this.bodyEl;
               
         if(ds.getCount() > 0){
             ds.data.each(function(d,rowIndex){
@@ -8423,6 +9604,10 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         this.fireEvent('rowsrendered', this);
         
         this.autoSize();
+        
+        this.initCSS(); /// resize cols
+
+        
     },
     
     
@@ -8436,7 +9621,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         if(isUpdate !== true){
             this.fireEvent("beforerowremoved", this, index, record);
         }
-        var bt = this.mainBody.dom;
+        var bt = this.bodyEl.dom;
         
         var rows = this.el.select('tbody > tr', true).elements;
         
@@ -8460,7 +9645,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     {
         //Roo.log('on Add called');
         // - note this does not handle multiple adding very well..
-        var bt = this.mainBody.dom;
+        var bt = this.bodyEl.dom;
         for (var i =0 ; i < records.length;i++) {
             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
             //Roo.log(records[i]);
@@ -8491,6 +9676,120 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         //this.layout();
         this.fireEvent("rowupdated", this, index, record);
     },
+    // private - called by RowSelection
+    onRowSelect : function(rowIndex){
+        var row = this.getRowDom(rowIndex);
+        row.addClass(['bg-info','info']);
+    },
+    // private - called by RowSelection
+    onRowDeselect : function(rowIndex)
+    {
+        if (rowIndex < 0) {
+            return;
+        }
+        var row = this.getRowDom(rowIndex);
+        row.removeClass(['bg-info','info']);
+    },
+      /**
+     * Focuses the specified row.
+     * @param {Number} row The row index
+     */
+    focusRow : function(row)
+    {
+        //Roo.log('GridView.focusRow');
+        var x = this.bodyEl.dom.scrollLeft;
+        this.focusCell(row, 0, false);
+        this.bodyEl.dom.scrollLeft = x;
+
+    },
+     /**
+     * Focuses the specified cell.
+     * @param {Number} row The row index
+     * @param {Number} col The column index
+     * @param {Boolean} hscroll false to disable horizontal scrolling
+     */
+    focusCell : function(row, col, hscroll)
+    {
+        //Roo.log('GridView.focusCell');
+        var el = this.ensureVisible(row, col, hscroll);
+        // not sure what focusEL achives = it's a <a> pos relative 
+        //this.focusEl.alignTo(el, "tl-tl");
+        //if(Roo.isGecko){
+        //    this.focusEl.focus();
+        //}else{
+        //    this.focusEl.focus.defer(1, this.focusEl);
+        //}
+    },
+    
+     /**
+     * Scrolls the specified cell into view
+     * @param {Number} row The row index
+     * @param {Number} col The column index
+     * @param {Boolean} hscroll false to disable horizontal scrolling
+     */
+    ensureVisible : function(row, col, hscroll)
+    {
+        //Roo.log('GridView.ensureVisible,' + row + ',' + col);
+        //return null; //disable for testing.
+        if(typeof row != "number"){
+            row = row.rowIndex;
+        }
+        if(row < 0 && row >= this.ds.getCount()){
+            return  null;
+        }
+        col = (col !== undefined ? col : 0);
+        var cm = this.cm;
+        while(cm.isHidden(col)){
+            col++;
+        }
+
+        var el = this.getCellDom(row, col);
+        if(!el){
+            return null;
+        }
+        var c = this.bodyEl.dom;
+
+        var ctop = parseInt(el.offsetTop, 10);
+        var cleft = parseInt(el.offsetLeft, 10);
+        var cbot = ctop + el.offsetHeight;
+        var cright = cleft + el.offsetWidth;
+
+        //var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
+        var ch = 0; //?? header is not withing the area?
+        var stop = parseInt(c.scrollTop, 10);
+        var sleft = parseInt(c.scrollLeft, 10);
+        var sbot = stop + ch;
+        var sright = sleft + c.clientWidth;
+        /*
+        Roo.log('GridView.ensureVisible:' +
+                ' ctop:' + ctop +
+                ' c.clientHeight:' + c.clientHeight +
+                ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
+                ' stop:' + stop +
+                ' cbot:' + cbot +
+                ' sbot:' + sbot +
+                ' ch:' + ch  
+                );
+        */
+        if(ctop < stop){
+            c.scrollTop = ctop;
+            //Roo.log("set scrolltop to ctop DISABLE?");
+        }else if(cbot > sbot){
+            //Roo.log("set scrolltop to cbot-ch");
+            c.scrollTop = cbot-ch;
+        }
+
+        if(hscroll !== false){
+            if(cleft < sleft){
+                c.scrollLeft = cleft;
+            }else if(cright > sright){
+                c.scrollLeft = cright-c.clientWidth;
+            }
+        }
+
+        return el;
+    },
+    
     
     insertRow : function(dm, rowIndex, isUpdate){
         
@@ -8500,7 +9799,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             //var s = this.getScrollState();
         var row = this.renderRow(this.cm, this.store, rowIndex);
         // insert before rowIndex..
-        var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
+        var e = this.bodyEl.createChild(row,this.getRowDom(rowIndex));
         
         var _this = this;
                 
@@ -8527,6 +9826,17 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
         
     },
+    getCellDom : function(rowIndex, colIndex)
+    {
+        var row = this.getRowDom(rowIndex);
+        if (row === false) {
+            return false;
+        }
+        var cols = row.select('td', true).elements;
+        return (typeof(cols[colIndex]) == 'undefined') ? false : cols[colIndex];
+        
+    },
+    
     // returns the object tree for a tr..
   
     
@@ -8574,6 +9884,9 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             
             var td = {
                 tag: 'td',
+                // this might end up displaying HTML?
+                // this is too messy... - better to only do it on columsn you know are going to be too long
+                //tooltip : (typeof(value) === 'object') ? '' : value,
                 cls : rowcfg.rowClass + ' x-col-' + i,
                 style: '',
                 html: (typeof(value) === 'object') ? '' : value
@@ -8587,9 +9900,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
                 td.colspan = config.colspan;
             }
             
-            if(typeof(config.hidden) != 'undefined' && config.hidden){
-                td.style += ' display:none;';
-            }
+            
             
             if(typeof(config.align) != 'undefined' && config.align.length){
                 td.style += ' text-align:' + config.align + ';';
@@ -8597,10 +9908,11 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             if(typeof(config.valign) != 'undefined' && config.valign.length){
                 td.style += ' vertical-align:' + config.valign + ';';
             }
-            
+            /*
             if(typeof(config.width) != 'undefined'){
                 td.style += ' width:' +  config.width + 'px;';
             }
+            */
             
             if(typeof(config.cursor) != 'undefined'){
                 td.style += ' cursor:' +  config.cursor + ';';
@@ -8609,28 +9921,28 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             if(typeof(config.cls) != 'undefined'){
                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
             }
-            
-            ['xs','sm','md','lg'].map(function(size){
-                
-                if(typeof(config[size]) == 'undefined'){
-                    return;
-                }
-                
-                
-                  
-                if (!config[size]) { // 0 = hidden
-                    // BS 4 '0' is treated as hide that column and below.
-                    td.cls += ' hidden-' + size + ' hidden' + size + '-down';
-                    return;
-                }
-                
-                td.cls += ' col-' + size + '-' + config[size] + (
-                    size == 'xs' ? (' col-' +   config[size] ) : '' // bs4 col-{num} replaces col-xs
-                );
-                 
-
-            });
-            
+            if (this.responsive) {
+                ['xs','sm','md','lg'].map(function(size){
+                    
+                    if(typeof(config[size]) == 'undefined'){
+                        return;
+                    }
+                    
+                    
+                      
+                    if (!config[size]) { // 0 = hidden
+                        // BS 4 '0' is treated as hide that column and below.
+                        td.cls += ' hidden-' + size + ' hidden' + size + '-down';
+                        return;
+                    }
+                    
+                    td.cls += ' col-' + size + '-' + config[size] + (
+                        size == 'xs' ? (' col-' +   config[size] ) : '' // bs4 col-{num} replaces col-xs
+                    );
+                     
+    
+                });
+            }
             row.cn.push(td);
            
         }
@@ -8661,14 +9973,15 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
      */
     setRowVisibility : function(rowIndex, state)
     {
-        var bt = this.mainBody.dom;
+        var bt = this.bodyEl.dom;
         
         var rows = this.el.select('tbody > tr', true).elements;
         
         if(typeof(rows[rowIndex]) == 'undefined'){
             return;
         }
-        rows[rowIndex].dom.style.display = state ? '' : 'none';
+        rows[rowIndex][ state ? 'removeClass' : 'addClass']('d-none');
+        
     },
     
     
@@ -8699,7 +10012,11 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             })
         }
     },
-    
+    /**
+     * get the Row Index from a dom element.
+     * @param {Roo.Element} row The row to look for
+     * @returns {Number} the row
+     */
     getRowIndex : function(row)
     {
         var rowIndex = -1;
@@ -8713,6 +10030,29 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         });
         
         return rowIndex;
+    },
+    /**
+     * get the header TH element for columnIndex
+     * @param {Number} columnIndex
+     * @returns {Roo.Element}
+     */
+    getHeaderIndex: function(colIndex)
+    {
+        var cols = this.headEl.select('th', true).elements;
+        return cols[colIndex]; 
+    },
+    /**
+     * get the Column Index from a dom element. (using regex on x-hcol-{colid})
+     * @param {domElement} cell to look for
+     * @returns {Number} the column
+     */
+    getCellIndex : function(cell)
+    {
+        var id = String(cell.className).match(Roo.bootstrap.Table.cellRE);
+        if(id){
+            return parseInt(id[1], 10);
+        }
+        return 0;
     },
      /**
      * Returns the grid's underlying element = used by panel.Grid
@@ -8750,6 +10090,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         }
         cw = Math.max(cw, this.totalWidth);
         this.getGridEl().select('tbody tr',true).setWidth(cw);
+        this.initCSS();
         
         // resize 'expandable coloumn?
         
@@ -8758,21 +10099,21 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     },
     onBodyScroll: function()
     {
-        //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
-        if(this.mainHead){
-            this.mainHead.setStyle({
+        //Roo.log("body scrolled');" + this.bodyEl.dom.scrollLeft);
+        if(this.headEl){
+            this.headEl.setStyle({
                 'position' : 'relative',
-                'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
+                'left': (-1* this.bodyEl.dom.scrollLeft) + 'px'
             });
         }
         
         if(this.lazyLoad){
             
-            var scrollHeight = this.mainBody.dom.scrollHeight;
+            var scrollHeight = this.bodyEl.dom.scrollHeight;
             
-            var scrollTop = Math.ceil(this.mainBody.getScroll().top);
+            var scrollTop = Math.ceil(this.bodyEl.getScroll().top);
             
-            var height = this.mainBody.getHeight();
+            var height = this.bodyEl.getHeight();
             
             if(scrollHeight - height == scrollTop) {
                 
@@ -8792,18 +10133,50 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             
         }
     },
-    
+    onColumnSplitterMoved : function(i, diff)
+    {
+        this.userResized = true;
+        
+        var cm = this.colModel;
+        
+        var w = this.getHeaderIndex(i).getWidth() + diff;
+        
+        
+        cm.setColumnWidth(i, w, true);
+        this.initCSS();
+        //var cid = cm.getColumnId(i); << not used in this version?
+       /* Roo.log(['#' + this.id + ' .x-col-' + i, "width", w + "px"]);
+        
+        this.CSS.updateRule( '#' + this.id + ' .x-col-' + i, "width", w + "px");
+        this.CSS.updateRule('#' + this.id + ' .x-hcol-' + i, "width", w + "px");
+        this.CSS.updateRule('#' + this.id + ' .x-grid-split-' + i, "left", w + "px");
+*/
+        //this.updateSplitters();
+        //this.layout(); << ??
+        this.fireEvent("columnresize", i, w);
+    },
     onHeaderChange : function()
     {
         var header = this.renderHeader();
         var table = this.el.select('table', true).first();
         
-        this.mainHead.remove();
-        this.mainHead = table.createChild(header, this.mainBody, false);
+        this.headEl.remove();
+        this.headEl = table.createChild(header, this.bodyEl, false);
+        
+        Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
+            e.on('click', this.sort, this);
+        }, this);
+        
+        if(this.enableColumnResize !== false && Roo.grid.SplitDragZone){
+            new Roo.grid.SplitDragZone(this, this.headEl.dom, false); // not sure what 'lockedHd is for this implementation..)
+        }
+        
     },
     
     onHiddenChange : function(colModel, colIndex, hidden)
     {
+        /*
+        this.cm.setHidden()
         var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
         var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
         
@@ -8814,7 +10187,8 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             this.CSS.updateRule(thSelector, "display", "none");
             this.CSS.updateRule(tdSelector, "display", "none");
         }
-        
+        */
+        // onload calls initCSS()
         this.onHeaderChange();
         this.onLoad();
     },
@@ -8885,9 +10259,15 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     }
 });
 
+// currently only used to find the split on drag.. 
+Roo.bootstrap.Table.cellRE = /(?:.*?)x-grid-(?:hd|cell|split)-([\d]+)(?:.*?)/;
 
- /*
+/**
+ * @depricated
+*/
+Roo.bootstrap.Table.AbstractSelectionModel = Roo.grid.AbstractSelectionModel;
+Roo.bootstrap.Table.RowSelectionModel = Roo.grid.RowSelectionModel;
+/*
  * - LGPL
  *
  * table cell
@@ -10493,7 +11873,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
     });
 };
 
@@ -10857,7 +12244,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             }
             
             if(this.labelWidth < 13 && this.labelmd == 0){
-                this.labelmd = this.labelWidth;
+                this.labellg = this.labellg > 0 ? this.labellg : this.labelWidth;
             }
             
             if(this.labellg > 0){
@@ -10996,6 +12383,7 @@ 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();
         
@@ -12496,11 +13884,29 @@ Roo.bootstrap.CardUploader = function(config){
     
     this.fileCollection   = new Roo.util.MixedCollection(false,function(r) {
         return r.data.id
-        });
-    
+     });
     
+     this.addEvents({
+         // raw events
+        /**
+         * @event preview
+         * When a image is clicked on - and needs to display a slideshow or similar..
+         * @param {Roo.bootstrap.Card} this
+         * @param {Object} The image information data 
+         *
+         */
+        'preview' : true,
+         /**
+         * @event download
+         * When a the download link is clicked
+         * @param {Roo.bootstrap.Card} this
+         * @param {Object} The image information data  contains 
+         */
+        'download' : true
+        
+    });
 };
-
 Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
     
      
@@ -12528,6 +13934,7 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
                 {
                     tag: 'input',
                     type : 'hidden',
+                    name : this.name,
                     value : this.value,
                     cls : 'd-none  form-control'
                 },
@@ -12659,14 +14066,34 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
             id : Roo.bootstrap.CardUploader.ID--,
             is_uploaded : false,
             src : url,
+            srcfile : file,
             title : file.name,
             mimetype : file.type,
             preview : false,
             is_deleted : 0
-        })
+        });
         
     },
     
+    /**
+     * addCard - add an Attachment to the uploader
+     * @param data - the data about the image to upload
+     *
+     * {
+          id : 123
+          title : "Title of file",
+          is_uploaded : false,
+          src : "http://.....",
+          srcfile : { the File upload object },
+          mimetype : file.type,
+          preview : false,
+          is_deleted : 0
+          .. any other data...
+        }
+     *
+     * 
+    */
+    
     addCard : function (data)
     {
         // hidden input element?
@@ -12678,7 +14105,7 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
             {
                 xns : Roo.bootstrap,
                 xtype : 'CardFooter',
-                items: [
+                 items: [
                     {
                         xns : Roo.bootstrap,
                         xtype : 'Element',
@@ -12689,13 +14116,14 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
                                 xns : Roo.bootstrap,
                                 xtype : 'Button',
                                 html : String.format("<small>{0}</small>", data.title),
-                                cls : 'col-11 text-left',
+                                cls : 'col-10 text-left',
                                 size: 'sm',
                                 weight: 'link',
                                 fa : 'download',
                                 listeners : {
                                     click : function() {
-                                        this.downloadCard(data.id)
+                                     
+                                        t.fireEvent( "download", t, data );
                                     }
                                 }
                             },
@@ -12703,10 +14131,10 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
                             {
                                 xns : Roo.bootstrap,
                                 xtype : 'Button',
-                                
+                                style: 'max-height: 28px; ',
                                 size : 'sm',
                                 weight: 'danger',
-                                cls : 'col-1',
+                                cls : 'col-2',
                                 fa : 'times',
                                 listeners : {
                                     click : function() {
@@ -12721,7 +14149,7 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
             }
             
         ];
-
+        
         var cn = this.addxtype(
             {
                  
@@ -12737,12 +14165,14 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
                 items : footer,
                 initEvents : function() {
                     Roo.bootstrap.Card.prototype.initEvents.call(this);
+                    var card = this;
                     this.imgEl = this.el.select('.card-img-top').first();
                     if (this.imgEl) {
-                        this.imgEl.on('click', function() { t.previewCard( data.id); }, this);
+                        this.imgEl.on('click', function() { t.fireEvent( "preview", t, data ); }, this);
                         this.imgEl.set({ 'pointer' : 'cursor' });
                                   
                     }
+                    this.getCardFooter().addClass('p-1');
                     
                   
                 }
@@ -12752,7 +14182,21 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
         // dont' really need ot update items.
         // this.items.push(cn);
         this.fileCollection.add(cn);
-        this.updateInput();
+        
+        if (!data.srcfile) {
+            this.updateInput();
+            return;
+        }
+            
+        var _t = this;
+        var reader = new FileReader();
+        reader.addEventListener("load", function() {  
+            data.srcdata =  reader.result;
+            _t.updateInput();
+        });
+        reader.readAsDataURL(data.srcfile);
+        
+        
         
     },
     removeCard : function(id)
@@ -12761,16 +14205,20 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
         var card  = this.fileCollection.get(id);
         card.data.is_deleted = 1;
         card.data.src = ''; /// delete the source - so it reduces size of not uploaded images etc.
-        this.fileCollection.remove(card);
+        //this.fileCollection.remove(card);
         //this.items = this.items.filter(function(e) { return e != card });
         // dont' really need ot update items.
         card.el.dom.parentNode.removeChild(card.el.dom);
+        this.updateInput();
+
         
     },
     reset: function()
     {
         this.fileCollection.each(function(card) {
-            card.el.dom.parentNode.removeChild(card.el.dom);    
+            if (card.el.dom && card.el.dom.parentNode) {
+                card.el.dom.parentNode.removeChild(card.el.dom);
+            }
         });
         this.fileCollection.clear();
         this.updateInput();
@@ -12778,12 +14226,15 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
     
     updateInput : function()
     {
-        var data = [];
+         var data = [];
         this.fileCollection.each(function(e) {
             data.push(e.data);
+            
         });
-        
         this.inputEl().dom.value = JSON.stringify(data);
+        
+        
+        
     }
     
     
@@ -14854,35 +16305,35 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
     readRecords : function(o)
     {
         var sid = this.meta ? this.meta.id : null;
-       var recordType = this.recordType, fields = recordType.prototype.fields;
-       var records = [];
-       var root = o;
-       for(var i = 0; i < root.length; i++){
-               var n = root[i];
-           var values = {};
-           var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
-           for(var j = 0, jlen = fields.length; j < jlen; j++){
-               var f = fields.items[j];
-               var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
-               var v = n[k] !== undefined ? n[k] : f.defaultValue;
-               v = f.convert(v);
-               values[f.name] = v;
-           }
-           var record = new recordType(values, id);
-           record.json = n;
-           records[records.length] = record;
-       }
-       return {
-           records : records,
-           totalRecords : records.length
-       };
+        var recordType = this.recordType, fields = recordType.prototype.fields;
+        var records = [];
+        var root = o;
+        for(var i = 0; i < root.length; i++){
+            var n = root[i];
+            var values = {};
+            var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
+            for(var j = 0, jlen = fields.length; j < jlen; j++){
+                var f = fields.items[j];
+                var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
+                var v = n[k] !== undefined ? n[k] : f.defaultValue;
+                v = f.convert(v);
+                values[f.name] = v;
+            }
+            var record = new recordType(values, id);
+            record.json = n;
+            records[records.length] = record;
+        }
+        return {
+            records : records,
+            totalRecords : records.length
+        };
     },
     // used when loading children.. @see loadDataFromChildren
     toLoadData: function(rec)
     {
-       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
-       return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
-       
+        // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+        return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+        
     }
     
     
@@ -16017,7 +17468,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             this.inputEl().on('mousedown', this.onTriggerClick,  this);
             this.inputEl().addClass('x-combo-noedit');
         }else{
-            this.inputEl().dom.setAttribute('readOnly', false);
+            this.inputEl().dom.removeAttribute('readOnly');
             this.inputEl().un('mousedown', this.onTriggerClick,  this);
             this.inputEl().removeClass('x-combo-noedit');
         }
@@ -17215,16 +18666,21 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             combobox.cls += ' roo-select2-container-multi';
         }
         
+        var required =  this.allowBlank ?  {
+                    tag : 'i',
+                    style: 'display: none'
+                } : {
+                   tag : 'i',
+                   cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
+                   tooltip : 'This field is required'
+                };
+        
         var align = this.labelAlign || this.parentLabelAlign();
         
         if (align ==='left' && 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'
-                },
+                required,
                 {
                     tag: 'label',
                     cls : 'control-label col-form-label',
@@ -17254,11 +18710,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                                 tag : 'span',
                                 html : this.fieldLabel
                             },
-                            {
-                                tag : 'i',
-                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
-                                tooltip : 'This field is required'
-                            }
+                            required
                         ]
                     },
                     {
@@ -17307,11 +18759,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                 
         } 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'
-                },
+               required,
                 {
                     tag: 'label',
                     cls : 'control-label',
@@ -17333,11 +18781,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                         cls : 'control-label',
                         html : this.fieldLabel,
                         cn : [
-                            {
-                               tag : 'i',
-                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
-                               tooltip : 'This field is required'
-                            }
+                            required
                         ]
                     },
                     {
@@ -19872,12 +21316,12 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
             if (this.parent() && (this.over == 'parent' || (this.over === false))) {
                 on_el = this.parent().el;
             } else if (this.over) {
-                Roo.get(this.over);
+                on_el = Roo.get(this.over);
             }
             
         }
         
-        this.alignEl = on_el;
+        this.alignEl = Roo.get( on_el );
 
         if (!this.el) {
             this.render(document.body);
@@ -20040,15 +21484,18 @@ Roo.apply(Roo.bootstrap.Popover, {
 
     clickHander : false,
     
+    
 
     onMouseDown : function(e)
     {
-        if (!e.getTarget(".roo-popover")) {
+        if (this.popups.length &&  !e.getTarget(".roo-popover")) {
+            /// what is nothing is showing..
             this.hideAll();
         }
          
     },
     
+    
     popups : [],
     
     register : function(popup)
@@ -20057,15 +21504,23 @@ Roo.apply(Roo.bootstrap.Popover, {
             Roo.bootstrap.Popover.clickHandler = Roo.get(document).on("mousedown", Roo.bootstrap.Popover.onMouseDown, Roo.bootstrap.Popover);
         }
         // hide other popups.
-        this.hideAll();
-        this.popups.push(popup);
+        popup.on('show', Roo.bootstrap.Popover.onShow,  popup);
+        popup.on('hide', Roo.bootstrap.Popover.onHide,  popup);
+        this.hideAll(); //<< why?
+        //this.popups.push(popup);
     },
     hideAll : function()
     {
         this.popups.forEach(function(p) {
             p.hide();
         });
-    }
+    },
+    onShow : function() {
+        Roo.bootstrap.Popover.popups.push(this);
+    },
+    onHide : function() {
+        Roo.bootstrap.Popover.popups.remove(this);
+    } 
 
 });/*
  * - LGPL
@@ -21556,7 +23011,10 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
                 break;
             case 'span':
                 if (className.indexOf('disabled') < 0) {
-                    this.viewDate.setUTCDate(1);
+                if (!this.viewDate) {
+                    this.viewDate = new Date();
+                }
+                this.viewDate.setUTCDate(1);
                     if (className.indexOf('month') > -1) {
                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
                     } else {
@@ -21580,8 +23038,8 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
                 //Roo.log(className);
                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
                     var day = parseInt(html, 10) || 1;
-                    var year = this.viewDate.getUTCFullYear(),
-                        month = this.viewDate.getUTCMonth();
+                    var year =  (this.viewDate || new Date()).getUTCFullYear(),
+                        month = (this.viewDate || new Date()).getUTCMonth();
 
                     if (className.indexOf('old') > -1) {
                         if(month === 0 ){
@@ -25763,8 +27221,8 @@ Roo.HtmlEditorCore.cblack= [
 
 
 Roo.HtmlEditorCore.swapCodes   =[ 
-    [    8211, "--" ], 
-    [    8212, "--" ], 
+    [    8211, "&#8211;" ], 
+    [    8212, "&#8212;" ], 
     [    8216,  "'" ],  
     [    8217, "'" ],  
     [    8220, '"' ],  
@@ -26588,553 +28046,7 @@ Roo.extend(Roo.bootstrap.Markdown, Roo.bootstrap.TextArea,  {
     }
 
 
-});
-/**
- * @class Roo.bootstrap.Table.AbstractSelectionModel
- * @extends Roo.util.Observable
- * Abstract base class for grid SelectionModels.  It provides the interface that should be
- * implemented by descendant classes.  This class should not be directly instantiated.
- * @constructor
- */
-Roo.bootstrap.Table.AbstractSelectionModel = function(){
-    this.locked = false;
-    Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
-};
-
-
-Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
-    /** @ignore Called by the grid automatically. Do not call directly. */
-    init : function(grid){
-        this.grid = grid;
-        this.initEvents();
-    },
-
-    /**
-     * Locks the selections.
-     */
-    lock : function(){
-        this.locked = true;
-    },
-
-    /**
-     * Unlocks the selections.
-     */
-    unlock : function(){
-        this.locked = false;
-    },
-
-    /**
-     * Returns true if the selections are locked.
-     * @return {Boolean}
-     */
-    isLocked : function(){
-        return this.locked;
-    },
-    
-    
-    initEvents : function ()
-    {
-        
-    }
-});
-/**
- * @extends Roo.bootstrap.Table.AbstractSelectionModel
- * @class Roo.bootstrap.Table.RowSelectionModel
- * The default SelectionModel used by {@link Roo.bootstrap.Table}.
- * It supports multiple selections and keyboard selection/navigation. 
- * @constructor
- * @param {Object} config
- */
-
-Roo.bootstrap.Table.RowSelectionModel = function(config){
-    Roo.apply(this, config);
-    this.selections = new Roo.util.MixedCollection(false, function(o){
-        return o.id;
-    });
-
-    this.last = false;
-    this.lastActive = false;
-
-    this.addEvents({
-        /**
-            * @event selectionchange
-            * Fires when the selection changes
-            * @param {SelectionModel} this
-            */
-           "selectionchange" : true,
-        /**
-            * @event afterselectionchange
-            * Fires after the selection changes (eg. by key press or clicking)
-            * @param {SelectionModel} this
-            */
-           "afterselectionchange" : true,
-        /**
-            * @event beforerowselect
-            * Fires when a row is selected being selected, return false to cancel.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected index
-            * @param {Boolean} keepExisting False if other selections will be cleared
-            */
-           "beforerowselect" : true,
-        /**
-            * @event rowselect
-            * Fires when a row is selected.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected index
-            * @param {Roo.data.Record} r The record
-            */
-           "rowselect" : true,
-        /**
-            * @event rowdeselect
-            * Fires when a row is deselected.
-            * @param {SelectionModel} this
-            * @param {Number} rowIndex The selected index
-            */
-        "rowdeselect" : true
-    });
-    Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
-    this.locked = false;
- };
-
-Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
-    /**
-     * @cfg {Boolean} singleSelect
-     * True to allow selection of only one row at a time (defaults to false)
-     */
-    singleSelect : false,
-
-    // private
-    initEvents : function()
-    {
-
-        //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
-        //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
-        //}else{ // allow click to work like normal
-         //   this.grid.on("rowclick", this.handleDragableRowClick, this);
-        //}
-        //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
-        this.grid.on("rowclick", this.handleMouseDown, this);
-        
-        this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
-            "up" : function(e){
-                if(!e.shiftKey){
-                    this.selectPrevious(e.shiftKey);
-                }else if(this.last !== false && this.lastActive !== false){
-                    var last = this.last;
-                    this.selectRange(this.last,  this.lastActive-1);
-                    this.grid.getView().focusRow(this.lastActive);
-                    if(last !== false){
-                        this.last = last;
-                    }
-                }else{
-                    this.selectFirstRow();
-                }
-                this.fireEvent("afterselectionchange", this);
-            },
-            "down" : function(e){
-                if(!e.shiftKey){
-                    this.selectNext(e.shiftKey);
-                }else if(this.last !== false && this.lastActive !== false){
-                    var last = this.last;
-                    this.selectRange(this.last,  this.lastActive+1);
-                    this.grid.getView().focusRow(this.lastActive);
-                    if(last !== false){
-                        this.last = last;
-                    }
-                }else{
-                    this.selectFirstRow();
-                }
-                this.fireEvent("afterselectionchange", this);
-            },
-            scope: this
-        });
-        this.grid.store.on('load', function(){
-            this.selections.clear();
-        },this);
-        /*
-        var view = this.grid.view;
-        view.on("refresh", this.onRefresh, this);
-        view.on("rowupdated", this.onRowUpdated, this);
-        view.on("rowremoved", this.onRemove, this);
-        */
-    },
-
-    // private
-    onRefresh : function()
-    {
-        var ds = this.grid.store, i, v = this.grid.view;
-        var s = this.selections;
-        s.each(function(r){
-            if((i = ds.indexOfId(r.id)) != -1){
-                v.onRowSelect(i);
-            }else{
-                s.remove(r);
-            }
-        });
-    },
-
-    // private
-    onRemove : function(v, index, r){
-        this.selections.remove(r);
-    },
-
-    // private
-    onRowUpdated : function(v, index, r){
-        if(this.isSelected(r)){
-            v.onRowSelect(index);
-        }
-    },
-
-    /**
-     * Select records.
-     * @param {Array} records The records to select
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectRecords : function(records, keepExisting)
-    {
-        if(!keepExisting){
-            this.clearSelections();
-        }
-           var ds = this.grid.store;
-        for(var i = 0, len = records.length; i < len; i++){
-            this.selectRow(ds.indexOf(records[i]), true);
-        }
-    },
-
-    /**
-     * Gets the number of selected rows.
-     * @return {Number}
-     */
-    getCount : function(){
-        return this.selections.length;
-    },
-
-    /**
-     * Selects the first row in the grid.
-     */
-    selectFirstRow : function(){
-        this.selectRow(0);
-    },
-
-    /**
-     * Select the last row.
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectLastRow : function(keepExisting){
-        //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
-        this.selectRow(this.grid.store.getCount() - 1, keepExisting);
-    },
-
-    /**
-     * Selects the row immediately following the last selected row.
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectNext : function(keepExisting)
-    {
-           if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
-            this.selectRow(this.last+1, keepExisting);
-            this.grid.getView().focusRow(this.last);
-        }
-    },
-
-    /**
-     * Selects the row that precedes the last selected row.
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectPrevious : function(keepExisting){
-        if(this.last){
-            this.selectRow(this.last-1, keepExisting);
-            this.grid.getView().focusRow(this.last);
-        }
-    },
-
-    /**
-     * Returns the selected records
-     * @return {Array} Array of selected records
-     */
-    getSelections : function(){
-        return [].concat(this.selections.items);
-    },
-
-    /**
-     * Returns the first selected record.
-     * @return {Record}
-     */
-    getSelected : function(){
-        return this.selections.itemAt(0);
-    },
-
-
-    /**
-     * Clears all selections.
-     */
-    clearSelections : function(fast)
-    {
-        if(this.locked) {
-            return;
-        }
-        if(fast !== true){
-               var ds = this.grid.store;
-            var s = this.selections;
-            s.each(function(r){
-                this.deselectRow(ds.indexOfId(r.id));
-            }, this);
-            s.clear();
-        }else{
-            this.selections.clear();
-        }
-        this.last = false;
-    },
-
-
-    /**
-     * Selects all rows.
-     */
-    selectAll : function(){
-        if(this.locked) {
-            return;
-        }
-        this.selections.clear();
-        for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
-            this.selectRow(i, true);
-        }
-    },
-
-    /**
-     * Returns True if there is a selection.
-     * @return {Boolean}
-     */
-    hasSelection : function(){
-        return this.selections.length > 0;
-    },
-
-    /**
-     * Returns True if the specified row is selected.
-     * @param {Number/Record} record The record or index of the record to check
-     * @return {Boolean}
-     */
-    isSelected : function(index){
-           var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
-        return (r && this.selections.key(r.id) ? true : false);
-    },
-
-    /**
-     * Returns True if the specified record id is selected.
-     * @param {String} id The id of record to check
-     * @return {Boolean}
-     */
-    isIdSelected : function(id){
-        return (this.selections.key(id) ? true : false);
-    },
-
-
-    // private
-    handleMouseDBClick : function(e, t){
-       
-    },
-    // private
-    handleMouseDown : function(e, t)
-    {
-           var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
-        if(this.isLocked() || rowIndex < 0 ){
-            return;
-        };
-        if(e.shiftKey && this.last !== false){
-            var last = this.last;
-            this.selectRange(last, rowIndex, e.ctrlKey);
-            this.last = last; // reset the last
-            t.focus();
-    
-        }else{
-            var isSelected = this.isSelected(rowIndex);
-            //Roo.log("select row:" + rowIndex);
-            if(isSelected){
-                this.deselectRow(rowIndex);
-            } else {
-                       this.selectRow(rowIndex, true);
-            }
-    
-            /*
-                if(e.button !== 0 && isSelected){
-                alert('rowIndex 2: ' + rowIndex);
-                    view.focusRow(rowIndex);
-                }else if(e.ctrlKey && isSelected){
-                    this.deselectRow(rowIndex);
-                }else if(!isSelected){
-                    this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
-                    view.focusRow(rowIndex);
-                }
-            */
-        }
-        this.fireEvent("afterselectionchange", this);
-    },
-    // private
-    handleDragableRowClick :  function(grid, rowIndex, e) 
-    {
-        if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
-            this.selectRow(rowIndex, false);
-            grid.view.focusRow(rowIndex);
-             this.fireEvent("afterselectionchange", this);
-        }
-    },
-    
-    /**
-     * Selects multiple rows.
-     * @param {Array} rows Array of the indexes of the row to select
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectRows : function(rows, keepExisting){
-        if(!keepExisting){
-            this.clearSelections();
-        }
-        for(var i = 0, len = rows.length; i < len; i++){
-            this.selectRow(rows[i], true);
-        }
-    },
-
-    /**
-     * Selects a range of rows. All rows in between startRow and endRow are also selected.
-     * @param {Number} startRow The index of the first row in the range
-     * @param {Number} endRow The index of the last row in the range
-     * @param {Boolean} keepExisting (optional) True to retain existing selections
-     */
-    selectRange : function(startRow, endRow, keepExisting){
-        if(this.locked) {
-            return;
-        }
-        if(!keepExisting){
-            this.clearSelections();
-        }
-        if(startRow <= endRow){
-            for(var i = startRow; i <= endRow; i++){
-                this.selectRow(i, true);
-            }
-        }else{
-            for(var i = startRow; i >= endRow; i--){
-                this.selectRow(i, true);
-            }
-        }
-    },
-
-    /**
-     * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
-     * @param {Number} startRow The index of the first row in the range
-     * @param {Number} endRow The index of the last row in the range
-     */
-    deselectRange : function(startRow, endRow, preventViewNotify){
-        if(this.locked) {
-            return;
-        }
-        for(var i = startRow; i <= endRow; i++){
-            this.deselectRow(i, preventViewNotify);
-        }
-    },
-
-    /**
-     * Selects a row.
-     * @param {Number} row The index of the row to select
-     * @param {Boolean} keepExisting (optional) True to keep existing selections
-     */
-    selectRow : function(index, keepExisting, preventViewNotify)
-    {
-           if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
-            return;
-        }
-        if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
-            if(!keepExisting || this.singleSelect){
-                this.clearSelections();
-            }
-           
-            var r = this.grid.store.getAt(index);
-            //console.log('selectRow - record id :' + r.id);
-            
-            this.selections.add(r);
-            this.last = this.lastActive = index;
-            if(!preventViewNotify){
-                var proxy = new Roo.Element(
-                                this.grid.getRowDom(index)
-                );
-                proxy.addClass('bg-info info');
-            }
-            this.fireEvent("rowselect", this, index, r);
-            this.fireEvent("selectionchange", this);
-        }
-    },
-
-    /**
-     * Deselects a row.
-     * @param {Number} row The index of the row to deselect
-     */
-    deselectRow : function(index, preventViewNotify)
-    {
-        if(this.locked) {
-            return;
-        }
-        if(this.last == index){
-            this.last = false;
-        }
-        if(this.lastActive == index){
-            this.lastActive = false;
-        }
-       
-        var r = this.grid.store.getAt(index);
-        if (!r) {
-            return;
-        }
-        
-        this.selections.remove(r);
-        //.console.log('deselectRow - record id :' + r.id);
-        if(!preventViewNotify){
-       
-           var proxy = new Roo.Element(
-                this.grid.getRowDom(index)
-            );
-            proxy.removeClass('bg-info info');
-        }
-        this.fireEvent("rowdeselect", this, index);
-        this.fireEvent("selectionchange", this);
-    },
-
-    // private
-    restoreLast : function(){
-        if(this._last){
-            this.last = this._last;
-        }
-    },
-
-    // private
-    acceptsNav : function(row, col, cm){
-        return !cm.isHidden(col) && cm.isCellEditable(col, row);
-    },
-
-    // private
-    onEditorKey : function(field, e){
-        var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
-        if(k == e.TAB){
-            e.stopEvent();
-            ed.completeEdit();
-            if(e.shiftKey){
-                newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
-            }else{
-                newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
-            }
-        }else if(k == e.ENTER && !e.ctrlKey){
-            e.stopEvent();
-            ed.completeEdit();
-            if(e.shiftKey){
-                newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
-            }else{
-                newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
-            }
-        }else if(k == e.ESC){
-            ed.cancelEdit();
-        }
-        if(newCell){
-            g.startEditing(newCell[0], newCell[1]);
-        }
-    }
-});
-/*
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -28641,7 +29553,7 @@ Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
     getAutoCreate : function(){
         var cfg = {
             tag : 'li',
-            cls: 'divider'
+            cls: 'dropdown-divider divider'
         };
         
         return cfg;
@@ -28730,10 +29642,19 @@ Roo.apply(Roo.bootstrap.Tooltip, {
             return;
         }
         
-        var bindEl = el;
+        var bindEl = el; 
+        var pel = false;
+        if (!el.attr('tooltip')) {
+            pel = el.findParent("[tooltip]");
+            if (pel) {
+                bindEl = Roo.get(pel);
+            }
+        }
+        
+       
         
         // you can not look for children, as if el is the body.. then everythign is the child..
-        if (!el.attr('tooltip')) { //
+        if (!pel && !el.attr('tooltip')) { //
             if (!el.select("[tooltip]").elements.length) {
                 return;
             }
@@ -28747,7 +29668,7 @@ Roo.apply(Roo.bootstrap.Tooltip, {
             //Roo.log("child element over..");
             
         }
-        this.currentEl = bindEl;
+        this.currentEl = el;
         this.currentTip.bind(bindEl);
         this.currentRegion = Roo.lib.Region.getRegion(dom);
         this.currentTip.enter();
@@ -28939,6 +29860,22 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
             
         }
         
+        var elems = document.getElementsByTagName('div');
+        var highest = Number.MIN_SAFE_INTEGER || -(Math.pow(2, 53) - 1);
+        for (var i = 0; i < elems.length; i++) {
+          var zindex = Number.parseInt(
+                document.defaultView.getComputedStyle(elems[i], null).getPropertyValue("z-index"),
+                10
+          );
+          if (zindex > highest) {
+            highest = zindex;
+          }
+        }
+        
+        
+        
+        this.el.dom.style.zIndex = highest;
+        
         this.el.alignTo(this.bindEl, align[0],align[1]);
         //var arrow = this.el.select('.arrow',true).first();
         //arrow.set(align[2], 
@@ -29466,8 +30403,11 @@ Roo.apply(Roo.bootstrap.LocationPicker, {
  * @licence LGPL
  * @cfg {String} title The title of alert
  * @cfg {String} html The content of alert
- * @cfg {String} weight (  success | info | warning | danger )
- * @cfg {String} faicon font-awesomeicon
+ * @cfg {String} weight (success|info|warning|danger) Weight of the message
+ * @cfg {String} fa font-awesomeicon
+ * @cfg {Number} seconds default:-1 Number of seconds until it disapears (-1 means never.)
+ * @cfg {Boolean} close true to show a x closer
+ * 
  * 
  * @constructor
  * Create a new alert
@@ -29485,7 +30425,10 @@ Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
     title: '',
     html: '',
     weight: false,
-    faicon: false,
+    fa: false,
+    faicon: false, // BC
+    close : false,
+    
     
     getAutoCreate : function()
     {
@@ -29494,6 +30437,13 @@ Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
             tag : 'div',
             cls : 'alert',
             cn : [
+                {
+                    tag: 'button',
+                    type :  "button",
+                    cls: "close",
+                    html : '×',
+                    style : this.close ? '' : 'display:none'
+                },
                 {
                     tag : 'i',
                     cls : 'roo-alert-icon'
@@ -29515,6 +30465,9 @@ Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
         if(this.faicon){
             cfg.cn[0].cls += ' fa ' + this.faicon;
         }
+        if(this.fa){
+            cfg.cn[0].cls += ' fa ' + this.fa;
+        }
         
         if(this.weight){
             cfg.cls += ' alert-' + this.weight;
@@ -29526,45 +30479,69 @@ Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
     initEvents: function() 
     {
         this.el.setVisibilityMode(Roo.Element.DISPLAY);
+        this.titleEl =  this.el.select('.roo-alert-title',true).first();
+        this.iconEl = this.el.select('.roo-alert-icon',true).first();
+        this.htmlEl = this.el.select('.roo-alert-text',true).first();
+        if (this.seconds > 0) {
+            this.hide.defer(this.seconds, this);
+        }
     },
-    
+    /**
+     * Set the Title Message HTML
+     * @param {String} html
+     */
     setTitle : function(str)
     {
-        this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
+        this.titleEl.dom.innerHTML = str;
     },
-    
-    setText : function(str)
+     
+     /**
+     * Set the Body Message HTML
+     * @param {String} html
+     */
+    setHtml : function(str)
     {
-        this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
+        this.htmlEl.dom.innerHTML = str;
     },
+    /**
+     * Set the Weight of the alert
+     * @param {String} (success|info|warning|danger) weight
+     */
     
     setWeight : function(weight)
     {
         if(this.weight){
-            this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
+            this.el.removeClass('alert-' + this.weight);
         }
         
         this.weight = weight;
         
-        this.el.select('.alert',true).first().addClass('alert-' + this.weight);
+        this.el.addClass('alert-' + this.weight);
     },
-    
+      /**
+     * Set the Icon of the alert
+     * @param {String} see fontawsome names (name without the 'fa-' bit)
+     */
     setIcon : function(icon)
     {
         if(this.faicon){
-            this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
+            this.alertEl.removeClass(['fa', 'fa-' + this.faicon]);
         }
         
         this.faicon = icon;
         
-        this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
+        this.alertEl.addClass(['fa', 'fa-' + this.faicon]);
     },
-    
+    /**
+     * Hide the Alert
+     */
     hide: function() 
     {
         this.el.hide();   
     },
-    
+    /**
+     * Show the Alert
+     */
     show: function() 
     {  
         this.el.show();   
@@ -39716,7 +40693,15 @@ Roo.bootstrap.panel.Content = function( config){
          * Fires when this tab is created
          * @param {Roo.ContentPanel} this
          */
-        "render" : true
+        "render" : true,
+        
+          /**
+         * @event scroll
+         * Fires when this content is scrolled
+         * @param {Roo.ContentPanel} this
+         * @param {Event} scrollEvent
+         */
+        "scroll" : true
         
         
         
@@ -39727,6 +40712,7 @@ Roo.bootstrap.panel.Content = function( config){
     
     if(this.autoScroll && !this.iframe){
         this.resizeEl.setStyle("overflow", "auto");
+        this.resizeEl.on('scroll', this.onScroll, this);
     } else {
         // fix randome scrolling
         //this.el.on('scroll', function() {
@@ -39766,6 +40752,9 @@ Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
     iframe : false,
     iframeEl : false,
     
+    /* Resize Element - use this to work out scroll etc. */
+    resizeEl : false,
+    
     setRegion : function(region){
         this.region = region;
         this.setActiveClass(region && !this.background);
@@ -40075,6 +41064,12 @@ layout.addxtype({
     
     getChildContainer: function () {
         return this.getEl();
+    },
+    
+    
+    onScroll : function(e)
+    {
+        this.fireEvent('scroll', this, e);
     }