Fix #7275 - handling odd word document
[roojs1] / roojs-bootstrap-debug.js
index 157945e..ea98f39 100644 (file)
@@ -1,18 +1,23 @@
-/**
+Roo.bootstrap = {};/**
  * set the version of bootstrap based on the stylesheet...
  *
  */
 
-Roo.bootstrap.version = (
-        function() {
-                var ret=3;
-                Roo.each(document.styleSheets, function(s) {
-                    if ( s.href  && s.href.match(/css-bootstrap4/)) {
-                        ret=4;
-                    }
-                });
-        return ret;
-})(); /*
+Roo.bootstrap.version = ( function() {
+    var ret=3;
+    Roo.each(document.styleSheets, function(s) {
+        if ( s.href  && s.href.match(/css-bootstrap4/)) {
+            ret=4;
+        }
+    });
+    if (ret > 3) {
+         Roo.Element.prototype.visibilityMode = Roo.Element.DISPLAY;
+    }
+    return ret;
+})(); Roo.bootstrap.menu = Roo.bootstrap.menu || {};
+Roo.bootstrap.nav = {};
+
+Roo.bootstrap.form = {};Roo.bootstrap.panel = {};Roo.bootstrap.layout = {};/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -93,6 +98,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)
@@ -220,6 +226,8 @@ Roo.bootstrap = Roo.bootstrap || {};
 /**
  * @class Roo.bootstrap.Component
  * @extends Roo.Component
+ * @abstract
+ * @children Roo.bootstrap.Component
  * Bootstrap Component base class
  * @cfg {String} cls css class
  * @cfg {String} style any extra css
@@ -328,11 +336,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){
@@ -360,6 +368,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
@@ -642,12 +655,16 @@ Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
 /**
  * @class Roo.bootstrap.Element
  * @extends Roo.bootstrap.Component
- * Bootstrap Element class
+ * @children Roo.bootstrap.Component
+ * Bootstrap Element class (basically a DIV used to make random stuff )
+ * 
  * @cfg {String} html contents of the element
  * @cfg {String} tag tag of the element
  * @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
@@ -665,7 +682,9 @@ Roo.bootstrap.Element = function(config){
          * @param {Roo.bootstrap.Element} this
          * @param {Roo.EventObject} e
          */
-        "click" : true
+        "click" : true 
+        
+      
     });
 };
 
@@ -676,6 +695,8 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
     html: '',
     preventDefault: false, 
     clickable: false,
+    tapedTwice : false,
+    role : false,
     
     getAutoCreate : function(){
         
@@ -684,6 +705,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;
     },
@@ -696,6 +720,7 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
             this.el.on('click', this.onClick, this);
         }
         
+        
     },
     
     onClick : function(e)
@@ -704,9 +729,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;
@@ -825,6 +855,8 @@ Roo.extend(Roo.bootstrap.DropTarget, Roo.bootstrap.Element,  {
 /**
  * @class Roo.bootstrap.Body
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Component 
+ * @parent none builder
  * Bootstrap Body class
  *
  * @constructor
@@ -876,6 +908,8 @@ Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
  * @class Roo.bootstrap.ButtonGroup
  * @extends Roo.bootstrap.Component
  * Bootstrap ButtonGroup class
+ * @children Roo.bootstrap.Button Roo.bootstrap.form.Form
+ * 
  * @cfg {String} size lg | sm | xs (default empty normal)
  * @cfg {String} align vertical | justified  (default none)
  * @cfg {String} direction up | down (default down)
@@ -981,7 +1015,9 @@ Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
  * @cfg {Boolean} preventDefault  default true (stop click event triggering the URL if it's a link.)
  * @cfg {Boolean} removeClass remove the standard class..
  * @cfg {String} target (_self|_blank|_parent|_top|other) target for a href. 
- * 
+ * @cfg {Boolean} grpup if parent is a btn group - then it turns it into a toogleGroup.
+ * @cfg {Roo.bootstrap.menu.Menu} menu a Menu 
+
  * @constructor
  * Create a new button
  * @param {Object} config The config object
@@ -995,11 +1031,18 @@ Roo.bootstrap.Button = function(config){
         // raw events
         /**
          * @event click
-         * When a butotn is pressed
+         * When a button is pressed
          * @param {Roo.bootstrap.Button} btn
          * @param {Roo.EventObject} e
          */
         "click" : true,
+        /**
+         * @event dblclick
+         * When a button is double clicked
+         * @param {Roo.bootstrap.Button} btn
+         * @param {Roo.EventObject} e
+         */
+        "dblclick" : true,
          /**
          * @event toggle
          * After the button has been toggles
@@ -1036,6 +1079,7 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
     removeClass: false,
     name: false,
     target: false,
+    group : false,
      
     pressed : null,
      
@@ -1263,17 +1307,30 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
         }
 
 
-       if (this.el.hasClass('roo-button')) {
+        if (this.el.hasClass('roo-button')) {
+             this.el.on('click', this.onClick, this);
+             this.el.on('dblclick', this.onDblClick, this);
+        } else {
+             this.el.select('.roo-button').on('click', this.onClick, this);
+             this.el.select('.roo-button').on('dblclick', this.onDblClick, this);
+             
+        }
+        // why?
+        if(this.removeClass){
             this.el.on('click', this.onClick, this);
-       } else {
-            this.el.select('.roo-button').on('click', this.onClick, this);
-       }
-       
-       if(this.removeClass){
-           this.el.on('click', this.onClick, this);
-       }
-       
-       this.el.enableDisplayMode();
+        }
+        
+        if (this.group === true) {
+             if (this.pressed === false || this.pressed === true) {
+                // nothing
+            } else {
+                this.pressed = false;
+                this.setActive(this.pressed);
+            }
+            
+        }
+        
+        this.el.enableDisplayMode();
         
     },
     onClick : function(e)
@@ -1283,10 +1340,29 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
         }
         
         Roo.log('button on click ');
-        if(this.preventDefault){
+        if(this.href === '' || this.preventDefault){
             e.preventDefault();
         }
         
+        if (this.group) {
+            if (this.pressed) {
+                // do nothing -
+                return;
+            }
+            this.setActive(true);
+            var pi = this.parent().items;
+            for (var i = 0;i < pi.length;i++) {
+                if (this == pi[i]) {
+                    continue;
+                }
+                if (pi[i].el.hasClass('roo-button')) {
+                    pi[i].setActive(false);
+                }
+            }
+            this.fireEvent('click', this, e);            
+            return;
+        }
+        
         if (this.pressed === true || this.pressed === false) {
             this.toggleActive(e);
         }
@@ -1294,7 +1370,16 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
         
         this.fireEvent('click', this, e);
     },
-    
+    onDblClick: function(e)
+    {
+        if (this.disabled) {
+            return;
+        }
+        if(this.preventDefault){
+            e.preventDefault();
+        }
+        this.fireEvent('dblclick', this, e);
+    },
     /**
      * Enables this button
      */
@@ -1302,6 +1387,7 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
     {
         this.disabled = false;
         this.el.removeClass('disabled');
+        this.el.dom.removeAttribute("disabled");
     },
     
     /**
@@ -1311,6 +1397,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, 
@@ -1326,8 +1413,8 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
      */
     toggleActive : function(e)
     {
-        this.setActive(!this.pressed);
-        this.fireEvent('toggle', this, e, !this.pressed);
+        this.setActive(!this.pressed); // this modifies pressed...
+        this.fireEvent('toggle', this, e, this.pressed);
     },
      /**
      * get the current active state
@@ -1391,6 +1478,7 @@ Roo.bootstrap.Button.weights = [
 /**
  * @class Roo.bootstrap.Column
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Component
  * Bootstrap Column class
  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
@@ -1518,6 +1606,8 @@ Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
 /**
  * @class Roo.bootstrap.Container
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Component
+ * @parent builder
  * Bootstrap Container class
  * @cfg {Boolean} jumbotron is it a jumbotron element
  * @cfg {String} html content of element
@@ -1881,22 +1971,19 @@ Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
     }
 });
 
- /*
- *  - LGPL
- *
- *  This is BS4's Card element.. - similar to our containers probably..
- * 
- */
-/**
+ /**
  * @class Roo.bootstrap.Card
  * @extends Roo.bootstrap.Component
- * Bootstrap Card class
+ * @children Roo.bootstrap.Component
+ * @licence LGPL
+ * Bootstrap Card class - note this has children as CardHeader/ImageTop/Footer.. - which should really be listed properties?
  *
  *
  * possible... may not be implemented..
  * @cfg {String} header_image  src url of image.
  * @cfg {String|Object} header
  * @cfg {Number} header_size (0|1|2|3|4|5) H1 or H2 etc.. 0 indicates default
+ * @cfg {Number} header_weight  (primary|secondary|success|info|warning|danger|light|dark)
  * 
  * @cfg {String} title
  * @cfg {String} subtitle
@@ -1914,7 +2001,7 @@ Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
  * @cfg {String} margin_y (0|1|2|3|4|5|auto)
  *
  * @cfg {String} padding (0|1|2|3|4|5)
- * @cfg {String} padding_top (0|1|2|3|4|5)
+ * @cfg {String} padding_top (0|1|2|3|4|5)next_to_card
  * @cfg {String} padding_bottom (0|1|2|3|4|5)
  * @cfg {String} padding_left (0|1|2|3|4|5)
  * @cfg {String} padding_right (0|1|2|3|4|5)
@@ -1950,22 +2037,31 @@ Roo.bootstrap.Card = function(config){
         /**
          * @event drop
          * When a element a card is dropped
-         * @param {Roo.bootstrap.Element} this
-         * @param {Roo.Element} n the node being dropped?
-         * @param {Object} dd Drag and drop data
-         * @param {Roo.EventObject} e
-         * @param {Roo.EventObject} data  the data passed via getDragData
+         * @param {Roo.bootstrap.Card} this
+         *
+         * 
+         * @param {Roo.bootstrap.Card} move_card the card being dropped?
+         * @param {String} position 'above' or 'below'
+         * @param {Roo.bootstrap.Card} next_to_card What card position is relative to of 'false' for empty list.
+        
          */
         'drop' : true,
          /**
          * @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
+         
     });
 };
 
@@ -2016,6 +2112,12 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     drop_group : false,
     childContainer : false,
     dropEl : false, /// the dom placeholde element that indicates drop location.
+    containerEl: false, // body container
+    bodyEl: false, // card-body
+    headerContainerEl : false, //
+    headerEl : false,
+    header_imageEl : false,
+    
     
     layoutCls : function()
     {
@@ -2035,7 +2137,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         
         ['', 'xs', 'sm', 'lg', 'xl'].forEach(function(v) {
             if (('' + t['display' + (v.length ? '_' : '') + v]).length) {
-                cls += ' d' +  (v.length ? '-' : '') + v + '-' + t['margin' + (v.length ? '_' : '') + v]
+                cls += ' d' +  (v.length ? '-' : '') + v + '-' + t['display' + (v.length ? '_' : '') + v]
             }
         });
         
@@ -2088,14 +2190,14 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
             cfg.cls += ' bg-' + this.weight;
         }
         
-        cfg.cls += this.layoutCls(); 
+        cfg.cls += ' ' + this.layoutCls(); 
         
         var hdr = false;
         var hdr_ctr = false;
         if (this.header.length) {
             hdr = {
                 tag : this.header_size > 0 ? 'h' + this.header_size : 'div',
-                cls : 'card-header',
+                cls : 'card-header ' + (this.header_weight ? 'bg-' + this.header_weight : ''),
                 cn : []
             };
             cfg.cn.push(hdr);
@@ -2103,7 +2205,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         } else {
             hdr = {
                 tag : 'div',
-                cls : 'card-header d-none',
+                cls : 'card-header d-none ' + (this.header_weight ? 'bg-' + this.header_weight : ''),
                 cn : []
             };
             cfg.cn.push(hdr);
@@ -2226,7 +2328,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');
         }
@@ -2245,8 +2347,8 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     
     initEvents: function() 
     {
-        
-        this.bodyEl = this.getChildContainer();
+        this.bodyEl = this.el.select('.card-body',true).first(); 
+        this.containerEl = this.getChildContainer();
         if(this.dragable){
             this.dragZone = new Roo.dd.DragZone(this.getEl(), {
                     containerScroll: true,
@@ -2272,16 +2374,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.headerEl = 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)
@@ -2309,11 +2414,22 @@ 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)
     {
         var target = e.getTarget();
-        while ((target !== null) && (target.parentNode != this.bodyEl.dom)) {
+        while ((target !== null) && (target.parentNode != this.containerEl.dom)) {
             target = target.parentNode;
         }
         
@@ -2402,7 +2518,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; 
@@ -2425,22 +2545,48 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         if (info === false) {
             return false;
         }
-        
-        if (this.fireEvent("drop", this, n, dd, e, data) === false) {
+        this.dropPlaceHolder('hide');
+  
+          
+    
+        this.acceptCard(data.source, info.position, info.card, info.items_n);
+        return true;
+         
+    },
+    firstChildCard : function()
+    {
+        for (var i = 0;i< this.items.length;i++) {
+            
+            if (!this.items[i].el.hasClass('card')) {
+                 continue;
+            }
+            return this.items[i];
+        }
+        return this.items.length ? this.items[this.items.length-1] : false; // don't try and put stuff after the cards...
+    },
+    /**
+     * accept card
+     *
+     * -        card.acceptCard(move_card, info.position, info.card, info.items_n);
+     */
+    acceptCard : function(move_card,  position, next_to_card )
+    {
+        if (this.fireEvent("drop", this, move_card, position, next_to_card) === false) {
             return false;
         }
-         
-        this.dropPlaceHolder('hide');
         
-        // do the dom manipulation first..
-        var dom = data.source.el.dom;
-        dom.parentNode.removeChild(dom);
+        var to_items_n = next_to_card ? this.items.indexOf(next_to_card) : 0;
         
+        move_card.parent().removeCard(move_card);
         
-        if (info.card !== true) {
-            var cardel = info.card.el.dom;
+        
+        var dom = move_card.el.dom;
+        dom.style.width = ''; // clear with - which is set by drag.
+        
+        if (next_to_card !== false && next_to_card !== true && next_to_card.el.dom.parentNode) {
+            var cardel = next_to_card.el.dom;
             
-            if (info.position == 'above') {
+            if (position == 'above' ) {
                 cardel.parentNode.insertBefore(dom, cardel);
             } else if (cardel.nextSibling) {
                 cardel.parentNode.insertBefore(dom,cardel.nextSibling);
@@ -2449,42 +2595,49 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
             }
         } else {
             // card container???
-            this.bodyEl.dom.append(dom);
+            this.containerEl.dom.append(dom);
         }
         
         //FIXME HANDLE card = true 
         
         // add this to the correct place in items.
         
-        
-        
         // remove Card from items.
         
-        var old_parent = data.source.parent();
-        
-        old_parent.items = old_parent.items.filter(function(e) { return e != data.source });
-        
+       
         if (this.items.length) {
             var nitems = [];
             //Roo.log([info.items_n, info.position, this.items.length]);
             for (var i =0; i < this.items.length; i++) {
-                if (i == info.items_n && info.position == 'above') {
-                    nitems.push(data.source);
+                if (i == to_items_n && position == 'above') {
+                    nitems.push(move_card);
                 }
                 nitems.push(this.items[i]);
-                if (i == info.items_n && info.position == 'below') {
-                    nitems.push(data.source);
+                if (i == to_items_n && position == 'below') {
+                    nitems.push(move_card);
                 }
             }
             this.items = nitems;
             Roo.log(this.items);
         } else {
-            this.items.push(data.source);
+            this.items.push(move_card);
         }
         
-        data.source.parentId = this.id;
+        move_card.parentId = this.id;
         
         return true;
+        
+        
+    },
+    removeCard : function(c)
+    {
+        this.items = this.items.filter(function(e) { return e != c });
+        var dom = c.el.dom;
+        dom.parentNode.removeChild(dom);
+        dom.style.width = ''; // clear with - which is set by drag.
+        c.parentId = false;
+        
     },
     
     /**    Decide whether to drop above or below a View node. */
@@ -2493,7 +2646,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         if (dd) {
              return false;
         }
-        if (n == this.bodyEl.dom) {
+        if (n == this.containerEl.dom) {
             return "above";
         }
         var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
@@ -2545,7 +2698,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     dropPlaceHolder: function (action, info, data)
     {
         if (this.dropEl === false) {
-            this.dropEl = Roo.DomHelper.append(this.bodyEl, {
+            this.dropEl = Roo.DomHelper.append(this.containerEl, {
             cls : 'd-none'
             },true);
         }
@@ -2570,7 +2723,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
             }
         } else {
             // card container???
-            this.bodyEl.dom.append(this.dropEl.dom);
+            this.containerEl.dom.append(this.dropEl.dom);
         }
         
         this.dropEl.addClass('d-block roo-card-dropzone');
@@ -2584,7 +2737,31 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     },
     setHeaderText: function(html)
     {
-        this.headerEl.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';
+        }
+
     }
 
     
@@ -2600,6 +2777,8 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
 /**
  * @class Roo.bootstrap.CardHeader
  * @extends Roo.bootstrap.Element
+ * @parent Roo.bootstrap.Card
+ * @children Roo.bootstrap.Component
  * Bootstrap CardHeader class
  * @constructor
  * Create a new Card Header - that you can embed children into
@@ -2633,7 +2812,10 @@ Roo.extend(Roo.bootstrap.CardHeader, Roo.bootstrap.Element,  {
 /**
  * @class Roo.bootstrap.CardFooter
  * @extends Roo.bootstrap.Element
+ * @parent Roo.bootstrap.Card
+ * @children Roo.bootstrap.Component
  * Bootstrap CardFooter class
+ * 
  * @constructor
  * Create a new Card Footer - that you can embed children into
  * @param {Object} config The config object
@@ -2666,7 +2848,10 @@ Roo.extend(Roo.bootstrap.CardFooter, Roo.bootstrap.Element,  {
 /**
  * @class Roo.bootstrap.CardImageTop
  * @extends Roo.bootstrap.Element
+ * @parent Roo.bootstrap.Card
+ * @children Roo.bootstrap.Component
  * Bootstrap CardImageTop class
+ * 
  * @constructor
  * Create a new Card Image Top container
  * @param {Object} config The config object
@@ -2688,6 +2873,172 @@ 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()
+    {
+       
+        
+        return  {
+            cls :'div' ,
+            cn : [
+                Roo.bootstrap.Button.prototype.getAutoCreate.call(this) 
+            ]
+        };
+           
+         
+    },
+     
+   
+    initEvents : function()
+    {
+        
+        Roo.bootstrap.Button.prototype.initEvents.call(this);
+        
+        
+        
+        
+        
+        this.urlAPI = (window.createObjectURL && window) || 
+                                (window.URL && URL.revokeObjectURL && URL) || 
+                                (window.webkitURL && webkitURL);
+                        
+        var im = {
+            tag: 'input',
+            type : 'file',
+            cls : 'd-none  roo-card-upload-selector' 
+          
+        };
+        if (this.multiple) {
+            im.multiple = 'multiple';
+        }
+        this.selectorEl = Roo.get(document.body).createChild(im); // so it does not capture click event for navitem.
+       
+        //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
  *
@@ -2710,6 +3061,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
@@ -2726,7 +3078,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
     });
 };
 
@@ -2741,6 +3099,7 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
     smUrl: '',
     mdUrl: '',
     lgUrl: '',
+    backgroundContain : false,
 
     getAutoCreate : function()
     {   
@@ -2813,12 +3172,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;
@@ -2851,6 +3218,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);
+        }
         
     },
     
@@ -2859,6 +3232,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
@@ -2869,7 +3248,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;
         }
         
@@ -2891,7 +3274,9 @@ Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
 /**
  * @class Roo.bootstrap.Link
  * @extends Roo.bootstrap.Component
- * Bootstrap Link Class
+ * @children Roo.bootstrap.Component
+ * Bootstrap Link Class (eg. '<a href>')
  * @cfg {String} alt image alternative text
  * @cfg {String} href a tag href
  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
@@ -2995,7 +3380,10 @@ Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
 /**
  * @class Roo.bootstrap.Header
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Component
  * Bootstrap Header class
+ *
+ * 
  * @cfg {String} html content of header
  * @cfg {Number} level (1|2|3|4|5|6) default 1
  * 
@@ -3033,23 +3421,13 @@ Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
 
  
 
- /*
- * 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.bootstrap.MenuMgr
+ * @licence LGPL
  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
- * @singleton
+ * @static
  */
-Roo.bootstrap.MenuMgr = function(){
+Roo.bootstrap.menu.Manager = function(){
    var menus, active, groups = {}, attached = false, lastShow = new Date();
 
    // private - called when first menu is created
@@ -3231,32 +3609,39 @@ Roo.bootstrap.MenuMgr = function(){
            }
        }
    };
-}();/*
- * - LGPL
- *
- * menu
- * 
- */
-
+}(); 
 /**
- * @class Roo.bootstrap.Menu
+ * @class Roo.bootstrap.menu.Menu
  * @extends Roo.bootstrap.Component
- * Bootstrap Menu class - container for MenuItems
+ * @licence LGPL
+ * @children Roo.bootstrap.menu.Item Roo.bootstrap.menu.Separator
+ * @parent none
+ * Bootstrap Menu class - container for MenuItems - normally has to be added to a object that supports the menu property
+ * 
  * @cfg {String} type (dropdown|treeview|submenu) type of menu
  * @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
+ * @param {Object} config The config objectQ
  */
 
 
-Roo.bootstrap.Menu = function(config){
-    Roo.bootstrap.Menu.superclass.constructor.call(this, config);
+Roo.bootstrap.menu.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.Menu.superclass.constructor.call(this, config);
     if (this.registerMenu && this.type != 'treeview')  {
-        Roo.bootstrap.MenuMgr.register(this);
+        Roo.bootstrap.menu.Manager.register(this);
     }
     
     
@@ -3320,10 +3705,10 @@ Roo.bootstrap.Menu = function(config){
     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
 };
 
-Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
     
    /// html : false,
-    //align : '',
+   
     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
     type: false,
     /**
@@ -3341,6 +3726,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;  
     },
@@ -3350,11 +3742,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'
             
         };
@@ -3372,18 +3763,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);
         }
@@ -3501,8 +3896,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
@@ -3522,18 +3940,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?
         
@@ -3565,9 +3982,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()){
            
@@ -3575,8 +3992,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);
         }
@@ -3621,7 +4041,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'){
@@ -3645,7 +4066,7 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
         });
     },
     addxtypeChild : function (tree, cntr) {
-        var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
+        var comp= Roo.bootstrap.menu.Menu.superclass.addxtypeChild.call(this, tree, cntr);
           
         this.menuitems.add(comp);
         return comp;
@@ -3665,18 +4086,14 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
 });
 
  
- /*
- * - LGPL
- *
- * menu item
- * 
- */
-
-
-/**
- * @class Roo.bootstrap.MenuItem
+ /**
+ * @class Roo.bootstrap.menu.Item
  * @extends Roo.bootstrap.Component
+ * @children  Roo.bootstrap.Button Roo.bootstrap.ButtonUploader Roo.bootstrap.Row Roo.bootstrap.Column Roo.bootstrap.Container
+ * @parent Roo.bootstrap.menu.Menu
+ * @licence LGPL
  * Bootstrap MenuItem class
+ * 
  * @cfg {String} html the menu label
  * @cfg {String} href the link
  * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
@@ -3692,21 +4109,21 @@ Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
  */
 
 
-Roo.bootstrap.MenuItem = function(config){
-    Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
+Roo.bootstrap.menu.Item = function(config){
+    Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
     this.addEvents({
         // raw events
         /**
          * @event click
          * The raw click event for the entire grid.
-         * @param {Roo.bootstrap.MenuItem} this
+         * @param {Roo.bootstrap.menu.Item} this
          * @param {Roo.EventObject} e
          */
         "click" : true
     });
 };
 
-Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
     
     href : false,
     html : false,
@@ -3779,9 +4196,9 @@ Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
     },
     onClick : function(e)
     {
-        Roo.log('item on click ');
+        //Roo.log('item on click ');
         
-        if(this.preventDefault){
+        if(this.href === false || this.preventDefault){
             e.preventDefault();
         }
         //this.parent().hideMenuItems();
@@ -3796,35 +4213,32 @@ Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
 
  
 
- /*
- * - LGPL
- *
- * menu separator
- * 
- */
-
 
+  
 /**
- * @class Roo.bootstrap.MenuSeparator
+ * @class Roo.bootstrap.menu.Separator
  * @extends Roo.bootstrap.Component
- * Bootstrap MenuSeparator class
+ * @licence LGPL
+ * @parent Roo.bootstrap.menu.Menu
+ * Bootstrap Separator class
  * 
  * @constructor
- * Create a new MenuItem
+ * Create a new Separator
  * @param {Object} config The config object
  */
 
 
-Roo.bootstrap.MenuSeparator = function(config){
-    Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
+Roo.bootstrap.menu.Separator = function(config){
+    Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
 };
 
-Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
     
     getAutoCreate : function(){
         var cfg = {
-            cls: 'divider',
-            tag : 'li'
+            tag : 'li',
+            cls: 'dropdown-divider divider'
         };
         
         return cfg;
@@ -3842,16 +4256,19 @@ Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
 /**
  * @class Roo.bootstrap.Modal
  * @extends Roo.bootstrap.Component
+ * @parent none builder
+ * @children Roo.bootstrap.Component
  * Bootstrap Modal class
  * @cfg {String} title Title of dialog
  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn
  * @cfg {Boolean} specificTitle default false
- * @cfg {Array} buttons Array of buttons or standard button set..
+ * @cfg {Roo.bootstrap.Button} buttons[] Array of buttons or standard button set..
  * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
  * @cfg {Boolean} animate default true
  * @cfg {Boolean} allow_close default true
  * @cfg {Boolean} fitwindow default false
+ * @cfg {Boolean} bodyOverflow should the body element have overflow auto added default false
  * @cfg {Number} width fixed width - usefull for chrome extension only really.
  * @cfg {Number} height fixed height - usefull for chrome extension only really.
  * @cfg {String} size (sm|lg|xl) default empty
@@ -3999,6 +4416,8 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
             delete this.items;
 
             for(var i =0;i < items.length;i++) {
+                // we force children not to montor widnow resize  - as we do that for them.
+                items[i].monitorWindowResize = false;
                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
             }
         }
@@ -4017,12 +4436,12 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
     {
         // we will default to modal-body-overflow - might need to remove or make optional later.
         var bdy = {
-                cls : 'modal-body enable-modal-body-overflow '
+                cls : 'modal-body ' + (this.bodyOverflow ? 'overflow-auto' : '')
                 html : this.html || ''
         };
 
         var title = {
-            tag: 'h4',
+            tag: 'h5',
             cls : 'modal-title',
             html : this.title
         };
@@ -4136,8 +4555,8 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
             this.headerEditEl =  this.headerEl.select('.form-control',true).first();
             this.headerEl.on('click', function() { this.toggleHeaderInput(true) } , this);
             this.headerEditEl.on('keyup', function(e) {
-                    if(e.isNavKeyPress()){
-                            this.toggleHeaderInput(false)
+                    if([  e.RETURN , e.TAB , e.ESC ].indexOf(e.keyCode) > -1) {
+                        this.toggleHeaderInput(false)
                     }
                 }, this);
             this.headerEditEl.on('blur', function(e) {
@@ -4157,7 +4576,7 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
         
         if (this.fitwindow) {
             
-           
+           this.dialogEl.setStyle( { 'max-width' : '100%' });
             this.setSize(
                 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
                 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
@@ -4206,6 +4625,14 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
         }
         
         this.resizeTo(w,h);
+        // any layout/border etc.. resize..
+        (function () {
+            this.items.forEach( function(e) {
+                e.layout ? e.layout() : false;
+
+            });
+        }).defer(100,this);
+        
     },
 
     show : function() {
@@ -4213,7 +4640,7 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
         if (!this.rendered) {
             this.render();
         }
-
+        this.toggleHeaderInput(false);
         //this.el.setStyle('display', 'block');
         this.el.removeClass('hideing');
         this.el.dom.style.display='block';
@@ -4250,7 +4677,9 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
 
         // set zindex here - otherwise it appears to be ignored...
         this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
-
+        
+        
+        // this is for children that are... layout.Border 
         (function () {
             this.items.forEach( function(e) {
                 e.layout ? e.layout() : false;
@@ -4434,7 +4863,9 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
     },
     toggleHeaderInput : function(is_edit)
     {
-        
+        if (!this.editableTitle) {
+            return; // not editable.
+        }
         if (is_edit && this.is_header_editing) {
             return; // already editing..
         }
@@ -4557,7 +4988,7 @@ Roo.Msg.show({
    animEl: 'elId'
 });
 </code></pre>
- * @singleton
+ * @static
  */
 Roo.bootstrap.MessageBox = function(){
     var dlg, opt, mask, waitTimer;
@@ -5100,8 +5531,9 @@ Roo.Msg = Roo.Msg || Roo.MessageBox;
  */
 
 /**
- * @class Roo.bootstrap.Navbar
+ * @class Roo.bootstrap.nav.Bar
  * @extends Roo.bootstrap.Component
+ * @abstract
  * Bootstrap Navbar class
 
  * @constructor
@@ -5110,8 +5542,8 @@ Roo.Msg = Roo.Msg || Roo.MessageBox;
  */
 
 
-Roo.bootstrap.Navbar = function(config){
-    Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
+Roo.bootstrap.nav.Bar = function(config){
+    Roo.bootstrap.nav.Bar.superclass.constructor.call(this, config);
     this.addEvents({
         // raw events
         /**
@@ -5123,7 +5555,7 @@ Roo.bootstrap.Navbar = function(config){
     });
 };
 
-Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.nav.Bar, Roo.bootstrap.Component,  {
     
     
    
@@ -5270,8 +5702,9 @@ Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
  */
 
 /**
- * @class Roo.bootstrap.NavSimplebar
- * @extends Roo.bootstrap.Navbar
+ * @class Roo.bootstrap.nav.Simplebar
+ * @extends Roo.bootstrap.nav.Bar
+ * @children Roo.bootstrap.nav.Group Roo.bootstrap.Container Roo.bootstrap.form.Form Roo.bootstrap.Row Roo.bootstrap.Column Roo.bootstrap.Link
  * Bootstrap Sidebar class
  *
  * @cfg {Boolean} inverse is inverted color
@@ -5294,11 +5727,11 @@ Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
  */
 
 
-Roo.bootstrap.NavSimplebar = function(config){
-    Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
+Roo.bootstrap.nav.Simplebar = function(config){
+    Roo.bootstrap.nav.Simplebar.superclass.constructor.call(this, config);
 };
 
-Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
+Roo.extend(Roo.bootstrap.nav.Simplebar, Roo.bootstrap.nav.Bar,  {
     
     inverse: false,
     
@@ -5398,8 +5831,9 @@ Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
  */
 
 /**
- * @class Roo.bootstrap.NavHeaderbar
- * @extends Roo.bootstrap.NavSimplebar
+ * @class Roo.bootstrap.nav.Headerbar
+ * @extends Roo.bootstrap.nav.Simplebar
+ * @children Roo.bootstrap.nav.Group Roo.bootstrap.Container Roo.bootstrap.form.Form Roo.bootstrap.Row Roo.bootstrap.Column Roo.bootstrap.Link
  * Bootstrap Sidebar class
  *
  * @cfg {String} brand what is brand
@@ -5416,12 +5850,12 @@ Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
  */
 
 
-Roo.bootstrap.NavHeaderbar = function(config){
-    Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
+Roo.bootstrap.nav.Headerbar = function(config){
+    Roo.bootstrap.nav.Headerbar.superclass.constructor.call(this, config);
       
 };
 
-Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
+Roo.extend(Roo.bootstrap.nav.Headerbar, Roo.bootstrap.nav.Simplebar,  {
     
     position: '',
     brand: '',
@@ -5544,7 +5978,7 @@ Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
     
     initEvents : function()
     {
-        Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
+        Roo.bootstrap.nav.Headerbar.superclass.initEvents.call(this);
         
         if (this.autohide) {
             
@@ -5583,8 +6017,9 @@ Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
  */
 
 /**
- * @class Roo.bootstrap.NavSidebar
- * @extends Roo.bootstrap.Navbar
+ * @class Roo.bootstrap.nav.Sidebar
+ * @extends Roo.bootstrap.nav.Bar
+ * @children Roo.bootstrap.nav.Group Roo.bootstrap.Container Roo.bootstrap.form.Form Roo.bootstrap.Row Roo.bootstrap.Column Roo.bootstrap.Link
  * Bootstrap Sidebar class
  * 
  * @constructor
@@ -5593,11 +6028,11 @@ Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
  */
 
 
-Roo.bootstrap.NavSidebar = function(config){
-    Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
+Roo.bootstrap.nav.Sidebar = function(config){
+    Roo.bootstrap.nav.Sidebar.superclass.constructor.call(this, config);
 };
 
-Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
+Roo.extend(Roo.bootstrap.nav.Sidebar, Roo.bootstrap.nav.Bar,  {
     
     sidebar : true, // used by Navbar Item and NavbarGroup at present...
     
@@ -5628,30 +6063,31 @@ Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
  */
 
 /**
- * @class Roo.bootstrap.NavGroup
+ * @class Roo.bootstrap.nav.Group
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.nav.Item
  * Bootstrap NavGroup class
  * @cfg {String} align (left|right)
  * @cfg {Boolean} inverse
  * @cfg {String} type (nav|pills|tab) default nav
  * @cfg {String} navId - reference Id for navbar.
-
+ * @cfg {Boolean} pilltype default true (turn to off to disable active toggle)
  * 
  * @constructor
  * Create a new nav group
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.NavGroup = function(config){
-    Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
+Roo.bootstrap.nav.Group = function(config){
+    Roo.bootstrap.nav.Group.superclass.constructor.call(this, config);
     this.navItems = [];
    
-    Roo.bootstrap.NavGroup.register(this);
+    Roo.bootstrap.nav.Group.register(this);
      this.addEvents({
         /**
             * @event changed
             * Fires when the active item changes
-            * @param {Roo.bootstrap.NavGroup} this
+            * @param {Roo.bootstrap.nav.Group} this
             * @param {Roo.bootstrap.Navbar.Item} selected The item selected
             * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
          */
@@ -5660,7 +6096,7 @@ Roo.bootstrap.NavGroup = function(config){
     
 };
 
-Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.nav.Group, Roo.bootstrap.Component,  {
     
     align: '',
     inverse: false,
@@ -5668,12 +6104,13 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
     type: 'nav',
     navId : '',
     // private
+    pilltype : true,
     
     navItems : false, 
     
     getAutoCreate : function()
     {
-        var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
+        var cfg = Roo.apply({}, Roo.bootstrap.nav.Group.superclass.getAutoCreate.call(this));
         
         cfg = {
             tag : 'ul',
@@ -5739,7 +6176,7 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
     },
     /**
     * sets the active Navigation item
-    * @param {Roo.bootstrap.NavItem} the new current navitem
+    * @param {Roo.bootstrap.nav.Item} the new current navitem
     */
     setActiveItem : function(item)
     {
@@ -5763,7 +6200,7 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
     },
     /**
     * gets the active Navigation item
-    * @return {Roo.bootstrap.NavItem} the current navitem
+    * @return {Roo.bootstrap.nav.Item} the current navitem
     */
     getActive : function()
     {
@@ -5796,14 +6233,14 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
     },
     /**
     * adds a Navigation item
-    * @param {Roo.bootstrap.NavItem} the navitem to add
+    * @param {Roo.bootstrap.nav.Item} the navitem to add
     */
     addItem : function(cfg)
     {
         if (this.form && Roo.bootstrap.version == 4) {
            cfg.tag = 'div';
        }
-       var cn = new Roo.bootstrap.NavItem(cfg);
+       var cn = new Roo.bootstrap.nav.Item(cfg);
         this.register(cn);
         cn.parentId = this.id;
         cn.onRender(this.el, null);
@@ -5811,7 +6248,7 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
     },
     /**
     * register a Navigation item
-    * @param {Roo.bootstrap.NavItem} the navitem to add
+    * @param {Roo.bootstrap.nav.Item} the navitem to add
     */
     register : function(item)
     {
@@ -5888,12 +6325,12 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
 });
 
  
-Roo.apply(Roo.bootstrap.NavGroup, {
+Roo.apply(Roo.bootstrap.nav.Group, {
     
     groups: {},
      /**
     * register a Navigation Group
-    * @param {Roo.bootstrap.NavGroup} the navgroup to add
+    * @param {Roo.bootstrap.nav.Group} the navgroup to add
     */
     register : function(navgrp)
     {
@@ -5903,12 +6340,12 @@ Roo.apply(Roo.bootstrap.NavGroup, {
     /**
     * fetch a Navigation Group based on the navigation ID
     * @param {string} the navgroup to add
-    * @returns {Roo.bootstrap.NavGroup} the navgroup 
+    * @returns {Roo.bootstrap.nav.Group} the navgroup 
     */
     get: function(navId) {
         if (typeof(this.groups[navId]) == 'undefined') {
             return false;
-            //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
+            //this.register(new Roo.bootstrap.nav.Group({ navId : navId }));
         }
         return this.groups[navId] ;
     }
@@ -5917,20 +6354,17 @@ Roo.apply(Roo.bootstrap.NavGroup, {
     
 });
 
- /*
- * - LGPL
- *
- * row
- * 
- */
-
-/**
- * @class Roo.bootstrap.NavItem
+ /**
+ * @class Roo.bootstrap.nav.Item
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Container Roo.bootstrap.Button
+ * @parent Roo.bootstrap.nav.Group
+ * @licence LGPL
  * Bootstrap Navbar.NavItem class
+ * 
  * @cfg {String} href  link to
- * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
-
+ * @cfg {String} button_weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default none
+ * @cfg {Boolean} button_outline show and outlined button
  * @cfg {String} html content of button
  * @cfg {String} badge text inside badge
  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
@@ -5939,18 +6373,19 @@ Roo.apply(Roo.bootstrap.NavGroup, {
  * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
  * @cfg {Boolean} active Is item active
  * @cfg {Boolean} disabled Is item disabled
+ * @cfg {String} linkcls  Link Class
  * @cfg {Boolean} preventDefault (true | false) default false
  * @cfg {String} tabId the tab that this item activates.
  * @cfg {String} tagtype (a|span) render as a href or span?
  * @cfg {Boolean} animateRef (true|false) link to element default false  
+ * @cfg {Roo.bootstrap.menu.Menu} menu a Menu 
   
  * @constructor
  * Create a new Navbar Item
  * @param {Object} config The config object
  */
-Roo.bootstrap.NavItem = function(config){
-    Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
+Roo.bootstrap.nav.Item = function(config){
+    Roo.bootstrap.nav.Item.superclass.constructor.call(this, config);
     this.addEvents({
         // raw events
         /**
@@ -5962,7 +6397,7 @@ Roo.bootstrap.NavItem = function(config){
         /**
            * @event changed
            * Fires when the active item active state changes
-           * @param {Roo.bootstrap.NavItem} this
+           * @param {Roo.bootstrap.nav.Item} this
            * @param {boolean} state the new state
             
          */
@@ -5970,7 +6405,7 @@ Roo.bootstrap.NavItem = function(config){
         /**
            * @event scrollto
            * Fires when scroll to element
-           * @param {Roo.bootstrap.NavItem} this
+           * @param {Roo.bootstrap.nav.Item} this
            * @param {Object} options
             * @param {Roo.EventObject} e
             
@@ -5980,7 +6415,7 @@ Roo.bootstrap.NavItem = function(config){
    
 };
 
-Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.nav.Item, Roo.bootstrap.Component,  {
     
     href: false,
     html: '',
@@ -5998,7 +6433,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
     was_active : false,
     button_weight : '',
     button_outline : false,
-    
+    linkcls : '',
     navLink: false,
     
     getAutoCreate : function(){
@@ -6008,8 +6443,10 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
             cls: 'nav-item'
         };
         
+       cfg.cls =  typeof(cfg.cls) == 'undefined'  ? '' : cfg.cls;
+       
         if (this.active) {
-            cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
+            cfg.cls +=  ' active' ;
         }
         if (this.disabled) {
             cfg.cls += ' disabled';
@@ -6024,8 +6461,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..
            
@@ -6041,30 +6480,30 @@ 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') {
-               cfg.cn[0].cls = 'nav-link';
+               cfg.cn[0].cls = 'nav-link' +  (this.active ?  ' active'  : '') + ' ' + this.linkcls;
+        
            }
             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>';
             }
         }
@@ -6080,8 +6519,9 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
            this.tag = 'div';
        }
        
-        var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
+        var ret = Roo.bootstrap.nav.Item.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;
     },
       
@@ -6094,11 +6534,11 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
             this.menu = this.addxtype(Roo.apply({}, this.menu));
         }
         
-        this.el.select('a',true).on('click', this.onClick, this);
+        this.el.on('click', this.onClick, this);
         
-        if(this.tagtype == 'span'){
-            this.el.select('span',true).on('click', this.onClick, this);
-        }
+        //if(this.tagtype == 'span'){
+        //    this.el.select('span',true).on('click', this.onClick, this);
+        //}
        
         // at this point parent should be available..
         this.parent().register(this);
@@ -6112,10 +6552,11 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
         }
         
         if(
-                this.preventDefault || 
-                this.href == '#' 
+                this.preventDefault ||
+                               this.href === false ||
+                this.href === '#' 
         ){
-            Roo.log("NavItem - prevent Default?");
+            //Roo.log("NavItem - prevent Default?");
             e.preventDefault();
         }
         
@@ -6157,7 +6598,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
         
         var p =  this.parent();
    
-        if (['tabs','pills'].indexOf(p.type)!==-1) {
+        if (['tabs','pills'].indexOf(p.type)!==-1 && p.pilltype) {
             if (typeof(p.setActiveItem) !== 'undefined') {
                 p.setActiveItem(this);
             }
@@ -6177,7 +6618,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
     {
         if (this.active && !state && this.navId) {
             this.was_active = true;
-            var nv = Roo.bootstrap.NavGroup.get(this.navId);
+            var nv = Roo.bootstrap.nav.Group.get(this.navId);
             if (nv) {
                 nv.clearWasActive(this);
             }
@@ -6216,7 +6657,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
         }
         // if we can not flip to new panel - go back to old nav highlight..
         if (false == tg.showPanel(pan)) {
-            var nv = Roo.bootstrap.NavGroup.get(this.navId);
+            var nv = Roo.bootstrap.nav.Group.get(this.navId);
             if (nv) {
                 var onav = nv.getWasActive();
                 if (onav) {
@@ -6247,7 +6688,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
      */
     tooltipEl : function()
     {
-        return this.el.select('' + this.tagtype + '', true).first();
+        return this.el; //this.tagtype  == 'a' ? this.el  : this.el.select('' + this.tagtype + '', true).first();
     },
     
     scrollToElement : function(e)
@@ -6279,7 +6720,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;
+       
+    } 
 });
  
 
@@ -6295,9 +6746,10 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
  */
 
 /**
- * @class Roo.bootstrap.NavSidebarItem
- * @extends Roo.bootstrap.NavItem
+ * @class Roo.bootstrap.nav.SidebarItem
+ * @extends Roo.bootstrap.nav.Item
  * Bootstrap Navbar.NavSidebarItem class
+ * 
  * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
  * {Boolean} open is the menu open
  * {Boolean} buttonView use button as the tigger el rather that a (default false)
@@ -6308,8 +6760,8 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
  * Create a new Navbar Button
  * @param {Object} config The config object
  */
-Roo.bootstrap.NavSidebarItem = function(config){
-    Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
+Roo.bootstrap.nav.SidebarItem = function(config){
+    Roo.bootstrap.nav.SidebarItem.superclass.constructor.call(this, config);
     this.addEvents({
         // raw events
         /**
@@ -6321,7 +6773,7 @@ Roo.bootstrap.NavSidebarItem = function(config){
         /**
            * @event changed
            * Fires when the active item active state changes
-           * @param {Roo.bootstrap.NavSidebarItem} this
+           * @param {Roo.bootstrap.nav.SidebarItem} this
            * @param {boolean} state the new state
             
          */
@@ -6330,7 +6782,7 @@ Roo.bootstrap.NavSidebarItem = function(config){
    
 };
 
-Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
+Roo.extend(Roo.bootstrap.nav.SidebarItem, Roo.bootstrap.nav.Item,  {
     
     badgeWeight : 'default',
     
@@ -6512,153 +6964,697 @@ Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
  /*
  * - LGPL
  *
- * row
+ * nav progress bar
  * 
  */
 
 /**
- * @class Roo.bootstrap.Row
+ * @class Roo.bootstrap.nav.ProgressBar
  * @extends Roo.bootstrap.Component
- * Bootstrap Row class (contains columns...)
+ * @children Roo.bootstrap.nav.ProgressBarItem
+ * Bootstrap NavProgressBar class
  * 
  * @constructor
- * Create a new Row
+ * Create a new nav progress bar - a bar indicating step along a process
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.Row = function(config){
-    Roo.bootstrap.Row.superclass.constructor.call(this, config);
+Roo.bootstrap.nav.ProgressBar = function(config){
+    Roo.bootstrap.nav.ProgressBar.superclass.constructor.call(this, config);
+
+    this.bullets = this.bullets || [];
+   
+//    Roo.bootstrap.nav.ProgressBar.register(this);
+     this.addEvents({
+        /**
+            * @event changed
+            * Fires when the active item changes
+            * @param {Roo.bootstrap.nav.ProgressBar} this
+            * @param {Roo.bootstrap.nav.ProgressItem} selected The item selected
+            * @param {Roo.bootstrap.nav.ProgressItem} prev The previously selected item 
+         */
+        'changed': true
+     });
+    
 };
 
-Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.nav.ProgressBar, Roo.bootstrap.Component,  {
+    /**
+     * @cfg {Roo.bootstrap.nav.ProgressItem} NavProgressBar:bullets[]
+     * Bullets for the Nav Progress bar for the toolbar
+     */
+    bullets : [],
+    barItems : [],
     
-    getAutoCreate : function(){
-       return {
-            cls: 'row clearfix'
-       };
-    }
+    getAutoCreate : function()
+    {
+        var cfg = Roo.apply({}, Roo.bootstrap.nav.ProgressBar.superclass.getAutoCreate.call(this));
+        
+        cfg = {
+            tag : 'div',
+            cls : 'roo-navigation-bar-group',
+            cn : [
+                {
+                    tag : 'div',
+                    cls : 'roo-navigation-top-bar'
+                },
+                {
+                    tag : 'div',
+                    cls : 'roo-navigation-bullets-bar',
+                    cn : [
+                        {
+                            tag : 'ul',
+                            cls : 'roo-navigation-bar'
+                        }
+                    ]
+                },
+                
+                {
+                    tag : 'div',
+                    cls : 'roo-navigation-bottom-bar'
+                }
+            ]
+            
+        };
+        
+        return cfg;
+        
+    },
     
+    initEvents: function() 
+    {
+        
+    },
     
-});
-
-
- /*
- * - LGPL
- *
- * pagination
- * 
- */
-
-/**
- * @class Roo.bootstrap.Pagination
- * @extends Roo.bootstrap.Component
- * Bootstrap Pagination class
- * @cfg {String} size xs | sm | md | lg
- * @cfg {Boolean} inverse false | true
- * 
- * @constructor
- * Create a new Pagination
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.Pagination = function(config){
-    Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
-};
+    onRender : function(ct, position) 
+    {
+        Roo.bootstrap.nav.ProgressBar.superclass.onRender.call(this, ct, position);
+        
+        if(this.bullets.length){
+            Roo.each(this.bullets, function(b){
+               this.addItem(b);
+            }, this);
+        }
+        
+        this.format();
+        
+    },
+    
+    addItem : function(cfg)
+    {
+        var item = new Roo.bootstrap.nav.ProgressItem(cfg);
+        
+        item.parentId = this.id;
+        item.render(this.el.select('.roo-navigation-bar', true).first(), null);
+        
+        if(cfg.html){
+            var top = new Roo.bootstrap.Element({
+                tag : 'div',
+                cls : 'roo-navigation-bar-text'
+            });
+            
+            var bottom = new Roo.bootstrap.Element({
+                tag : 'div',
+                cls : 'roo-navigation-bar-text'
+            });
+            
+            top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
+            bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
+            
+            var topText = new Roo.bootstrap.Element({
+                tag : 'span',
+                html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
+            });
+            
+            var bottomText = new Roo.bootstrap.Element({
+                tag : 'span',
+                html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
+            });
+            
+            topText.onRender(top.el, null);
+            bottomText.onRender(bottom.el, null);
+            
+            item.topEl = top;
+            item.bottomEl = bottom;
+        }
+        
+        this.barItems.push(item);
+        
+        return item;
+    },
+    
+    getActive : function()
+    {
+        var active = false;
+        
+        Roo.each(this.barItems, function(v){
+            
+            if (!v.isActive()) {
+                return;
+            }
+            
+            active = v;
+            return false;
+            
+        });
+        
+        return active;
+    },
+    
+    setActiveItem : function(item)
+    {
+        var prev = false;
+        
+        Roo.each(this.barItems, function(v){
+            if (v.rid == item.rid) {
+                return ;
+            }
+            
+            if (v.isActive()) {
+                v.setActive(false);
+                prev = v;
+            }
+        });
 
-Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
+        item.setActive(true);
+        
+        this.fireEvent('changed', this, item, prev);
+    },
     
-    cls: false,
-    size: false,
-    inverse: false,
+    getBarItem: function(rid)
+    {
+        var ret = false;
+        
+        Roo.each(this.barItems, function(e) {
+            if (e.rid != rid) {
+                return;
+            }
+            
+            ret =  e;
+            return false;
+        });
+        
+        return ret;
+    },
     
-    getAutoCreate : function(){
-        var cfg = {
-            tag: 'ul',
-                cls: 'pagination'
-        };
-        if (this.inverse) {
-            cfg.cls += ' inverse';
+    indexOfItem : function(item)
+    {
+        var index = false;
+        
+        Roo.each(this.barItems, function(v, i){
+            
+            if (v.rid != item.rid) {
+                return;
+            }
+            
+            index = i;
+            return false
+        });
+        
+        return index;
+    },
+    
+    setActiveNext : function()
+    {
+        var i = this.indexOfItem(this.getActive());
+        
+        if (i > this.barItems.length) {
+            return;
         }
-        if (this.html) {
-            cfg.html=this.html;
+        
+        this.setActiveItem(this.barItems[i+1]);
+    },
+    
+    setActivePrev : function()
+    {
+        var i = this.indexOfItem(this.getActive());
+        
+        if (i  < 1) {
+            return;
         }
-        if (this.cls) {
-            cfg.cls += " " + this.cls;
+        
+        this.setActiveItem(this.barItems[i-1]);
+    },
+    
+    format : function()
+    {
+        if(!this.barItems.length){
+            return;
         }
-        return cfg;
+     
+        var width = 100 / this.barItems.length;
+        
+        Roo.each(this.barItems, function(i){
+            i.el.setStyle('width', width + '%');
+            i.topEl.el.setStyle('width', width + '%');
+            i.bottomEl.el.setStyle('width', width + '%');
+        }, this);
+        
     }
-   
+    
 });
-
-
- /*
+/*
  * - LGPL
  *
- * Pagination item
+ * Nav Progress Item
  * 
  */
 
-
 /**
- * @class Roo.bootstrap.PaginationItem
+ * @class Roo.bootstrap.nav.ProgressBarItem
  * @extends Roo.bootstrap.Component
- * Bootstrap PaginationItem class
- * @cfg {String} html text
- * @cfg {String} href the link
- * @cfg {Boolean} preventDefault (true | false) default true
- * @cfg {Boolean} active (true | false) default false
- * @cfg {Boolean} disabled default false
- * 
+ * Bootstrap NavProgressBarItem class
+ * @cfg {String} rid the reference id
+ * @cfg {Boolean} active (true|false) Is item active default false
+ * @cfg {Boolean} disabled (true|false) Is item active default false
+ * @cfg {String} html
+ * @cfg {String} position (top|bottom) text position default bottom
+ * @cfg {String} icon show icon instead of number
  * 
  * @constructor
- * Create a new PaginationItem
+ * Create a new NavProgressBarItem
  * @param {Object} config The config object
  */
-
-
-Roo.bootstrap.PaginationItem = function(config){
-    Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
+Roo.bootstrap.nav.ProgressBarItem = function(config){
+    Roo.bootstrap.nav.ProgressBarItem.superclass.constructor.call(this, config);
     this.addEvents({
         // raw events
         /**
          * @event click
          * The raw click event for the entire grid.
+         * @param {Roo.bootstrap.nav.ProgressBarItem} this
          * @param {Roo.EventObject} e
          */
         "click" : true
     });
+   
 };
 
-Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.nav.ProgressBarItem, Roo.bootstrap.Component,  {
     
-    href : false,
-    html : false,
-    preventDefault: true,
+    rid : '',
     active : false,
-    cls : false,
-    disabled: false,
+    disabled : false,
+    html : '',
+    position : 'bottom',
+    icon : false,
     
-    getAutoCreate : function(){
-        var cfg= {
-           tag: 'li',
-           cn: [
-               {
-                   tag : 'a',
-                   href : this.href ? this.href : '#',
-                   html : this.html ? this.html : ''
-               }
-           ]
-        };
-        
-        if(this.cls){
-            cfg.cls = this.cls;
-        }
+    getAutoCreate : function()
+    {
+        var iconCls = 'roo-navigation-bar-item-icon';
         
-        if(this.disabled){
-            cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
-        }
+        iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
+        
+        var cfg = {
+            tag: 'li',
+            cls: 'roo-navigation-bar-item',
+            cn : [
+                {
+                    tag : 'i',
+                    cls : iconCls
+                }
+            ]
+        };
+        
+        if(this.active){
+            cfg.cls += ' active';
+        }
+        if(this.disabled){
+            cfg.cls += ' disabled';
+        }
+        
+        return cfg;
+    },
+    
+    disable : function()
+    {
+        this.setDisabled(true);
+    },
+    
+    enable : function()
+    {
+        this.setDisabled(false);
+    },
+    
+    initEvents: function() 
+    {
+        this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
+        
+        this.iconEl.on('click', this.onClick, this);
+    },
+    
+    onClick : function(e)
+    {
+        e.preventDefault();
+        
+        if(this.disabled){
+            return;
+        }
+        
+        if(this.fireEvent('click', this, e) === false){
+            return;
+        };
+        
+        this.parent().setActiveItem(this);
+    },
+    
+    isActive: function () 
+    {
+        return this.active;
+    },
+    
+    setActive : function(state)
+    {
+        if(this.active == state){
+            return;
+        }
+        
+        this.active = state;
+        
+        if (state) {
+            this.el.addClass('active');
+            return;
+        }
+        
+        this.el.removeClass('active');
+        
+        return;
+    },
+    
+    setDisabled : function(state)
+    {
+        if(this.disabled == state){
+            return;
+        }
+        
+        this.disabled = state;
+        
+        if (state) {
+            this.el.addClass('disabled');
+            return;
+        }
+        
+        this.el.removeClass('disabled');
+    },
+    
+    tooltipEl : function()
+    {
+        return this.el.select('.roo-navigation-bar-item-icon', true).first();;
+    }
+});
+
+ /*
+ * - LGPL
+ *
+ *  Breadcrumb Nav
+ * 
+ */
+Roo.namespace('Roo.bootstrap.breadcrumb');
+
+
+/**
+ * @class Roo.bootstrap.breadcrumb.Nav
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Breadcrumb Nav Class
+ *  
+ * @children Roo.bootstrap.breadcrumb.Item
+ * 
+ * @constructor
+ * Create a new breadcrumb.Nav
+ * @param {Object} config The config object
+ */
+
+
+Roo.bootstrap.breadcrumb.Nav = function(config){
+    Roo.bootstrap.breadcrumb.Nav.superclass.constructor.call(this, config);
+    
+    
+};
+
+Roo.extend(Roo.bootstrap.breadcrumb.Nav, Roo.bootstrap.Component,  {
+    
+    getAutoCreate : function()
+    {
+
+        var cfg = {
+            tag: 'nav',
+            cn : [
+                {
+                    tag : 'ol',
+                    cls : 'breadcrumb'
+                }
+            ]
+            
+        };
+          
+        return cfg;
+    },
+    
+    initEvents: function()
+    {
+        this.olEl = this.el.select('ol',true).first();    
+    },
+    getChildContainer : function()
+    {
+        return this.olEl;  
+    }
+    
+});
+
+ /*
+ * - LGPL
+ *
+ *  Breadcrumb Item
+ * 
+ */
+
+
+/**
+ * @class Roo.bootstrap.breadcrumb.Nav
+ * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Component
+ * @parent Roo.bootstrap.breadcrumb.Nav
+ * Bootstrap Breadcrumb Nav Class
+ *  
+ * 
+ * @cfg {String} html the content of the link.
+ * @cfg {String} href where it links to if '#' is used the link will be handled by onClick.
+ * @cfg {Boolean} active is it active
+
+ * 
+ * @constructor
+ * Create a new breadcrumb.Nav
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.breadcrumb.Item = function(config){
+    Roo.bootstrap.breadcrumb.Item.superclass.constructor.call(this, config);
+    this.addEvents({
+        // img events
+        /**
+         * @event click
+         * The img click event for the img.
+         * @param {Roo.EventObject} e
+         */
+        "click" : true
+    });
+    
+};
+
+Roo.extend(Roo.bootstrap.breadcrumb.Item, Roo.bootstrap.Component,  {
+    
+    href: false,
+    html : '',
+    
+    getAutoCreate : function()
+    {
+
+        var cfg = {
+            tag: 'li',
+            cls : 'breadcrumb-item' + (this.active ? ' active' : '')
+        };
+        if (this.href !== false) {
+            cfg.cn = [{
+                tag : 'a',
+                href : this.href,
+                html : this.html
+            }];
+        } else {
+            cfg.html = this.html;
+        }
+        
+        return cfg;
+    },
+    
+    initEvents: function()
+    {
+        if (this.href) {
+            this.el.select('a', true).first().on('click',this.onClick, this)
+        }
+        
+    },
+    onClick : function(e)
+    {
+        e.preventDefault();
+        this.fireEvent('click',this,  e);
+    }
+    
+});
+
+ /*
+ * - LGPL
+ *
+ * row
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.Row
+ * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Component
+ * Bootstrap Row class (contains columns...)
+ * 
+ * @constructor
+ * Create a new Row
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.Row = function(config){
+    Roo.bootstrap.Row.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
+    
+    getAutoCreate : function(){
+       return {
+            cls: 'row clearfix'
+       };
+    }
+    
+    
+});
+
+
+ /*
+ * - LGPL
+ *
+ * pagination
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.Pagination
+ * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Pagination
+ * Bootstrap Pagination class
+ * 
+ * @cfg {String} size (xs|sm|md|lg|xl)
+ * @cfg {Boolean} inverse 
+ * 
+ * @constructor
+ * Create a new Pagination
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.Pagination = function(config){
+    Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
+    
+    cls: false,
+    size: false,
+    inverse: false,
+    
+    getAutoCreate : function(){
+        var cfg = {
+            tag: 'ul',
+                cls: 'pagination'
+        };
+        if (this.inverse) {
+            cfg.cls += ' inverse';
+        }
+        if (this.html) {
+            cfg.html=this.html;
+        }
+        if (this.cls) {
+            cfg.cls += " " + this.cls;
+        }
+        return cfg;
+    }
+   
+});
+
+
+ /*
+ * - LGPL
+ *
+ * Pagination item
+ * 
+ */
+
+
+/**
+ * @class Roo.bootstrap.PaginationItem
+ * @extends Roo.bootstrap.Component
+ * Bootstrap PaginationItem class
+ * @cfg {String} html text
+ * @cfg {String} href the link
+ * @cfg {Boolean} preventDefault (true | false) default true
+ * @cfg {Boolean} active (true | false) default false
+ * @cfg {Boolean} disabled default false
+ * 
+ * 
+ * @constructor
+ * Create a new PaginationItem
+ * @param {Object} config The config object
+ */
+
+
+Roo.bootstrap.PaginationItem = function(config){
+    Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
+    this.addEvents({
+        // raw events
+        /**
+         * @event click
+         * The raw click event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "click" : true
+    });
+};
+
+Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
+    
+    href : false,
+    html : false,
+    preventDefault: true,
+    active : false,
+    cls : false,
+    disabled: false,
+    
+    getAutoCreate : function(){
+        var cfg= {
+           tag: 'li',
+           cn: [
+               {
+                   tag : 'a',
+                   href : this.href ? this.href : '#',
+                   html : this.html ? this.html : ''
+               }
+           ]
+        };
+        
+        if(this.cls){
+            cfg.cls = this.cls;
+        }
+        
+        if(this.disabled){
+            cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
+        }
         
         if(this.active){
             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
@@ -6742,545 +7738,623 @@ Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
  * Fork - LGPL
  * <script type="text/javascript">
  */
-
-/**
- * @class Roo.grid.ColumnModel
- * @extends Roo.util.Observable
- * This is the default implementation of a ColumnModel used by the Grid. It defines
- * the columns in the grid.
- * <br>Usage:<br>
- <pre><code>
- var colModel = new Roo.grid.ColumnModel([
-       {header: "Ticker", width: 60, sortable: true, locked: true},
-       {header: "Company Name", width: 150, sortable: true},
-       {header: "Market Cap.", width: 100, sortable: true},
-       {header: "$ Sales", width: 100, sortable: true, renderer: money},
-       {header: "Employees", width: 100, sortable: true, resizable: false}
- ]);
- </code></pre>
- * <p>
- * The config options listed for this class are options which may appear in each
- * individual column definition.
- * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
+ /**
+ * @extends Roo.dd.DDProxy
+ * @class Roo.grid.SplitDragZone
+ * Support for Column Header resizing
  * @constructor
- * @param {Object} config An Array of column config objects. See this class's
- * config objects for details.
-*/
-Roo.grid.ColumnModel = function(config){
-       /**
-     * The config passed into the constructor
-     */
-    this.config = config;
-    this.lookup = {};
+ * @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,
 
-    // 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];
+    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();
         }
-        if(typeof c.id == "undefined"){
-            c.id = Roo.id();
+        
+        
+        
+        // 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';
         }
-        if(c.editor && c.editor.xtype){
-            c.editor  = Roo.factory(c.editor, Roo.grid);
+        
+        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);
+            }
         }
-        if(c.editor && c.editor.isFormField){
-            c.editor = new Roo.grid.GridEditor(c.editor);
+    },
+
+    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.lookup[c.id] = c;
+        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">
+ */
 
-    /**
-     * The width of columns which have no width specified (defaults to 100)
-     * @type Number
-     */
-    this.defaultWidth = 100;
+/**
+ * @class Roo.grid.AbstractSelectionModel
+ * @extends Roo.util.Observable
+ * @abstract
+ * 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();
+    },
 
     /**
-     * Default sortable of columns which have no sortable specified (defaults to false)
-     * @type Boolean
+     * Locks the selections.
      */
-    this.defaultSortable = false;
+    lock : function(){
+        this.locked = true;
+    },
 
-    this.addEvents({
-        /**
-            * @event widthchange
-            * Fires when the width of a column changes.
-            * @param {ColumnModel} this
-            * @param {Number} columnIndex The column index
-            * @param {Number} newWidth The new width
-            */
-           "widthchange": true,
-        /**
-            * @event headerchange
-            * Fires when the text of a header changes.
-            * @param {ColumnModel} this
-            * @param {Number} columnIndex The column index
-            * @param {Number} newText The new header text
-            */
-           "headerchange": true,
-        /**
-            * @event hiddenchange
-            * Fires when a column is hidden or "unhidden".
-            * @param {ColumnModel} this
-            * @param {Number} columnIndex The column index
-            * @param {Boolean} hidden true if hidden, false otherwise
-            */
-           "hiddenchange": true,
-           /**
-         * @event columnmoved
-         * Fires when a column is moved.
-         * @param {ColumnModel} this
-         * @param {Number} oldIndex
-         * @param {Number} newIndex
-         */
-        "columnmoved" : true,
-        /**
-         * @event columlockchange
-         * Fires when a column's locked state is changed
-         * @param {ColumnModel} this
-         * @param {Number} colIndex
-         * @param {Boolean} locked true if locked
-         */
-        "columnlockchange" : true
-    });
-    Roo.grid.ColumnModel.superclass.constructor.call(this);
-};
-Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
-     * @cfg {String} header The header text to display in the Grid view.
+     * Unlocks the selections.
      */
+    unlock : function(){
+        this.locked = false;
+    },
+
     /**
-     * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
-     * {@link Roo.data.Record} definition from which to draw the column's value. If not
-     * specified, the column's index is used as an index into the Record's data Array.
-     */
-    /**
-     * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
-     * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
-     */
-    /**
-     * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
-     * Defaults to the value of the {@link #defaultSortable} property.
-     * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
-     */
-    /**
-     * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
-     */
-    /**
-     * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
-     */
-    /**
-     * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
-     */
-    /**
-     * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
-     */
-    /**
-     * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
-     * given the cell's data value. See {@link #setRenderer}. If not specified, the
-     * default renderer returns the escaped data value. If an object is returned (bootstrap only)
-     * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
+     * 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,
        /**
-     * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
-     */
-    /**
-     * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
-     */
-    /**
-     * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc).  Defaults to undefined.
-     */
-    /**
-     * @cfg {String} cursor (Optional)
-     */
-    /**
-     * @cfg {String} tooltip (Optional)
-     */
-    /**
-     * @cfg {Number} xs (Optional)
-     */
-    /**
-     * @cfg {Number} sm (Optional)
-     */
-    /**
-     * @cfg {Number} md (Optional)
-     */
-    /**
-     * @cfg {Number} lg (Optional)
-     */
-    /**
-     * Returns the id of the column at the specified index.
-     * @param {Number} index The column index
-     * @return {String} the id
-     */
-    getColumnId : function(index){
-        return this.config[index].id;
-    },
+        * @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,  {
     /**
-     * Returns the column for a specified id.
-     * @param {String} id The column id
-     * @return {Object} the column
+     * @cfg {Boolean} singleSelect
+     * True to allow selection of only one row at a time (defaults to false)
      */
-    getColumnById : function(id){
-        return this.lookup[id];
-    },
+    singleSelect : false,
 
-    
-    /**
-     * Returns the column for a specified dataIndex.
-     * @param {String} dataIndex The column dataIndex
-     * @return {Object|Boolean} the column or false if not found
-     */
-    getColumnByDataIndex: function(dataIndex){
-        var index = this.findColumnIndex(dataIndex);
-        return index > -1 ? this.config[index] : false;
-    },
-    
-    /**
-     * Returns the index for a specified column id.
-     * @param {String} id The column id
-     * @return {Number} the index, or -1 if not found
-     */
-    getIndexById : function(id){
-        for(var i = 0, len = this.config.length; i < len; i++){
-            if(this.config[i].id == id){
-                return i;
-            }
+    // 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);
         }
-        return -1;
+        // 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);
     },
-    
-    /**
-     * Returns the index for a specified column dataIndex.
-     * @param {String} dataIndex The column dataIndex
-     * @return {Number} the index, or -1 if not found
-     */
-    
-    findColumnIndex : function(dataIndex){
-        for(var i = 0, len = this.config.length; i < len; i++){
-            if(this.config[i].dataIndex == dataIndex){
-                return i;
+
+    // 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);
             }
-        }
-        return -1;
-    },
-    
-    
-    moveColumn : function(oldIndex, newIndex){
-        var c = this.config[oldIndex];
-        this.config.splice(oldIndex, 1);
-        this.config.splice(newIndex, 0, c);
-        this.dataMap = null;
-        this.fireEvent("columnmoved", this, oldIndex, newIndex);
+        });
     },
 
-    isLocked : function(colIndex){
-        return this.config[colIndex].locked === true;
+    // private
+    onRemove : function(v, index, r){
+        this.selections.remove(r);
     },
 
-    setLocked : function(colIndex, value, suppressEvent){
-        if(this.isLocked(colIndex) == value){
-            return;
-        }
-        this.config[colIndex].locked = value;
-        if(!suppressEvent){
-            this.fireEvent("columnlockchange", this, colIndex, value);
+    // private
+    onRowUpdated : function(v, index, r){
+        if(this.isSelected(r)){
+            v.onRowSelect(index);
         }
     },
 
-    getTotalLockedWidth : function(){
-        var totalWidth = 0;
-        for(var i = 0; i < this.config.length; i++){
-            if(this.isLocked(i) && !this.isHidden(i)){
-                this.totalWidth += this.getColumnWidth(i);
-            }
+    /**
+     * 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();
         }
-        return totalWidth;
-    },
-
-    getLockedCount : function(){
-        for(var i = 0, len = this.config.length; i < len; i++){
-            if(!this.isLocked(i)){
-                return i;
-            }
+        var ds = this.grid.ds;
+        for(var i = 0, len = records.length; i < len; i++){
+            this.selectRow(ds.indexOf(records[i]), true);
         }
-        
-        return this.config.length;
     },
 
     /**
-     * Returns the number of columns.
+     * Gets the number of selected rows.
      * @return {Number}
      */
-    getColumnCount : function(visibleOnly){
-        if(visibleOnly === true){
-            var c = 0;
-            for(var i = 0, len = this.config.length; i < len; i++){
-                if(!this.isHidden(i)){
-                    c++;
-                }
-            }
-            return c;
-        }
-        return this.config.length;
+    getCount : function(){
+        return this.selections.length;
     },
 
     /**
-     * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
-     * @param {Function} fn
-     * @param {Object} scope (optional)
-     * @return {Array} result
+     * Selects the first row in the grid.
      */
-    getColumnsBy : function(fn, scope){
-        var r = [];
-        for(var i = 0, len = this.config.length; i < len; i++){
-            var c = this.config[i];
-            if(fn.call(scope||this, c, i) === true){
-                r[r.length] = c;
-            }
-        }
-        return r;
+    selectFirstRow : function(){
+        this.selectRow(0);
     },
 
     /**
-     * Returns true if the specified column is sortable.
-     * @param {Number} col The column index
-     * @return {Boolean}
+     * Select the last row.
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
-    isSortable : function(col){
-        if(typeof this.config[col].sortable == "undefined"){
-            return this.defaultSortable;
-        }
-        return this.config[col].sortable;
+    selectLastRow : function(keepExisting){
+        this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
     },
 
     /**
-     * Returns the rendering (formatting) function defined for the column.
-     * @param {Number} col The column index.
-     * @return {Function} The function used to render the cell. See {@link #setRenderer}.
+     * Selects the row immediately following the last selected row.
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
-    getRenderer : function(col){
-        if(!this.config[col].renderer){
-            return Roo.grid.ColumnModel.defaultRenderer;
+    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);
         }
-        return this.config[col].renderer;
     },
 
     /**
-     * Sets the rendering (formatting) function for a column.
-     * @param {Number} col The column index
-     * @param {Function} fn The function to use to process the cell's raw data
-     * to return HTML markup for the grid view. The render function is called with
-     * the following parameters:<ul>
-     * <li>Data value.</li>
-     * <li>Cell metadata. An object in which you may set the following attributes:<ul>
-     * <li>css A CSS style string to apply to the table cell.</li>
-     * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
-     * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
-     * <li>Row index</li>
-     * <li>Column index</li>
-     * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
+     * Selects the row that precedes the last selected row.
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
-    setRenderer : function(col, fn){
-        this.config[col].renderer = fn;
+    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 width for the specified column.
-     * @param {Number} col The column index
-     * @return {Number}
+     * Returns the selected records
+     * @return {Array} Array of selected records
      */
-    getColumnWidth : function(col){
-        return this.config[col].width * 1 || this.defaultWidth;
+    getSelections : function(){
+        return [].concat(this.selections.items);
     },
 
     /**
-     * Sets the width for a column.
-     * @param {Number} col The column index
-     * @param {Number} width The new width
+     * Returns the first selected record.
+     * @return {Record}
      */
-    setColumnWidth : function(col, width, suppressEvent){
-        this.config[col].width = width;
-        this.totalWidth = null;
-        if(!suppressEvent){
-             this.fireEvent("widthchange", this, col, width);
-        }
+    getSelected : function(){
+        return this.selections.itemAt(0);
     },
 
+
     /**
-     * Returns the total width of all columns.
-     * @param {Boolean} includeHidden True to include hidden column widths
-     * @return {Number}
+     * Clears all selections.
      */
-    getTotalWidth : function(includeHidden){
-        if(!this.totalWidth){
-            this.totalWidth = 0;
-            for(var i = 0, len = this.config.length; i < len; i++){
-                if(includeHidden || !this.isHidden(i)){
-                    this.totalWidth += this.getColumnWidth(i);
-                }
-            }
+    clearSelections : function(fast){
+        if(this.locked) {
+            return;
         }
-        return this.totalWidth;
+        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;
     },
 
-    /**
-     * Returns the header for the specified column.
-     * @param {Number} col The column index
-     * @return {String}
-     */
-    getColumnHeader : function(col){
-        return this.config[col].header;
-    },
 
     /**
-     * Sets the header for a column.
-     * @param {Number} col The column index
-     * @param {String} header The new header
+     * Selects all rows.
      */
-    setColumnHeader : function(col, header){
-        this.config[col].header = header;
-        this.fireEvent("headerchange", this, col, header);
+    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 the tooltip for the specified column.
-     * @param {Number} col The column index
-     * @return {String}
-     */
-    getColumnTooltip : function(col){
-            return this.config[col].tooltip;
-    },
-    /**
-     * Sets the tooltip for a column.
-     * @param {Number} col The column index
-     * @param {String} tooltip The new tooltip
+     * Returns True if there is a selection.
+     * @return {Boolean}
      */
-    setColumnTooltip : function(col, tooltip){
-            this.config[col].tooltip = tooltip;
+    hasSelection : function(){
+        return this.selections.length > 0;
     },
 
     /**
-     * Returns the dataIndex for the specified column.
-     * @param {Number} col The column index
-     * @return {Number}
+     * Returns True if the specified row is selected.
+     * @param {Number/Record} record The record or index of the record to check
+     * @return {Boolean}
      */
-    getDataIndex : function(col){
-        return this.config[col].dataIndex;
+    isSelected : function(index){
+        var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
+        return (r && this.selections.key(r.id) ? true : false);
     },
 
     /**
-     * Sets the dataIndex for a column.
-     * @param {Number} col The column index
-     * @param {Number} dataIndex The new dataIndex
+     * Returns True if the specified record id is selected.
+     * @param {String} id The id of record to check
+     * @return {Boolean}
      */
-    setDataIndex : function(col, dataIndex){
-        this.config[col].dataIndex = dataIndex;
+    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);
+        }
+    },
     
     /**
-     * Returns true if the cell is editable.
-     * @param {Number} colIndex The column index
-     * @param {Number} rowIndex The row index - this is nto actually used..?
-     * @return {Boolean}
+     * Selects multiple rows.
+     * @param {Array} rows Array of the indexes of the row to select
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
-    isCellEditable : function(colIndex, rowIndex){
-        return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
+    selectRows : function(rows, keepExisting){
+        if(!keepExisting){
+            this.clearSelections();
+        }
+        for(var i = 0, len = rows.length; i < len; i++){
+            this.selectRow(rows[i], true);
+        }
     },
 
     /**
-     * Returns the editor defined for the cell/column.
-     * return false or null to disable editing.
-     * @param {Number} colIndex The column index
-     * @param {Number} rowIndex The row index
-     * @return {Object}
+     * 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
      */
-    getCellEditor : function(colIndex, rowIndex){
-        return this.config[colIndex].editor;
+    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);
+            }
+        }
     },
 
     /**
-     * Sets if a column is editable.
-     * @param {Number} col The column index
-     * @param {Boolean} editable True if the column is editable
+     * 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
      */
-    setEditable : function(col, editable){
-        this.config[col].editable = editable;
+    deselectRange : function(startRow, endRow, preventViewNotify){
+        if(this.locked) {
+            return;
+        }
+        for(var i = startRow; i <= endRow; i++){
+            this.deselectRow(i, preventViewNotify);
+        }
     },
 
-
     /**
-     * Returns true if the column is hidden.
-     * @param {Number} colIndex The column index
-     * @return {Boolean}
+     * Selects a row.
+     * @param {Number} row The index of the row to select
+     * @param {Boolean} keepExisting (optional) True to keep existing selections
      */
-    isHidden : function(colIndex){
-        return this.config[colIndex].hidden;
+    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);
+        }
     },
 
-
     /**
-     * Returns true if the column width cannot be changed
+     * Deselects a row.
+     * @param {Number} row The index of the row to deselect
      */
-    isFixed : function(colIndex){
-        return this.config[colIndex].fixed;
+    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);
     },
 
-    /**
-     * Returns true if the column can be resized
-     * @return {Boolean}
-     */
-    isResizable : function(colIndex){
-        return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
-    },
-    /**
-     * Sets if a column is hidden.
-     * @param {Number} colIndex The column index
-     * @param {Boolean} hidden True if the column is hidden
-     */
-    setHidden : function(colIndex, hidden){
-        this.config[colIndex].hidden = hidden;
-        this.totalWidth = null;
-        this.fireEvent("hiddenchange", this, colIndex, hidden);
+    // private
+    restoreLast : function(){
+        if(this._last){
+            this.last = this._last;
+        }
     },
 
-    /**
-     * Sets the editor for a column.
-     * @param {Number} col The column index
-     * @param {Object} editor The editor object
-     */
-    setEditor : function(col, editor){
-        this.config[col].editor = editor;
-    }
-});
+    // private
+    acceptsNav : function(row, col, cm){
+        return !cm.isHidden(col) && cm.isCellEditable(col, row);
+    },
 
-Roo.grid.ColumnModel.defaultRenderer = function(value)
-{
-    if(typeof value == "object") {
-        return value;
+    // 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]);
+        }
     }
-       if(typeof value == "string" && value.length < 1){
-           return "&#160;";
-       }
-    
-       return String.format("{0}", value);
-};
-
-// Alias for backwards compatibility
-Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
-/*
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -7291,691 +8365,1456 @@ Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
  * <script type="text/javascript">
  */
  
+
 /**
- * @class Roo.LoadMask
- * A simple utility class for generically masking elements while loading data.  If the element being masked has
- * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
- * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
- * element's UpdateManager load indicator and will be destroyed after the initial load.
+ * @class Roo.grid.ColumnModel
+ * @extends Roo.util.Observable
+ * This is the default implementation of a ColumnModel used by the Grid. It defines
+ * the columns in the grid.
+ * <br>Usage:<br>
+ <pre><code>
+ var colModel = new Roo.grid.ColumnModel([
+       {header: "Ticker", width: 60, sortable: true, locked: true},
+       {header: "Company Name", width: 150, sortable: true},
+       {header: "Market Cap.", width: 100, sortable: true},
+       {header: "$ Sales", width: 100, sortable: true, renderer: money},
+       {header: "Employees", width: 100, sortable: true, resizable: false}
+ ]);
+ </code></pre>
+ * <p>
+ * The config options listed for this class are options which may appear in each
+ * individual column definition.
+ * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
  * @constructor
- * Create a new LoadMask
- * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
- * @param {Object} config The config object
- */
-Roo.LoadMask = function(el, config){
-    this.el = Roo.get(el);
-    Roo.apply(this, config);
-    if(this.store){
-        this.store.on('beforeload', this.onBeforeLoad, this);
-        this.store.on('load', this.onLoad, this);
-        this.store.on('loadexception', this.onLoadException, this);
-        this.removeMask = false;
-    }else{
-        var um = this.el.getUpdateManager();
-        um.showLoadIndicator = false; // disable the default indicator
-        um.on('beforeupdate', this.onBeforeLoad, this);
-        um.on('update', this.onLoad, this);
-        um.on('failure', this.onLoad, this);
-        this.removeMask = true;
+ * @param {Object} config An Array of column config objects. See this class's
+ * config objects for details.
+*/
+Roo.grid.ColumnModel = function(config){
+       /**
+     * The config passed into the constructor
+     */
+    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++){
+       this.addColumn(config[i]);
+       
     }
-};
 
-Roo.LoadMask.prototype = {
     /**
-     * @cfg {Boolean} removeMask
-     * 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.
+     * The width of columns which have no width specified (defaults to 100)
+     * @type Number
      */
+    this.defaultWidth = 100;
+
     /**
-     * @cfg {String} msg
-     * The text to display in a centered loading message box (defaults to 'Loading...')
+     * Default sortable of columns which have no sortable specified (defaults to false)
+     * @type Boolean
      */
-    msg : 'Loading...',
+    this.defaultSortable = false;
+
+    this.addEvents({
+        /**
+            * @event widthchange
+            * Fires when the width of a column changes.
+            * @param {ColumnModel} this
+            * @param {Number} columnIndex The column index
+            * @param {Number} newWidth The new width
+            */
+           "widthchange": true,
+        /**
+            * @event headerchange
+            * Fires when the text of a header changes.
+            * @param {ColumnModel} this
+            * @param {Number} columnIndex The column index
+            * @param {Number} newText The new header text
+            */
+           "headerchange": true,
+        /**
+            * @event hiddenchange
+            * Fires when a column is hidden or "unhidden".
+            * @param {ColumnModel} this
+            * @param {Number} columnIndex The column index
+            * @param {Boolean} hidden true if hidden, false otherwise
+            */
+           "hiddenchange": true,
+           /**
+         * @event columnmoved
+         * Fires when a column is moved.
+         * @param {ColumnModel} this
+         * @param {Number} oldIndex
+         * @param {Number} newIndex
+         */
+        "columnmoved" : true,
+        /**
+         * @event columlockchange
+         * Fires when a column's locked state is changed
+         * @param {ColumnModel} this
+         * @param {Number} colIndex
+         * @param {Boolean} locked true if locked
+         */
+        "columnlockchange" : true
+    });
+    Roo.grid.ColumnModel.superclass.constructor.call(this);
+};
+Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
-     * @cfg {String} msgCls
-     * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
+     * @cfg {String} header [required] 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
      */
-    msgCls : 'x-mask-loading',
-
     /**
-     * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
-     * @type Boolean
+     * @cfg {String} dataIndex  The name of the field in the grid's {@link Roo.data.Store}'s
+     * {@link Roo.data.Record} definition from which to draw the column's value. If not
+     * specified, the column's index is used as an index into the Record's data Array.
      */
-    disabled: false,
+    /**
+     * @cfg {Number} width  The initial width in pixels of the column. Using this
+     * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
+     */
+    /**
+     * @cfg {Boolean} sortable True if sorting is to be allowed on this column.
+     * Defaults to the value of the {@link #defaultSortable} property.
+     * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
+     */
+    /**
+     * @cfg {Boolean} locked  True to lock the column in place while scrolling the Grid.  Defaults to false.
+     */
+    /**
+     * @cfg {Boolean} fixed  True if the column width cannot be changed.  Defaults to false.
+     */
+    /**
+     * @cfg {Boolean} resizable  False to disable column resizing. Defaults to true.
+     */
+    /**
+     * @cfg {Boolean} hidden  True to hide the column. Defaults to false.
+     */
+    /**
+     * @cfg {Function} renderer A function used to generate HTML markup for a cell
+     * given the cell's data value. See {@link #setRenderer}. If not specified, the
+     * default renderer returns the escaped data value. If an object is returned (bootstrap only)
+     * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
+     */
+       /**
+     * @cfg {Roo.grid.GridEditor} editor  For grid editors - returns the grid editor 
+     */
+    /**
+     * @cfg {String} align (left|right) Set the CSS text-align property of the column.  Defaults to undefined (left).
+     */
+    /**
+     * @cfg {String} valign (top|bottom|middle) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc).  Defaults to undefined (middle)
+     */
+    /**
+     * @cfg {String} cursor ( auto|default|none|context-menu|help|pointer|progress|wait|cell|crosshair|text|vertical-text|alias|copy|move|no-drop|not-allowed|e-resize|n-resize|ne-resize|nw-resize|s-resize|se-resize|sw-resize|w-resize|ew-resize|ns-resize|nesw-resize|nwse-resize|col-resize|row-resize|all-scroll|zoom-in|zoom-out|grab|grabbing)
+     */
+    /**
+     * @cfg {String} tooltip mouse over tooltip text
+     */
+    /**
+     * @cfg {Number} xs  can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * @cfg {Number} sm can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * @cfg {Number} md can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * @cfg {Number} lg   can be '0' for hidden at this size (number less than 12)
+     */
+       /**
+     * @cfg {Number} xl   can be '0' for hidden at this size (number less than 12)
+     */
+    /**
+     * Returns the id of the column at the specified index.
+     * @param {Number} index The column index
+     * @return {String} the id
+     */
+    getColumnId : function(index){
+        return this.config[index].id;
+    },
 
     /**
-     * Disables the mask to prevent it from being displayed
+     * Returns the column for a specified id.
+     * @param {String} id The column id
+     * @return {Object} the column
      */
-    disable : function(){
-       this.disabled = true;
+    getColumnById : function(id){
+        return this.lookup[id];
     },
 
+    
     /**
-     * Enables the mask so that it can be displayed
+     * Returns the column Object for a specified dataIndex.
+     * @param {String} dataIndex The column dataIndex
+     * @return {Object|Boolean} the column or false if not found
      */
-    enable : function(){
-        this.disabled = false;
+    getColumnByDataIndex: function(dataIndex){
+        var index = this.findColumnIndex(dataIndex);
+        return index > -1 ? this.config[index] : false;
     },
     
-    onLoadException : function()
-    {
-        Roo.log(arguments);
-        
-        if (typeof(arguments[3]) != 'undefined') {
-            Roo.MessageBox.alert("Error loading",arguments[3]);
-        } 
-        /*
-        try {
-            if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
-                Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
-            }   
-        } catch(e) {
-            
+    /**
+     * Returns the index for a specified column id.
+     * @param {String} id The column id
+     * @return {Number} the index, or -1 if not found
+     */
+    getIndexById : function(id){
+        for(var i = 0, len = this.config.length; i < len; i++){
+            if(this.config[i].id == id){
+                return i;
+            }
         }
-        */
+        return -1;
+    },
     
-        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
+    /**
+     * Returns the index for a specified column dataIndex.
+     * @param {String} dataIndex The column dataIndex
+     * @return {Number} the index, or -1 if not found
+     */
+    
+    findColumnIndex : function(dataIndex){
+        for(var i = 0, len = this.config.length; i < len; i++){
+            if(this.config[i].dataIndex == dataIndex){
+                return i;
+            }
+        }
+        return -1;
     },
-    // private
-    onLoad : function()
-    {
-        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
+    
+    
+    moveColumn : function(oldIndex, newIndex){
+        var c = this.config[oldIndex];
+        this.config.splice(oldIndex, 1);
+        this.config.splice(newIndex, 0, c);
+        this.dataMap = null;
+        this.fireEvent("columnmoved", this, oldIndex, newIndex);
     },
 
-    // private
-    onBeforeLoad : function(){
-        if(!this.disabled){
-            (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
+    isLocked : function(colIndex){
+        return this.config[colIndex].locked === true;
+    },
+
+    setLocked : function(colIndex, value, suppressEvent){
+        if(this.isLocked(colIndex) == value){
+            return;
+        }
+        this.config[colIndex].locked = value;
+        if(!suppressEvent){
+            this.fireEvent("columnlockchange", this, colIndex, value);
         }
     },
 
-    // private
-    destroy : function(){
-        if(this.store){
-            this.store.un('beforeload', this.onBeforeLoad, this);
-            this.store.un('load', this.onLoad, this);
-            this.store.un('loadexception', this.onLoadException, this);
-        }else{
-            var um = this.el.getUpdateManager();
-            um.un('beforeupdate', this.onBeforeLoad, this);
-            um.un('update', this.onLoad, this);
-            um.un('failure', this.onLoad, this);
+    getTotalLockedWidth : function(){
+        var totalWidth = 0;
+        for(var i = 0; i < this.config.length; i++){
+            if(this.isLocked(i) && !this.isHidden(i)){
+                this.totalWidth += this.getColumnWidth(i);
+            }
         }
-    }
-};/*
- * - LGPL
- *
- * table
- * 
- */
+        return totalWidth;
+    },
 
-/**
- * @class Roo.bootstrap.Table
- * @extends Roo.bootstrap.Component
- * Bootstrap Table class
- * @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} loadMask (true|false) default false
- * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
- * @cfg {Boolean} headerShow (true|false) generate thead, default true
- * @cfg {Boolean} rowSelection (true|false) default false
- * @cfg {Boolean} cellSelection (true|false) default false
- * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
- * @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)
- * 
- * @constructor
- * Create a new Table
- * @param {Object} config The config object
- */
+    getLockedCount : function(){
+        for(var i = 0, len = this.config.length; i < len; i++){
+            if(!this.isLocked(i)){
+                return i;
+            }
+        }
+        
+        return this.config.length;
+    },
 
-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.sm = this.sm || {xtype: 'RowSelectionModel'};
-    if (this.sm) {
-        this.sm.grid = this;
-        this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
-        this.sm = this.selModel;
-        this.sm.xmodule = this.xmodule || false;
-    }
-    
-    if (this.cm && typeof(this.cm.config) == 'undefined') {
-        this.colModel = new Roo.grid.ColumnModel(this.cm);
-        this.cm = this.colModel;
-        this.cm.xmodule = this.xmodule || false;
-    }
-    if (this.store) {
-        this.store= Roo.factory(this.store, Roo.data);
-        this.ds = this.store;
-        this.ds.xmodule = this.xmodule || false;
-         
-    }
-    if (this.footer && this.store) {
-        this.footer.dataSource = this.ds;
-        this.footer = Roo.factory(this.footer);
-    }
-    
-    /** @private */
-    this.addEvents({
-        /**
-         * @event cellclick
-         * Fires when a cell is clicked
-         * @param {Roo.bootstrap.Table} this
-         * @param {Roo.Element} el
-         * @param {Number} rowIndex
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "cellclick" : true,
-        /**
-         * @event celldblclick
-         * Fires when a cell is double clicked
-         * @param {Roo.bootstrap.Table} this
-         * @param {Roo.Element} el
-         * @param {Number} rowIndex
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "celldblclick" : true,
-        /**
-         * @event rowclick
-         * Fires when a row is clicked
-         * @param {Roo.bootstrap.Table} this
-         * @param {Roo.Element} el
-         * @param {Number} rowIndex
-         * @param {Roo.EventObject} e
-         */
-        "rowclick" : true,
-        /**
-         * @event rowdblclick
-         * Fires when a row is double clicked
-         * @param {Roo.bootstrap.Table} this
-         * @param {Roo.Element} el
-         * @param {Number} rowIndex
-         * @param {Roo.EventObject} e
-         */
-        "rowdblclick" : true,
-        /**
-         * @event mouseover
-         * Fires when a mouseover occur
-         * @param {Roo.bootstrap.Table} this
-         * @param {Roo.Element} el
-         * @param {Number} rowIndex
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "mouseover" : true,
-        /**
-         * @event mouseout
-         * Fires when a mouseout occur
-         * @param {Roo.bootstrap.Table} this
-         * @param {Roo.Element} el
-         * @param {Number} rowIndex
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "mouseout" : true,
-        /**
-         * @event rowclass
-         * Fires when a row is rendered, so you can change add a style to it.
-         * @param {Roo.bootstrap.Table} this
-         * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
-         */
-        'rowclass' : true,
-          /**
-         * @event rowsrendered
-         * Fires when all the  rows have been rendered
-         * @param {Roo.bootstrap.Table} this
-         */
-        'rowsrendered' : true,
-        /**
-         * @event contextmenu
-         * The raw contextmenu event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        "contextmenu" : true,
-        /**
-         * @event rowcontextmenu
-         * Fires when a row is right clicked
-         * @param {Roo.bootstrap.Table} this
-         * @param {Number} rowIndex
-         * @param {Roo.EventObject} e
-         */
-        "rowcontextmenu" : true,
-        /**
-         * @event cellcontextmenu
-         * Fires when a cell is right clicked
-         * @param {Roo.bootstrap.Table} this
-         * @param {Number} rowIndex
-         * @param {Number} cellIndex
-         * @param {Roo.EventObject} e
-         */
-         "cellcontextmenu" : true,
-         /**
-         * @event headercontextmenu
-         * Fires when a header is right clicked
-         * @param {Roo.bootstrap.Table} this
-         * @param {Number} columnIndex
-         * @param {Roo.EventObject} e
-         */
-        "headercontextmenu" : 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,
-    hover:  false,
-    condensed : false,
-    responsive : false,
-    sm : false,
-    cm : false,
-    store : false,
-    loadMask : false,
-    footerShow : true,
-    headerShow : true,
-  
-    rowSelection : false,
-    cellSelection : false,
-    layout : false,
-    
-    // Roo.Element - the tbody
-    mainBody: false,
-    // Roo.Element - thead element
-    mainHead: false,
-    
-    container: false, // used by gridpanel...
-    
-    lazyLoad : false,
-    
-    CSS : Roo.util.CSS,
-    
-    auto_hide_footer : false,
-    
-    getAutoCreate : function()
-    {
-        var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
-        
-        cfg = {
-            tag: 'table',
-            cls : 'table',
-            cn : []
-        };
-        if (this.scrollBody) {
-            cfg.cls += ' table-body-fixed';
-        }    
-        if (this.striped) {
-            cfg.cls += ' table-striped';
-        }
-        
-        if (this.hover) {
-            cfg.cls += ' table-hover';
-        }
-        if (this.bordered) {
-            cfg.cls += ' table-bordered';
-        }
-        if (this.condensed) {
-            cfg.cls += ' table-condensed';
-        }
-        if (this.responsive) {
-            cfg.cls += ' table-responsive';
-        }
-        
-        if (this.cls) {
-            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];
+    /**
+     * Returns the number of columns.
+     * @return {Number}
+     */
+    getColumnCount : function(visibleOnly){
+        if(visibleOnly === true){
+            var c = 0;
+            for(var i = 0, len = this.config.length; i < len; i++){
+                if(!this.isHidden(i)){
+                    c++;
+                }
             }
-        });
-        
-        
-        if (this.layout) {
-            cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
+            return c;
         }
-        
-        if(this.store || this.cm){
-            if(this.headerShow){
-                cfg.cn.push(this.renderHeader());
-            }
-            
-            cfg.cn.push(this.renderBody());
-            
-            if(this.footerShow){
-                cfg.cn.push(this.renderFooter());
+        return this.config.length;
+    },
+
+    /**
+     * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
+     * @param {Function} fn
+     * @param {Object} scope (optional)
+     * @return {Array} result
+     */
+    getColumnsBy : function(fn, scope){
+        var r = [];
+        for(var i = 0, len = this.config.length; i < len; i++){
+            var c = this.config[i];
+            if(fn.call(scope||this, c, i) === true){
+                r[r.length] = c;
             }
-            // where does this come from?
-            //cfg.cls+=  ' TableGrid';
         }
-        
-        return { cn : [ cfg ] };
+        return r;
     },
-    
-    initEvents : function()
-    {   
-        if(!this.store || !this.cm){
-            return;
-        }
-        if (this.selModel) {
-            this.selModel.initEvents();
+
+    /**
+     * Returns true if the specified column is sortable.
+     * @param {Number} col The column index
+     * @return {Boolean}
+     */
+    isSortable : function(col){
+        if(typeof this.config[col].sortable == "undefined"){
+            return this.defaultSortable;
         }
-        
-        
-        //Roo.log('initEvents with ds!!!!');
-        
-        this.mainBody = this.el.select('tbody', true).first();
-        this.mainHead = 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);
-        });
-        
-        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');
-        
-        
-        if (this.footer) {
-            this.footer.parentId = this.id;
-            this.footer.onRender(this.el.select('tfoot tr td').first(), null);
-            
-            if(this.lazyLoad){
-                this.el.select('tfoot tr td').first().addClass('hide');
-            }
-        } 
-        
-        if(this.loadMask) {
-            this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
+        return this.config[col].sortable;
+    },
+
+    /**
+     * Returns the rendering (formatting) function defined for the column.
+     * @param {Number} col The column index.
+     * @return {Function} The function used to render the cell. See {@link #setRenderer}.
+     */
+    getRenderer : function(col){
+        if(!this.config[col].renderer){
+            return Roo.grid.ColumnModel.defaultRenderer;
         }
-        
-        this.store.on('load', this.onLoad, this);
-        this.store.on('beforeload', this.onBeforeLoad, this);
-        this.store.on('update', this.onUpdate, this);
-        this.store.on('add', this.onAdd, this);
-        this.store.on("clear", this.clear, this);
-        
-        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);
-        
+        return this.config[col].renderer;
     },
-    
-    onContextMenu : function(e, t)
-    {
-        this.processEvent("contextmenu", e);
+
+    /**
+     * Sets the rendering (formatting) function for a column.
+     * @param {Number} col The column index
+     * @param {Function} fn The function to use to process the cell's raw data
+     * to return HTML markup for the grid view. The render function is called with
+     * the following parameters:<ul>
+     * <li>Data value.</li>
+     * <li>Cell metadata. An object in which you may set the following attributes:<ul>
+     * <li>css A CSS style string to apply to the table cell.</li>
+     * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
+     * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
+     * <li>Row index</li>
+     * <li>Column index</li>
+     * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
+     */
+    setRenderer : function(col, fn){
+        this.config[col].renderer = fn;
     },
-    
-    processEvent : function(name, e)
-    {
-        if (name != 'touchstart' ) {
-            this.fireEvent(name, e);    
-        }
-        
-        var t = e.getTarget();
-        
-        var cell = Roo.get(t);
-        
-        if(!cell){
-            return;
-        }
-        
-        if(cell.findParent('tfoot', false, true)){
-            return;
+
+    /**
+     * 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, 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;
+               
+    },
+
+    /**
+     * Sets the width for a column.
+     * @param {Number} col The column index
+     * @param {Number} width The new width
+     */
+    setColumnWidth : function(col, width, suppressEvent){
+        this.config[col].width = width;
+        this.totalWidth = null;
+        if(!suppressEvent){
+             this.fireEvent("widthchange", this, col, width);
         }
-        
-        if(cell.findParent('thead', false, true)){
-            
-            if(e.getTarget().nodeName.toLowerCase() != 'th'){
-                cell = Roo.get(t).findParent('th', false, true);
-                if (!cell) {
-                    Roo.log("failed to find th in thead?");
-                    Roo.log(e.getTarget());
-                    return;
+    },
+
+    /**
+     * Returns the total width of all columns.
+     * @param {Boolean} includeHidden True to include hidden column widths
+     * @return {Number}
+     */
+    getTotalWidth : function(includeHidden){
+        if(!this.totalWidth){
+            this.totalWidth = 0;
+            for(var i = 0, len = this.config.length; i < len; i++){
+                if(includeHidden || !this.isHidden(i)){
+                    this.totalWidth += this.getColumnWidth(i);
                 }
             }
-            
-            var cellIndex = cell.dom.cellIndex;
-            
-            var ename = name == 'touchstart' ? 'click' : name;
-            this.fireEvent("header" + ename, this, cellIndex, e);
-            
-            return;
-        }
-        
-        if(e.getTarget().nodeName.toLowerCase() != 'td'){
-            cell = Roo.get(t).findParent('td', false, true);
-            if (!cell) {
-                Roo.log("failed to find th in tbody?");
-                Roo.log(e.getTarget());
-                return;
-            }
-        }
-        
-        var row = cell.findParent('tr', false, true);
-        var cellIndex = cell.dom.cellIndex;
-        var rowIndex = row.dom.rowIndex - 1;
-        
-        if(row !== false){
-            
-            this.fireEvent("row" + name, this, rowIndex, e);
-            
-            if(cell !== false){
-            
-                this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
-            }
         }
-        
+        return this.totalWidth;
+    },
+
+    /**
+     * Returns the header for the specified column.
+     * @param {Number} col The column index
+     * @return {String}
+     */
+    getColumnHeader : function(col){
+        return this.config[col].header;
+    },
+
+    /**
+     * Sets the header for a column.
+     * @param {Number} col The column index
+     * @param {String} header The new header
+     */
+    setColumnHeader : function(col, header){
+        this.config[col].header = header;
+        this.fireEvent("headerchange", this, col, header);
+    },
+
+    /**
+     * Returns the tooltip for the specified column.
+     * @param {Number} col The column index
+     * @return {String}
+     */
+    getColumnTooltip : function(col){
+            return this.config[col].tooltip;
+    },
+    /**
+     * Sets the tooltip for a column.
+     * @param {Number} col The column index
+     * @param {String} tooltip The new tooltip
+     */
+    setColumnTooltip : function(col, tooltip){
+            this.config[col].tooltip = tooltip;
+    },
+
+    /**
+     * Returns the dataIndex for the specified column.
+     * @param {Number} col The column index
+     * @return {Number}
+     */
+    getDataIndex : function(col){
+        return this.config[col].dataIndex;
+    },
+
+    /**
+     * Sets the dataIndex for a column.
+     * @param {Number} col The column index
+     * @param {Number} dataIndex The new dataIndex
+     */
+    setDataIndex : function(col, dataIndex){
+        this.config[col].dataIndex = dataIndex;
     },
+
     
-    onMouseover : function(e, el)
+    
+    /**
+     * Returns true if the cell is editable.
+     * @param {Number} colIndex The column index
+     * @param {Number} rowIndex The row index - this is nto actually used..?
+     * @return {Boolean}
+     */
+    isCellEditable : function(colIndex, rowIndex){
+        return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
+    },
+
+    /**
+     * Returns the editor defined for the cell/column.
+     * return false or null to disable editing.
+     * @param {Number} colIndex The column index
+     * @param {Number} rowIndex The row index
+     * @return {Object}
+     */
+    getCellEditor : function(colIndex, rowIndex){
+        return this.config[colIndex].editor;
+    },
+
+    /**
+     * Sets if a column is editable.
+     * @param {Number} col The column index
+     * @param {Boolean} editable True if the column is editable
+     */
+    setEditable : function(col, editable){
+        this.config[col].editable = editable;
+    },
+
+
+    /**
+     * Returns true if the column is hidden.
+     * @param {Number} colIndex The column index
+     * @return {Boolean}
+     */
+    isHidden : function(colIndex){
+        return this.config[colIndex].hidden;
+    },
+
+
+    /**
+     * Returns true if the column width cannot be changed
+     */
+    isFixed : function(colIndex){
+        return this.config[colIndex].fixed;
+    },
+
+    /**
+     * Returns true if the column can be resized
+     * @return {Boolean}
+     */
+    isResizable : function(colIndex){
+        return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
+    },
+    /**
+     * Sets if a column is hidden.
+     * @param {Number} colIndex The column index
+     * @param {Boolean} hidden True if the column is hidden
+     */
+    setHidden : function(colIndex, hidden){
+        this.config[colIndex].hidden = hidden;
+        this.totalWidth = null;
+        this.fireEvent("hiddenchange", this, colIndex, hidden);
+    },
+
+    /**
+     * Sets the editor for a column.
+     * @param {Number} col The column index
+     * @param {Object} editor The editor object
+     */
+    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 cell = Roo.get(el);
-        
-        if(!cell){
-            return;
+    
+       var i = this.config.length;
+       this.config[i] = c;
+       
+       if(typeof c.dataIndex == "undefined"){
+            c.dataIndex = i;
         }
-        
-        if(e.getTarget().nodeName.toLowerCase() != 'td'){
-            cell = cell.findParent('td', false, true);
+        if(typeof c.renderer == "string"){
+            c.renderer = Roo.util.Format[c.renderer];
         }
-        
-        var row = cell.findParent('tr', false, true);
-        var cellIndex = cell.dom.cellIndex;
-        var rowIndex = row.dom.rowIndex - 1; // start from 0
-        
-        this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
-        
-    },
-    
-    onMouseout : function(e, el)
-    {
-        var cell = Roo.get(el);
-        
-        if(!cell){
-            return;
+        if(typeof c.id == "undefined"){
+            c.id = Roo.id();
         }
-        
-        if(e.getTarget().nodeName.toLowerCase() != 'td'){
-            cell = cell.findParent('td', false, true);
+        if(c.editor && c.editor.xtype){
+            c.editor  = Roo.factory(c.editor, Roo.grid);
         }
-        
-        var row = cell.findParent('tr', false, true);
-        var cellIndex = cell.dom.cellIndex;
-        var rowIndex = row.dom.rowIndex - 1; // start from 0
-        
-        this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
-        
+        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)
+{
+    if(typeof value == "object") {
+        return value;
+    }
+       if(typeof value == "string" && value.length < 1){
+           return "&#160;";
+       }
+    
+       return String.format("{0}", value);
+};
+
+// Alias for backwards compatibility
+Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
+/*
+ * 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.LoadMask
+ * A simple utility class for generically masking elements while loading data.  If the element being masked has
+ * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
+ * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
+ * element's UpdateManager load indicator and will be destroyed after the initial load.
+ * @constructor
+ * Create a new LoadMask
+ * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
+ * @param {Object} config The config object
+ */
+Roo.LoadMask = function(el, config){
+    this.el = Roo.get(el);
+    Roo.apply(this, config);
+    if(this.store){
+        this.store.on('beforeload', this.onBeforeLoad, this);
+        this.store.on('load', this.onLoad, this);
+        this.store.on('loadexception', this.onLoadException, this);
+        this.removeMask = false;
+    }else{
+        var um = this.el.getUpdateManager();
+        um.showLoadIndicator = false; // disable the default indicator
+        um.on('beforeupdate', this.onBeforeLoad, this);
+        um.on('update', this.onLoad, this);
+        um.on('failure', this.onLoad, this);
+        this.removeMask = true;
+    }
+};
+
+Roo.LoadMask.prototype = {
+    /**
+     * @cfg {Boolean} removeMask
+     * 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...')
+     */
+    msg : 'Loading...',
+    /**
+     * @cfg {String} msgCls
+     * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
+     */
+    msgCls : 'x-mask-loading',
+
+    /**
+     * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
+     * @type Boolean
+     */
+    disabled: false,
+
+    /**
+     * Disables the mask to prevent it from being displayed
+     */
+    disable : function(){
+       this.disabled = true;
+    },
+
+    /**
+     * Enables the mask so that it can be displayed
+     */
+    enable : function(){
+        this.disabled = false;
     },
     
-    onClick : function(e, el)
+    onLoadException : function()
     {
-        var cell = Roo.get(el);
+        Roo.log(arguments);
         
-        if(!cell || (!this.cellSelection && !this.rowSelection)){
-            return;
+        if (typeof(arguments[3]) != 'undefined') {
+            Roo.MessageBox.alert("Error loading",arguments[3]);
+        } 
+        /*
+        try {
+            if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+                Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+            }   
+        } catch(e) {
+            
         }
-        
-        if(e.getTarget().nodeName.toLowerCase() != 'td'){
-            cell = cell.findParent('td', false, true);
+        */
+    
+        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
+    },
+    // private
+    onLoad : function()
+    {
+        (function() { this.el.unmask(this.removeMask); }).defer(50, this);
+    },
+
+    // private
+    onBeforeLoad : function(){
+        if(!this.disabled){
+            (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
         }
-        
-        if(!cell || typeof(cell) == 'undefined'){
-            return;
+    },
+
+    // private
+    destroy : function(){
+        if(this.store){
+            this.store.un('beforeload', this.onBeforeLoad, this);
+            this.store.un('load', this.onLoad, this);
+            this.store.un('loadexception', this.onLoadException, this);
+        }else{
+            var um = this.el.getUpdateManager();
+            um.un('beforeupdate', this.onBeforeLoad, this);
+            um.un('update', this.onLoad, this);
+            um.un('failure', this.onLoad, this);
+        }
+    }
+};/**
+ * @class Roo.bootstrap.Table
+ * @licence LGBL
+ * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.TableBody
+ * 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.AbstractSelectionModel} sm The selection model to use (cell selection is not supported yet)
+ * @cfg {Roo.data.Store} store The data store to use
+ * @cfg {Roo.grid.ColumnModel} cm[] A column for the grid.
+ * 
+ * @cfg {String} cls table class
+ *
+ *
+ * @cfg {string} empty_results  Text to display for no results 
+ * @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 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
+ * @cfg {Boolean} rowSelection (true|false) default false
+ * @cfg {Boolean} cellSelection (true|false) default false
+ * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header (with resizable columns)
+ * @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 = needs scrollBody to be set to work (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.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.grid);
+        this.sm = this.selModel;
+        this.sm.xmodule = this.xmodule || false;
+    }
+    
+    if (this.cm && typeof(this.cm.config) == 'undefined') {
+        this.colModel = new Roo.grid.ColumnModel(this.cm);
+        this.cm = this.colModel;
+        this.cm.xmodule = this.xmodule || false;
+    }
+    if (this.store) {
+        this.store= Roo.factory(this.store, Roo.data);
+        this.ds = this.store;
+        this.ds.xmodule = this.xmodule || false;
+         
+    }
+    if (this.footer && this.store) {
+        this.footer.dataSource = this.ds;
+        this.footer = Roo.factory(this.footer);
+    }
+    
+    /** @private */
+    this.addEvents({
+        /**
+         * @event cellclick
+         * Fires when a cell is clicked
+         * @param {Roo.bootstrap.Table} this
+         * @param {Roo.Element} el
+         * @param {Number} rowIndex
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "cellclick" : true,
+        /**
+         * @event celldblclick
+         * Fires when a cell is double clicked
+         * @param {Roo.bootstrap.Table} this
+         * @param {Roo.Element} el
+         * @param {Number} rowIndex
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "celldblclick" : true,
+        /**
+         * @event rowclick
+         * Fires when a row is clicked
+         * @param {Roo.bootstrap.Table} this
+         * @param {Roo.Element} el
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowclick" : true,
+        /**
+         * @event rowdblclick
+         * Fires when a row is double clicked
+         * @param {Roo.bootstrap.Table} this
+         * @param {Roo.Element} el
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowdblclick" : true,
+        /**
+         * @event mouseover
+         * Fires when a mouseover occur
+         * @param {Roo.bootstrap.Table} this
+         * @param {Roo.Element} el
+         * @param {Number} rowIndex
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "mouseover" : true,
+        /**
+         * @event mouseout
+         * Fires when a mouseout occur
+         * @param {Roo.bootstrap.Table} this
+         * @param {Roo.Element} el
+         * @param {Number} rowIndex
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "mouseout" : true,
+        /**
+         * @event rowclass
+         * Fires when a row is rendered, so you can change add a style to it.
+         * @param {Roo.bootstrap.Table} this
+         * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
+         */
+        'rowclass' : true,
+          /**
+         * @event rowsrendered
+         * Fires when all the  rows have been rendered
+         * @param {Roo.bootstrap.Table} this
+         */
+        'rowsrendered' : true,
+        /**
+         * @event contextmenu
+         * The raw contextmenu event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "contextmenu" : true,
+        /**
+         * @event rowcontextmenu
+         * Fires when a row is right clicked
+         * @param {Roo.bootstrap.Table} this
+         * @param {Number} rowIndex
+         * @param {Roo.EventObject} e
+         */
+        "rowcontextmenu" : true,
+        /**
+         * @event cellcontextmenu
+         * Fires when a cell is right clicked
+         * @param {Roo.bootstrap.Table} this
+         * @param {Number} rowIndex
+         * @param {Number} cellIndex
+         * @param {Roo.EventObject} e
+         */
+         "cellcontextmenu" : true,
+         /**
+         * @event headercontextmenu
+         * Fires when a header is right clicked
+         * @param {Roo.bootstrap.Table} this
+         * @param {Number} columnIndex
+         * @param {Roo.EventObject} e
+         */
+        "headercontextmenu" : true,
+        /**
+         * @event mousedown
+         * The raw mousedown event for the entire grid.
+         * @param {Roo.EventObject} e
+         */
+        "mousedown" : true
         
-        var row = cell.findParent('tr', false, true);
+    });
+};
+
+Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
+    
+    cls: false,
+    
+    empty_results : '',
+    striped : false,
+    scrollBody : false,
+    bordered: false,
+    hover:  false,
+    condensed : false,
+    responsive : false,
+    sm : false,
+    cm : false,
+    store : false,
+    loadMask : false,
+    footerShow : true,
+    headerShow : true,
+    enableColumnResize: true,
+  
+    rowSelection : false,
+    cellSelection : false,
+    layout : false,
+
+    minColumnWidth : 50,
+    
+    // Roo.Element - the tbody
+    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...
+    
+    lazyLoad : false,
+    
+    CSS : Roo.util.CSS,
+    
+    auto_hide_footer : false,
+    
+    view: false, // actually points to this..
+    
+    getAutoCreate : function()
+    {
+        var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
         
-        if(!row || typeof(row) == 'undefined'){
-            return;
+        cfg = {
+            tag: 'table',
+            cls : 'table', 
+            cn : []
+        };
+        // this get's auto added by panel.Grid
+        if (this.scrollBody) {
+            cfg.cls += ' table-body-fixed';
+        }    
+        if (this.striped) {
+            cfg.cls += ' table-striped';
         }
         
-        var cellIndex = cell.dom.cellIndex;
-        var rowIndex = this.getRowIndex(row);
-        
-        // why??? - should these not be based on SelectionModel?
-        if(this.cellSelection){
-            this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
+        if (this.hover) {
+            cfg.cls += ' table-hover';
+        }
+        if (this.bordered) {
+            cfg.cls += ' table-bordered';
+        }
+        if (this.condensed) {
+            cfg.cls += ' table-condensed';
         }
         
-        if(this.rowSelection){
-            this.fireEvent('rowclick', this, row, rowIndex, e);
+        if (this.responsive) {
+            cfg.cls += ' table-responsive';
         }
         
+        if (this.cls) {
+            cfg.cls+=  ' ' +this.cls;
+        }
         
-    },
         
-    onDblClick : function(e,el)
-    {
-        var cell = Roo.get(el);
         
-        if(!cell || (!this.cellSelection && !this.rowSelection)){
-            return;
+        if (this.layout) {
+            cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
         }
         
-        if(e.getTarget().nodeName.toLowerCase() != 'td'){
-            cell = cell.findParent('td', false, true);
+        if(this.store || this.cm){
+            if(this.headerShow){
+                cfg.cn.push(this.renderHeader());
+            }
+            
+            cfg.cn.push(this.renderBody());
+            
+            if(this.footerShow){
+                cfg.cn.push(this.renderFooter());
+            }
+            // where does this come from?
+            //cfg.cls+=  ' TableGrid';
         }
         
-        if(!cell || typeof(cell) == 'undefined'){
+        return { cn : [ cfg ] };
+    },
+    
+    initEvents : function()
+    {   
+        if(!this.store || !this.cm){
             return;
         }
+        if (this.selModel) {
+            this.selModel.initEvents();
+        }
         
-        var row = cell.findParent('tr', false, true);
         
-        if(!row || typeof(row) == 'undefined'){
-            return;
-        }
+        //Roo.log('initEvents with ds!!!!');
         
-        var cellIndex = cell.dom.cellIndex;
-        var rowIndex = this.getRowIndex(row);
+        this.bodyEl = this.el.select('tbody', true).first();
+        this.headEl = this.el.select('thead', true).first();
+        this.mainFoot = this.el.select('tfoot', true).first();
         
-        if(this.cellSelection){
-            this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
-        }
         
-        if(this.rowSelection){
-            this.fireEvent('rowdblclick', this, row, rowIndex, e);
-        }
-    },
-    
-    sort : function(e,el)
-    {
-        var col = Roo.get(el);
         
-        if(!col.hasClass('sortable')){
-            return;
-        }
         
-        var sort = col.attr('sort');
-        var dir = 'ASC';
+        Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
+            e.on('click', this.sort, this);
+        }, this);
         
-        if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
-            dir = 'DESC';
-        }
         
-        this.store.sortInfo = {field : sort, direction : dir};
+        // why is this done????? = it breaks dialogs??
+        //this.parent().el.setStyle('position', 'relative');
+        
         
         if (this.footer) {
-            Roo.log("calling footer first");
-            this.footer.onClick('first');
-        } else {
+            this.footer.parentId = this.id;
+            this.footer.onRender(this.el.select('tfoot tr td').first(), null);
+            
+            if(this.lazyLoad){
+                this.el.select('tfoot tr td').first().addClass('hide');
+            }
+        } 
         
-            this.store.load({ params : { start : 0 } });
+        if(this.loadMask) {
+            this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
+        }
+        
+        this.store.on('load', this.onLoad, this);
+        this.store.on('beforeload', this.onBeforeLoad, this);
+        this.store.on('update', this.onUpdate, this);
+        this.store.on('add', this.onAdd, this);
+        this.store.on("clear", this.clear, this);
+        
+        this.el.on("contextmenu", this.onContextMenu, 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;
     },
     
-    renderHeader : function()
+    initCSS : function()
     {
-        var header = {
-            tag: 'thead',
-            cn : []
-        };
+        
+        
+        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",
+                            // this is the popover version..
+                            '.popover-inner #' , this.id , ' .x-grid-split-' , i, " { ", left, splithide, 'height:', 100, "%;}\n"
+                );
+            }
+            
+        }
+        //Roo.log(styles.join(''));
+        this.CSS.createStyleSheet( styles.join(''), this.id + '-cssrules');
+        
+    },
+    
+    
+    
+    onContextMenu : function(e, t)
+    {
+        this.processEvent("contextmenu", e);
+    },
+    
+    processEvent : function(name, e)
+    {
+        if (name != 'touchstart' ) {
+            this.fireEvent(name, e);    
+        }
+        
+        var t = e.getTarget();
+        
+        var cell = Roo.get(t);
+        
+        if(!cell){
+            return;
+        }
+        
+        if(cell.findParent('tfoot', false, true)){
+            return;
+        }
+        
+        if(cell.findParent('thead', false, true)){
+            
+            if(e.getTarget().nodeName.toLowerCase() != 'th'){
+                cell = Roo.get(t).findParent('th', false, true);
+                if (!cell) {
+                    Roo.log("failed to find th in thead?");
+                    Roo.log(e.getTarget());
+                    return;
+                }
+            }
+            
+            var cellIndex = cell.dom.cellIndex;
+            
+            var ename = name == 'touchstart' ? 'click' : name;
+            this.fireEvent("header" + ename, this, cellIndex, e);
+            
+            return;
+        }
+        
+        if(e.getTarget().nodeName.toLowerCase() != 'td'){
+            cell = Roo.get(t).findParent('td', false, true);
+            if (!cell) {
+                Roo.log("failed to find th in tbody?");
+                Roo.log(e.getTarget());
+                return;
+            }
+        }
+        
+        var row = cell.findParent('tr', false, true);
+        var cellIndex = cell.dom.cellIndex;
+        var rowIndex = row.dom.rowIndex - 1;
+        
+        if(row !== false){
+            
+            this.fireEvent("row" + name, this, rowIndex, e);
+            
+            if(cell !== false){
+            
+                this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
+            }
+        }
+        
+    },
+    
+    onMouseover : function(e, el)
+    {
+        var cell = Roo.get(el);
+        
+        if(!cell){
+            return;
+        }
+        
+        if(e.getTarget().nodeName.toLowerCase() != 'td'){
+            cell = cell.findParent('td', false, true);
+        }
+        
+        var row = cell.findParent('tr', false, true);
+        var cellIndex = cell.dom.cellIndex;
+        var rowIndex = row.dom.rowIndex - 1; // start from 0
+        
+        this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
+        
+    },
+    
+    onMouseout : function(e, el)
+    {
+        var cell = Roo.get(el);
+        
+        if(!cell){
+            return;
+        }
+        
+        if(e.getTarget().nodeName.toLowerCase() != 'td'){
+            cell = cell.findParent('td', false, true);
+        }
+        
+        var row = cell.findParent('tr', false, true);
+        var cellIndex = cell.dom.cellIndex;
+        var rowIndex = row.dom.rowIndex - 1; // start from 0
+        
+        this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
+        
+    },
+    
+    onClick : function(e, el)
+    {
+        var cell = Roo.get(el);
+        
+        if(!cell || (!this.cellSelection && !this.rowSelection)){
+            return;
+        }
+        
+        if(e.getTarget().nodeName.toLowerCase() != 'td'){
+            cell = cell.findParent('td', false, true);
+        }
+        
+        if(!cell || typeof(cell) == 'undefined'){
+            return;
+        }
+        
+        var row = cell.findParent('tr', false, true);
+        
+        if(!row || typeof(row) == 'undefined'){
+            return;
+        }
+        
+        var cellIndex = cell.dom.cellIndex;
+        var rowIndex = this.getRowIndex(row);
+        
+        // why??? - should these not be based on SelectionModel?
+        //if(this.cellSelection){
+            this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
+        //}
+        
+        //if(this.rowSelection){
+            this.fireEvent('rowclick', this, row, rowIndex, e);
+        //}
+         
+    },
+        
+    onDblClick : function(e,el)
+    {
+        var cell = Roo.get(el);
+        
+        if(!cell || (!this.cellSelection && !this.rowSelection)){
+            return;
+        }
+        
+        if(e.getTarget().nodeName.toLowerCase() != 'td'){
+            cell = cell.findParent('td', false, true);
+        }
+        
+        if(!cell || typeof(cell) == 'undefined'){
+            return;
+        }
+        
+        var row = cell.findParent('tr', false, true);
+        
+        if(!row || typeof(row) == 'undefined'){
+            return;
+        }
+        
+        var cellIndex = cell.dom.cellIndex;
+        var rowIndex = this.getRowIndex(row);
+        
+        if(this.cellSelection){
+            this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
+        }
+        
+        if(this.rowSelection){
+            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);
+        
+        if(!col.hasClass('sortable')){
+            return;
+        }
+        
+        var sort = col.attr('sort');
+        var dir = 'ASC';
+        
+        if(col.select('i', true).first().hasClass('fa-arrow-up')){
+            dir = 'DESC';
+        }
+        
+        this.store.sortInfo = {field : sort, direction : dir};
+        
+        if (this.footer) {
+            Roo.log("calling footer first");
+            this.footer.onClick('first');
+        } else {
+        
+            this.store.load({ params : { start : 0 } });
+        }
+    },
+    
+    renderHeader : function()
+    {
+        var header = {
+            tag: 'thead',
+            cn : []
+        };
         
         var cm = this.cm;
         this.totalWidth = 0;
@@ -7988,14 +9827,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 
@@ -8028,9 +9874,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;
@@ -8042,35 +9886,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)
         }
@@ -8130,20 +9987,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){
@@ -8160,6 +10017,8 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
                 }
                 
             }, this);
+        } else if (this.empty_results.length) {
+            this.el.mask(this.empty_results, 'no-spinner');
         }
         
         var tfoot = this.el.select('tfoot', true).first();
@@ -8185,6 +10044,10 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         this.fireEvent('rowsrendered', this);
         
         this.autoSize();
+        
+        this.initCSS(); /// resize cols
+
+        
     },
     
     
@@ -8198,7 +10061,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;
         
@@ -8222,7 +10085,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]);
@@ -8241,6 +10104,9 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             record = ds.getAt(index);
         }else{
             index = ds.indexOf(record);
+            if (index < 0) {
+                return; // should not happen - but seems to 
+            }
         }
         this.insertRow(ds, index, true);
         this.autoSize();
@@ -8250,6 +10116,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){
         
@@ -8259,7 +10239,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;
                 
@@ -8286,6 +10266,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..
   
     
@@ -8333,6 +10324,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
@@ -8346,9 +10340,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 + ';';
@@ -8356,10 +10348,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 + ';';
@@ -8368,28 +10361,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);
            
         }
@@ -8404,7 +10397,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     
     onBeforeLoad : function()
     {
-        
+        this.el.unmask(); // if needed.
     },
      /**
      * Remove all rows
@@ -8420,14 +10413,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');
+        
     },
     
     
@@ -8458,7 +10452,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;
@@ -8472,6 +10470,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
@@ -8494,6 +10515,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         var tfd = this.getGridEl().select('tfoot', true).first();
         
         var cw = ctr.getWidth();
+        this.getGridEl().select('tfoot tr, tfoot  td',true).setWidth(cw);
         
         if (tbd) {
             
@@ -8507,7 +10529,9 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             cw -= barsize;
         }
         cw = Math.max(cw, this.totalWidth);
-        this.getGridEl().select('tr',true).setWidth(cw);
+        this.getGridEl().select('tbody tr',true).setWidth(cw);
+        this.initCSS();
+        
         // resize 'expandable coloumn?
         
         return; // we doe not have a view in this design..
@@ -8515,21 +10539,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) {
                 
@@ -8549,18 +10573,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;
         
@@ -8571,7 +10627,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();
     },
@@ -8642,9 +10699,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
@@ -8654,7 +10717,10 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
 /**
  * @class Roo.bootstrap.TableCell
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Component
+ * @parent Roo.bootstrap.TableRow
  * Bootstrap TableCell class
+ * 
  * @cfg {String} html cell contain text
  * @cfg {String} cls cell class
  * @cfg {String} tag cell tag (td|th) default td
@@ -8776,6 +10842,8 @@ Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
 /**
  * @class Roo.bootstrap.TableRow
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.TableCell
+ * @parent Roo.bootstrap.TableBody
  * Bootstrap TableRow class
  * @cfg {String} cls row class
  * @cfg {String} align Aligns the content in a table row
@@ -8840,6 +10908,8 @@ Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
 /**
  * @class Roo.bootstrap.TableBody
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.TableRow
+ * @parent Roo.bootstrap.Table
  * Bootstrap TableBody class
  * @cfg {String} cls element class
  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
@@ -9276,8 +11346,9 @@ Roo.form.Action.ACTION_TYPES = {
  */
 
 /**
- * @class Roo.bootstrap.Form
+ * @class Roo.bootstrap.form.Form
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Component
  * Bootstrap Form class
  * @cfg {String} method  GET | POST (default POST)
  * @cfg {String} labelAlign top | left (default top)
@@ -9291,11 +11362,11 @@ Roo.form.Action.ACTION_TYPES = {
  */
 
 
-Roo.bootstrap.Form = function(config){
+Roo.bootstrap.form.Form = function(config){
     
-    Roo.bootstrap.Form.superclass.constructor.call(this, config);
+    Roo.bootstrap.form.Form.superclass.constructor.call(this, config);
     
-    Roo.bootstrap.Form.popover.apply();
+    Roo.bootstrap.form.Form.popover.apply();
     
     this.addEvents({
         /**
@@ -9329,7 +11400,7 @@ Roo.bootstrap.Form = function(config){
     });
 };
 
-Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.form.Form, Roo.bootstrap.Component,  {
 
      /**
      * @cfg {String} method
@@ -9459,7 +11530,7 @@ Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
         });
         
         if(this.errorMask && !valid){
-            Roo.bootstrap.Form.popover.mask(this, target);
+            Roo.bootstrap.form.Form.popover.mask(this, target);
         }
         
         return valid;
@@ -9876,7 +11947,7 @@ clientValidation  Boolean          Applies to submit only.  Pass true to call fo
 
 });
 
-Roo.apply(Roo.bootstrap.Form, {
+Roo.apply(Roo.bootstrap.form.Form, {
     
     popover : {
         
@@ -10012,7 +12083,7 @@ Roo.apply(Roo.bootstrap.Form, {
             this.toolTip.show(tip);
 
             this.intervalID = window.setInterval(function() {
-                Roo.bootstrap.Form.popover.unmask();
+                Roo.bootstrap.form.Form.popover.unmask();
             }, 10000);
 
             window.onwheel = function(){ return false;};
@@ -10075,7 +12146,7 @@ Roo.apply(Roo.bootstrap.Form, {
 /**
  * @class Roo.form.VTypes
  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
- * @singleton
+ * @static
  */
 Roo.form.VTypes = function(){
     // closure these in so they are only created once.
@@ -10161,15 +12232,15 @@ Roo.form.VTypes = function(){
  */
 
 /**
- * @class Roo.bootstrap.Input
+ * @class Roo.bootstrap.form.Input
  * @extends Roo.bootstrap.Component
  * Bootstrap Input class
  * @cfg {Boolean} disabled is it disabled
- * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
+ * @cfg {String} inputType (button|checkbox|email|file|hidden|image|number|password|radio|range|reset|search|submit|text)  
  * @cfg {String} name name of the input
  * @cfg {string} fieldLabel - the label associated
  * @cfg {string} placeholder - placeholder to put in text.
- * @cfg {string}  before - input group add on before
+ * @cfg {string} before - input group add on before
  * @cfg {string} after - input group add on after
  * @cfg {string} size - (lg|sm) or leave empty..
  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
@@ -10189,7 +12260,8 @@ Roo.form.VTypes = function(){
  * @cfg {String} capture (user|camera) use for file input only. (default empty)
  * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
  * @cfg {Boolean} preventMark Do not show tick or cross if error/success
-
+ * @cfg {Roo.bootstrap.Button} before Button to show before
+ * @cfg {Roo.bootstrap.Button} afterButton to show before
  * @cfg {String} align (left|center|right) Default left
  * @cfg {Boolean} forceFeedback (true|false) Default false
  * 
@@ -10198,9 +12270,9 @@ Roo.form.VTypes = function(){
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.Input = function(config){
+Roo.bootstrap.form.Input = function(config){
     
-    Roo.bootstrap.Input.superclass.constructor.call(this, config);
+    Roo.bootstrap.form.Input.superclass.constructor.call(this, config);
     
     this.addEvents({
         /**
@@ -10250,11 +12322,18 @@ 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
     });
 };
 
-Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.form.Input, Roo.bootstrap.Component,  {
      /**
      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
       automatic validation (defaults to "keyup").
@@ -10439,6 +12518,9 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             placeholder : this.placeholder || '',
             autocomplete : this.autocomplete || 'new-password'
         };
+        if (this.inputType == 'file') {
+            input.style = 'overflow:hidden'; // why not in CSS?
+        }
         
         if(this.capture.length){
             input.capture = this.capture;
@@ -10517,7 +12599,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
                 
                 inputblock.cn.push({
                     tag :'span',
-                    cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
+                    cls : 'roo-input-before input-group-prepend   input-group-' +
                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
                 });
             }
@@ -10536,7 +12618,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
                 
                 inputblock.cn.push({
                     tag :'span',
-                    cls : 'roo-input-after input-group-append input-group-text input-group-' +
+                    cls : 'roo-input-after input-group-append  input-group-' +
                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
                 });
             }
@@ -10551,11 +12633,8 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             cls : 'roo-required-indicator ' + (this.indicatorpos == 'right'  ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
             tooltip : 'This field is required'
         };
-        if (Roo.bootstrap.version == 4) {
-            indicator = {
-                tag : 'i',
-                style : 'display-none'
-            };
+        if (this.allowBlank ) {
+            indicator.style = this.allowBlank ? ' display:none' : '';
         }
         if (align ==='left' && this.fieldLabel.length) {
             
@@ -10614,7 +12693,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){
@@ -10640,11 +12719,14 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             
         } else if ( this.fieldLabel.length) {
                 
+            
+            
             cfg.cn = [
                 {
                     tag : 'i',
                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
-                    tooltip : 'This field is required'
+                    tooltip : 'This field is required',
+                    style : this.allowBlank ? ' display:none' : '' 
                 },
                 {
                     tag: 'label',
@@ -10658,7 +12740,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
            ];
            
            if(this.indicatorpos == 'right'){
-                
+       
                 cfg.cn = [
                     {
                         tag: 'label',
@@ -10669,7 +12751,8 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
                     {
                         tag : 'i',
                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
-                        tooltip : 'This field is required'
+                        tooltip : 'This field is required',
+                        style : this.allowBlank ? ' display:none' : '' 
                     },
 
                    inputblock
@@ -10749,6 +12832,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();
         
@@ -11255,8 +13339,8 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
  */
 
 /**
- * @class Roo.bootstrap.TextArea
- * @extends Roo.bootstrap.Input
+ * @class Roo.bootstrap.form.TextArea
+ * @extends Roo.bootstrap.form.Input
  * Bootstrap TextArea class
  * @cfg {Number} cols Specifies the visible width of a text area
  * @cfg {Number} rows Specifies the visible number of lines in a text area
@@ -11269,12 +13353,12 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.TextArea = function(config){
-    Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
+Roo.bootstrap.form.TextArea = function(config){
+    Roo.bootstrap.form.TextArea.superclass.constructor.call(this, config);
    
 };
 
-Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
+Roo.extend(Roo.bootstrap.form.TextArea, Roo.bootstrap.form.Input,  {
      
     cols : false,
     rows : 5,
@@ -11624,35 +13708,35 @@ Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
  */
  
 /**
- * @class Roo.bootstrap.TriggerField
- * @extends Roo.bootstrap.Input
+ * @class Roo.bootstrap.form.TriggerField
+ * @extends Roo.bootstrap.form.Input
  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
  * for which you can provide a custom implementation.  For example:
  * <pre><code>
-var trigger = new Roo.bootstrap.TriggerField();
+var trigger = new Roo.bootstrap.form.TriggerField();
 trigger.onTriggerClick = myTriggerFn;
 trigger.applyTo('my-field');
 </code></pre>
  *
  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
- * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
+ * {@link Roo.bootstrap.form.DateField} and {@link Roo.bootstrap.form.ComboBox} are perfect examples of this.
  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
  * @cfg {String} caret (search|calendar) BS3 only - carat fa name
 
  * @constructor
  * Create a new TriggerField.
- * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
+ * @param {Object} config Configuration options (valid {@Roo.bootstrap.form.Input} config options will also be applied
  * to the base TextField)
  */
-Roo.bootstrap.TriggerField = function(config){
+Roo.bootstrap.form.TriggerField = function(config){
     this.mimicing = false;
-    Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
+    Roo.bootstrap.form.TriggerField.superclass.constructor.call(this, config);
 };
 
-Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
+Roo.extend(Roo.bootstrap.form.TriggerField, Roo.bootstrap.form.Input,  {
     /**
      * @cfg {String} triggerClass A CSS class to apply to the trigger
      */
@@ -12018,7 +14102,7 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
     
     // private
     onResize : function(w, h){
-//        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
+//        Roo.bootstrap.form.TriggerField.superclass.onResize.apply(this, arguments);
 //        if(typeof w == 'number'){
 //            var x = w - this.trigger.getWidth();
 //            this.inputEl().setWidth(this.adjustWidth('input', x));
@@ -12049,7 +14133,7 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
         
         this.createList();
         
-        Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
+        Roo.bootstrap.form.TriggerField.superclass.initEvents.call(this);
         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
         if(!this.multiple && this.showToggleBtn){
             this.trigger = this.el.select('span.dropdown-toggle',true).first();
@@ -12100,7 +14184,7 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
     {
         this.list = Roo.get(document.body).createChild({
             tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
-            cls: 'typeahead typeahead-long dropdown-menu',
+            cls: 'typeahead typeahead-long dropdown-menu shadow',
             style: 'display:none'
         });
         
@@ -12122,12 +14206,12 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
         //if(this.wrap){
         //    this.wrap.remove();
         //}
-        Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
+        Roo.bootstrap.form.TriggerField.superclass.onDestroy.call(this);
     },
 
     // private
     onFocus : function(){
-        Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
+        Roo.bootstrap.form.TriggerField.superclass.onFocus.call(this);
         /*
         if(!this.mimicing){
             this.wrap.addClass('x-trigger-wrap-focus');
@@ -12169,7 +14253,7 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
             this.el.un("keydown", this.checkTab, this);
         }
         //this.wrap.removeClass('x-trigger-wrap-focus');
-        Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
+        Roo.bootstrap.form.TriggerField.superclass.onBlur.call(this);
     },
 
     // private
@@ -12181,7 +14265,7 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
     // private
     onDisable : function(){
         this.inputEl().dom.disabled = true;
-        //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
+        //Roo.bootstrap.form.TriggerField.superclass.onDisable.call(this);
         //if(this.wrap){
         //    this.wrap.addClass('x-item-disabled');
         //}
@@ -12190,7 +14274,7 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
     // private
     onEnable : function(){
         this.inputEl().dom.disabled = false;
-        //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
+        //Roo.bootstrap.form.TriggerField.superclass.onEnable.call(this);
         //if(this.wrap){
         //    this.el.removeClass('x-item-disabled');
         //}
@@ -12227,7 +14311,7 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
 */
 
 /**
- * @class Roo.bootstrap.CardUploader
+ * @class Roo.bootstrap.form.CardUploader
  * @extends Roo.bootstrap.Button
  * Bootstrap Card Uploader class - it's a button which when you add files to it, adds cards below with preview and the name...
  * @cfg {Number} errorTimeout default 3000
@@ -12240,21 +14324,39 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.CardUploader = function(config){
+Roo.bootstrap.form.CardUploader = function(config){
     
  
     
-    Roo.bootstrap.CardUploader.superclass.constructor.call(this, config);
+    Roo.bootstrap.form.CardUploader.superclass.constructor.call(this, 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,  {
+Roo.extend(Roo.bootstrap.form.CardUploader, Roo.bootstrap.form.Input,  {
     
      
     errorTimeout : 3000,
@@ -12281,6 +14383,7 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
                 {
                     tag: 'input',
                     type : 'hidden',
+                    name : this.name,
                     value : this.value,
                     cls : 'd-none  form-control'
                 },
@@ -12319,7 +14422,7 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
     initEvents : function()
     {
         
-        Roo.bootstrap.Input.prototype.initEvents.call(this);
+        Roo.bootstrap.form.Input.prototype.initEvents.call(this);
         
         var t = this;
         this.addxtype({
@@ -12409,17 +14512,37 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
         var url = _this.urlAPI.createObjectURL( file);
            
         this.addCard({
-            id : Roo.bootstrap.CardUploader.ID--,
+            id : Roo.bootstrap.form.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?
@@ -12431,7 +14554,7 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
             {
                 xns : Roo.bootstrap,
                 xtype : 'CardFooter',
-                items: [
+                 items: [
                     {
                         xns : Roo.bootstrap,
                         xtype : 'Element',
@@ -12442,13 +14565,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 );
                                     }
                                 }
                             },
@@ -12456,10 +14580,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() {
@@ -12474,7 +14598,7 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
             }
             
         ];
-
+        
         var cn = this.addxtype(
             {
                  
@@ -12490,12 +14614,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');
                     
                   
                 }
@@ -12505,7 +14631,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)
@@ -12514,16 +14654,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();
@@ -12531,19 +14675,22 @@ 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);
+        
+        
+        
     }
     
     
 });
 
 
-Roo.bootstrap.CardUploader.ID = -1;/*
+Roo.bootstrap.form.CardUploader.ID = -1;/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -12557,7 +14704,7 @@ Roo.bootstrap.CardUploader.ID = -1;/*
 
 /**
  * @class Roo.data.SortTypes
- * @singleton
+ * @static
  * Defines the default sorting (casting?) comparison functions used when sorting data.
  */
 Roo.data.SortTypes = {
@@ -13056,13 +15203,13 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     */
     
     /**
-    * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
+    * @cfg {Roo.data.DataProxy} proxy [required] The Proxy object which provides access to a data object.
     */
     /**
     * @cfg {Array} data Inline data to be loaded when the store is initialized.
     */
     /**
-    * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
+    * @cfg {Roo.data.DataReader} reader [required]  The Reader object which processes the data object and returns
     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
     */
     /**
@@ -13211,6 +15358,16 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
      * <p>
      * @param {Object} options An object containing properties which control loading options:<ul>
      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
+     * <li>params.data {Object} if you are using a MemoryProxy / JsonReader, use this as the data to load stuff..
+     * <pre>
+                {
+                    data : data,  // array of key=>value data like JsonReader
+                    total : data.length,
+                    success : true
+                    
+                }
+        </pre>
+            }.</li>
      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
      * passed the following arguments:<ul>
      * <li>r : Roo.data.Record[]</li>
@@ -13257,7 +15414,8 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
     // private
     // Called as a callback by the Reader during a load operation.
     loadRecords : function(o, options, success){
-        if(!o || success === false){
+         
+        if(!o){
             if(success !== false){
                 this.fireEvent("load", this, [], options, o);
             }
@@ -13645,6 +15803,8 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
  * @cfg {Array} fields An array of field definition objects, or field name strings.
  * @cfg {Object} an existing reader (eg. copied from another store)
  * @cfg {Array} data The multi-dimensional array of data
+ * @cfg {Roo.data.DataProxy} proxy [not-required]  
+ * @cfg {Roo.data.Reader} reader  [not-required] 
  * @constructor
  * @param {Object} config
  */
@@ -13816,6 +15976,7 @@ Roo.data.Field.prototype = {
 
 /**
  * @class Roo.data.DataReader
+ * @abstract
  * Base class for reading structured data from a data source.  This class is intended to be
  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
  */
@@ -13866,7 +16027,8 @@ Roo.data.DataReader.prototype = {
 
 /**
  * @class Roo.data.DataProxy
- * @extends Roo.data.Observable
+ * @extends Roo.util.Observable
+ * @abstract
  * This class is an abstract base class for implementations which provide retrieval of
  * unformatted data objects.<br>
  * <p>
@@ -13924,14 +16086,16 @@ Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
  */
 /**
  * @class Roo.data.MemoryProxy
+ * @extends Roo.data.DataProxy
  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
  * to the Reader when its load method is called.
  * @constructor
- * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
+ * @param {Object} config  A config object containing the objects needed for the Store to access data,
  */
-Roo.data.MemoryProxy = function(data){
-    if (data.data) {
-        data = data.data;
+Roo.data.MemoryProxy = function(config){
+    var data = config;
+    if (typeof(config) != 'undefined' && typeof(config.data) != 'undefined') {
+        data = config.data;
     }
     Roo.data.MemoryProxy.superclass.constructor.call(this);
     this.data = data;
@@ -13939,6 +16103,9 @@ Roo.data.MemoryProxy = function(data){
 
 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
     
+    /**
+     *  @cfg {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
+     */
     /**
      * Load data from the requested source (in this case an in-memory
      * data object passed to the constructor), read the data object into
@@ -14104,8 +16271,10 @@ Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
         try {
             result = o.reader.read(response);
         }catch(e){
+            o.success = false;
+            o.raw = { errorMsg : response.responseText };
             this.fireEvent("loadexception", this, o, response, e);
-            o.request.callback.call(o.request.scope, null, o.request.arg, false);
+            o.request.callback.call(o.request.scope, o, o.request.arg, false);
             return;
         }
         
@@ -14511,19 +16680,27 @@ Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
         }
         var records = [];
         for(var i = 0; i < c; i++){
-                var n = root[i];
+            var n = root[i];
             var values = {};
             var id = this.getId(n);
             for(var j = 0; j < fl; j++){
                 f = fi[j];
-            var v = this.ef[j](n);
-            if (!f.convert) {
-                Roo.log('missing convert for ' + f.name);
-                Roo.log(f);
-                continue;
-            }
-            values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
-            }
+                               var v = this.ef[j](n);
+                               if (!f.convert) {
+                                       Roo.log('missing convert for ' + f.name);
+                                       Roo.log(f);
+                                       continue;
+                               }
+                               values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
+            }
+                       if (!Record) {
+                               return {
+                                       raw : { errorMsg : "JSON Reader Error: fields or metadata not available to create Record" },
+                                       success : false,
+                                       records : [],
+                                       totalRecords : 0
+                               };
+                       }
             var record = new Record(values, id);
             record.json = n;
             records[i] = record;
@@ -14607,35 +16784,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;
+        
     }
     
     
@@ -14645,8 +16822,8 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
  */
 
 /**
- * @class Roo.bootstrap.ComboBox
- * @extends Roo.bootstrap.TriggerField
+ * @class Roo.bootstrap.form.ComboBox
+ * @extends Roo.bootstrap.form.TriggerField
  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
  * @cfg {Boolean} append (true|false) default false
  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
@@ -14658,29 +16835,30 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
  * @cfg {Boolean} emptyResultText only for touch device
  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
  * @cfg {String} emptyTitle default ''
+ * @cfg {Number} width fixed with? experimental
  * @constructor
  * Create a new ComboBox.
  * @param {Object} config Configuration options
  */
-Roo.bootstrap.ComboBox = function(config){
-    Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
+Roo.bootstrap.form.ComboBox = function(config){
+    Roo.bootstrap.form.ComboBox.superclass.constructor.call(this, config);
     this.addEvents({
         /**
          * @event expand
          * Fires when the dropdown list is expanded
-        * @param {Roo.bootstrap.ComboBox} combo This combo box
+        * @param {Roo.bootstrap.form.ComboBox} combo This combo box
         */
         'expand' : true,
         /**
          * @event collapse
          * Fires when the dropdown list is collapsed
-        * @param {Roo.bootstrap.ComboBox} combo This combo box
+        * @param {Roo.bootstrap.form.ComboBox} combo This combo box
         */
         'collapse' : true,
         /**
          * @event beforeselect
          * Fires before a list item is selected. Return false to cancel the selection.
-        * @param {Roo.bootstrap.ComboBox} combo This combo box
+        * @param {Roo.bootstrap.form.ComboBox} combo This combo box
         * @param {Roo.data.Record} record The data record returned from the underlying store
         * @param {Number} index The index of the selected item in the dropdown list
         */
@@ -14688,7 +16866,7 @@ Roo.bootstrap.ComboBox = function(config){
         /**
          * @event select
          * Fires when a list item is selected
-        * @param {Roo.bootstrap.ComboBox} combo This combo box
+        * @param {Roo.bootstrap.form.ComboBox} combo This combo box
         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
         * @param {Number} index The index of the selected item in the dropdown list
         */
@@ -14697,7 +16875,7 @@ Roo.bootstrap.ComboBox = function(config){
          * @event beforequery
          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
          * The event object passed has these properties:
-        * @param {Roo.bootstrap.ComboBox} combo This combo box
+        * @param {Roo.bootstrap.form.ComboBox} combo This combo box
         * @param {String} query The query
         * @param {Boolean} forceAll true to force "all" query
         * @param {Boolean} cancel true to cancel the query
@@ -14707,44 +16885,44 @@ Roo.bootstrap.ComboBox = function(config){
          /**
          * @event add
          * Fires when the 'add' icon is pressed (add a listener to enable add button)
-        * @param {Roo.bootstrap.ComboBox} combo This combo box
+        * @param {Roo.bootstrap.form.ComboBox} combo This combo box
         */
         'add' : true,
         /**
          * @event edit
          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
-        * @param {Roo.bootstrap.ComboBox} combo This combo box
+        * @param {Roo.bootstrap.form.ComboBox} combo This combo box
         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
         */
         'edit' : true,
         /**
          * @event remove
          * Fires when the remove value from the combobox array
-        * @param {Roo.bootstrap.ComboBox} combo This combo box
+        * @param {Roo.bootstrap.form.ComboBox} combo This combo box
         */
         'remove' : true,
         /**
          * @event afterremove
          * Fires when the remove value from the combobox array
-        * @param {Roo.bootstrap.ComboBox} combo This combo box
+        * @param {Roo.bootstrap.form.ComboBox} combo This combo box
         */
         'afterremove' : true,
         /**
          * @event specialfilter
          * Fires when specialfilter
-            * @param {Roo.bootstrap.ComboBox} combo This combo box
+            * @param {Roo.bootstrap.form.ComboBox} combo This combo box
             */
         'specialfilter' : true,
         /**
          * @event tick
          * Fires when tick the element
-            * @param {Roo.bootstrap.ComboBox} combo This combo box
+            * @param {Roo.bootstrap.form.ComboBox} combo This combo box
             */
         'tick' : true,
         /**
          * @event touchviewdisplay
          * Fires when touch view require special display (default is using displayField)
-            * @param {Roo.bootstrap.ComboBox} combo This combo box
+            * @param {Roo.bootstrap.form.ComboBox} combo This combo box
             * @param {Object} cfg set html .
             */
         'touchviewdisplay' : true
@@ -14765,7 +16943,7 @@ Roo.bootstrap.ComboBox = function(config){
     }
 };
 
-Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
+Roo.extend(Roo.bootstrap.form.ComboBox, Roo.bootstrap.form.TriggerField, {
      
     /**
      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
@@ -14950,223 +17128,2050 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
      */
     specialFilter : false,
     
-    /**
-     * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
-     */
-    mobileTouchView : true,
+    /**
+     * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
+     */
+    mobileTouchView : true,
+    
+    /**
+     * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
+     */
+    useNativeIOS : false,
+    
+    /**
+     * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
+     */
+    mobile_restrict_height : false,
+    
+    ios_options : false,
+    
+    //private
+    addicon : false,
+    editicon: false,
+    
+    page: 0,
+    hasQuery: false,
+    append: false,
+    loadNext: false,
+    autoFocus : true,
+    tickable : false,
+    btnPosition : 'right',
+    triggerList : true,
+    showToggleBtn : true,
+    animate : true,
+    emptyResultText: 'Empty',
+    triggerText : 'Select',
+    emptyTitle : '',
+    width : false,
+    
+    // element that contains real text value.. (when hidden is used..)
+    
+    getAutoCreate : function()
+    {   
+        var cfg = false;
+        //render
+        /*
+         * Render classic select for iso
+         */
+        
+        if(Roo.isIOS && this.useNativeIOS){
+            cfg = this.getAutoCreateNativeIOS();
+            return cfg;
+        }
+        
+        /*
+         * Touch Devices
+         */
+        
+        if(Roo.isTouch && this.mobileTouchView){
+            cfg = this.getAutoCreateTouchView();
+            return cfg;;
+        }
+        
+        /*
+         *  Normal ComboBox
+         */
+        if(!this.tickable){
+            cfg = Roo.bootstrap.form.ComboBox.superclass.getAutoCreate.call(this);
+            return cfg;
+        }
+        
+        /*
+         *  ComboBox with tickable selections
+         */
+             
+        var align = this.labelAlign || this.parentLabelAlign();
+        
+        cfg = {
+            cls : 'form-group roo-combobox-tickable' //input-group
+        };
+        
+        var btn_text_select = '';
+        var btn_text_done = '';
+        var btn_text_cancel = '';
+        
+        if (this.btn_text_show) {
+            btn_text_select = 'Select';
+            btn_text_done = 'Done';
+            btn_text_cancel = 'Cancel'; 
+        }
+        
+        var buttons = {
+            tag : 'div',
+            cls : 'tickable-buttons',
+            cn : [
+                {
+                    tag : 'button',
+                    type : 'button',
+                    cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
+                    //html : this.triggerText
+                    html: btn_text_select
+                },
+                {
+                    tag : 'button',
+                    type : 'button',
+                    name : 'ok',
+                    cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
+                    //html : 'Done'
+                    html: btn_text_done
+                },
+                {
+                    tag : 'button',
+                    type : 'button',
+                    name : 'cancel',
+                    cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
+                    //html : 'Cancel'
+                    html: btn_text_cancel
+                }
+            ]
+        };
+        
+        if(this.editable){
+            buttons.cn.unshift({
+                tag: 'input',
+                cls: 'roo-select2-search-field-input'
+            });
+        }
+        
+        var _this = this;
+        
+        Roo.each(buttons.cn, function(c){
+            if (_this.size) {
+                c.cls += ' btn-' + _this.size;
+            }
+
+            if (_this.disabled) {
+                c.disabled = true;
+            }
+        });
+        
+        var box = {
+            tag: 'div',
+            style : 'display: contents',
+            cn: [
+                {
+                    tag: 'input',
+                    type : 'hidden',
+                    cls: 'form-hidden-field'
+                },
+                {
+                    tag: 'ul',
+                    cls: 'roo-select2-choices',
+                    cn:[
+                        {
+                            tag: 'li',
+                            cls: 'roo-select2-search-field',
+                            cn: [
+                                buttons
+                            ]
+                        }
+                    ]
+                }
+            ]
+        };
+        
+        var combobox = {
+            cls: 'roo-select2-container input-group roo-select2-container-multi',
+            cn: [
+                
+                box
+//                {
+//                    tag: 'ul',
+//                    cls: 'typeahead typeahead-long dropdown-menu',
+//                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
+//                }
+            ]
+        };
+        
+        if(this.hasFeedback && !this.allowBlank){
+            
+            var feedback = {
+                tag: 'span',
+                cls: 'glyphicon form-control-feedback'
+            };
+
+            combobox.cn.push(feedback);
+        }
+        
+        
+        
+        var indicator = {
+            tag : 'i',
+            cls : 'roo-required-indicator ' + (this.indicatorpos == 'right'  ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
+            tooltip : 'This field is required'
+        };
+        if (Roo.bootstrap.version == 4) {
+            indicator = {
+                tag : 'i',
+                style : 'display:none'
+            };
+        }
+        if (align ==='left' && this.fieldLabel.length) {
+            
+            cfg.cls += ' roo-form-group-label-left'  + (Roo.bootstrap.version == 4 ? ' row' : '');
+            
+            cfg.cn = [
+                indicator,
+                {
+                    tag: 'label',
+                    'for' :  id,
+                    cls : 'control-label col-form-label',
+                    html : this.fieldLabel
+
+                },
+                {
+                    cls : "", 
+                    cn: [
+                        combobox
+                    ]
+                }
+
+            ];
+            
+            var labelCfg = cfg.cn[1];
+            var contentCfg = cfg.cn[2];
+            
+
+            if(this.indicatorpos == 'right'){
+                
+                cfg.cn = [
+                    {
+                        tag: 'label',
+                        'for' :  id,
+                        cls : 'control-label col-form-label',
+                        cn : [
+                            {
+                                tag : 'span',
+                                html : this.fieldLabel
+                            },
+                            indicator
+                        ]
+                    },
+                    {
+                        cls : "",
+                        cn: [
+                            combobox
+                        ]
+                    }
+
+                ];
+                
+                
+                
+                labelCfg = cfg.cn[0];
+                contentCfg = cfg.cn[1];
+            
+            }
+            
+            if(this.labelWidth > 12){
+                labelCfg.style = "width: " + this.labelWidth + 'px';
+            }
+            if(this.width * 1 > 0){
+                contentCfg.style = "width: " + this.width + 'px';
+            }
+            if(this.labelWidth < 13 && this.labelmd == 0){
+                this.labelmd = this.labelWidth;
+            }
+            
+            if(this.labellg > 0){
+                labelCfg.cls += ' col-lg-' + this.labellg;
+                contentCfg.cls += ' col-lg-' + (12 - this.labellg);
+            }
+            
+            if(this.labelmd > 0){
+                labelCfg.cls += ' col-md-' + this.labelmd;
+                contentCfg.cls += ' col-md-' + (12 - this.labelmd);
+            }
+            
+            if(this.labelsm > 0){
+                labelCfg.cls += ' col-sm-' + this.labelsm;
+                contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
+            }
+            
+            if(this.labelxs > 0){
+                labelCfg.cls += ' col-xs-' + this.labelxs;
+                contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
+            }
+                
+                
+        } else if ( this.fieldLabel.length) {
+//                Roo.log(" label");
+                 cfg.cn = [
+                   indicator,
+                    {
+                        tag: 'label',
+                        //cls : 'input-group-addon',
+                        html : this.fieldLabel
+                    },
+                    combobox
+                ];
+                
+                if(this.indicatorpos == 'right'){
+                    cfg.cn = [
+                        {
+                            tag: 'label',
+                            //cls : 'input-group-addon',
+                            html : this.fieldLabel
+                        },
+                        indicator,
+                        combobox
+                    ];
+                    
+                }
+
+        } else {
+            
+//                Roo.log(" no label && no align");
+                cfg = combobox
+                     
+                
+        }
+         
+        var settings=this;
+        ['xs','sm','md','lg'].map(function(size){
+            if (settings[size]) {
+                cfg.cls += ' col-' + size + '-' + settings[size];
+            }
+        });
+        
+        return cfg;
+        
+    },
+    
+    _initEventsCalled : false,
+    
+    // private
+    initEvents: function()
+    {   
+        if (this._initEventsCalled) { // as we call render... prevent looping...
+            return;
+        }
+        this._initEventsCalled = true;
+        
+        if (!this.store) {
+            throw "can not find store for combo";
+        }
+        
+        this.indicator = this.indicatorEl();
+        
+        this.store = Roo.factory(this.store, Roo.data);
+        this.store.parent = this;
+        
+        // if we are building from html. then this element is so complex, that we can not really
+        // use the rendered HTML.
+        // so we have to trash and replace the previous code.
+        if (Roo.XComponent.build_from_html) {
+            // remove this element....
+            var e = this.el.dom, k=0;
+            while (e ) { e = e.previousSibling;  ++k;}
+
+            this.el.remove();
+            
+            this.el=false;
+            this.rendered = false;
+            
+            this.render(this.parent().getChildContainer(true), k);
+        }
+        
+        if(Roo.isIOS && this.useNativeIOS){
+            this.initIOSView();
+            return;
+        }
+        
+        /*
+         * Touch Devices
+         */
+        
+        if(Roo.isTouch && this.mobileTouchView){
+            this.initTouchView();
+            return;
+        }
+        
+        if(this.tickable){
+            this.initTickableEvents();
+            return;
+        }
+        
+        Roo.bootstrap.form.ComboBox.superclass.initEvents.call(this);
+        
+        if(this.hiddenName){
+            
+            this.hiddenField = this.el.select('input.form-hidden-field',true).first();
+            
+            this.hiddenField.dom.value =
+                this.hiddenValue !== undefined ? this.hiddenValue :
+                this.value !== undefined ? this.value : '';
+
+            // prevent input submission
+            this.el.dom.removeAttribute('name');
+            this.hiddenField.dom.setAttribute('name', this.hiddenName);
+             
+             
+        }
+        //if(Roo.isGecko){
+        //    this.el.dom.setAttribute('autocomplete', 'off');
+        //}
+        
+        var cls = 'x-combo-list';
+        
+        //this.list = new Roo.Layer({
+        //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
+        //});
+        
+        var _this = this;
+        
+        (function(){
+            var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
+            _this.list.setWidth(lw);
+        }).defer(100);
+        
+        this.list.on('mouseover', this.onViewOver, this);
+        this.list.on('mousemove', this.onViewMove, this);
+        this.list.on('scroll', this.onViewScroll, this);
+        
+        /*
+        this.list.swallowEvent('mousewheel');
+        this.assetHeight = 0;
+
+        if(this.title){
+            this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
+            this.assetHeight += this.header.getHeight();
+        }
+
+        this.innerList = this.list.createChild({cls:cls+'-inner'});
+        this.innerList.on('mouseover', this.onViewOver, this);
+        this.innerList.on('mousemove', this.onViewMove, this);
+        this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
+        
+        if(this.allowBlank && !this.pageSize && !this.disableClear){
+            this.footer = this.list.createChild({cls:cls+'-ft'});
+            this.pageTb = new Roo.Toolbar(this.footer);
+           
+        }
+        if(this.pageSize){
+            this.footer = this.list.createChild({cls:cls+'-ft'});
+            this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
+                    {pageSize: this.pageSize});
+            
+        }
+        
+        if (this.pageTb && this.allowBlank && !this.disableClear) {
+            var _this = this;
+            this.pageTb.add(new Roo.Toolbar.Fill(), {
+                cls: 'x-btn-icon x-btn-clear',
+                text: '&#160;',
+                handler: function()
+                {
+                    _this.collapse();
+                    _this.clearValue();
+                    _this.onSelect(false, -1);
+                }
+            });
+        }
+        if (this.footer) {
+            this.assetHeight += this.footer.getHeight();
+        }
+        */
+            
+        if(!this.tpl){
+            this.tpl = Roo.bootstrap.version == 4 ?
+                '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' :  // 4 does not need <li> and it get's really confisued.
+                '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
+        }
+
+        this.view = new Roo.View(this.list, this.tpl, {
+            singleSelect:true, store: this.store, selectedClass: this.selectedClass
+        });
+        //this.view.wrapEl.setDisplayed(false);
+        this.view.on('click', this.onViewClick, this);
+        
+        
+        this.store.on('beforeload', this.onBeforeLoad, this);
+        this.store.on('load', this.onLoad, this);
+        this.store.on('loadexception', this.onLoadException, this);
+        /*
+        if(this.resizable){
+            this.resizer = new Roo.Resizable(this.list,  {
+               pinned:true, handles:'se'
+            });
+            this.resizer.on('resize', function(r, w, h){
+                this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
+                this.listWidth = w;
+                this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
+                this.restrictHeight();
+            }, this);
+            this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
+        }
+        */
+        if(!this.editable){
+            this.editable = true;
+            this.setEditable(false);
+        }
+        
+        /*
+        
+        if (typeof(this.events.add.listeners) != 'undefined') {
+            
+            this.addicon = this.wrap.createChild(
+                {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
+       
+            this.addicon.on('click', function(e) {
+                this.fireEvent('add', this);
+            }, this);
+        }
+        if (typeof(this.events.edit.listeners) != 'undefined') {
+            
+            this.editicon = this.wrap.createChild(
+                {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
+            if (this.addicon) {
+                this.editicon.setStyle('margin-left', '40px');
+            }
+            this.editicon.on('click', function(e) {
+                
+                // we fire even  if inothing is selected..
+                this.fireEvent('edit', this, this.lastData );
+                
+            }, this);
+        }
+        */
+        
+        this.keyNav = new Roo.KeyNav(this.inputEl(), {
+            "up" : function(e){
+                this.inKeyMode = true;
+                this.selectPrev();
+            },
+
+            "down" : function(e){
+                if(!this.isExpanded()){
+                    this.onTriggerClick();
+                }else{
+                    this.inKeyMode = true;
+                    this.selectNext();
+                }
+            },
+
+            "enter" : function(e){
+//                this.onViewClick();
+                //return true;
+                this.collapse();
+                
+                if(this.fireEvent("specialkey", this, e)){
+                    this.onViewClick(false);
+                }
+                
+                return true;
+            },
+
+            "esc" : function(e){
+                this.collapse();
+            },
+
+            "tab" : function(e){
+                this.collapse();
+                
+                if(this.fireEvent("specialkey", this, e)){
+                    this.onViewClick(false);
+                }
+                
+                return true;
+            },
+
+            scope : this,
+
+            doRelay : function(foo, bar, hname){
+                if(hname == 'down' || this.scope.isExpanded()){
+                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
+                }
+                return true;
+            },
+
+            forceKeyDown: true
+        });
+        
+        
+        this.queryDelay = Math.max(this.queryDelay || 10,
+                this.mode == 'local' ? 10 : 250);
+        
+        
+        this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
+        
+        if(this.typeAhead){
+            this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
+        }
+        if(this.editable !== false){
+            this.inputEl().on("keyup", this.onKeyUp, this);
+        }
+        if(this.forceSelection){
+            this.inputEl().on('blur', this.doForce, this);
+        }
+        
+        if(this.multiple){
+            this.choices = this.el.select('ul.roo-select2-choices', true).first();
+            this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
+        }
+    },
+    
+    initTickableEvents: function()
+    {   
+        this.createList();
+        
+        if(this.hiddenName){
+            
+            this.hiddenField = this.el.select('input.form-hidden-field',true).first();
+            
+            this.hiddenField.dom.value =
+                this.hiddenValue !== undefined ? this.hiddenValue :
+                this.value !== undefined ? this.value : '';
+
+            // prevent input submission
+            this.el.dom.removeAttribute('name');
+            this.hiddenField.dom.setAttribute('name', this.hiddenName);
+             
+             
+        }
+        
+//        this.list = this.el.select('ul.dropdown-menu',true).first();
+        
+        this.choices = this.el.select('ul.roo-select2-choices', true).first();
+        this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
+        if(this.triggerList){
+            this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
+        }
+         
+        this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
+        this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
+        
+        this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
+        this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
+        
+        this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
+        this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
+        
+        this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
+        this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
+        this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
+        
+        this.okBtn.hide();
+        this.cancelBtn.hide();
+        
+        var _this = this;
+        
+        (function(){
+            var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
+            _this.list.setWidth(lw);
+        }).defer(100);
+        
+        this.list.on('mouseover', this.onViewOver, this);
+        this.list.on('mousemove', this.onViewMove, this);
+        
+        this.list.on('scroll', this.onViewScroll, this);
+        
+        if(!this.tpl){
+            this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' + 
+                'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
+        }
+
+        this.view = new Roo.View(this.list, this.tpl, {
+            singleSelect:true,
+            tickable:true,
+            parent:this,
+            store: this.store,
+            selectedClass: this.selectedClass
+        });
+        
+        //this.view.wrapEl.setDisplayed(false);
+        this.view.on('click', this.onViewClick, this);
+        
+        
+        
+        this.store.on('beforeload', this.onBeforeLoad, this);
+        this.store.on('load', this.onLoad, this);
+        this.store.on('loadexception', this.onLoadException, this);
+        
+        if(this.editable){
+            this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
+                "up" : function(e){
+                    this.inKeyMode = true;
+                    this.selectPrev();
+                },
+
+                "down" : function(e){
+                    this.inKeyMode = true;
+                    this.selectNext();
+                },
+
+                "enter" : function(e){
+                    if(this.fireEvent("specialkey", this, e)){
+                        this.onViewClick(false);
+                    }
+                    
+                    return true;
+                },
+
+                "esc" : function(e){
+                    this.onTickableFooterButtonClick(e, false, false);
+                },
+
+                "tab" : function(e){
+                    this.fireEvent("specialkey", this, e);
+                    
+                    this.onTickableFooterButtonClick(e, false, false);
+                    
+                    return true;
+                },
+
+                scope : this,
+
+                doRelay : function(e, fn, key){
+                    if(this.scope.isExpanded()){
+                       return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
+                    }
+                    return true;
+                },
+
+                forceKeyDown: true
+            });
+        }
+        
+        this.queryDelay = Math.max(this.queryDelay || 10,
+                this.mode == 'local' ? 10 : 250);
+        
+        
+        this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
+        
+        if(this.typeAhead){
+            this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
+        }
+        
+        if(this.editable !== false){
+            this.tickableInputEl().on("keyup", this.onKeyUp, this);
+        }
+        
+        this.indicator = this.indicatorEl();
+        
+        if(this.indicator){
+            this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
+            this.indicator.hide();
+        }
+        
+    },
+
+    onDestroy : function(){
+        if(this.view){
+            this.view.setStore(null);
+            this.view.el.removeAllListeners();
+            this.view.el.remove();
+            this.view.purgeListeners();
+        }
+        if(this.list){
+            this.list.dom.innerHTML  = '';
+        }
+        
+        if(this.store){
+            this.store.un('beforeload', this.onBeforeLoad, this);
+            this.store.un('load', this.onLoad, this);
+            this.store.un('loadexception', this.onLoadException, this);
+        }
+        Roo.bootstrap.form.ComboBox.superclass.onDestroy.call(this);
+    },
+
+    // private
+    fireKey : function(e){
+        if(e.isNavKeyPress() && !this.list.isVisible()){
+            this.fireEvent("specialkey", this, e);
+        }
+    },
+
+    // private
+    onResize: function(w, h)
+    {
+        
+        
+//        Roo.bootstrap.form.ComboBox.superclass.onResize.apply(this, arguments);
+//        
+//        if(typeof w != 'number'){
+//            // we do not handle it!?!?
+//            return;
+//        }
+//        var tw = this.trigger.getWidth();
+//       // tw += this.addicon ? this.addicon.getWidth() : 0;
+//       // tw += this.editicon ? this.editicon.getWidth() : 0;
+//        var x = w - tw;
+//        this.inputEl().setWidth( this.adjustWidth('input', x));
+//            
+//        //this.trigger.setStyle('left', x+'px');
+//        
+//        if(this.list && this.listWidth === undefined){
+//            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
+//            this.list.setWidth(lw);
+//            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
+//        }
+        
+    
+        
+    },
+
+    /**
+     * Allow or prevent the user from directly editing the field text.  If false is passed,
+     * the user will only be able to select from the items defined in the dropdown list.  This method
+     * is the runtime equivalent of setting the 'editable' config option at config time.
+     * @param {Boolean} value True to allow the user to directly edit the field text
+     */
+    setEditable : function(value){
+        if(value == this.editable){
+            return;
+        }
+        this.editable = value;
+        if(!value){
+            this.inputEl().dom.setAttribute('readOnly', true);
+            this.inputEl().on('mousedown', this.onTriggerClick,  this);
+            this.inputEl().addClass('x-combo-noedit');
+        }else{
+            this.inputEl().dom.removeAttribute('readOnly');
+            this.inputEl().un('mousedown', this.onTriggerClick,  this);
+            this.inputEl().removeClass('x-combo-noedit');
+        }
+    },
+
+    // private
+    
+    onBeforeLoad : function(combo,opts){
+        if(!this.hasFocus){
+            return;
+        }
+         if (!opts.add) {
+            this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
+         }
+        this.restrictHeight();
+        this.selectedIndex = -1;
+    },
+
+    // private
+    onLoad : function(){
+        
+        this.hasQuery = false;
+        
+        if(!this.hasFocus){
+            return;
+        }
+        
+        if(typeof(this.loading) !== 'undefined' && this.loading !== null){
+            this.loading.hide();
+        }
+        
+        if(this.store.getCount() > 0){
+            
+            this.expand();
+            this.restrictHeight();
+            if(this.lastQuery == this.allQuery){
+                if(this.editable && !this.tickable){
+                    this.inputEl().dom.select();
+                }
+                
+                if(
+                    !this.selectByValue(this.value, true) &&
+                    this.autoFocus && 
+                    (
+                        !this.store.lastOptions ||
+                        typeof(this.store.lastOptions.add) == 'undefined' || 
+                        this.store.lastOptions.add != true
+                    )
+                ){
+                    this.select(0, true);
+                }
+            }else{
+                if(this.autoFocus){
+                    this.selectNext();
+                }
+                if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
+                    this.taTask.delay(this.typeAheadDelay);
+                }
+            }
+        }else{
+            this.onEmptyResults();
+        }
+        
+        //this.el.focus();
+    },
+    // private
+    onLoadException : function()
+    {
+        this.hasQuery = false;
+        
+        if(typeof(this.loading) !== 'undefined' && this.loading !== null){
+            this.loading.hide();
+        }
+        
+        if(this.tickable && this.editable){
+            return;
+        }
+        
+        this.collapse();
+        // only causes errors at present
+        //Roo.log(this.store.reader.jsonData);
+        //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
+            // fixme
+            //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
+        //}
+        
+        
+    },
+    // private
+    onTypeAhead : function(){
+        if(this.store.getCount() > 0){
+            var r = this.store.getAt(0);
+            var newValue = r.data[this.displayField];
+            var len = newValue.length;
+            var selStart = this.getRawValue().length;
+            
+            if(selStart != len){
+                this.setRawValue(newValue);
+                this.selectText(selStart, newValue.length);
+            }
+        }
+    },
+
+    // private
+    onSelect : function(record, index){
+        
+        if(this.fireEvent('beforeselect', this, record, index) !== false){
+        
+            this.setFromData(index > -1 ? record.data : false);
+            
+            this.collapse();
+            this.fireEvent('select', this, record, index);
+        }
+    },
+
+    /**
+     * Returns the currently selected field value or empty string if no value is set.
+     * @return {String} value The selected value
+     */
+    getValue : function()
+    {
+        if(Roo.isIOS && this.useNativeIOS){
+            return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
+        }
+        
+        if(this.multiple){
+            return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
+        }
+        
+        if(this.valueField){
+            return typeof this.value != 'undefined' ? this.value : '';
+        }else{
+            return Roo.bootstrap.form.ComboBox.superclass.getValue.call(this);
+        }
+    },
+    
+    getRawValue : function()
+    {
+        if(Roo.isIOS && this.useNativeIOS){
+            return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
+        }
+        
+        var v = this.inputEl().getValue();
+        
+        return v;
+    },
+
+    /**
+     * Clears any text/value currently set in the field
+     */
+    clearValue : function(){
+        
+        if(this.hiddenField){
+            this.hiddenField.dom.value = '';
+        }
+        this.value = '';
+        this.setRawValue('');
+        this.lastSelectionText = '';
+        this.lastData = false;
+        
+        var close = this.closeTriggerEl();
+        
+        if(close){
+            close.hide();
+        }
+        
+        this.validate();
+        
+    },
+
+    /**
+     * Sets the specified value into the field.  If the value finds a match, the corresponding record text
+     * will be displayed in the field.  If the value does not match the data value of an existing item,
+     * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
+     * Otherwise the field will be blank (although the value will still be set).
+     * @param {String} value The value to match
+     */
+    setValue : function(v)
+    {
+        if(Roo.isIOS && this.useNativeIOS){
+            this.setIOSValue(v);
+            return;
+        }
+        
+        if(this.multiple){
+            this.syncValue();
+            return;
+        }
+        
+        var text = v;
+        if(this.valueField){
+            var r = this.findRecord(this.valueField, v);
+            if(r){
+                text = r.data[this.displayField];
+            }else if(this.valueNotFoundText !== undefined){
+                text = this.valueNotFoundText;
+            }
+        }
+        this.lastSelectionText = text;
+        if(this.hiddenField){
+            this.hiddenField.dom.value = v;
+        }
+        Roo.bootstrap.form.ComboBox.superclass.setValue.call(this, text);
+        this.value = v;
+        
+        var close = this.closeTriggerEl();
+        
+        if(close){
+            (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
+        }
+        
+        this.validate();
+    },
+    /**
+     * @property {Object} the last set data for the element
+     */
+    
+    lastData : false,
+    /**
+     * Sets the value of the field based on a object which is related to the record format for the store.
+     * @param {Object} value the value to set as. or false on reset?
+     */
+    setFromData : function(o){
+        
+        if(this.multiple){
+            this.addItem(o);
+            return;
+        }
+            
+        var dv = ''; // display value
+        var vv = ''; // value value..
+        this.lastData = o;
+        if (this.displayField) {
+            dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
+        } else {
+            // this is an error condition!!!
+            Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
+        }
+        
+        if(this.valueField){
+            vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
+        }
+        
+        var close = this.closeTriggerEl();
+        
+        if(close){
+            if(dv.length || vv * 1 > 0){
+                close.show() ;
+                this.blockFocus=true;
+            } else {
+                close.hide();
+            }             
+        }
+        
+        if(this.hiddenField){
+            this.hiddenField.dom.value = vv;
+            
+            this.lastSelectionText = dv;
+            Roo.bootstrap.form.ComboBox.superclass.setValue.call(this, dv);
+            this.value = vv;
+            return;
+        }
+        // no hidden field.. - we store the value in 'value', but still display
+        // display field!!!!
+        this.lastSelectionText = dv;
+        Roo.bootstrap.form.ComboBox.superclass.setValue.call(this, dv);
+        this.value = vv;
+        
+        
+        
+    },
+    // private
+    reset : function(){
+        // overridden so that last data is reset..
+        
+        if(this.multiple){
+            this.clearItem();
+            return;
+        }
+        
+        this.setValue(this.originalValue);
+        //this.clearInvalid();
+        this.lastData = false;
+        if (this.view) {
+            this.view.clearSelections();
+        }
+        
+        this.validate();
+    },
+    // private
+    findRecord : function(prop, value){
+        var record;
+        if(this.store.getCount() > 0){
+            this.store.each(function(r){
+                if(r.data[prop] == value){
+                    record = r;
+                    return false;
+                }
+                return true;
+            });
+        }
+        return record;
+    },
+    
+    getName: function()
+    {
+        // returns hidden if it's set..
+        if (!this.rendered) {return ''};
+        return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
+        
+    },
+    // private
+    onViewMove : function(e, t){
+        this.inKeyMode = false;
+    },
+
+    // private
+    onViewOver : function(e, t){
+        if(this.inKeyMode){ // prevent key nav and mouse over conflicts
+            return;
+        }
+        var item = this.view.findItemFromChild(t);
+        
+        if(item){
+            var index = this.view.indexOf(item);
+            this.select(index, false);
+        }
+    },
+
+    // private
+    onViewClick : function(view, doFocus, el, e)
+    {
+        var index = this.view.getSelectedIndexes()[0];
+        
+        var r = this.store.getAt(index);
+        
+        if(this.tickable){
+            
+            if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
+                return;
+            }
+            
+            var rm = false;
+            var _this = this;
+            
+            Roo.each(this.tickItems, function(v,k){
+                
+                if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
+                    Roo.log(v);
+                    _this.tickItems.splice(k, 1);
+                    
+                    if(typeof(e) == 'undefined' && view == false){
+                        Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
+                    }
+                    
+                    rm = true;
+                    return;
+                }
+            });
+            
+            if(rm){
+                return;
+            }
+            
+            if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
+                this.tickItems.push(r.data);
+            }
+            
+            if(typeof(e) == 'undefined' && view == false){
+                Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
+            }
+                    
+            return;
+        }
+        
+        if(r){
+            this.onSelect(r, index);
+        }
+        if(doFocus !== false && !this.blockFocus){
+            this.inputEl().focus();
+        }
+    },
+
+    // private
+    restrictHeight : function(){
+        //this.innerList.dom.style.height = '';
+        //var inner = this.innerList.dom;
+        //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
+        //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
+        //this.list.beginUpdate();
+        //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
+        this.list.alignTo(this.inputEl(), this.listAlign);
+        this.list.alignTo(this.inputEl(), this.listAlign);
+        //this.list.endUpdate();
+    },
+
+    // private
+    onEmptyResults : function(){
+        
+        if(this.tickable && this.editable){
+            this.hasFocus = false;
+            this.restrictHeight();
+            return;
+        }
+        
+        this.collapse();
+    },
+
+    /**
+     * Returns true if the dropdown list is expanded, else false.
+     */
+    isExpanded : function(){
+        return this.list.isVisible();
+    },
+
+    /**
+     * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
+     * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
+     * @param {String} value The data value of the item to select
+     * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
+     * selected item if it is not currently in view (defaults to true)
+     * @return {Boolean} True if the value matched an item in the list, else false
+     */
+    selectByValue : function(v, scrollIntoView){
+        if(v !== undefined && v !== null){
+            var r = this.findRecord(this.valueField || this.displayField, v);
+            if(r){
+                this.select(this.store.indexOf(r), scrollIntoView);
+                return true;
+            }
+        }
+        return false;
+    },
+
+    /**
+     * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
+     * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
+     * @param {Number} index The zero-based index of the list item to select
+     * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
+     * selected item if it is not currently in view (defaults to true)
+     */
+    select : function(index, scrollIntoView){
+        this.selectedIndex = index;
+        this.view.select(index);
+        if(scrollIntoView !== false){
+            var el = this.view.getNode(index);
+            /*
+             * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
+             */
+            if(el){
+                this.list.scrollChildIntoView(el, false);
+            }
+        }
+    },
+
+    // private
+    selectNext : function(){
+        var ct = this.store.getCount();
+        if(ct > 0){
+            if(this.selectedIndex == -1){
+                this.select(0);
+            }else if(this.selectedIndex < ct-1){
+                this.select(this.selectedIndex+1);
+            }
+        }
+    },
+
+    // private
+    selectPrev : function(){
+        var ct = this.store.getCount();
+        if(ct > 0){
+            if(this.selectedIndex == -1){
+                this.select(0);
+            }else if(this.selectedIndex != 0){
+                this.select(this.selectedIndex-1);
+            }
+        }
+    },
+
+    // private
+    onKeyUp : function(e){
+        if(this.editable !== false && !e.isSpecialKey()){
+            this.lastKey = e.getKey();
+            this.dqTask.delay(this.queryDelay);
+        }
+    },
+
+    // private
+    validateBlur : function(){
+        return !this.list || !this.list.isVisible();   
+    },
+
+    // private
+    initQuery : function(){
+        
+        var v = this.getRawValue();
+        
+        if(this.tickable && this.editable){
+            v = this.tickableInputEl().getValue();
+        }
+        
+        this.doQuery(v);
+    },
+
+    // private
+    doForce : function(){
+        if(this.inputEl().dom.value.length > 0){
+            this.inputEl().dom.value =
+                this.lastSelectionText === undefined ? '' : this.lastSelectionText;
+             
+        }
+    },
+
+    /**
+     * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
+     * query allowing the query action to be canceled if needed.
+     * @param {String} query The SQL query to execute
+     * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
+     * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
+     * saved in the current store (defaults to false)
+     */
+    doQuery : function(q, forceAll){
+        
+        if(q === undefined || q === null){
+            q = '';
+        }
+        var qe = {
+            query: q,
+            forceAll: forceAll,
+            combo: this,
+            cancel:false
+        };
+        if(this.fireEvent('beforequery', qe)===false || qe.cancel){
+            return false;
+        }
+        q = qe.query;
+        
+        forceAll = qe.forceAll;
+        if(forceAll === true || (q.length >= this.minChars)){
+            
+            this.hasQuery = true;
+            
+            if(this.lastQuery != q || this.alwaysQuery){
+                this.lastQuery = q;
+                if(this.mode == 'local'){
+                    this.selectedIndex = -1;
+                    if(forceAll){
+                        this.store.clearFilter();
+                    }else{
+                        
+                        if(this.specialFilter){
+                            this.fireEvent('specialfilter', this);
+                            this.onLoad();
+                            return;
+                        }
+                        
+                        this.store.filter(this.displayField, q);
+                    }
+                    
+                    this.store.fireEvent("datachanged", this.store);
+                    
+                    this.onLoad();
+                    
+                    
+                }else{
+                    
+                    this.store.baseParams[this.queryParam] = q;
+                    
+                    var options = {params : this.getParams(q)};
+                    
+                    if(this.loadNext){
+                        options.add = true;
+                        options.params.start = this.page * this.pageSize;
+                    }
+                    
+                    this.store.load(options);
+                    
+                    /*
+                     *  this code will make the page width larger, at the beginning, the list not align correctly, 
+                     *  we should expand the list on onLoad
+                     *  so command out it
+                     */
+//                    this.expand();
+                }
+            }else{
+                this.selectedIndex = -1;
+                this.onLoad();   
+            }
+        }
+        
+        this.loadNext = false;
+    },
+    
+    // private
+    getParams : function(q){
+        var p = {};
+        //p[this.queryParam] = q;
+        
+        if(this.pageSize){
+            p.start = 0;
+            p.limit = this.pageSize;
+        }
+        return p;
+    },
+
+    /**
+     * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
+     */
+    collapse : function(){
+        if(!this.isExpanded()){
+            return;
+        }
+        
+        this.list.hide();
+        
+        this.hasFocus = false;
+        
+        if(this.tickable){
+            this.okBtn.hide();
+            this.cancelBtn.hide();
+            this.trigger.show();
+            
+            if(this.editable){
+                this.tickableInputEl().dom.value = '';
+                this.tickableInputEl().blur();
+            }
+            
+        }
+        
+        Roo.get(document).un('mousedown', this.collapseIf, this);
+        Roo.get(document).un('mousewheel', this.collapseIf, this);
+        if (!this.editable) {
+            Roo.get(document).un('keydown', this.listKeyPress, this);
+        }
+        this.fireEvent('collapse', this);
+        
+        this.validate();
+    },
+
+    // private
+    collapseIf : function(e){
+        var in_combo  = e.within(this.el);
+        var in_list =  e.within(this.list);
+        var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
+        
+        if (in_combo || in_list || is_list) {
+            //e.stopPropagation();
+            return;
+        }
+        
+        if(this.tickable){
+            this.onTickableFooterButtonClick(e, false, false);
+        }
+
+        this.collapse();
+        
+    },
+
+    /**
+     * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
+     */
+    expand : function(){
+       
+        if(this.isExpanded() || !this.hasFocus){
+            return;
+        }
+        
+        var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
+        this.list.setWidth(lw);
+        
+        Roo.log('expand');
+        
+        this.list.show();
+        
+        this.restrictHeight();
+        
+        if(this.tickable){
+            
+            this.tickItems = Roo.apply([], this.item);
+            
+            this.okBtn.show();
+            this.cancelBtn.show();
+            this.trigger.hide();
+            
+            if(this.editable){
+                this.tickableInputEl().focus();
+            }
+            
+        }
+        
+        Roo.get(document).on('mousedown', this.collapseIf, this);
+        Roo.get(document).on('mousewheel', this.collapseIf, this);
+        if (!this.editable) {
+            Roo.get(document).on('keydown', this.listKeyPress, this);
+        }
+        
+        this.fireEvent('expand', this);
+    },
+
+    // private
+    // Implements the default empty TriggerField.onTriggerClick function
+    onTriggerClick : function(e)
+    {
+        Roo.log('trigger click');
+        
+        if(this.disabled || !this.triggerList){
+            return;
+        }
+        
+        this.page = 0;
+        this.loadNext = false;
+        
+        if(this.isExpanded()){
+            this.collapse();
+            if (!this.blockFocus) {
+                this.inputEl().focus();
+            }
+            
+        }else {
+            this.hasFocus = true;
+            if(this.triggerAction == 'all') {
+                this.doQuery(this.allQuery, true);
+            } else {
+                this.doQuery(this.getRawValue());
+            }
+            if (!this.blockFocus) {
+                this.inputEl().focus();
+            }
+        }
+    },
+    
+    onTickableTriggerClick : function(e)
+    {
+        if(this.disabled){
+            return;
+        }
+        
+        this.page = 0;
+        this.loadNext = false;
+        this.hasFocus = true;
+        
+        if(this.triggerAction == 'all') {
+            this.doQuery(this.allQuery, true);
+        } else {
+            this.doQuery(this.getRawValue());
+        }
+    },
     
-    /**
-     * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
-     */
-    useNativeIOS : false,
+    onSearchFieldClick : function(e)
+    {
+        if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
+            this.onTickableFooterButtonClick(e, false, false);
+            return;
+        }
+        
+        if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
+            return;
+        }
+        
+        this.page = 0;
+        this.loadNext = false;
+        this.hasFocus = true;
+        
+        if(this.triggerAction == 'all') {
+            this.doQuery(this.allQuery, true);
+        } else {
+            this.doQuery(this.getRawValue());
+        }
+    },
     
-    /**
-     * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
-     */
-    mobile_restrict_height : false,
+    listKeyPress : function(e)
+    {
+        //Roo.log('listkeypress');
+        // scroll to first matching element based on key pres..
+        if (e.isSpecialKey()) {
+            return false;
+        }
+        var k = String.fromCharCode(e.getKey()).toUpperCase();
+        //Roo.log(k);
+        var match  = false;
+        var csel = this.view.getSelectedNodes();
+        var cselitem = false;
+        if (csel.length) {
+            var ix = this.view.indexOf(csel[0]);
+            cselitem  = this.store.getAt(ix);
+            if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
+                cselitem = false;
+            }
+            
+        }
+        
+        this.store.each(function(v) { 
+            if (cselitem) {
+                // start at existing selection.
+                if (cselitem.id == v.id) {
+                    cselitem = false;
+                }
+                return true;
+            }
+                
+            if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
+                match = this.store.indexOf(v);
+                return false;
+            }
+            return true;
+        }, this);
+        
+        if (match === false) {
+            return true; // no more action?
+        }
+        // scroll to?
+        this.view.select(match);
+        var sn = Roo.get(this.view.getSelectedNodes()[0]);
+        sn.scrollIntoView(sn.dom.parentNode, false);
+    },
     
-    ios_options : false,
+    onViewScroll : function(e, t){
+        
+        if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
+            return;
+        }
+        
+        this.hasQuery = true;
+        
+        this.loading = this.list.select('.loading', true).first();
+        
+        if(this.loading === null){
+            this.list.createChild({
+                tag: 'div',
+                cls: 'loading roo-select2-more-results roo-select2-active',
+                html: 'Loading more results...'
+            });
+            
+            this.loading = this.list.select('.loading', true).first();
+            
+            this.loading.setVisibilityMode(Roo.Element.DISPLAY);
+            
+            this.loading.hide();
+        }
+        
+        this.loading.show();
+        
+        var _combo = this;
+        
+        this.page++;
+        this.loadNext = true;
+        
+        (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
+        
+        return;
+    },
     
-    //private
-    addicon : false,
-    editicon: false,
+    addItem : function(o)
+    {   
+        var dv = ''; // display value
+        
+        if (this.displayField) {
+            dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
+        } else {
+            // this is an error condition!!!
+            Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
+        }
+        
+        if(!dv.length){
+            return;
+        }
+        
+        var choice = this.choices.createChild({
+            tag: 'li',
+            cls: 'roo-select2-search-choice',
+            cn: [
+                {
+                    tag: 'div',
+                    html: dv
+                },
+                {
+                    tag: 'a',
+                    href: '#',
+                    cls: 'roo-select2-search-choice-close fa fa-times',
+                    tabindex: '-1'
+                }
+            ]
+            
+        }, this.searchField);
+        
+        var close = choice.select('a.roo-select2-search-choice-close', true).first();
+        
+        close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
+        
+        this.item.push(o);
+        
+        this.lastData = o;
+        
+        this.syncValue();
+        
+        this.inputEl().dom.value = '';
+        
+        this.validate();
+    },
     
-    page: 0,
-    hasQuery: false,
-    append: false,
-    loadNext: false,
-    autoFocus : true,
-    tickable : false,
-    btnPosition : 'right',
-    triggerList : true,
-    showToggleBtn : true,
-    animate : true,
-    emptyResultText: 'Empty',
-    triggerText : 'Select',
-    emptyTitle : '',
+    onRemoveItem : function(e, _self, o)
+    {
+        e.preventDefault();
+        
+        this.lastItem = Roo.apply([], this.item);
+        
+        var index = this.item.indexOf(o.data) * 1;
+        
+        if( index < 0){
+            Roo.log('not this item?!');
+            return;
+        }
+        
+        this.item.splice(index, 1);
+        o.item.remove();
+        
+        this.syncValue();
+        
+        this.fireEvent('remove', this, e);
+        
+        this.validate();
+        
+    },
     
-    // element that contains real text value.. (when hidden is used..)
+    syncValue : function()
+    {
+        if(!this.item.length){
+            this.clearValue();
+            return;
+        }
+            
+        var value = [];
+        var _this = this;
+        Roo.each(this.item, function(i){
+            if(_this.valueField){
+                value.push(i[_this.valueField]);
+                return;
+            }
+
+            value.push(i);
+        });
+
+        this.value = value.join(',');
+
+        if(this.hiddenField){
+            this.hiddenField.dom.value = this.value;
+        }
+        
+        this.store.fireEvent("datachanged", this.store);
+        
+        this.validate();
+    },
     
-    getAutoCreate : function()
-    {   
-        var cfg = false;
-        //render
-        /*
-         * Render classic select for iso
-         */
+    clearItem : function()
+    {
+        if(!this.multiple){
+            return;
+        }
+        
+        this.item = [];
+        
+        Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
+           c.remove();
+        });
+        
+        this.syncValue();
         
+        this.validate();
+        
+        if(this.tickable && !Roo.isTouch){
+            this.view.refresh();
+        }
+    },
+    
+    inputEl: function ()
+    {
         if(Roo.isIOS && this.useNativeIOS){
-            cfg = this.getAutoCreateNativeIOS();
-            return cfg;
+            return this.el.select('select.roo-ios-select', true).first();
         }
         
-        /*
-         * Touch Devices
-         */
-        
         if(Roo.isTouch && this.mobileTouchView){
-            cfg = this.getAutoCreateTouchView();
-            return cfg;;
+            return this.el.select('input.form-control',true).first();
         }
         
-        /*
-         *  Normal ComboBox
-         */
-        if(!this.tickable){
-            cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
-            return cfg;
+        if(this.tickable){
+            return this.searchField;
         }
         
-        /*
-         *  ComboBox with tickable selections
-         */
-             
-        var align = this.labelAlign || this.parentLabelAlign();
+        return this.el.select('input.form-control',true).first();
+    },
+    
+    onTickableFooterButtonClick : function(e, btn, el)
+    {
+        e.preventDefault();
         
-        cfg = {
-            cls : 'form-group roo-combobox-tickable' //input-group
+        this.lastItem = Roo.apply([], this.item);
+        
+        if(btn && btn.name == 'cancel'){
+            this.tickItems = Roo.apply([], this.item);
+            this.collapse();
+            return;
+        }
+        
+        this.clearItem();
+        
+        var _this = this;
+        
+        Roo.each(this.tickItems, function(o){
+            _this.addItem(o);
+        });
+        
+        this.collapse();
+        
+    },
+    
+    validate : function()
+    {
+        if(this.getVisibilityEl().hasClass('hidden')){
+            return true;
+        }
+        
+        var v = this.getRawValue();
+        
+        if(this.multiple){
+            v = this.getValue();
+        }
+        
+        if(this.disabled || this.allowBlank || v.length){
+            this.markValid();
+            return true;
+        }
+        
+        this.markInvalid();
+        return false;
+    },
+    
+    tickableInputEl : function()
+    {
+        if(!this.tickable || !this.editable){
+            return this.inputEl();
+        }
+        
+        return this.inputEl().select('.roo-select2-search-field-input', true).first();
+    },
+    
+    
+    getAutoCreateTouchView : function()
+    {
+        var id = Roo.id();
+        
+        var cfg = {
+            cls: 'form-group' //input-group
         };
         
-        var btn_text_select = '';
-        var btn_text_done = '';
-        var btn_text_cancel = '';
+        var input =  {
+            tag: 'input',
+            id : id,
+            type : this.inputType,
+            cls : 'form-control x-combo-noedit',
+            autocomplete: 'new-password',
+            placeholder : this.placeholder || '',
+            readonly : true
+        };
         
-        if (this.btn_text_show) {
-            btn_text_select = 'Select';
-            btn_text_done = 'Done';
-            btn_text_cancel = 'Cancel'; 
+        if (this.name) {
+            input.name = this.name;
         }
         
-        var buttons = {
-            tag : 'div',
-            cls : 'tickable-buttons',
+        if (this.size) {
+            input.cls += ' input-' + this.size;
+        }
+        
+        if (this.disabled) {
+            input.disabled = true;
+        }
+        
+        var inputblock = {
+            cls : 'roo-combobox-wrap',
             cn : [
-                {
-                    tag : 'button',
-                    type : 'button',
-                    cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
-                    //html : this.triggerText
-                    html: btn_text_select
-                },
-                {
-                    tag : 'button',
-                    type : 'button',
-                    name : 'ok',
-                    cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
-                    //html : 'Done'
-                    html: btn_text_done
-                },
-                {
-                    tag : 'button',
-                    type : 'button',
-                    name : 'cancel',
-                    cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
-                    //html : 'Cancel'
-                    html: btn_text_cancel
-                }
+                input
             ]
         };
         
-        if(this.editable){
-            buttons.cn.unshift({
-                tag: 'input',
-                cls: 'roo-select2-search-field-input'
+        if(this.before){
+            inputblock.cls += ' input-group';
+            
+            inputblock.cn.unshift({
+                tag :'span',
+                cls : 'input-group-addon input-group-prepend input-group-text',
+                html : this.before
             });
         }
         
-        var _this = this;
+        if(this.removable && !this.multiple){
+            inputblock.cls += ' roo-removable';
+            
+            inputblock.cn.push({
+                tag: 'button',
+                html : 'x',
+                cls : 'roo-combo-removable-btn close'
+            });
+        }
+
+        if(this.hasFeedback && !this.allowBlank){
+            
+            inputblock.cls += ' has-feedback';
+            
+            inputblock.cn.push({
+                tag: 'span',
+                cls: 'glyphicon form-control-feedback'
+            });
+            
+        }
         
-        Roo.each(buttons.cn, function(c){
-            if (_this.size) {
-                c.cls += ' btn-' + _this.size;
-            }
+        if (this.after) {
+            
+            inputblock.cls += (this.before) ? '' : ' input-group';
+            
+            inputblock.cn.push({
+                tag :'span',
+                cls : 'input-group-addon input-group-append input-group-text',
+                html : this.after
+            });
+        }
 
-            if (_this.disabled) {
-                c.disabled = true;
-            }
-        });
         
-        var box = {
-            tag: 'div',
-            style : 'display: contents',
-            cn: [
-                {
-                    tag: 'input',
-                    type : 'hidden',
-                    cls: 'form-hidden-field'
-                },
-                {
-                    tag: 'ul',
-                    cls: 'roo-select2-choices',
-                    cn:[
-                        {
-                            tag: 'li',
-                            cls: 'roo-select2-search-field',
-                            cn: [
-                                buttons
-                            ]
-                        }
-                    ]
-                }
-            ]
-        };
+        var ibwrap = inputblock;
+        
+        if(this.multiple){
+            ibwrap = {
+                tag: 'ul',
+                cls: 'roo-select2-choices',
+                cn:[
+                    {
+                        tag: 'li',
+                        cls: 'roo-select2-search-field',
+                        cn: [
+
+                            inputblock
+                        ]
+                    }
+                ]
+            };
+        
+            
+        }
         
         var combobox = {
-            cls: 'roo-select2-container input-group roo-select2-container-multi',
+            cls: 'roo-select2-container input-group roo-touchview-combobox ',
             cn: [
-                
-                box
-//                {
-//                    tag: 'ul',
-//                    cls: 'typeahead typeahead-long dropdown-menu',
-//                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
-//                }
+                {
+                    tag: 'input',
+                    type : 'hidden',
+                    cls: 'form-hidden-field'
+                },
+                ibwrap
             ]
         };
         
-        if(this.hasFeedback && !this.allowBlank){
+        if(!this.multiple && this.showToggleBtn){
             
-            var feedback = {
-                tag: 'span',
-                cls: 'glyphicon form-control-feedback'
+            var caret = {
+                cls: 'caret'
             };
+            
+            if (this.caret != false) {
+                caret = {
+                     tag: 'i',
+                     cls: 'fa fa-' + this.caret
+                };
+                
+            }
+            
+            combobox.cn.push({
+                tag :'span',
+                cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
+                cn : [
+                    Roo.bootstrap.version == 3 ? caret : '',
+                    {
+                        tag: 'span',
+                        cls: 'combobox-clear',
+                        cn  : [
+                            {
+                                tag : 'i',
+                                cls: 'icon-remove'
+                            }
+                        ]
+                    }
+                ]
 
-            combobox.cn.push(feedback);
+            })
         }
         
+        if(this.multiple){
+            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();
         
-        var indicator = {
-            tag : 'i',
-            cls : 'roo-required-indicator ' + (this.indicatorpos == 'right'  ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
-            tooltip : 'This field is required'
-        };
-        if (Roo.bootstrap.version == 4) {
-            indicator = {
-                tag : 'i',
-                style : 'display:none'
-            };
-        }
         if (align ==='left' && this.fieldLabel.length) {
-            
-            cfg.cls += ' roo-form-group-label-left'  + (Roo.bootstrap.version == 4 ? ' row' : '');
-            
+
             cfg.cn = [
-                indicator,
+                required,
                 {
                     tag: 'label',
-                    'for' :  id,
                     cls : 'control-label col-form-label',
                     html : this.fieldLabel
 
                 },
                 {
-                    cls : ""
+                    cls : 'roo-combobox-wrap '
                     cn: [
                         combobox
                     ]
                 }
-
             ];
             
             var labelCfg = cfg.cn[1];
@@ -15174,7 +19179,6 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             
 
             if(this.indicatorpos == 'right'){
-                
                 cfg.cn = [
                     {
                         tag: 'label',
@@ -15185,11 +19189,11 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                                 tag : 'span',
                                 html : this.fieldLabel
                             },
-                            indicator
+                            required
                         ]
                     },
                     {
-                        cls : "",
+                        cls : "roo-combobox-wrap ",
                         cn: [
                             combobox
                         ]
@@ -15197,17 +19201,16 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
 
                 ];
                 
-                
-                
                 labelCfg = cfg.cn[0];
                 contentCfg = cfg.cn[1];
-            
             }
             
+           
+            
             if(this.labelWidth > 12){
                 labelCfg.style = "width: " + this.labelWidth + 'px';
             }
-            
+           
             if(this.labelWidth < 13 && this.labelmd == 0){
                 this.labelmd = this.labelWidth;
             }
@@ -15234,39 +19237,47 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                 
                 
         } else if ( this.fieldLabel.length) {
-//                Roo.log(" label");
-                 cfg.cn = [
-                   indicator,
+            cfg.cn = [
+               required,
+                {
+                    tag: 'label',
+                    cls : 'control-label',
+                    html : this.fieldLabel
+
+                },
+                {
+                    cls : '', 
+                    cn: [
+                        combobox
+                    ]
+                }
+            ];
+            
+            if(this.indicatorpos == 'right'){
+                cfg.cn = [
                     {
                         tag: 'label',
-                        //cls : 'input-group-addon',
-                        html : this.fieldLabel
+                        cls : 'control-label',
+                        html : this.fieldLabel,
+                        cn : [
+                            required
+                        ]
                     },
-                    combobox
+                    {
+                        cls : '', 
+                        cn: [
+                            combobox
+                        ]
+                    }
                 ];
-                
-                if(this.indicatorpos == 'right'){
-                    cfg.cn = [
-                        {
-                            tag: 'label',
-                            //cls : 'input-group-addon',
-                            html : this.fieldLabel
-                        },
-                        indicator,
-                        combobox
-                    ];
-                    
-                }
-
+            }
         } else {
-            
-//                Roo.log(" no label && no align");
-                cfg = combobox
-                     
-                
+            cfg.cn = combobox;    
         }
-         
-        var settings=this;
+        
+        
+        var settings = this;
+        
         ['xs','sm','md','lg'].map(function(size){
             if (settings[size]) {
                 cfg.cls += ' col-' + size + '-' + settings[size];
@@ -15274,8277 +19285,9525 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
         });
         
         return cfg;
+    },
+    
+    initTouchView : function()
+    {
+        this.renderTouchView();
+        
+        this.touchViewEl.on('scroll', function(){
+            this.el.dom.scrollTop = 0;
+        }, this);
+        
+        this.originalValue = this.getValue();
+        
+        this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
+        
+        this.inputEl().on("click", this.showTouchView, this);
+        if (this.triggerEl) {
+            this.triggerEl.on("click", this.showTouchView, this);
+        }
+        
+        
+        this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
+        this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
+        
+        this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
+        
+        this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
+        this.store.on('load', this.onTouchViewLoad, this);
+        this.store.on('loadexception', this.onTouchViewLoadException, this);
+        
+        if(this.hiddenName){
+            
+            this.hiddenField = this.el.select('input.form-hidden-field',true).first();
+            
+            this.hiddenField.dom.value =
+                this.hiddenValue !== undefined ? this.hiddenValue :
+                this.value !== undefined ? this.value : '';
+        
+            this.el.dom.removeAttribute('name');
+            this.hiddenField.dom.setAttribute('name', this.hiddenName);
+        }
+        
+        if(this.multiple){
+            this.choices = this.el.select('ul.roo-select2-choices', true).first();
+            this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
+        }
+        
+        if(this.removable && !this.multiple){
+            var close = this.closeTriggerEl();
+            if(close){
+                close.setVisibilityMode(Roo.Element.DISPLAY).hide();
+                close.on('click', this.removeBtnClick, this, close);
+            }
+        }
+        /*
+         * fix the bug in Safari iOS8
+         */
+        this.inputEl().on("focus", function(e){
+            document.activeElement.blur();
+        }, this);
+        
+        this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
+        
+        return;
+        
         
     },
     
-    _initEventsCalled : false,
+    renderTouchView : function()
+    {
+        this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.form.ComboBox.touchViewTemplate);
+        this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        
+        this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
+        this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        
+        this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
+        this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        this.touchViewBodyEl.setStyle('overflow', 'auto');
+        
+        this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
+        this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        
+        this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
+        this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        
+    },
     
-    // private
-    initEvents: function()
-    {   
-        if (this._initEventsCalled) { // as we call render... prevent looping...
+    showTouchView : function()
+    {
+        if(this.disabled){
             return;
         }
-        this._initEventsCalled = true;
         
-        if (!this.store) {
-            throw "can not find store for combo";
+        this.touchViewHeaderEl.hide();
+
+        if(this.modalTitle.length){
+            this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
+            this.touchViewHeaderEl.show();
+        }
+
+        this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
+        this.touchViewEl.show();
+
+        this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
+        
+        //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
+        //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
+
+        var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
+
+        if(this.modalTitle.length){
+            bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
         }
         
-        this.indicator = this.indicatorEl();
+        this.touchViewBodyEl.setHeight(bodyHeight);
+
+        if(this.animate){
+            var _this = this;
+            (function(){ _this.touchViewEl.addClass(['in','show']); }).defer(50);
+        }else{
+            this.touchViewEl.addClass(['in','show']);
+        }
         
-        this.store = Roo.factory(this.store, Roo.data);
-        this.store.parent = this;
+        if(this._touchViewMask){
+            Roo.get(document.body).addClass("x-body-masked");
+            this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
+            this._touchViewMask.setStyle('z-index', 10000);
+            this._touchViewMask.addClass('show');
+        }
         
-        // if we are building from html. then this element is so complex, that we can not really
-        // use the rendered HTML.
-        // so we have to trash and replace the previous code.
-        if (Roo.XComponent.build_from_html) {
-            // remove this element....
-            var e = this.el.dom, k=0;
-            while (e ) { e = e.previousSibling;  ++k;}
+        this.doTouchViewQuery();
+        
+    },
+    
+    hideTouchView : function()
+    {
+        this.touchViewEl.removeClass(['in','show']);
 
-            this.el.remove();
-            
-            this.el=false;
-            this.rendered = false;
-            
-            this.render(this.parent().getChildContainer(true), k);
+        if(this.animate){
+            var _this = this;
+            (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
+        }else{
+            this.touchViewEl.setStyle('display', 'none');
         }
         
-        if(Roo.isIOS && this.useNativeIOS){
-            this.initIOSView();
-            return;
+        if(this._touchViewMask){
+            this._touchViewMask.removeClass('show');
+            Roo.get(document.body).removeClass("x-body-masked");
         }
+    },
+    
+    setTouchViewValue : function()
+    {
+        if(this.multiple){
+            this.clearItem();
         
-        /*
-         * Touch Devices
-         */
+            var _this = this;
+
+            Roo.each(this.tickItems, function(o){
+                this.addItem(o);
+            }, this);
+        }
         
-        if(Roo.isTouch && this.mobileTouchView){
-            this.initTouchView();
+        this.hideTouchView();
+    },
+    
+    doTouchViewQuery : function()
+    {
+        var qe = {
+            query: '',
+            forceAll: true,
+            combo: this,
+            cancel:false
+        };
+        
+        if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
+            return false;
+        }
+        
+        if(!this.alwaysQuery || this.mode == 'local'){
+            this.onTouchViewLoad();
             return;
         }
         
-        if(this.tickable){
-            this.initTickableEvents();
+        this.store.load();
+    },
+    
+    onTouchViewBeforeLoad : function(combo,opts)
+    {
+        return;
+    },
+
+    // private
+    onTouchViewLoad : function()
+    {
+        if(this.store.getCount() < 1){
+            this.onTouchViewEmptyResults();
             return;
         }
         
-        Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
+        this.clearTouchView();
         
-        if(this.hiddenName){
+        var rawValue = this.getRawValue();
+        
+        var template = (this.multiple) ? Roo.bootstrap.form.ComboBox.listItemCheckbox : Roo.bootstrap.form.ComboBox.listItemRadio;
+        
+        this.tickItems = [];
+        
+        this.store.data.each(function(d, rowIndex){
+            var row = this.touchViewListGroup.createChild(template);
             
-            this.hiddenField = this.el.select('input.form-hidden-field',true).first();
+            if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
+                row.addClass(d.data.cls);
+            }
             
-            this.hiddenField.dom.value =
-                this.hiddenValue !== undefined ? this.hiddenValue :
-                this.value !== undefined ? this.value : '';
+            if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
+                var cfg = {
+                    data : d.data,
+                    html : d.data[this.displayField]
+                };
+                
+                if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
+                    row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
+                }
+            }
+            row.removeClass('selected');
+            if(!this.multiple && this.valueField &&
+                    typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
+            {
+                // radio buttons..
+                row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
+                row.addClass('selected');
+            }
+            
+            if(this.multiple && this.valueField &&
+                    typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
+            {
+                
+                // checkboxes...
+                row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
+                this.tickItems.push(d.data);
+            }
+            
+            row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
+            
+        }, this);
+        
+        var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
+        
+        var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
 
-            // prevent input submission
-            this.el.dom.removeAttribute('name');
-            this.hiddenField.dom.setAttribute('name', this.hiddenName);
-             
-             
+        if(this.modalTitle.length){
+            bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
+        }
+
+        var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
+        
+        if(this.mobile_restrict_height && listHeight < bodyHeight){
+            this.touchViewBodyEl.setHeight(listHeight);
+        }
+        
+        var _this = this;
+        
+        if(firstChecked && listHeight > bodyHeight){
+            (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
+        }
+        
+    },
+    
+    onTouchViewLoadException : function()
+    {
+        this.hideTouchView();
+    },
+    
+    onTouchViewEmptyResults : function()
+    {
+        this.clearTouchView();
+        
+        this.touchViewListGroup.createChild(Roo.bootstrap.form.ComboBox.emptyResult);
+        
+        this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
+        
+    },
+    
+    clearTouchView : function()
+    {
+        this.touchViewListGroup.dom.innerHTML = '';
+    },
+    
+    onTouchViewClick : function(e, el, o)
+    {
+        e.preventDefault();
+        
+        var row = o.row;
+        var rowIndex = o.rowIndex;
+        
+        var r = this.store.getAt(rowIndex);
+        
+        if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
+            
+            if(!this.multiple){
+                Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
+                    c.dom.removeAttribute('checked');
+                }, this);
+
+                row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
+
+                this.setFromData(r.data);
+
+                var close = this.closeTriggerEl();
+
+                if(close){
+                    close.show();
+                }
+
+                this.hideTouchView();
+
+                this.fireEvent('select', this, r, rowIndex);
+
+                return;
+            }
+
+            if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
+                row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
+                this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
+                return;
+            }
+
+            row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
+            this.addItem(r.data);
+            this.tickItems.push(r.data);
+        }
+    },
+    
+    getAutoCreateNativeIOS : function()
+    {
+        var cfg = {
+            cls: 'form-group' //input-group,
+        };
+        
+        var combobox =  {
+            tag: 'select',
+            cls : 'roo-ios-select'
+        };
+        
+        if (this.name) {
+            combobox.name = this.name;
+        }
+        
+        if (this.disabled) {
+            combobox.disabled = true;
         }
-        //if(Roo.isGecko){
-        //    this.el.dom.setAttribute('autocomplete', 'off');
-        //}
         
-        var cls = 'x-combo-list';
+        var settings = this;
         
-        //this.list = new Roo.Layer({
-        //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
-        //});
+        ['xs','sm','md','lg'].map(function(size){
+            if (settings[size]) {
+                cfg.cls += ' col-' + size + '-' + settings[size];
+            }
+        });
         
-        var _this = this;
+        cfg.cn = combobox;
         
-        (function(){
-            var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
-            _this.list.setWidth(lw);
-        }).defer(100);
+        return cfg;
         
-        this.list.on('mouseover', this.onViewOver, this);
-        this.list.on('mousemove', this.onViewMove, this);
-        this.list.on('scroll', this.onViewScroll, this);
+    },
+    
+    initIOSView : function()
+    {
+        this.store.on('load', this.onIOSViewLoad, this);
         
-        /*
-        this.list.swallowEvent('mousewheel');
-        this.assetHeight = 0;
-
-        if(this.title){
-            this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
-            this.assetHeight += this.header.getHeight();
+        return;
+    },
+    
+    onIOSViewLoad : function()
+    {
+        if(this.store.getCount() < 1){
+            return;
         }
-
-        this.innerList = this.list.createChild({cls:cls+'-inner'});
-        this.innerList.on('mouseover', this.onViewOver, this);
-        this.innerList.on('mousemove', this.onViewMove, this);
-        this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
         
-        if(this.allowBlank && !this.pageSize && !this.disableClear){
-            this.footer = this.list.createChild({cls:cls+'-ft'});
-            this.pageTb = new Roo.Toolbar(this.footer);
-           
-        }
-        if(this.pageSize){
-            this.footer = this.list.createChild({cls:cls+'-ft'});
-            this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
-                    {pageSize: this.pageSize});
-            
-        }
+        this.clearIOSView();
         
-        if (this.pageTb && this.allowBlank && !this.disableClear) {
-            var _this = this;
-            this.pageTb.add(new Roo.Toolbar.Fill(), {
-                cls: 'x-btn-icon x-btn-clear',
-                text: '&#160;',
-                handler: function()
-                {
-                    _this.collapse();
-                    _this.clearValue();
-                    _this.onSelect(false, -1);
-                }
+        if(this.allowBlank) {
+            
+            var default_text = '-- SELECT --';
+            
+            if(this.placeholder.length){
+                default_text = this.placeholder;
+            }
+            
+            if(this.emptyTitle.length){
+                default_text += ' - ' + this.emptyTitle + ' -';
+            }
+            
+            var opt = this.inputEl().createChild({
+                tag: 'option',
+                value : 0,
+                html : default_text
             });
-        }
-        if (this.footer) {
-            this.assetHeight += this.footer.getHeight();
-        }
-        */
             
-        if(!this.tpl){
-            this.tpl = Roo.bootstrap.version == 4 ?
-                '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' :  // 4 does not need <li> and it get's really confisued.
-                '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
-        }
-
-        this.view = new Roo.View(this.list, this.tpl, {
-            singleSelect:true, store: this.store, selectedClass: this.selectedClass
-        });
-        //this.view.wrapEl.setDisplayed(false);
-        this.view.on('click', this.onViewClick, this);
-        
-        
-        this.store.on('beforeload', this.onBeforeLoad, this);
-        this.store.on('load', this.onLoad, this);
-        this.store.on('loadexception', this.onLoadException, this);
-        /*
-        if(this.resizable){
-            this.resizer = new Roo.Resizable(this.list,  {
-               pinned:true, handles:'se'
+            var o = {};
+            o[this.valueField] = 0;
+            o[this.displayField] = default_text;
+            
+            this.ios_options.push({
+                data : o,
+                el : opt
             });
-            this.resizer.on('resize', function(r, w, h){
-                this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
-                this.listWidth = w;
-                this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
-                this.restrictHeight();
-            }, this);
-            this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
-        }
-        */
-        if(!this.editable){
-            this.editable = true;
-            this.setEditable(false);
+            
         }
         
-        /*
-        
-        if (typeof(this.events.add.listeners) != 'undefined') {
+        this.store.data.each(function(d, rowIndex){
             
-            this.addicon = this.wrap.createChild(
-                {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
-       
-            this.addicon.on('click', function(e) {
-                this.fireEvent('add', this);
-            }, this);
-        }
-        if (typeof(this.events.edit.listeners) != 'undefined') {
+            var html = '';
             
-            this.editicon = this.wrap.createChild(
-                {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
-            if (this.addicon) {
-                this.editicon.setStyle('margin-left', '40px');
+            if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
+                html = d.data[this.displayField];
             }
-            this.editicon.on('click', function(e) {
-                
-                // we fire even  if inothing is selected..
-                this.fireEvent('edit', this, this.lastData );
-                
-            }, this);
+            
+            var value = '';
+            
+            if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
+                value = d.data[this.valueField];
+            }
+            
+            var option = {
+                tag: 'option',
+                value : value,
+                html : html
+            };
+            
+            if(this.value == d.data[this.valueField]){
+                option['selected'] = true;
+            }
+            
+            var opt = this.inputEl().createChild(option);
+            
+            this.ios_options.push({
+                data : d.data,
+                el : opt
+            });
+            
+        }, this);
+        
+        this.inputEl().on('change', function(){
+           this.fireEvent('select', this);
+        }, this);
+        
+    },
+    
+    clearIOSView: function()
+    {
+        this.inputEl().dom.innerHTML = '';
+        
+        this.ios_options = [];
+    },
+    
+    setIOSValue: function(v)
+    {
+        this.value = v;
+        
+        if(!this.ios_options){
+            return;
         }
-        */
         
-        this.keyNav = new Roo.KeyNav(this.inputEl(), {
-            "up" : function(e){
-                this.inKeyMode = true;
-                this.selectPrev();
-            },
+        Roo.each(this.ios_options, function(opts){
+           
+           opts.el.dom.removeAttribute('selected');
+           
+           if(opts.data[this.valueField] != v){
+               return;
+           }
+           
+           opts.el.dom.setAttribute('selected', true);
+           
+        }, this);
+    }
 
-            "down" : function(e){
-                if(!this.isExpanded()){
-                    this.onTriggerClick();
-                }else{
-                    this.inKeyMode = true;
-                    this.selectNext();
-                }
-            },
+    /** 
+    * @cfg {Boolean} grow 
+    * @hide 
+    */
+    /** 
+    * @cfg {Number} growMin 
+    * @hide 
+    */
+    /** 
+    * @cfg {Number} growMax 
+    * @hide 
+    */
+    /**
+     * @hide
+     * @method autoSize
+     */
+});
 
-            "enter" : function(e){
-//                this.onViewClick();
-                //return true;
-                this.collapse();
-                
-                if(this.fireEvent("specialkey", this, e)){
-                    this.onViewClick(false);
-                }
-                
-                return true;
+Roo.apply(Roo.bootstrap.form.ComboBox,  {
+    
+    header : {
+        tag: 'div',
+        cls: 'modal-header',
+        cn: [
+            {
+                tag: 'h4',
+                cls: 'modal-title'
+            }
+        ]
+    },
+    
+    body : {
+        tag: 'div',
+        cls: 'modal-body',
+        cn: [
+            {
+                tag: 'ul',
+                cls: 'list-group'
+            }
+        ]
+    },
+    
+    listItemRadio : {
+        tag: 'li',
+        cls: 'list-group-item',
+        cn: [
+            {
+                tag: 'span',
+                cls: 'roo-combobox-list-group-item-value'
             },
-
-            "esc" : function(e){
-                this.collapse();
+            {
+                tag: 'div',
+                cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
+                cn: [
+                    {
+                        tag: 'input',
+                        type: 'radio'
+                    },
+                    {
+                        tag: 'label'
+                    }
+                ]
+            }
+        ]
+    },
+    
+    listItemCheckbox : {
+        tag: 'li',
+        cls: 'list-group-item',
+        cn: [
+            {
+                tag: 'span',
+                cls: 'roo-combobox-list-group-item-value'
             },
+            {
+                tag: 'div',
+                cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
+                cn: [
+                    {
+                        tag: 'input',
+                        type: 'checkbox'
+                    },
+                    {
+                        tag: 'label'
+                    }
+                ]
+            }
+        ]
+    },
+    
+    emptyResult : {
+        tag: 'div',
+        cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
+    },
+    
+    footer : {
+        tag: 'div',
+        cls: 'modal-footer',
+        cn: [
+            {
+                tag: 'div',
+                cls: 'row',
+                cn: [
+                    {
+                        tag: 'div',
+                        cls: 'col-xs-6 text-left',
+                        cn: {
+                            tag: 'button',
+                            cls: 'btn btn-danger roo-touch-view-cancel',
+                            html: 'Cancel'
+                        }
+                    },
+                    {
+                        tag: 'div',
+                        cls: 'col-xs-6 text-right',
+                        cn: {
+                            tag: 'button',
+                            cls: 'btn btn-success roo-touch-view-ok',
+                            html: 'OK'
+                        }
+                    }
+                ]
+            }
+        ]
+        
+    }
+});
+
+Roo.apply(Roo.bootstrap.form.ComboBox,  {
+    
+    touchViewTemplate : {
+        tag: 'div',
+        cls: 'modal fade roo-combobox-touch-view',
+        cn: [
+            {
+                tag: 'div',
+                cls: 'modal-dialog',
+                style : 'position:fixed', // we have to fix position....
+                cn: [
+                    {
+                        tag: 'div',
+                        cls: 'modal-content',
+                        cn: [
+                            Roo.bootstrap.form.ComboBox.header,
+                            Roo.bootstrap.form.ComboBox.body,
+                            Roo.bootstrap.form.ComboBox.footer
+                        ]
+                    }
+                ]
+            }
+        ]
+    }
+});/*
+ * 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.View
+ * @extends Roo.util.Observable
+ * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
+ * This class also supports single and multi selection modes. <br>
+ * Create a data model bound view:
+ <pre><code>
+ var store = new Roo.data.Store(...);
+
+ var view = new Roo.View({
+    el : "my-element",
+    tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
+    singleSelect: true,
+    selectedClass: "ydataview-selected",
+    store: store
+ });
+
+ // listen for node click?
+ view.on("click", function(vw, index, node, e){
+ alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
+ });
+
+ // load XML data
+ dataModel.load("foobar.xml");
+ </code></pre>
+ For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
+ * <br><br>
+ * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
+ * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
+ * 
+ * Note: old style constructor is still suported (container, template, config)
+ * 
+ * @constructor
+ * Create a new View
+ * @param {Object} config The config object
+ * 
+ */
+Roo.View = function(config, depreciated_tpl, depreciated_config){
+    
+    this.parent = false;
+    
+    if (typeof(depreciated_tpl) == 'undefined') {
+        // new way.. - universal constructor.
+        Roo.apply(this, config);
+        this.el  = Roo.get(this.el);
+    } else {
+        // old format..
+        this.el  = Roo.get(config);
+        this.tpl = depreciated_tpl;
+        Roo.apply(this, depreciated_config);
+    }
+    this.wrapEl  = this.el.wrap().wrap();
+    ///this.el = this.wrapEla.appendChild(document.createElement("div"));
+    
+    
+    if(typeof(this.tpl) == "string"){
+        this.tpl = new Roo.Template(this.tpl);
+    } else {
+        // support xtype ctors..
+        this.tpl = new Roo.factory(this.tpl, Roo);
+    }
+    
+    
+    this.tpl.compile();
+    
+    /** @private */
+    this.addEvents({
+        /**
+         * @event beforeclick
+         * Fires before a click is processed. Returns false to cancel the default action.
+         * @param {Roo.View} this
+         * @param {Number} index The index of the target node
+         * @param {HTMLElement} node The target node
+         * @param {Roo.EventObject} e The raw event object
+         */
+            "beforeclick" : true,
+        /**
+         * @event click
+         * Fires when a template node is clicked.
+         * @param {Roo.View} this
+         * @param {Number} index The index of the target node
+         * @param {HTMLElement} node The target node
+         * @param {Roo.EventObject} e The raw event object
+         */
+            "click" : true,
+        /**
+         * @event dblclick
+         * Fires when a template node is double clicked.
+         * @param {Roo.View} this
+         * @param {Number} index The index of the target node
+         * @param {HTMLElement} node The target node
+         * @param {Roo.EventObject} e The raw event object
+         */
+            "dblclick" : true,
+        /**
+         * @event contextmenu
+         * Fires when a template node is right clicked.
+         * @param {Roo.View} this
+         * @param {Number} index The index of the target node
+         * @param {HTMLElement} node The target node
+         * @param {Roo.EventObject} e The raw event object
+         */
+            "contextmenu" : true,
+        /**
+         * @event selectionchange
+         * Fires when the selected nodes change.
+         * @param {Roo.View} this
+         * @param {Array} selections Array of the selected nodes
+         */
+            "selectionchange" : true,
+    
+        /**
+         * @event beforeselect
+         * Fires before a selection is made. If any handlers return false, the selection is cancelled.
+         * @param {Roo.View} this
+         * @param {HTMLElement} node The node to be selected
+         * @param {Array} selections Array of currently selected nodes
+         */
+            "beforeselect" : true,
+        /**
+         * @event preparedata
+         * Fires on every row to render, to allow you to change the data.
+         * @param {Roo.View} this
+         * @param {Object} data to be rendered (change this)
+         */
+          "preparedata" : true
+          
+          
+        });
 
-            "tab" : function(e){
-                this.collapse();
-                
-                if(this.fireEvent("specialkey", this, e)){
-                    this.onViewClick(false);
-                }
-                
-                return true;
-            },
 
-            scope : this,
 
-            doRelay : function(foo, bar, hname){
-                if(hname == 'down' || this.scope.isExpanded()){
-                   return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
-                }
-                return true;
-            },
+    this.el.on({
+        "click": this.onClick,
+        "dblclick": this.onDblClick,
+        "contextmenu": this.onContextMenu,
+        scope:this
+    });
 
-            forceKeyDown: true
-        });
-        
+    this.selections = [];
+    this.nodes = [];
+    this.cmp = new Roo.CompositeElementLite([]);
+    if(this.store){
+        this.store = Roo.factory(this.store, Roo.data);
+        this.setStore(this.store, true);
+    }
+    
+    if ( this.footer && this.footer.xtype) {
+           
+         var fctr = this.wrapEl.appendChild(document.createElement("div"));
         
-        this.queryDelay = Math.max(this.queryDelay || 10,
-                this.mode == 'local' ? 10 : 250);
+        this.footer.dataSource = this.store;
+        this.footer.container = fctr;
+        this.footer = Roo.factory(this.footer, Roo);
+        fctr.insertFirst(this.el);
         
+        // this is a bit insane - as the paging toolbar seems to detach the el..
+//        dom.parentNode.parentNode.parentNode
+         // they get detached?
+    }
+    
+    
+    Roo.View.superclass.constructor.call(this);
+    
+    
+};
+
+Roo.extend(Roo.View, Roo.util.Observable, {
+    
+     /**
+     * @cfg {Roo.data.Store} store Data store to load data from.
+     */
+    store : false,
+    
+    /**
+     * @cfg {String|Roo.Element} el The container element.
+     */
+    el : '',
+    
+    /**
+     * @cfg {String|Roo.Template} tpl The template used by this View 
+     */
+    tpl : false,
+    /**
+     * @cfg {String} dataName the named area of the template to use as the data area
+     *                          Works with domtemplates roo-name="name"
+     */
+    dataName: false,
+    /**
+     * @cfg {String} selectedClass The css class to add to selected nodes
+     */
+    selectedClass : "x-view-selected",
+     /**
+     * @cfg {String} emptyText The empty text to show when nothing is loaded.
+     */
+    emptyText : "",
+    
+    /**
+     * @cfg {String} text to display on mask (default Loading)
+     */
+    mask : false,
+    /**
+     * @cfg {Boolean} multiSelect Allow multiple selection
+     */
+    multiSelect : false,
+    /**
+     * @cfg {Boolean} singleSelect Allow single selection
+     */
+    singleSelect:  false,
+    
+    /**
+     * @cfg {Boolean} toggleSelect - selecting 
+     */
+    toggleSelect : false,
+    
+    /**
+     * @cfg {Boolean} tickable - selecting 
+     */
+    tickable : false,
+    
+    /**
+     * Returns the element this view is bound to.
+     * @return {Roo.Element}
+     */
+    getEl : function(){
+        return this.wrapEl;
+    },
+    
+    
+
+    /**
+     * Refreshes the view. - called by datachanged on the store. - do not call directly.
+     */
+    refresh : function(){
+        //Roo.log('refresh');
+        var t = this.tpl;
         
-        this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
+        // if we are using something like 'domtemplate', then
+        // the what gets used is:
+        // t.applySubtemplate(NAME, data, wrapping data..)
+        // the outer template then get' applied with
+        //     the store 'extra data'
+        // and the body get's added to the
+        //      roo-name="data" node?
+        //      <span class='roo-tpl-{name}'></span> ?????
         
-        if(this.typeAhead){
-            this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
-        }
-        if(this.editable !== false){
-            this.inputEl().on("keyup", this.onKeyUp, this);
-        }
-        if(this.forceSelection){
-            this.inputEl().on('blur', this.doForce, this);
-        }
         
-        if(this.multiple){
-            this.choices = this.el.select('ul.roo-select2-choices', true).first();
-            this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
-        }
-    },
-    
-    initTickableEvents: function()
-    {   
-        this.createList();
         
-        if(this.hiddenName){
+        this.clearSelections();
+        this.el.update("");
+        var html = [];
+        var records = this.store.getRange();
+        if(records.length < 1) {
             
-            this.hiddenField = this.el.select('input.form-hidden-field',true).first();
+            // is this valid??  = should it render a template??
             
-            this.hiddenField.dom.value =
-                this.hiddenValue !== undefined ? this.hiddenValue :
-                this.value !== undefined ? this.value : '';
-
-            // prevent input submission
-            this.el.dom.removeAttribute('name');
-            this.hiddenField.dom.setAttribute('name', this.hiddenName);
-             
-             
+            this.el.update(this.emptyText);
+            return;
         }
-        
-//        this.list = this.el.select('ul.dropdown-menu',true).first();
-        
-        this.choices = this.el.select('ul.roo-select2-choices', true).first();
-        this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
-        if(this.triggerList){
-            this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
+        var el = this.el;
+        if (this.dataName) {
+            this.el.update(t.apply(this.store.meta)); //????
+            el = this.el.child('.roo-tpl-' + this.dataName);
         }
-         
-        this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
-        this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
-        
-        this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
-        this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
-        
-        this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
-        this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
-        
-        this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
-        this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
-        this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
         
-        this.okBtn.hide();
-        this.cancelBtn.hide();
-        
-        var _this = this;
-        
-        (function(){
-            var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
-            _this.list.setWidth(lw);
-        }).defer(100);
-        
-        this.list.on('mouseover', this.onViewOver, this);
-        this.list.on('mousemove', this.onViewMove, this);
-        
-        this.list.on('scroll', this.onViewScroll, this);
-        
-        if(!this.tpl){
-            this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' + 
-                'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
+        for(var i = 0, len = records.length; i < len; i++){
+            var data = this.prepareData(records[i].data, i, records[i]);
+            this.fireEvent("preparedata", this, data, i, records[i]);
+            
+            var d = Roo.apply({}, data);
+            
+            if(this.tickable){
+                Roo.apply(d, {'roo-id' : Roo.id()});
+                
+                var _this = this;
+            
+                Roo.each(this.parent.item, function(item){
+                    if(item[_this.parent.valueField] != data[_this.parent.valueField]){
+                        return;
+                    }
+                    Roo.apply(d, {'roo-data-checked' : 'checked'});
+                });
+            }
+            
+            html[html.length] = Roo.util.Format.trim(
+                this.dataName ?
+                    t.applySubtemplate(this.dataName, d, this.store.meta) :
+                    t.apply(d)
+            );
         }
-
-        this.view = new Roo.View(this.list, this.tpl, {
-            singleSelect:true,
-            tickable:true,
-            parent:this,
-            store: this.store,
-            selectedClass: this.selectedClass
-        });
-        
-        //this.view.wrapEl.setDisplayed(false);
-        this.view.on('click', this.onViewClick, this);
-        
         
         
-        this.store.on('beforeload', this.onBeforeLoad, this);
-        this.store.on('load', this.onLoad, this);
-        this.store.on('loadexception', this.onLoadException, this);
         
-        if(this.editable){
-            this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
-                "up" : function(e){
-                    this.inKeyMode = true;
-                    this.selectPrev();
-                },
-
-                "down" : function(e){
-                    this.inKeyMode = true;
-                    this.selectNext();
-                },
-
-                "enter" : function(e){
-                    if(this.fireEvent("specialkey", this, e)){
-                        this.onViewClick(false);
-                    }
-                    
-                    return true;
-                },
-
-                "esc" : function(e){
-                    this.onTickableFooterButtonClick(e, false, false);
-                },
-
-                "tab" : function(e){
-                    this.fireEvent("specialkey", this, e);
-                    
-                    this.onTickableFooterButtonClick(e, false, false);
-                    
-                    return true;
-                },
+        el.update(html.join(""));
+        this.nodes = el.dom.childNodes;
+        this.updateIndexes(0);
+    },
+    
 
-                scope : this,
+    /**
+     * Function to override to reformat the data that is sent to
+     * the template for each node.
+     * DEPRICATED - use the preparedata event handler.
+     * @param {Array/Object} data The raw data (array of colData for a data model bound view or
+     * a JSON object for an UpdateManager bound view).
+     */
+    prepareData : function(data, index, record)
+    {
+        this.fireEvent("preparedata", this, data, index, record);
+        return data;
+    },
 
-                doRelay : function(e, fn, key){
-                    if(this.scope.isExpanded()){
-                       return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
-                    }
-                    return true;
-                },
+    onUpdate : function(ds, record){
+        // Roo.log('on update');   
+        this.clearSelections();
+        var index = this.store.indexOf(record);
+        var n = this.nodes[index];
+        this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
+        n.parentNode.removeChild(n);
+        this.updateIndexes(index, index);
+    },
 
-                forceKeyDown: true
-            });
-        }
-        
-        this.queryDelay = Math.max(this.queryDelay || 10,
-                this.mode == 'local' ? 10 : 250);
-        
-        
-        this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
-        
-        if(this.typeAhead){
-            this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
+    
+    
+// --------- FIXME     
+    onAdd : function(ds, records, index)
+    {
+        //Roo.log(['on Add', ds, records, index] );        
+        this.clearSelections();
+        if(this.nodes.length == 0){
+            this.refresh();
+            return;
         }
-        
-        if(this.editable !== false){
-            this.tickableInputEl().on("keyup", this.onKeyUp, this);
+        var n = this.nodes[index];
+        for(var i = 0, len = records.length; i < len; i++){
+            var d = this.prepareData(records[i].data, i, records[i]);
+            if(n){
+                this.tpl.insertBefore(n, d);
+            }else{
+                
+                this.tpl.append(this.el, d);
+            }
         }
+        this.updateIndexes(index);
+    },
+
+    onRemove : function(ds, record, index){
+       // Roo.log('onRemove');
+        this.clearSelections();
+        var el = this.dataName  ?
+            this.el.child('.roo-tpl-' + this.dataName) :
+            this.el; 
         
-        this.indicator = this.indicatorEl();
-        
-        if(this.indicator){
-            this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
-            this.indicator.hide();
+        el.dom.removeChild(this.nodes[index]);
+        this.updateIndexes(index);
+    },
+
+    /**
+     * Refresh an individual node.
+     * @param {Number} index
+     */
+    refreshNode : function(index){
+        this.onUpdate(this.store, this.store.getAt(index));
+    },
+
+    updateIndexes : function(startIndex, endIndex){
+        var ns = this.nodes;
+        startIndex = startIndex || 0;
+        endIndex = endIndex || ns.length - 1;
+        for(var i = startIndex; i <= endIndex; i++){
+            ns[i].nodeIndex = i;
         }
-        
     },
 
-    onDestroy : function(){
-        if(this.view){
-            this.view.setStore(null);
-            this.view.el.removeAllListeners();
-            this.view.el.remove();
-            this.view.purgeListeners();
+    /**
+     * Changes the data store this view uses and refresh the view.
+     * @param {Store} store
+     */
+    setStore : function(store, initial){
+        if(!initial && this.store){
+            this.store.un("datachanged", this.refresh);
+            this.store.un("add", this.onAdd);
+            this.store.un("remove", this.onRemove);
+            this.store.un("update", this.onUpdate);
+            this.store.un("clear", this.refresh);
+            this.store.un("beforeload", this.onBeforeLoad);
+            this.store.un("load", this.onLoad);
+            this.store.un("loadexception", this.onLoad);
         }
-        if(this.list){
-            this.list.dom.innerHTML  = '';
+        if(store){
+          
+            store.on("datachanged", this.refresh, this);
+            store.on("add", this.onAdd, this);
+            store.on("remove", this.onRemove, this);
+            store.on("update", this.onUpdate, this);
+            store.on("clear", this.refresh, this);
+            store.on("beforeload", this.onBeforeLoad, this);
+            store.on("load", this.onLoad, this);
+            store.on("loadexception", this.onLoad, this);
         }
         
-        if(this.store){
-            this.store.un('beforeload', this.onBeforeLoad, this);
-            this.store.un('load', this.onLoad, this);
-            this.store.un('loadexception', this.onLoadException, this);
+        if(store){
+            this.refresh();
         }
-        Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
     },
-
-    // private
-    fireKey : function(e){
-        if(e.isNavKeyPress() && !this.list.isVisible()){
-            this.fireEvent("specialkey", this, e);
+    /**
+     * onbeforeLoad - masks the loading area.
+     *
+     */
+    onBeforeLoad : function(store,opts)
+    {
+         //Roo.log('onBeforeLoad');   
+        if (!opts.add) {
+            this.el.update("");
         }
+        this.el.mask(this.mask ? this.mask : "Loading" ); 
     },
-
-    // private
-    onResize: function(w, h){
-//        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
-//        
-//        if(typeof w != 'number'){
-//            // we do not handle it!?!?
-//            return;
-//        }
-//        var tw = this.trigger.getWidth();
-//       // tw += this.addicon ? this.addicon.getWidth() : 0;
-//       // tw += this.editicon ? this.editicon.getWidth() : 0;
-//        var x = w - tw;
-//        this.inputEl().setWidth( this.adjustWidth('input', x));
-//            
-//        //this.trigger.setStyle('left', x+'px');
-//        
-//        if(this.list && this.listWidth === undefined){
-//            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
-//            this.list.setWidth(lw);
-//            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
-//        }
-        
-    
-        
+    onLoad : function ()
+    {
+        this.el.unmask();
     },
+    
 
     /**
-     * Allow or prevent the user from directly editing the field text.  If false is passed,
-     * the user will only be able to select from the items defined in the dropdown list.  This method
-     * is the runtime equivalent of setting the 'editable' config option at config time.
-     * @param {Boolean} value True to allow the user to directly edit the field text
+     * Returns the template node the passed child belongs to or null if it doesn't belong to one.
+     * @param {HTMLElement} node
+     * @return {HTMLElement} The template node
      */
-    setEditable : function(value){
-        if(value == this.editable){
-            return;
+    findItemFromChild : function(node){
+        var el = this.dataName  ?
+            this.el.child('.roo-tpl-' + this.dataName,true) :
+            this.el.dom; 
+        
+        if(!node || node.parentNode == el){
+                   return node;
+           }
+           var p = node.parentNode;
+           while(p && p != el){
+            if(p.parentNode == el){
+               return p;
+            }
+            p = p.parentNode;
         }
-        this.editable = value;
-        if(!value){
-            this.inputEl().dom.setAttribute('readOnly', true);
-            this.inputEl().on('mousedown', this.onTriggerClick,  this);
-            this.inputEl().addClass('x-combo-noedit');
+           return null;
+    },
+
+    /** @ignore */
+    onClick : function(e){
+        var item = this.findItemFromChild(e.getTarget());
+        if(item){
+            var index = this.indexOf(item);
+            if(this.onItemClick(item, index, e) !== false){
+                this.fireEvent("click", this, index, item, e);
+            }
         }else{
-            this.inputEl().dom.setAttribute('readOnly', false);
-            this.inputEl().un('mousedown', this.onTriggerClick,  this);
-            this.inputEl().removeClass('x-combo-noedit');
+            this.clearSelections();
         }
     },
 
-    // private
-    
-    onBeforeLoad : function(combo,opts){
-        if(!this.hasFocus){
-            return;
+    /** @ignore */
+    onContextMenu : function(e){
+        var item = this.findItemFromChild(e.getTarget());
+        if(item){
+            this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
         }
-         if (!opts.add) {
-            this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
-         }
-        this.restrictHeight();
-        this.selectedIndex = -1;
     },
 
-    // private
-    onLoad : function(){
-        
-        this.hasQuery = false;
-        
-        if(!this.hasFocus){
-            return;
-        }
-        
-        if(typeof(this.loading) !== 'undefined' && this.loading !== null){
-            this.loading.hide();
-        }
-        
-        if(this.store.getCount() > 0){
-            
-            this.expand();
-            this.restrictHeight();
-            if(this.lastQuery == this.allQuery){
-                if(this.editable && !this.tickable){
-                    this.inputEl().dom.select();
-                }
-                
-                if(
-                    !this.selectByValue(this.value, true) &&
-                    this.autoFocus && 
-                    (
-                        !this.store.lastOptions ||
-                        typeof(this.store.lastOptions.add) == 'undefined' || 
-                        this.store.lastOptions.add != true
-                    )
-                ){
-                    this.select(0, true);
-                }
-            }else{
-                if(this.autoFocus){
-                    this.selectNext();
-                }
-                if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
-                    this.taTask.delay(this.typeAheadDelay);
-                }
-            }
-        }else{
-            this.onEmptyResults();
+    /** @ignore */
+    onDblClick : function(e){
+        var item = this.findItemFromChild(e.getTarget());
+        if(item){
+            this.fireEvent("dblclick", this, this.indexOf(item), item, e);
         }
-        
-        //this.el.focus();
     },
-    // private
-    onLoadException : function()
+
+    onItemClick : function(item, index, e)
     {
-        this.hasQuery = false;
-        
-        if(typeof(this.loading) !== 'undefined' && this.loading !== null){
-            this.loading.hide();
+        if(this.fireEvent("beforeclick", this, index, item, e) === false){
+            return false;
         }
-        
-        if(this.tickable && this.editable){
-            return;
+        if (this.toggleSelect) {
+            var m = this.isSelected(item) ? 'unselect' : 'select';
+            //Roo.log(m);
+            var _t = this;
+            _t[m](item, true, false);
+            return true;
         }
-        
-        this.collapse();
-        // only causes errors at present
-        //Roo.log(this.store.reader.jsonData);
-        //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
-            // fixme
-            //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
-        //}
-        
-        
-    },
-    // private
-    onTypeAhead : function(){
-        if(this.store.getCount() > 0){
-            var r = this.store.getAt(0);
-            var newValue = r.data[this.displayField];
-            var len = newValue.length;
-            var selStart = this.getRawValue().length;
+        if(this.multiSelect || this.singleSelect){
+            if(this.multiSelect && e.shiftKey && this.lastSelection){
+                this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
+            }else{
+                this.select(item, this.multiSelect && e.ctrlKey);
+                this.lastSelection = item;
+            }
             
-            if(selStart != len){
-                this.setRawValue(newValue);
-                this.selectText(selStart, newValue.length);
+            if(!this.tickable){
+                e.preventDefault();
             }
-        }
-    },
-
-    // private
-    onSelect : function(record, index){
-        
-        if(this.fireEvent('beforeselect', this, record, index) !== false){
-        
-            this.setFromData(index > -1 ? record.data : false);
             
-            this.collapse();
-            this.fireEvent('select', this, record, index);
         }
+        return true;
     },
 
     /**
-     * Returns the currently selected field value or empty string if no value is set.
-     * @return {String} value The selected value
+     * Get the number of selected nodes.
+     * @return {Number}
      */
-    getValue : function()
-    {
-        if(Roo.isIOS && this.useNativeIOS){
-            return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
-        }
-        
-        if(this.multiple){
-            return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
-        }
-        
-        if(this.valueField){
-            return typeof this.value != 'undefined' ? this.value : '';
-        }else{
-            return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
-        }
+    getSelectionCount : function(){
+        return this.selections.length;
     },
-    
-    getRawValue : function()
-    {
-        if(Roo.isIOS && this.useNativeIOS){
-            return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
-        }
-        
-        var v = this.inputEl().getValue();
-        
-        return v;
+
+    /**
+     * Get the currently selected nodes.
+     * @return {Array} An array of HTMLElements
+     */
+    getSelectedNodes : function(){
+        return this.selections;
     },
 
     /**
-     * Clears any text/value currently set in the field
+     * Get the indexes of the selected nodes.
+     * @return {Array}
      */
-    clearValue : function(){
-        
-        if(this.hiddenField){
-            this.hiddenField.dom.value = '';
-        }
-        this.value = '';
-        this.setRawValue('');
-        this.lastSelectionText = '';
-        this.lastData = false;
-        
-        var close = this.closeTriggerEl();
-        
-        if(close){
-            close.hide();
+    getSelectedIndexes : function(){
+        var indexes = [], s = this.selections;
+        for(var i = 0, len = s.length; i < len; i++){
+            indexes.push(s[i].nodeIndex);
         }
-        
-        this.validate();
-        
+        return indexes;
     },
 
     /**
-     * Sets the specified value into the field.  If the value finds a match, the corresponding record text
-     * will be displayed in the field.  If the value does not match the data value of an existing item,
-     * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
-     * Otherwise the field will be blank (although the value will still be set).
-     * @param {String} value The value to match
+     * Clear all selections
+     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
      */
-    setValue : function(v)
-    {
-        if(Roo.isIOS && this.useNativeIOS){
-            this.setIOSValue(v);
-            return;
-        }
-        
-        if(this.multiple){
-            this.syncValue();
-            return;
-        }
-        
-        var text = v;
-        if(this.valueField){
-            var r = this.findRecord(this.valueField, v);
-            if(r){
-                text = r.data[this.displayField];
-            }else if(this.valueNotFoundText !== undefined){
-                text = this.valueNotFoundText;
+    clearSelections : function(suppressEvent){
+        if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
+            this.cmp.elements = this.selections;
+            this.cmp.removeClass(this.selectedClass);
+            this.selections = [];
+            if(!suppressEvent){
+                this.fireEvent("selectionchange", this, this.selections);
             }
         }
-        this.lastSelectionText = text;
-        if(this.hiddenField){
-            this.hiddenField.dom.value = v;
-        }
-        Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
-        this.value = v;
-        
-        var close = this.closeTriggerEl();
-        
-        if(close){
-            (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
-        }
-        
-        this.validate();
     },
+
     /**
-     * @property {Object} the last set data for the element
+     * Returns true if the passed node is selected
+     * @param {HTMLElement/Number} node The node or node index
+     * @return {Boolean}
      */
-    
-    lastData : false,
+    isSelected : function(node){
+        var s = this.selections;
+        if(s.length < 1){
+            return false;
+        }
+        node = this.getNode(node);
+        return s.indexOf(node) !== -1;
+    },
+
     /**
-     * Sets the value of the field based on a object which is related to the record format for the store.
-     * @param {Object} value the value to set as. or false on reset?
+     * Selects nodes.
+     * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
+     * @param {Boolean} keepExisting (optional) true to keep existing selections
+     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
      */
-    setFromData : function(o){
-        
-        if(this.multiple){
-            this.addItem(o);
+    select : function(nodeInfo, keepExisting, suppressEvent){
+        if(nodeInfo instanceof Array){
+            if(!keepExisting){
+                this.clearSelections(true);
+            }
+            for(var i = 0, len = nodeInfo.length; i < len; i++){
+                this.select(nodeInfo[i], true, true);
+            }
             return;
+        } 
+        var node = this.getNode(nodeInfo);
+        if(!node || this.isSelected(node)){
+            return; // already selected.
         }
-            
-        var dv = ''; // display value
-        var vv = ''; // value value..
-        this.lastData = o;
-        if (this.displayField) {
-            dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
-        } else {
-            // this is an error condition!!!
-            Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
-        }
-        
-        if(this.valueField){
-            vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
-        }
-        
-        var close = this.closeTriggerEl();
-        
-        if(close){
-            if(dv.length || vv * 1 > 0){
-                close.show() ;
-                this.blockFocus=true;
-            } else {
-                close.hide();
-            }             
-        }
-        
-        if(this.hiddenField){
-            this.hiddenField.dom.value = vv;
-            
-            this.lastSelectionText = dv;
-            Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
-            this.value = vv;
-            return;
+        if(!keepExisting){
+            this.clearSelections(true);
         }
-        // no hidden field.. - we store the value in 'value', but still display
-        // display field!!!!
-        this.lastSelectionText = dv;
-        Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
-        this.value = vv;
-        
-        
-        
-    },
-    // private
-    reset : function(){
-        // overridden so that last data is reset..
         
-        if(this.multiple){
-            this.clearItem();
-            return;
+        if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
+            Roo.fly(node).addClass(this.selectedClass);
+            this.selections.push(node);
+            if(!suppressEvent){
+                this.fireEvent("selectionchange", this, this.selections);
+            }
         }
         
-        this.setValue(this.originalValue);
-        //this.clearInvalid();
-        this.lastData = false;
-        if (this.view) {
-            this.view.clearSelections();
-        }
         
-        this.validate();
-    },
-    // private
-    findRecord : function(prop, value){
-        var record;
-        if(this.store.getCount() > 0){
-            this.store.each(function(r){
-                if(r.data[prop] == value){
-                    record = r;
-                    return false;
-                }
-                return true;
-            });
-        }
-        return record;
     },
-    
-    getName: function()
+      /**
+     * Unselects nodes.
+     * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
+     * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
+     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
+     */
+    unselect : function(nodeInfo, keepExisting, suppressEvent)
     {
-        // returns hidden if it's set..
-        if (!this.rendered) {return ''};
-        return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
-        
-    },
-    // private
-    onViewMove : function(e, t){
-        this.inKeyMode = false;
-    },
-
-    // private
-    onViewOver : function(e, t){
-        if(this.inKeyMode){ // prevent key nav and mouse over conflicts
+        if(nodeInfo instanceof Array){
+            Roo.each(this.selections, function(s) {
+                this.unselect(s, nodeInfo);
+            }, this);
             return;
         }
-        var item = this.view.findItemFromChild(t);
-        
-        if(item){
-            var index = this.view.indexOf(item);
-            this.select(index, false);
+        var node = this.getNode(nodeInfo);
+        if(!node || !this.isSelected(node)){
+            //Roo.log("not selected");
+            return; // not selected.
         }
-    },
+        // fireevent???
+        var ns = [];
+        Roo.each(this.selections, function(s) {
+            if (s == node ) {
+                Roo.fly(node).removeClass(this.selectedClass);
 
-    // private
-    onViewClick : function(view, doFocus, el, e)
-    {
-        var index = this.view.getSelectedIndexes()[0];
-        
-        var r = this.store.getAt(index);
-        
-        if(this.tickable){
-            
-            if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
-                return;
-            }
-            
-            var rm = false;
-            var _this = this;
-            
-            Roo.each(this.tickItems, function(v,k){
-                
-                if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
-                    Roo.log(v);
-                    _this.tickItems.splice(k, 1);
-                    
-                    if(typeof(e) == 'undefined' && view == false){
-                        Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
-                    }
-                    
-                    rm = true;
-                    return;
-                }
-            });
-            
-            if(rm){
                 return;
             }
-            
-            if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
-                this.tickItems.push(r.data);
-            }
-            
-            if(typeof(e) == 'undefined' && view == false){
-                Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
-            }
-                    
-            return;
-        }
-        
-        if(r){
-            this.onSelect(r, index);
-        }
-        if(doFocus !== false && !this.blockFocus){
-            this.inputEl().focus();
-        }
-    },
-
-    // private
-    restrictHeight : function(){
-        //this.innerList.dom.style.height = '';
-        //var inner = this.innerList.dom;
-        //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
-        //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
-        //this.list.beginUpdate();
-        //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
-        this.list.alignTo(this.inputEl(), this.listAlign);
-        this.list.alignTo(this.inputEl(), this.listAlign);
-        //this.list.endUpdate();
-    },
-
-    // private
-    onEmptyResults : function(){
-        
-        if(this.tickable && this.editable){
-            this.hasFocus = false;
-            this.restrictHeight();
-            return;
-        }
+            ns.push(s);
+        },this);
         
-        this.collapse();
+        this.selections= ns;
+        this.fireEvent("selectionchange", this, this.selections);
     },
 
     /**
-     * Returns true if the dropdown list is expanded, else false.
+     * Gets a template node.
+     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
+     * @return {HTMLElement} The node or null if it wasn't found
      */
-    isExpanded : function(){
-        return this.list.isVisible();
+    getNode : function(nodeInfo){
+        if(typeof nodeInfo == "string"){
+            return document.getElementById(nodeInfo);
+        }else if(typeof nodeInfo == "number"){
+            return this.nodes[nodeInfo];
+        }
+        return nodeInfo;
     },
 
     /**
-     * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
-     * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
-     * @param {String} value The data value of the item to select
-     * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
-     * selected item if it is not currently in view (defaults to true)
-     * @return {Boolean} True if the value matched an item in the list, else false
+     * Gets a range template nodes.
+     * @param {Number} startIndex
+     * @param {Number} endIndex
+     * @return {Array} An array of nodes
      */
-    selectByValue : function(v, scrollIntoView){
-        if(v !== undefined && v !== null){
-            var r = this.findRecord(this.valueField || this.displayField, v);
-            if(r){
-                this.select(this.store.indexOf(r), scrollIntoView);
-                return true;
+    getNodes : function(start, end){
+        var ns = this.nodes;
+        start = start || 0;
+        end = typeof end == "undefined" ? ns.length - 1 : end;
+        var nodes = [];
+        if(start <= end){
+            for(var i = start; i <= end; i++){
+                nodes.push(ns[i]);
+            }
+        } else{
+            for(var i = start; i >= end; i--){
+                nodes.push(ns[i]);
             }
         }
-        return false;
+        return nodes;
     },
 
     /**
-     * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
-     * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
-     * @param {Number} index The zero-based index of the list item to select
-     * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
-     * selected item if it is not currently in view (defaults to true)
+     * Finds the index of the passed node
+     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
+     * @return {Number} The index of the node or -1
      */
-    select : function(index, scrollIntoView){
-        this.selectedIndex = index;
-        this.view.select(index);
-        if(scrollIntoView !== false){
-            var el = this.view.getNode(index);
-            /*
-             * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
-             */
-            if(el){
-                this.list.scrollChildIntoView(el, false);
-            }
+    indexOf : function(node){
+        node = this.getNode(node);
+        if(typeof node.nodeIndex == "number"){
+            return node.nodeIndex;
         }
-    },
-
-    // private
-    selectNext : function(){
-        var ct = this.store.getCount();
-        if(ct > 0){
-            if(this.selectedIndex == -1){
-                this.select(0);
-            }else if(this.selectedIndex < ct-1){
-                this.select(this.selectedIndex+1);
+        var ns = this.nodes;
+        for(var i = 0, len = ns.length; i < len; i++){
+            if(ns[i] == node){
+                return i;
             }
         }
-    },
+        return -1;
+    }
+});
+/*
+ * - LGPL
+ *
+ * based on jquery fullcalendar
+ * 
+ */
 
-    // private
-    selectPrev : function(){
-        var ct = this.store.getCount();
-        if(ct > 0){
-            if(this.selectedIndex == -1){
-                this.select(0);
-            }else if(this.selectedIndex != 0){
-                this.select(this.selectedIndex-1);
-            }
-        }
-    },
+Roo.bootstrap = Roo.bootstrap || {};
+/**
+ * @class Roo.bootstrap.Calendar
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Calendar class
+ * @cfg {Boolean} loadMask (true|false) default false
+ * @cfg {Object} header generate the user specific header of the calendar, default false
 
-    // private
-    onKeyUp : function(e){
-        if(this.editable !== false && !e.isSpecialKey()){
-            this.lastKey = e.getKey();
-            this.dqTask.delay(this.queryDelay);
-        }
-    },
+ * @constructor
+ * Create a new Container
+ * @param {Object} config The config object
+ */
 
-    // private
-    validateBlur : function(){
-        return !this.list || !this.list.isVisible();   
-    },
 
-    // private
-    initQuery : function(){
-        
-        var v = this.getRawValue();
-        
-        if(this.tickable && this.editable){
-            v = this.tickableInputEl().getValue();
-        }
+
+Roo.bootstrap.Calendar = function(config){
+    Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
+     this.addEvents({
+        /**
+            * @event select
+            * Fires when a date is selected
+            * @param {DatePicker} this
+            * @param {Date} date The selected date
+            */
+        'select': true,
+        /**
+            * @event monthchange
+            * Fires when the displayed month changes 
+            * @param {DatePicker} this
+            * @param {Date} date The selected month
+            */
+        'monthchange': true,
+        /**
+            * @event evententer
+            * Fires when mouse over an event
+            * @param {Calendar} this
+            * @param {event} Event
+            */
+        'evententer': true,
+        /**
+            * @event eventleave
+            * Fires when the mouse leaves an
+            * @param {Calendar} this
+            * @param {event}
+            */
+        'eventleave': true,
+        /**
+            * @event eventclick
+            * Fires when the mouse click an
+            * @param {Calendar} this
+            * @param {event}
+            */
+        'eventclick': true
         
-        this.doQuery(v);
-    },
+    });
 
-    // private
-    doForce : function(){
-        if(this.inputEl().dom.value.length > 0){
-            this.inputEl().dom.value =
-                this.lastSelectionText === undefined ? '' : this.lastSelectionText;
-             
-        }
-    },
+};
 
-    /**
-     * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
-     * query allowing the query action to be canceled if needed.
-     * @param {String} query The SQL query to execute
-     * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
-     * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
-     * saved in the current store (defaults to false)
+Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
+    
+         /**
+     * @cfg {Roo.data.Store} store
+     * The data source for the calendar
      */
-    doQuery : function(q, forceAll){
+       store : false,
+     /**
+     * @cfg {Number} startDay
+     * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
+     */
+    startDay : 0,
+    
+    loadMask : false,
+    
+    header : false,
+      
+    getAutoCreate : function(){
         
-        if(q === undefined || q === null){
-            q = '';
-        }
-        var qe = {
-            query: q,
-            forceAll: forceAll,
-            combo: this,
-            cancel:false
-        };
-        if(this.fireEvent('beforequery', qe)===false || qe.cancel){
-            return false;
-        }
-        q = qe.query;
         
-        forceAll = qe.forceAll;
-        if(forceAll === true || (q.length >= this.minChars)){
-            
-            this.hasQuery = true;
-            
-            if(this.lastQuery != q || this.alwaysQuery){
-                this.lastQuery = q;
-                if(this.mode == 'local'){
-                    this.selectedIndex = -1;
-                    if(forceAll){
-                        this.store.clearFilter();
-                    }else{
-                        
-                        if(this.specialFilter){
-                            this.fireEvent('specialfilter', this);
-                            this.onLoad();
-                            return;
-                        }
-                        
-                        this.store.filter(this.displayField, q);
-                    }
-                    
-                    this.store.fireEvent("datachanged", this.store);
-                    
-                    this.onLoad();
-                    
-                    
-                }else{
-                    
-                    this.store.baseParams[this.queryParam] = q;
-                    
-                    var options = {params : this.getParams(q)};
-                    
-                    if(this.loadNext){
-                        options.add = true;
-                        options.params.start = this.page * this.pageSize;
-                    }
-                    
-                    this.store.load(options);
-                    
-                    /*
-                     *  this code will make the page width larger, at the beginning, the list not align correctly, 
-                     *  we should expand the list on onLoad
-                     *  so command out it
-                     */
-//                    this.expand();
-                }
-            }else{
-                this.selectedIndex = -1;
-                this.onLoad();   
-            }
-        }
+        var fc_button = function(name, corner, style, content ) {
+            return Roo.apply({},{
+                tag : 'span',
+                cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
+                         (corner.length ?
+                            'fc-corner-' + corner.split(' ').join(' fc-corner-') :
+                            ''
+                        ),
+                html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
+                unselectable: 'on'
+            });
+        };
         
-        this.loadNext = false;
-    },
-    
-    // private
-    getParams : function(q){
-        var p = {};
-        //p[this.queryParam] = q;
+        var header = {};
         
-        if(this.pageSize){
-            p.start = 0;
-            p.limit = this.pageSize;
-        }
-        return p;
-    },
+        if(!this.header){
+            header = {
+                tag : 'table',
+                cls : 'fc-header',
+                style : 'width:100%',
+                cn : [
+                    {
+                        tag: 'tr',
+                        cn : [
+                            {
+                                tag : 'td',
+                                cls : 'fc-header-left',
+                                cn : [
+                                    fc_button('prev', 'left', 'arrow', '&#8249;' ),
+                                    fc_button('next', 'right', 'arrow', '&#8250;' ),
+                                    { tag: 'span', cls: 'fc-header-space' },
+                                    fc_button('today', 'left right', '', 'today' )  // neds state disabled..
 
-    /**
-     * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
-     */
-    collapse : function(){
-        if(!this.isExpanded()){
-            return;
+
+                                ]
+                            },
+
+                            {
+                                tag : 'td',
+                                cls : 'fc-header-center',
+                                cn : [
+                                    {
+                                        tag: 'span',
+                                        cls: 'fc-header-title',
+                                        cn : {
+                                            tag: 'H2',
+                                            html : 'month / year'
+                                        }
+                                    }
+
+                                ]
+                            },
+                            {
+                                tag : 'td',
+                                cls : 'fc-header-right',
+                                cn : [
+                              /*      fc_button('month', 'left', '', 'month' ),
+                                    fc_button('week', '', '', 'week' ),
+                                    fc_button('day', 'right', '', 'day' )
+                                */    
+
+                                ]
+                            }
+
+                        ]
+                    }
+                ]
+            };
         }
         
-        this.list.hide();
-        
-        this.hasFocus = false;
+        header = this.header;
         
-        if(this.tickable){
-            this.okBtn.hide();
-            this.cancelBtn.hide();
-            this.trigger.show();
+       
+        var cal_heads = function() {
+            var ret = [];
+            // fixme - handle this.
             
-            if(this.editable){
-                this.tickableInputEl().dom.value = '';
-                this.tickableInputEl().blur();
+            for (var i =0; i < Date.dayNames.length; i++) {
+                var d = Date.dayNames[i];
+                ret.push({
+                    tag: 'th',
+                    cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
+                    html : d.substring(0,3)
+                });
+                
+            }
+            ret[0].cls += ' fc-first';
+            ret[6].cls += ' fc-last';
+            return ret;
+        };
+        var cal_cell = function(n) {
+            return  {
+                tag: 'td',
+                cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
+                cn : [
+                    {
+                        cn : [
+                            {
+                                cls: 'fc-day-number',
+                                html: 'D'
+                            },
+                            {
+                                cls: 'fc-day-content',
+                             
+                                cn : [
+                                     {
+                                        style: 'position: relative;' // height: 17px;
+                                    }
+                                ]
+                            }
+                            
+                            
+                        ]
+                    }
+                ]
+                
             }
+        };
+        var cal_rows = function() {
             
-        }
+            var ret = [];
+            for (var r = 0; r < 6; r++) {
+                var row= {
+                    tag : 'tr',
+                    cls : 'fc-week',
+                    cn : []
+                };
+                
+                for (var i =0; i < Date.dayNames.length; i++) {
+                    var d = Date.dayNames[i];
+                    row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
+
+                }
+                row.cn[0].cls+=' fc-first';
+                row.cn[0].cn[0].style = 'min-height:90px';
+                row.cn[6].cls+=' fc-last';
+                ret.push(row);
+                
+            }
+            ret[0].cls += ' fc-first';
+            ret[4].cls += ' fc-prev-last';
+            ret[5].cls += ' fc-last';
+            return ret;
+            
+        };
         
-        Roo.get(document).un('mousedown', this.collapseIf, this);
-        Roo.get(document).un('mousewheel', this.collapseIf, this);
-        if (!this.editable) {
-            Roo.get(document).un('keydown', this.listKeyPress, this);
-        }
-        this.fireEvent('collapse', this);
+        var cal_table = {
+            tag: 'table',
+            cls: 'fc-border-separate',
+            style : 'width:100%',
+            cellspacing  : 0,
+            cn : [
+                { 
+                    tag: 'thead',
+                    cn : [
+                        { 
+                            tag: 'tr',
+                            cls : 'fc-first fc-last',
+                            cn : cal_heads()
+                        }
+                    ]
+                },
+                { 
+                    tag: 'tbody',
+                    cn : cal_rows()
+                }
+                  
+            ]
+        };
+         
+         var cfg = {
+            cls : 'fc fc-ltr',
+            cn : [
+                header,
+                {
+                    cls : 'fc-content',
+                    style : "position: relative;",
+                    cn : [
+                        {
+                            cls : 'fc-view fc-view-month fc-grid',
+                            style : 'position: relative',
+                            unselectable : 'on',
+                            cn : [
+                                {
+                                    cls : 'fc-event-container',
+                                    style : 'position:absolute;z-index:8;top:0;left:0;'
+                                },
+                                cal_table
+                            ]
+                        }
+                    ]
+    
+                }
+           ] 
+            
+        };
         
-        this.validate();
-    },
-
-    // private
-    collapseIf : function(e){
-        var in_combo  = e.within(this.el);
-        var in_list =  e.within(this.list);
-        var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
+         
         
-        if (in_combo || in_list || is_list) {
-            //e.stopPropagation();
-            return;
+        return cfg;
+    },
+    
+    
+    initEvents : function()
+    {
+        if(!this.store){
+            throw "can not find store for calendar";
         }
         
-        if(this.tickable){
-            this.onTickableFooterButtonClick(e, false, false);
-        }
-
-        this.collapse();
+        var mark = {
+            tag: "div",
+            cls:"x-dlg-mask",
+            style: "text-align:center",
+            cn: [
+                {
+                    tag: "div",
+                    style: "background-color:white;width:50%;margin:250 auto",
+                    cn: [
+                        {
+                            tag: "img",
+                            src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
+                        },
+                        {
+                            tag: "span",
+                            html: "Loading"
+                        }
+                        
+                    ]
+                }
+            ]
+        };
+        this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
         
-    },
-
-    /**
-     * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
-     */
-    expand : function(){
-       
-        if(this.isExpanded() || !this.hasFocus){
-            return;
+        var size = this.el.select('.fc-content', true).first().getSize();
+        this.maskEl.setSize(size.width, size.height);
+        this.maskEl.enableDisplayMode("block");
+        if(!this.loadMask){
+            this.maskEl.hide();
         }
         
-        var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
-        this.list.setWidth(lw);
+        this.store = Roo.factory(this.store, Roo.data);
+        this.store.on('load', this.onLoad, this);
+        this.store.on('beforeload', this.onBeforeLoad, this);
         
-        Roo.log('expand');
+        this.resize();
         
-        this.list.show();
+        this.cells = this.el.select('.fc-day',true);
+        //Roo.log(this.cells);
+        this.textNodes = this.el.query('.fc-day-number');
+        this.cells.addClassOnOver('fc-state-hover');
         
-        this.restrictHeight();
+        this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
+        this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
+        this.el.select('.fc-button-today',true).on('click', this.showToday, this);
+        this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
         
-        if(this.tickable){
-            
-            this.tickItems = Roo.apply([], this.item);
-            
-            this.okBtn.show();
-            this.cancelBtn.show();
-            this.trigger.hide();
-            
-            if(this.editable){
-                this.tickableInputEl().focus();
-            }
-            
-        }
+        this.on('monthchange', this.onMonthChange, this);
         
-        Roo.get(document).on('mousedown', this.collapseIf, this);
-        Roo.get(document).on('mousewheel', this.collapseIf, this);
-        if (!this.editable) {
-            Roo.get(document).on('keydown', this.listKeyPress, this);
-        }
+        this.update(new Date().clearTime());
+    },
+    
+    resize : function() {
+        var sz  = this.el.getSize();
         
-        this.fireEvent('expand', this);
+        this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
+        this.el.select('.fc-day-content div',true).setHeight(34);
+    },
+    
+    
+    // private
+    showPrevMonth : function(e){
+        this.update(this.activeDate.add("mo", -1));
+    },
+    showToday : function(e){
+        this.update(new Date().clearTime());
+    },
+    // private
+    showNextMonth : function(e){
+        this.update(this.activeDate.add("mo", 1));
     },
 
     // private
-    // Implements the default empty TriggerField.onTriggerClick function
-    onTriggerClick : function(e)
-    {
-        Roo.log('trigger click');
-        
-        if(this.disabled || !this.triggerList){
-            return;
-        }
-        
-        this.page = 0;
-        this.loadNext = false;
-        
-        if(this.isExpanded()){
-            this.collapse();
-            if (!this.blockFocus) {
-                this.inputEl().focus();
-            }
-            
-        }else {
-            this.hasFocus = true;
-            if(this.triggerAction == 'all') {
-                this.doQuery(this.allQuery, true);
-            } else {
-                this.doQuery(this.getRawValue());
-            }
-            if (!this.blockFocus) {
-                this.inputEl().focus();
-            }
-        }
+    showPrevYear : function(){
+        this.update(this.activeDate.add("y", -1));
     },
-    
-    onTickableTriggerClick : function(e)
-    {
-        if(this.disabled){
-            return;
-        }
-        
-        this.page = 0;
-        this.loadNext = false;
-        this.hasFocus = true;
-        
-        if(this.triggerAction == 'all') {
-            this.doQuery(this.allQuery, true);
-        } else {
-            this.doQuery(this.getRawValue());
-        }
+
+    // private
+    showNextYear : function(){
+        this.update(this.activeDate.add("y", 1));
     },
+
     
-    onSearchFieldClick : function(e)
+   // private
+    update : function(date)
     {
-        if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
-            this.onTickableFooterButtonClick(e, false, false);
-            return;
-        }
+        var vd = this.activeDate;
+        this.activeDate = date;
+//        if(vd && this.el){
+//            var t = date.getTime();
+//            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
+//                Roo.log('using add remove');
+//                
+//                this.fireEvent('monthchange', this, date);
+//                
+//                this.cells.removeClass("fc-state-highlight");
+//                this.cells.each(function(c){
+//                   if(c.dateValue == t){
+//                       c.addClass("fc-state-highlight");
+//                       setTimeout(function(){
+//                            try{c.dom.firstChild.focus();}catch(e){}
+//                       }, 50);
+//                       return false;
+//                   }
+//                   return true;
+//                });
+//                return;
+//            }
+//        }
         
-        if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
-            return;
-        }
+        var days = date.getDaysInMonth();
         
-        this.page = 0;
-        this.loadNext = false;
-        this.hasFocus = true;
+        var firstOfMonth = date.getFirstDateOfMonth();
+        var startingPos = firstOfMonth.getDay()-this.startDay;
         
-        if(this.triggerAction == 'all') {
-            this.doQuery(this.allQuery, true);
-        } else {
-            this.doQuery(this.getRawValue());
-        }
-    },
-    
-    listKeyPress : function(e)
-    {
-        //Roo.log('listkeypress');
-        // scroll to first matching element based on key pres..
-        if (e.isSpecialKey()) {
-            return false;
-        }
-        var k = String.fromCharCode(e.getKey()).toUpperCase();
-        //Roo.log(k);
-        var match  = false;
-        var csel = this.view.getSelectedNodes();
-        var cselitem = false;
-        if (csel.length) {
-            var ix = this.view.indexOf(csel[0]);
-            cselitem  = this.store.getAt(ix);
-            if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
-                cselitem = false;
-            }
-            
+        if(startingPos < this.startDay){
+            startingPos += 7;
         }
         
-        this.store.each(function(v) { 
-            if (cselitem) {
-                // start at existing selection.
-                if (cselitem.id == v.id) {
-                    cselitem = false;
-                }
-                return true;
-            }
-                
-            if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
-                match = this.store.indexOf(v);
-                return false;
-            }
-            return true;
-        }, this);
+        var pm = date.add(Date.MONTH, -1);
+        var prevStart = pm.getDaysInMonth()-startingPos;
+//        
+        this.cells = this.el.select('.fc-day',true);
+        this.textNodes = this.el.query('.fc-day-number');
+        this.cells.addClassOnOver('fc-state-hover');
         
-        if (match === false) {
-            return true; // no more action?
-        }
-        // scroll to?
-        this.view.select(match);
-        var sn = Roo.get(this.view.getSelectedNodes()[0]);
-        sn.scrollIntoView(sn.dom.parentNode, false);
-    },
-    
-    onViewScroll : function(e, t){
+        var cells = this.cells.elements;
+        var textEls = this.textNodes;
         
-        if(this.view.el.getScroll().top == 0 ||this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
-            return;
-        }
+        Roo.each(cells, function(cell){
+            cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
+        });
         
-        this.hasQuery = true;
+        days += startingPos;
+
+        // convert everything to numbers so it's fast
+        var day = 86400000;
+        var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
+        //Roo.log(d);
+        //Roo.log(pm);
+        //Roo.log(prevStart);
         
-        this.loading = this.list.select('.loading', true).first();
+        var today = new Date().clearTime().getTime();
+        var sel = date.clearTime().getTime();
+        var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
+        var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
+        var ddMatch = this.disabledDatesRE;
+        var ddText = this.disabledDatesText;
+        var ddays = this.disabledDays ? this.disabledDays.join("") : false;
+        var ddaysText = this.disabledDaysText;
+        var format = this.format;
         
-        if(this.loading === null){
-            this.list.createChild({
-                tag: 'div',
-                cls: 'loading roo-select2-more-results roo-select2-active',
-                html: 'Loading more results...'
-            });
+        var setCellClass = function(cal, cell){
+            cell.row = 0;
+            cell.events = [];
+            cell.more = [];
+            //Roo.log('set Cell Class');
+            cell.title = "";
+            var t = d.getTime();
             
-            this.loading = this.list.select('.loading', true).first();
+            //Roo.log(d);
             
-            this.loading.setVisibilityMode(Roo.Element.DISPLAY);
+            cell.dateValue = t;
+            if(t == today){
+                cell.className += " fc-today";
+                cell.className += " fc-state-highlight";
+                cell.title = cal.todayText;
+            }
+            if(t == sel){
+                // disable highlight in other month..
+                //cell.className += " fc-state-highlight";
+                
+            }
+            // disabling
+            if(t < min) {
+                cell.className = " fc-state-disabled";
+                cell.title = cal.minText;
+                return;
+            }
+            if(t > max) {
+                cell.className = " fc-state-disabled";
+                cell.title = cal.maxText;
+                return;
+            }
+            if(ddays){
+                if(ddays.indexOf(d.getDay()) != -1){
+                    cell.title = ddaysText;
+                    cell.className = " fc-state-disabled";
+                }
+            }
+            if(ddMatch && format){
+                var fvalue = d.dateFormat(format);
+                if(ddMatch.test(fvalue)){
+                    cell.title = ddText.replace("%0", fvalue);
+                    cell.className = " fc-state-disabled";
+                }
+            }
             
-            this.loading.hide();
-        }
-        
-        this.loading.show();
-        
-        var _combo = this;
-        
-        this.page++;
-        this.loadNext = true;
+            if (!cell.initialClassName) {
+                cell.initialClassName = cell.dom.className;
+            }
+            
+            cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
+        };
+
+        var i = 0;
         
-        (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
+        for(; i < startingPos; i++) {
+            textEls[i].innerHTML = (++prevStart);
+            d.setDate(d.getDate()+1);
+            
+            cells[i].className = "fc-past fc-other-month";
+            setCellClass(this, cells[i]);
+        }
         
-        return;
-    },
-    
-    addItem : function(o)
-    {   
-        var dv = ''; // display value
+        var intDay = 0;
         
-        if (this.displayField) {
-            dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
-        } else {
-            // this is an error condition!!!
-            Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
+        for(; i < days; i++){
+            intDay = i - startingPos + 1;
+            textEls[i].innerHTML = (intDay);
+            d.setDate(d.getDate()+1);
+            
+            cells[i].className = ''; // "x-date-active";
+            setCellClass(this, cells[i]);
         }
+        var extraDays = 0;
         
-        if(!dv.length){
-            return;
+        for(; i < 42; i++) {
+            textEls[i].innerHTML = (++extraDays);
+            d.setDate(d.getDate()+1);
+            
+            cells[i].className = "fc-future fc-other-month";
+            setCellClass(this, cells[i]);
         }
         
-        var choice = this.choices.createChild({
-            tag: 'li',
-            cls: 'roo-select2-search-choice',
-            cn: [
-                {
-                    tag: 'div',
-                    html: dv
-                },
-                {
-                    tag: 'a',
-                    href: '#',
-                    cls: 'roo-select2-search-choice-close fa fa-times',
-                    tabindex: '-1'
-                }
-            ]
-            
-        }, this.searchField);
+        this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
         
-        var close = choice.select('a.roo-select2-search-choice-close', true).first();
+        var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
         
-        close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
+        this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
+        this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
         
-        this.item.push(o);
+        if(totalRows != 6){
+            this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
+            this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
+        }
         
-        this.lastData = o;
+        this.fireEvent('monthchange', this, date);
         
-        this.syncValue();
         
-        this.inputEl().dom.value = '';
+        /*
+        if(!this.internalRender){
+            var main = this.el.dom.firstChild;
+            var w = main.offsetWidth;
+            this.el.setWidth(w + this.el.getBorderWidth("lr"));
+            Roo.fly(main).setWidth(w);
+            this.internalRender = true;
+            // opera does not respect the auto grow header center column
+            // then, after it gets a width opera refuses to recalculate
+            // without a second pass
+            if(Roo.isOpera && !this.secondPass){
+                main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
+                this.secondPass = true;
+                this.update.defer(10, this, [date]);
+            }
+        }
+        */
         
-        this.validate();
     },
     
-    onRemoveItem : function(e, _self, o)
-    {
-        e.preventDefault();
-        
-        this.lastItem = Roo.apply([], this.item);
-        
-        var index = this.item.indexOf(o.data) * 1;
-        
-        if( index < 0){
-            Roo.log('not this item?!');
-            return;
-        }
-        
-        this.item.splice(index, 1);
-        o.item.remove();
-        
-        this.syncValue();
-        
-        this.fireEvent('remove', this, e);
-        
-        this.validate();
+    findCell : function(dt) {
+        dt = dt.clearTime().getTime();
+        var ret = false;
+        this.cells.each(function(c){
+            //Roo.log("check " +c.dateValue + '?=' + dt);
+            if(c.dateValue == dt){
+                ret = c;
+                return false;
+            }
+            return true;
+        });
         
+        return ret;
     },
     
-    syncValue : function()
-    {
-        if(!this.item.length){
-            this.clearValue();
-            return;
-        }
+    findCells : function(ev) {
+        var s = ev.start.clone().clearTime().getTime();
+       // Roo.log(s);
+        var e= ev.end.clone().clearTime().getTime();
+       // Roo.log(e);
+        var ret = [];
+        this.cells.each(function(c){
+             ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
             
-        var value = [];
-        var _this = this;
-        Roo.each(this.item, function(i){
-            if(_this.valueField){
-                value.push(i[_this.valueField]);
-                return;
+            if(c.dateValue > e){
+                return ;
             }
-
-            value.push(i);
+            if(c.dateValue < s){
+                return ;
+            }
+            ret.push(c);
         });
-
-        this.value = value.join(',');
-
-        if(this.hiddenField){
-            this.hiddenField.dom.value = this.value;
-        }
         
-        this.store.fireEvent("datachanged", this.store);
-        
-        this.validate();
+        return ret;    
     },
     
-    clearItem : function()
+//    findBestRow: function(cells)
+//    {
+//        var ret = 0;
+//        
+//        for (var i =0 ; i < cells.length;i++) {
+//            ret  = Math.max(cells[i].rows || 0,ret);
+//        }
+//        return ret;
+//        
+//    },
+    
+    
+    addItem : function(ev)
     {
-        if(!this.multiple){
-            return;
-        }
-        
-        this.item = [];
-        
-        Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
-           c.remove();
-        });
+        // look for vertical location slot in
+        var cells = this.findCells(ev);
         
-        this.syncValue();
+//        ev.row = this.findBestRow(cells);
         
-        this.validate();
+        // work out the location.
         
-        if(this.tickable && !Roo.isTouch){
-            this.view.refresh();
-        }
-    },
-    
-    inputEl: function ()
-    {
-        if(Roo.isIOS && this.useNativeIOS){
-            return this.el.select('select.roo-ios-select', true).first();
+        var crow = false;
+        var rows = [];
+        for(var i =0; i < cells.length; i++) {
+            
+            cells[i].row = cells[0].row;
+            
+            if(i == 0){
+                cells[i].row = cells[i].row + 1;
+            }
+            
+            if (!crow) {
+                crow = {
+                    start : cells[i],
+                    end :  cells[i]
+                };
+                continue;
+            }
+            if (crow.start.getY() == cells[i].getY()) {
+                // on same row.
+                crow.end = cells[i];
+                continue;
+            }
+            // different row.
+            rows.push(crow);
+            crow = {
+                start: cells[i],
+                end : cells[i]
+            };
+            
         }
         
-        if(Roo.isTouch && this.mobileTouchView){
-            return this.el.select('input.form-control',true).first();
-        }
+        rows.push(crow);
+        ev.els = [];
+        ev.rows = rows;
+        ev.cells = cells;
         
-        if(this.tickable){
-            return this.searchField;
-        }
+        cells[0].events.push(ev);
         
-        return this.el.select('input.form-control',true).first();
+        this.calevents.push(ev);
     },
     
-    onTickableFooterButtonClick : function(e, btn, el)
-    {
-        e.preventDefault();
-        
-        this.lastItem = Roo.apply([], this.item);
+    clearEvents: function() {
         
-        if(btn && btn.name == 'cancel'){
-            this.tickItems = Roo.apply([], this.item);
-            this.collapse();
+        if(!this.calevents){
             return;
         }
         
-        this.clearItem();
-        
-        var _this = this;
-        
-        Roo.each(this.tickItems, function(o){
-            _this.addItem(o);
+        Roo.each(this.cells.elements, function(c){
+            c.row = 0;
+            c.events = [];
+            c.more = [];
         });
         
-        this.collapse();
-        
-    },
-    
-    validate : function()
-    {
-        if(this.getVisibilityEl().hasClass('hidden')){
-            return true;
-        }
-        
-        var v = this.getRawValue();
-        
-        if(this.multiple){
-            v = this.getValue();
-        }
-        
-        if(this.disabled || this.allowBlank || v.length){
-            this.markValid();
-            return true;
-        }
+        Roo.each(this.calevents, function(e) {
+            Roo.each(e.els, function(el) {
+                el.un('mouseenter' ,this.onEventEnter, this);
+                el.un('mouseleave' ,this.onEventLeave, this);
+                el.remove();
+            },this);
+        },this);
         
-        this.markInvalid();
-        return false;
-    },
-    
-    tickableInputEl : function()
-    {
-        if(!this.tickable || !this.editable){
-            return this.inputEl();
-        }
+        Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
+            e.remove();
+        });
         
-        return this.inputEl().select('.roo-select2-search-field-input', true).first();
     },
     
-    
-    getAutoCreateTouchView : function()
-    {
-        var id = Roo.id();
-        
-        var cfg = {
-            cls: 'form-group' //input-group
-        };
-        
-        var input =  {
-            tag: 'input',
-            id : id,
-            type : this.inputType,
-            cls : 'form-control x-combo-noedit',
-            autocomplete: 'new-password',
-            placeholder : this.placeholder || '',
-            readonly : true
-        };
-        
-        if (this.name) {
-            input.name = this.name;
-        }
-        
-        if (this.size) {
-            input.cls += ' input-' + this.size;
-        }
-        
-        if (this.disabled) {
-            input.disabled = true;
-        }
-        
-        var inputblock = {
-            cls : '',
-            cn : [
-                input
-            ]
-        };
+    renderEvents: function()
+    {   
+        var _this = this;
         
-        if(this.before){
-            inputblock.cls += ' input-group';
+        this.cells.each(function(c) {
             
-            inputblock.cn.unshift({
-                tag :'span',
-                cls : 'input-group-addon input-group-prepend input-group-text',
-                html : this.before
-            });
-        }
-        
-        if(this.removable && !this.multiple){
-            inputblock.cls += ' roo-removable';
+            if(c.row < 5){
+                return;
+            }
             
-            inputblock.cn.push({
-                tag: 'button',
-                html : 'x',
-                cls : 'roo-combo-removable-btn close'
-            });
-        }
-
-        if(this.hasFeedback && !this.allowBlank){
+            var ev = c.events;
             
-            inputblock.cls += ' has-feedback';
+            var r = 4;
+            if(c.row != c.events.length){
+                r = 4 - (4 - (c.row - c.events.length));
+            }
             
-            inputblock.cn.push({
-                tag: 'span',
-                cls: 'glyphicon form-control-feedback'
-            });
+            c.events = ev.slice(0, r);
+            c.more = ev.slice(r);
             
-        }
-        
-        if (this.after) {
+            if(c.more.length && c.more.length == 1){
+                c.events.push(c.more.pop());
+            }
             
-            inputblock.cls += (this.before) ? '' : ' input-group';
+            c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
             
-            inputblock.cn.push({
-                tag :'span',
-                cls : 'input-group-addon input-group-append input-group-text',
-                html : this.after
-            });
-        }
-
-        
-        var ibwrap = inputblock;
-        
-        if(this.multiple){
-            ibwrap = {
-                tag: 'ul',
-                cls: 'roo-select2-choices',
-                cn:[
-                    {
-                        tag: 'li',
-                        cls: 'roo-select2-search-field',
-                        cn: [
-
-                            inputblock
-                        ]
-                    }
-                ]
-            };
-        
+        });
             
-        }
-        
-        var combobox = {
-            cls: 'roo-select2-container input-group roo-touchview-combobox ',
-            cn: [
-                {
-                    tag: 'input',
-                    type : 'hidden',
-                    cls: 'form-hidden-field'
-                },
-                ibwrap
-            ]
-        };
-        
-        if(!this.multiple && this.showToggleBtn){
+        this.cells.each(function(c) {
             
-            var caret = {
-                cls: 'caret'
-            };
+            c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
             
-            if (this.caret != false) {
-                caret = {
-                     tag: 'i',
-                     cls: 'fa fa-' + this.caret
-                };
-                
-            }
             
-            combobox.cn.push({
-                tag :'span',
-                cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
-                cn : [
-                    Roo.bootstrap.version == 3 ? caret : '',
-                    {
-                        tag: 'span',
-                        cls: 'combobox-clear',
-                        cn  : [
-                            {
-                                tag : 'i',
-                                cls: 'icon-remove'
-                            }
-                        ]
-                    }
-                ]
-
-            })
-        }
-        
-        if(this.multiple){
-            combobox.cls += ' roo-select2-container-multi';
-        }
-        
-        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'
-                },
-                {
-                    tag: 'label',
-                    cls : 'control-label col-form-label',
-                    html : this.fieldLabel
+            for (var e = 0; e < c.events.length; e++){
+                var ev = c.events[e];
+                var rows = ev.rows;
+                
+                for(var i = 0; i < rows.length; i++) {
+                
+                    // how many rows should it span..
 
-                },
-                {
-                    cls : '', 
-                    cn: [
-                        combobox
-                    ]
-                }
-            ];
-            
-            var labelCfg = cfg.cn[1];
-            var contentCfg = cfg.cn[2];
-            
+                    var  cfg = {
+                        cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
+                        style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
 
-            if(this.indicatorpos == 'right'){
-                cfg.cn = [
-                    {
-                        tag: 'label',
-                        'for' :  id,
-                        cls : 'control-label col-form-label',
+                        unselectable : "on",
                         cn : [
                             {
-                                tag : 'span',
-                                html : this.fieldLabel
+                                cls: 'fc-event-inner',
+                                cn : [
+    //                                {
+    //                                  tag:'span',
+    //                                  cls: 'fc-event-time',
+    //                                  html : cells.length > 1 ? '' : ev.time
+    //                                },
+                                    {
+                                      tag:'span',
+                                      cls: 'fc-event-title',
+                                      html : String.format('{0}', ev.title)
+                                    }
+
+
+                                ]
                             },
                             {
-                                tag : 'i',
-                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
-                                tooltip : 'This field is required'
+                                cls: 'ui-resizable-handle ui-resizable-e',
+                                html : '&nbsp;&nbsp;&nbsp'
                             }
+
                         ]
-                    },
-                    {
-                        cls : "",
-                        cn: [
-                            combobox
-                        ]
+                    };
+
+                    if (i == 0) {
+                        cfg.cls += ' fc-event-start';
+                    }
+                    if ((i+1) == rows.length) {
+                        cfg.cls += ' fc-event-end';
                     }
 
-                ];
+                    var ctr = _this.el.select('.fc-event-container',true).first();
+                    var cg = ctr.createChild(cfg);
+
+                    var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
+                    var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
+
+                    var r = (c.more.length) ? 1 : 0;
+                    cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
+                    cg.setWidth(ebox.right - sbox.x -2);
+
+                    cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
+                    cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
+                    cg.on('click', _this.onEventClick, _this, ev);
+
+                    ev.els.push(cg);
+                    
+                }
                 
-                labelCfg = cfg.cn[0];
-                contentCfg = cfg.cn[1];
-            }
-            
-           
-            
-            if(this.labelWidth > 12){
-                labelCfg.style = "width: " + this.labelWidth + 'px';
-            }
-            
-            if(this.labelWidth < 13 && this.labelmd == 0){
-                this.labelmd = this.labelWidth;
             }
             
-            if(this.labellg > 0){
-                labelCfg.cls += ' col-lg-' + this.labellg;
-                contentCfg.cls += ' col-lg-' + (12 - this.labellg);
-            }
             
-            if(this.labelmd > 0){
-                labelCfg.cls += ' col-md-' + this.labelmd;
-                contentCfg.cls += ' col-md-' + (12 - this.labelmd);
+            if(c.more.length){
+                var  cfg = {
+                    cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
+                    style : 'position: absolute',
+                    unselectable : "on",
+                    cn : [
+                        {
+                            cls: 'fc-event-inner',
+                            cn : [
+                                {
+                                  tag:'span',
+                                  cls: 'fc-event-title',
+                                  html : 'More'
+                                }
+
+
+                            ]
+                        },
+                        {
+                            cls: 'ui-resizable-handle ui-resizable-e',
+                            html : '&nbsp;&nbsp;&nbsp'
+                        }
+
+                    ]
+                };
+
+                var ctr = _this.el.select('.fc-event-container',true).first();
+                var cg = ctr.createChild(cfg);
+
+                var sbox = c.select('.fc-day-content',true).first().getBox();
+                var ebox = c.select('.fc-day-content',true).first().getBox();
+                //Roo.log(cg);
+                cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
+                cg.setWidth(ebox.right - sbox.x -2);
+
+                cg.on('click', _this.onMoreEventClick, _this, c.more);
+                
             }
             
-            if(this.labelsm > 0){
-                labelCfg.cls += ' col-sm-' + this.labelsm;
-                contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
-            }
+        });
+        
+        
+        
+    },
+    
+    onEventEnter: function (e, el,event,d) {
+        this.fireEvent('evententer', this, el, event);
+    },
+    
+    onEventLeave: function (e, el,event,d) {
+        this.fireEvent('eventleave', this, el, event);
+    },
+    
+    onEventClick: function (e, el,event,d) {
+        this.fireEvent('eventclick', this, el, event);
+    },
+    
+    onMonthChange: function () {
+        this.store.load();
+    },
+    
+    onMoreEventClick: function(e, el, more)
+    {
+        var _this = this;
+        
+        this.calpopover.placement = 'right';
+        this.calpopover.setTitle('More');
+        
+        this.calpopover.setContent('');
+        
+        var ctr = this.calpopover.el.select('.popover-content', true).first();
+        
+        Roo.each(more, function(m){
+            var cfg = {
+                cls : 'fc-event-hori fc-event-draggable',
+                html : m.title
+            };
+            var cg = ctr.createChild(cfg);
             
-            if(this.labelxs > 0){
-                labelCfg.cls += ' col-xs-' + this.labelxs;
-                contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
-            }
-                
-                
-        } 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'
-                },
-                {
-                    tag: 'label',
-                    cls : 'control-label',
-                    html : this.fieldLabel
+            cg.on('click', _this.onEventClick, _this, m);
+        });
+        
+        this.calpopover.show(el);
+        
+        
+    },
+    
+    onLoad: function () 
+    {   
+        this.calevents = [];
+        var cal = this;
+        
+        if(this.store.getCount() > 0){
+            this.store.data.each(function(d){
+               cal.addItem({
+                    id : d.data.id,
+                    start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
+                    end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
+                    time : d.data.start_time,
+                    title : d.data.title,
+                    description : d.data.description,
+                    venue : d.data.venue
+                });
+            });
+        }
+        
+        this.renderEvents();
+        
+        if(this.calevents.length && this.loadMask){
+            this.maskEl.hide();
+        }
+    },
+    
+    onBeforeLoad: function()
+    {
+        this.clearEvents();
+        if(this.loadMask){
+            this.maskEl.show();
+        }
+    }
+});
+
+ /*
+ * - LGPL
+ *
+ * element
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.Popover
+ * @extends Roo.bootstrap.Component
+ * @parent none builder
+ * @children Roo.bootstrap.Component
+ * Bootstrap Popover class
+ * @cfg {String} html contents of the popover   (or false to use children..)
+ * @cfg {String} title of popover (or false to hide)
+ * @cfg {String|function} (right|top|bottom|left|auto) placement how it is placed
+ * @cfg {String} trigger click || hover (or false to trigger manually)
+ * @cfg {Boolean} modal - popovers that are modal will mask the screen, and must be closed with another event.
+ * @cfg {String|Boolean|Roo.Element} add click hander to trigger show over what element
+ *      - if false and it has a 'parent' then it will be automatically added to that element
+ *      - if string - Roo.get  will be called 
+ * @cfg {Number} delay - delay before showing
+ * @constructor
+ * Create a new Popover
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.Popover = function(config){
+    Roo.bootstrap.Popover.superclass.constructor.call(this, config);
+    
+    this.addEvents({
+        // raw events
+         /**
+         * @event show
+         * After the popover show
+         * 
+         * @param {Roo.bootstrap.Popover} this
+         */
+        "show" : true,
+        /**
+         * @event hide
+         * After the popover hide
+         * 
+         * @param {Roo.bootstrap.Popover} this
+         */
+        "hide" : true
+    });
+};
 
+Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
+    
+    title: false,
+    html: false,
+    
+    placement : 'right',
+    trigger : 'hover', // hover
+    modal : false,
+    delay : 0,
+    
+    over: false,
+    
+    can_build_overlaid : false,
+    
+    maskEl : false, // the mask element
+    headerEl : false,
+    contentEl : false,
+    alignEl : false, // when show is called with an element - this get's stored.
+    
+    getChildContainer : function()
+    {
+        return this.contentEl;
+        
+    },
+    getPopoverHeader : function()
+    {
+        this.title = true; // flag not to hide it..
+        this.headerEl.addClass('p-0');
+        return this.headerEl
+    },
+    
+    
+    getAutoCreate : function(){
+         
+        var cfg = {
+           cls : 'popover roo-dynamic shadow roo-popover' + (this.modal ? '-modal' : ''),
+           style: 'display:block',
+           cn : [
+                {
+                    cls : 'arrow'
                 },
                 {
-                    cls : '', 
-                    cn: [
-                        combobox
+                    cls : 'popover-inner ',
+                    cn : [
+                        {
+                            tag: 'h3',
+                            cls: 'popover-title popover-header',
+                            html : this.title === false ? '' : this.title
+                        },
+                        {
+                            cls : 'popover-content popover-body '  + (this.cls || ''),
+                            html : this.html || ''
+                        }
                     ]
+                    
                 }
-            ];
+           ]
+        };
+        
+        return cfg;
+    },
+    /**
+     * @param {string} the title
+     */
+    setTitle: function(str)
+    {
+        this.title = str;
+        if (this.el) {
+            this.headerEl.dom.innerHTML = str;
+        }
+        
+    },
+    /**
+     * @param {string} the body content
+     */
+    setContent: function(str)
+    {
+        this.html = str;
+        if (this.contentEl) {
+            this.contentEl.dom.innerHTML = str;
+        }
+        
+    },
+    // as it get's added to the bottom of the page.
+    onRender : function(ct, position)
+    {
+        Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
+        
+        
+        
+        if(!this.el){
+            var cfg = Roo.apply({},  this.getAutoCreate());
+            cfg.id = Roo.id();
             
-            if(this.indicatorpos == 'right'){
-                cfg.cn = [
-                    {
-                        tag: 'label',
-                        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'
-                            }
-                        ]
-                    },
-                    {
-                        cls : '', 
-                        cn: [
-                            combobox
-                        ]
-                    }
-                ];
+            if (this.cls) {
+                cfg.cls += ' ' + this.cls;
             }
-        } else {
-            cfg.cn = combobox;    
+            if (this.style) {
+                cfg.style = this.style;
+            }
+            //Roo.log("adding to ");
+            this.el = Roo.get(document.body).createChild(cfg, position);
+//            Roo.log(this.el);
         }
         
+        this.contentEl = this.el.select('.popover-content',true).first();
+        this.headerEl =  this.el.select('.popover-title',true).first();
         
-        var settings = this;
-        
-        ['xs','sm','md','lg'].map(function(size){
-            if (settings[size]) {
-                cfg.cls += ' col-' + size + '-' + settings[size];
+        var nitems = [];
+        if(typeof(this.items) != 'undefined'){
+            var items = this.items;
+            delete this.items;
+
+            for(var i =0;i < items.length;i++) {
+                nitems.push(this.addxtype(Roo.apply({}, items[i])));
             }
-        });
+        }
+
+        this.items = nitems;
         
-        return cfg;
+        this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
+        Roo.EventManager.onWindowResize(this.resizeMask, this, true);
+        
+        
+        
+        this.initEvents();
     },
     
-    initTouchView : function()
+    resizeMask : function()
+    {
+        this.maskEl.setSize(
+            Roo.lib.Dom.getViewWidth(true),
+            Roo.lib.Dom.getViewHeight(true)
+        );
+    },
+    
+    initEvents : function()
     {
-        this.renderTouchView();
-        
-        this.touchViewEl.on('scroll', function(){
-            this.el.dom.scrollTop = 0;
-        }, this);
-        
-        this.originalValue = this.getValue();
         
-        this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
+        if (!this.modal) { 
+            Roo.bootstrap.Popover.register(this);
+        }
+         
+        this.arrowEl = this.el.select('.arrow',true).first();
+        this.headerEl.setVisibilityMode(Roo.Element.DISPLAY); // probably not needed as it's default in BS4
+        this.el.enableDisplayMode('block');
+        this.el.hide();
         
-        this.inputEl().on("click", this.showTouchView, this);
-        if (this.triggerEl) {
-            this.triggerEl.on("click", this.showTouchView, this);
+        if (this.over === false && !this.parent()) {
+            return; 
+        }
+        if (this.triggers === false) {
+            return;
         }
+         
+        // support parent
+        var on_el = (this.over == 'parent' || this.over === false) ? this.parent().el : Roo.get(this.over);
+        var triggers = this.trigger ? this.trigger.split(' ') : [];
+        Roo.each(triggers, function(trigger) {
         
+            if (trigger == 'click') {
+                on_el.on('click', this.toggle, this);
+            } else if (trigger != 'manual') {
+                var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
+                var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
+      
+                on_el.on(eventIn  ,this.enter, this);
+                on_el.on(eventOut, this.leave, this);
+            }
+        }, this);
+    },
+    
+    
+    // private
+    timeout : null,
+    hoverState : null,
+    
+    toggle : function () {
+        this.hoverState == 'in' ? this.leave() : this.enter();
+    },
+    
+    enter : function () {
         
-        this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
-        this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
+        clearTimeout(this.timeout);
+    
+        this.hoverState = 'in';
+    
+        if (!this.delay || !this.delay.show) {
+            this.show();
+            return;
+        }
+        var _t = this;
+        this.timeout = setTimeout(function () {
+            if (_t.hoverState == 'in') {
+                _t.show();
+            }
+        }, this.delay.show)
+    },
+    
+    leave : function() {
+        clearTimeout(this.timeout);
+    
+        this.hoverState = 'out';
+    
+        if (!this.delay || !this.delay.hide) {
+            this.hide();
+            return;
+        }
+        var _t = this;
+        this.timeout = setTimeout(function () {
+            if (_t.hoverState == 'out') {
+                _t.hide();
+            }
+        }, this.delay.hide)
+    },
+    
+    /**
+     * update the position of the dialog
+     * normally this is needed if the popover get's bigger - due to a Table reload etc..
+     * 
+     *
+     */
+    
+    doAlign : function()
+    {
         
-        this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
+        if (this.alignEl) {
+            this.updatePosition(this.placement, true);
+             
+        } else {
+            // this is usually just done by the builder = to show the popoup in the middle of the scren.
+            var es = this.el.getSize();
+            var x = Roo.lib.Dom.getViewWidth()/2;
+            var y = Roo.lib.Dom.getViewHeight()/2;
+            this.el.setXY([ x-(es.width/2),  y-(es.height/2)] );
+            
+        }
+
+         
+         
         
-        this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
-        this.store.on('load', this.onTouchViewLoad, this);
-        this.store.on('loadexception', this.onTouchViewLoadException, this);
         
-        if(this.hiddenName){
-            
-            this.hiddenField = this.el.select('input.form-hidden-field',true).first();
+    },
+    
+    /**
+     * Show the popover
+     * @param {Roo.Element|string|Boolean} - element to align and point to. (set align to [ pos, offset ])
+     * @param {string} (left|right|top|bottom) position
+     */
+    show : function (on_el, placement)
+    {
+        this.placement = typeof(placement) == 'undefined' ?  this.placement   : placement;
+        on_el = on_el || false; // default to false
+         
+        if (!on_el) {
+            if (this.parent() && (this.over == 'parent' || (this.over === false))) {
+                on_el = this.parent().el;
+            } else if (this.over) {
+                on_el = Roo.get(this.over);
+            }
             
-            this.hiddenField.dom.value =
-                this.hiddenValue !== undefined ? this.hiddenValue :
-                this.value !== undefined ? this.value : '';
-        
-            this.el.dom.removeAttribute('name');
-            this.hiddenField.dom.setAttribute('name', this.hiddenName);
         }
         
-        if(this.multiple){
-            this.choices = this.el.select('ul.roo-select2-choices', true).first();
-            this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
+        this.alignEl = Roo.get( on_el );
+
+        if (!this.el) {
+            this.render(document.body);
         }
         
-        if(this.removable && !this.multiple){
-            var close = this.closeTriggerEl();
-            if(close){
-                close.setVisibilityMode(Roo.Element.DISPLAY).hide();
-                close.on('click', this.removeBtnClick, this, close);
-            }
+        
+         
+        
+        if (this.title === false) {
+            this.headerEl.hide();
         }
-        /*
-         * fix the bug in Safari iOS8
-         */
-        this.inputEl().on("focus", function(e){
-            document.activeElement.blur();
-        }, this);
         
-        this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
+       
+        this.el.show();
+        this.el.dom.style.display = 'block';
+         
+        this.doAlign();
         
-        return;
+        //var arrow = this.el.select('.arrow',true).first();
+        //arrow.set(align[2], 
         
+        this.el.addClass('in');
+        
+         
+        
+        this.hoverState = 'in';
+        
+        if (this.modal) {
+            this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
+            this.maskEl.setStyle('z-index', Roo.bootstrap.Popover.zIndex++);
+            this.maskEl.dom.style.display = 'block';
+            this.maskEl.addClass('show');
+        }
+        this.el.setStyle('z-index', Roo.bootstrap.Popover.zIndex++);
+        this.fireEvent('show', this);
         
     },
-    
-    renderTouchView : function()
+    /**
+     * fire this manually after loading a grid in the table for example
+     * @param {string} (left|right|top|bottom) where to try and put it (use false to use the last one)
+     * @param {Boolean} try and move it if we cant get right position.
+     */
+    updatePosition : function(placement, try_move)
     {
-        this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
-        this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        // allow for calling with no parameters
+        placement = placement   ? placement :  this.placement;
+        try_move = typeof(try_move) == 'undefined' ? true : try_move;
         
-        this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
-        this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        this.el.removeClass([
+            'fade','top','bottom', 'left', 'right','in',
+            'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
+        ]);
+        this.el.addClass(placement + ' bs-popover-' + placement);
         
-        this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
-        this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
-        this.touchViewBodyEl.setStyle('overflow', 'auto');
+        if (!this.alignEl ) {
+            return false;
+        }
         
-        this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
-        this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        switch (placement) {
+            case 'right':
+                var exact = this.el.getAlignToXY(this.alignEl, 'tl-tr', [10,0]);
+                var offset = this.el.getAlignToXY(this.alignEl, 'tl-tr?',[10,0]);
+                if (!try_move || exact.equals(offset) || exact[0] == offset[0] ) {
+                    //normal display... or moved up/down.
+                    this.el.setXY(offset);
+                    var xy = this.alignEl.getAnchorXY('tr', false);
+                    xy[0]+=2;xy[1]+=5;
+                    this.arrowEl.setXY(xy);
+                    return true;
+                }
+                // continue through...
+                return this.updatePosition('left', false);
+                
+            
+            case 'left':
+                var exact = this.el.getAlignToXY(this.alignEl, 'tr-tl', [-10,0]);
+                var offset = this.el.getAlignToXY(this.alignEl, 'tr-tl?',[-10,0]);
+                if (!try_move || exact.equals(offset) || exact[0] == offset[0] ) {
+                    //normal display... or moved up/down.
+                    this.el.setXY(offset);
+                    var xy = this.alignEl.getAnchorXY('tl', false);
+                    xy[0]-=10;xy[1]+=5; // << fix me
+                    this.arrowEl.setXY(xy);
+                    return true;
+                }
+                // call self...
+                return this.updatePosition('right', false);
+            
+            case 'top':
+                var exact = this.el.getAlignToXY(this.alignEl, 'b-t', [0,-10]);
+                var offset = this.el.getAlignToXY(this.alignEl, 'b-t?',[0,-10]);
+                if (!try_move || exact.equals(offset) || exact[1] == offset[1] ) {
+                    //normal display... or moved up/down.
+                    this.el.setXY(offset);
+                    var xy = this.alignEl.getAnchorXY('t', false);
+                    xy[1]-=10; // << fix me
+                    this.arrowEl.setXY(xy);
+                    return true;
+                }
+                // fall through
+               return this.updatePosition('bottom', false);
+            
+            case 'bottom':
+                 var exact = this.el.getAlignToXY(this.alignEl, 't-b', [0,10]);
+                var offset = this.el.getAlignToXY(this.alignEl, 't-b?',[0,10]);
+                if (!try_move || exact.equals(offset) || exact[1] == offset[1] ) {
+                    //normal display... or moved up/down.
+                    this.el.setXY(offset);
+                    var xy = this.alignEl.getAnchorXY('b', false);
+                     xy[1]+=2; // << fix me
+                    this.arrowEl.setXY(xy);
+                    return true;
+                }
+                // fall through
+                return this.updatePosition('top', false);
+                
+            
+        }
         
-        this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
-        this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         
+        return false;
     },
     
-    showTouchView : function()
+    hide : function()
     {
-        if(this.disabled){
-            return;
-        }
-        
-        this.touchViewHeaderEl.hide();
+        this.el.setXY([0,0]);
+        this.el.removeClass('in');
+        this.el.hide();
+        this.hoverState = null;
+        this.maskEl.hide(); // always..
+        this.fireEvent('hide', this);
+    }
+    
+});
 
-        if(this.modalTitle.length){
-            this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
-            this.touchViewHeaderEl.show();
+
+Roo.apply(Roo.bootstrap.Popover, {
+
+    alignment : {
+        'left' : ['r-l', [-10,0], 'left bs-popover-left'],
+        'right' : ['l-br', [10,0], 'right bs-popover-right'],
+        'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
+        'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
+    },
+    
+    zIndex : 20001,
+
+    clickHander : false,
+    
+    
+
+    onMouseDown : function(e)
+    {
+        if (this.popups.length &&  !e.getTarget(".roo-popover")) {
+            /// what is nothing is showing..
+            this.hideAll();
         }
+         
+    },
+    
+    
+    popups : [],
+    
+    register : function(popup)
+    {
+        if (!Roo.bootstrap.Popover.clickHandler) {
+            Roo.bootstrap.Popover.clickHandler = Roo.get(document).on("mousedown", Roo.bootstrap.Popover.onMouseDown, Roo.bootstrap.Popover);
+        }
+        // hide other popups.
+        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);
+    } 
 
-        this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
-        this.touchViewEl.show();
+});
+/**
+ * @class Roo.bootstrap.PopoverNav
+ * @extends Roo.bootstrap.nav.Simplebar
+ * @parent Roo.bootstrap.Popover
+ * @children Roo.bootstrap.nav.Group Roo.bootstrap.Container
+ * @licence LGPL
+ * Bootstrap Popover header navigation class
+ * FIXME? should this go under nav?
+ *
+ * 
+ * @constructor
+ * Create a new Popover Header Navigation 
+ * @param {Object} config The config object
+ */
 
-        this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
-        
-        //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
-        //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
+Roo.bootstrap.PopoverNav = function(config){
+    Roo.bootstrap.PopoverNav.superclass.constructor.call(this, config);
+};
 
-        var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
+Roo.extend(Roo.bootstrap.PopoverNav, Roo.bootstrap.nav.Simplebar,  {
+    
+    
+    container_method : 'getPopoverHeader' 
+    
+     
+    
+    
+   
+});
 
-        if(this.modalTitle.length){
-            bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
+
+ /*
+ * - LGPL
+ *
+ * Progress
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.Progress
+ * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.ProgressBar
+ * Bootstrap Progress class
+ * @cfg {Boolean} striped striped of the progress bar
+ * @cfg {Boolean} active animated of the progress bar
+ * 
+ * 
+ * @constructor
+ * Create a new Progress
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.Progress = function(config){
+    Roo.bootstrap.Progress.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
+    
+    striped : false,
+    active: false,
+    
+    getAutoCreate : function(){
+        var cfg = {
+            tag: 'div',
+            cls: 'progress'
+        };
+        
+        
+        if(this.striped){
+            cfg.cls += ' progress-striped';
+        }
+      
+        if(this.active){
+            cfg.cls += ' active';
         }
         
-        this.touchViewBodyEl.setHeight(bodyHeight);
-
-        if(this.animate){
-            var _this = this;
-            (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
-        }else{
-            this.touchViewEl.addClass('in');
+        
+        return cfg;
+    }
+   
+});
+
+
+ /*
+ * - LGPL
+ *
+ * ProgressBar
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.ProgressBar
+ * @extends Roo.bootstrap.Component
+ * Bootstrap ProgressBar class
+ * @cfg {Number} aria_valuenow aria-value now
+ * @cfg {Number} aria_valuemin aria-value min
+ * @cfg {Number} aria_valuemax aria-value max
+ * @cfg {String} label label for the progress bar
+ * @cfg {String} panel (success | info | warning | danger )
+ * @cfg {String} role role of the progress bar
+ * @cfg {String} sr_only text
+ * 
+ * 
+ * @constructor
+ * Create a new ProgressBar
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.ProgressBar = function(config){
+    Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
+    
+    aria_valuenow : 0,
+    aria_valuemin : 0,
+    aria_valuemax : 100,
+    label : false,
+    panel : false,
+    role : false,
+    sr_only: false,
+    
+    getAutoCreate : function()
+    {
+        
+        var cfg = {
+            tag: 'div',
+            cls: 'progress-bar',
+            style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
+        };
+        
+        if(this.sr_only){
+            cfg.cn = {
+                tag: 'span',
+                cls: 'sr-only',
+                html: this.sr_only
+            }
         }
         
-        if(this._touchViewMask){
-            Roo.get(document.body).addClass("x-body-masked");
-            this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
-            this._touchViewMask.setStyle('z-index', 10000);
-            this._touchViewMask.addClass('show');
+        if(this.role){
+            cfg.role = this.role;
         }
         
-        this.doTouchViewQuery();
-        
-    },
-    
-    hideTouchView : function()
-    {
-        this.touchViewEl.removeClass('in');
-
-        if(this.animate){
-            var _this = this;
-            (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
-        }else{
-            this.touchViewEl.setStyle('display', 'none');
+        if(this.aria_valuenow){
+            cfg['aria-valuenow'] = this.aria_valuenow;
         }
         
-        if(this._touchViewMask){
-            this._touchViewMask.removeClass('show');
-            Roo.get(document.body).removeClass("x-body-masked");
+        if(this.aria_valuemin){
+            cfg['aria-valuemin'] = this.aria_valuemin;
         }
-    },
-    
-    setTouchViewValue : function()
-    {
-        if(this.multiple){
-            this.clearItem();
         
-            var _this = this;
-
-            Roo.each(this.tickItems, function(o){
-                this.addItem(o);
-            }, this);
+        if(this.aria_valuemax){
+            cfg['aria-valuemax'] = this.aria_valuemax;
         }
         
-        this.hideTouchView();
-    },
-    
-    doTouchViewQuery : function()
-    {
-        var qe = {
-            query: '',
-            forceAll: true,
-            combo: this,
-            cancel:false
-        };
-        
-        if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
-            return false;
+        if(this.label && !this.sr_only){
+            cfg.html = this.label;
         }
         
-        if(!this.alwaysQuery || this.mode == 'local'){
-            this.onTouchViewLoad();
-            return;
+        if(this.panel){
+            cfg.cls += ' progress-bar-' + this.panel;
         }
         
-        this.store.load();
+        return cfg;
     },
     
-    onTouchViewBeforeLoad : function(combo,opts)
+    update : function(aria_valuenow)
     {
-        return;
-    },
+        this.aria_valuenow = aria_valuenow;
+        
+        this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
+    }
+   
+});
 
-    // private
-    onTouchViewLoad : function()
+
+ /**
+ * @class Roo.bootstrap.TabGroup
+ * @extends Roo.bootstrap.Column
+ * @children Roo.bootstrap.TabPanel
+ * Bootstrap Column class
+ * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
+ * @cfg {Boolean} carousel true to make the group behave like a carousel
+ * @cfg {Boolean} bullets show bullets for the panels
+ * @cfg {Boolean} autoslide (true|false) auto slide .. default false
+ * @cfg {Number} timer auto slide timer .. default 0 millisecond
+ * @cfg {Boolean} showarrow (true|false) show arrow default true
+ * 
+ * @constructor
+ * Create a new TabGroup
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.TabGroup = function(config){
+    Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
+    if (!this.navId) {
+        this.navId = Roo.id();
+    }
+    this.tabs = [];
+    Roo.bootstrap.TabGroup.register(this);
+    
+};
+
+Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
+    
+    carousel : false,
+    transition : false,
+    bullets : 0,
+    timer : 0,
+    autoslide : false,
+    slideFn : false,
+    slideOnTouch : false,
+    showarrow : true,
+    
+    getAutoCreate : function()
     {
-        if(this.store.getCount() < 1){
-            this.onTouchViewEmptyResults();
-            return;
-        }
-        
-        this.clearTouchView();
-        
-        var rawValue = this.getRawValue();
-        
-        var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
+        var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
         
-        this.tickItems = [];
+        cfg.cls += ' tab-content';
         
-        this.store.data.each(function(d, rowIndex){
-            var row = this.touchViewListGroup.createChild(template);
-            
-            if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
-                row.addClass(d.data.cls);
-            }
+        if (this.carousel) {
+            cfg.cls += ' carousel slide';
             
-            if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
-                var cfg = {
-                    data : d.data,
-                    html : d.data[this.displayField]
-                };
+            cfg.cn = [{
+               cls : 'carousel-inner',
+               cn : []
+            }];
+        
+            if(this.bullets  && !Roo.isTouch){
                 
-                if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
-                    row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
+                var bullets = {
+                    cls : 'carousel-bullets',
+                    cn : []
+                };
+               
+                if(this.bullets_cls){
+                    bullets.cls = bullets.cls + ' ' + this.bullets_cls;
                 }
-            }
-            row.removeClass('selected');
-            if(!this.multiple && this.valueField &&
-                    typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
-            {
-                // radio buttons..
-                row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
-                row.addClass('selected');
-            }
-            
-            if(this.multiple && this.valueField &&
-                    typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
-            {
                 
-                // checkboxes...
-                row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
-                this.tickItems.push(d.data);
+                bullets.cn.push({
+                    cls : 'clear'
+                });
+                
+                cfg.cn[0].cn.push(bullets);
             }
             
-            row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
+            if(this.showarrow){
+                cfg.cn[0].cn.push({
+                    tag : 'div',
+                    class : 'carousel-arrow',
+                    cn : [
+                        {
+                            tag : 'div',
+                            class : 'carousel-prev',
+                            cn : [
+                                {
+                                    tag : 'i',
+                                    class : 'fa fa-chevron-left'
+                                }
+                            ]
+                        },
+                        {
+                            tag : 'div',
+                            class : 'carousel-next',
+                            cn : [
+                                {
+                                    tag : 'i',
+                                    class : 'fa fa-chevron-right'
+                                }
+                            ]
+                        }
+                    ]
+                });
+            }
             
-        }, this);
+        }
         
-        var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
+        return cfg;
+    },
+    
+    initEvents:  function()
+    {
+//        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
+//            this.el.on("touchstart", this.onTouchStart, this);
+//        }
         
-        var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
-
-        if(this.modalTitle.length){
-            bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
+        if(this.autoslide){
+            var _this = this;
+            
+            this.slideFn = window.setInterval(function() {
+                _this.showPanelNext();
+            }, this.timer);
         }
-
-        var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
         
-        if(this.mobile_restrict_height && listHeight < bodyHeight){
-            this.touchViewBodyEl.setHeight(listHeight);
+        if(this.showarrow){
+            this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
+            this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
         }
         
-        var _this = this;
-        
-        if(firstChecked && listHeight > bodyHeight){
-            (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
-        }
         
     },
     
-    onTouchViewLoadException : function()
-    {
-        this.hideTouchView();
-    },
+//    onTouchStart : function(e, el, o)
+//    {
+//        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
+//            return;
+//        }
+//        
+//        this.showPanelNext();
+//    },
     
-    onTouchViewEmptyResults : function()
+    
+    getChildContainer : function()
     {
-        this.clearTouchView();
-        
-        this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
-        
-        this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
-        
+        return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
     },
     
-    clearTouchView : function()
+    /**
+    * register a Navigation item
+    * @param {Roo.bootstrap.nav.Item} the navitem to add
+    */
+    register : function(item)
     {
-        this.touchViewListGroup.dom.innerHTML = '';
+        this.tabs.push( item);
+        item.navId = this.navId; // not really needed..
+        this.addBullet();
+    
     },
     
-    onTouchViewClick : function(e, el, o)
+    getActivePanel : function()
     {
-        e.preventDefault();
-        
-        var row = o.row;
-        var rowIndex = o.rowIndex;
-        
-        var r = this.store.getAt(rowIndex);
+        var r = false;
+        Roo.each(this.tabs, function(t) {
+            if (t.active) {
+                r = t;
+                return false;
+            }
+            return null;
+        });
+        return r;
         
-        if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
-            
-            if(!this.multiple){
-                Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
-                    c.dom.removeAttribute('checked');
-                }, this);
-
-                row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
-
-                this.setFromData(r.data);
-
-                var close = this.closeTriggerEl();
-
-                if(close){
-                    close.show();
-                }
-
-                this.hideTouchView();
-
-                this.fireEvent('select', this, r, rowIndex);
-
-                return;
+    },
+    getPanelByName : function(n)
+    {
+        var r = false;
+        Roo.each(this.tabs, function(t) {
+            if (t.tabId == n) {
+                r = t;
+                return false;
             }
-
-            if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
-                row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
-                this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
-                return;
+            return null;
+        });
+        return r;
+    },
+    indexOfPanel : function(p)
+    {
+        var r = false;
+        Roo.each(this.tabs, function(t,i) {
+            if (t.tabId == p.tabId) {
+                r = i;
+                return false;
             }
-
-            row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
-            this.addItem(r.data);
-            this.tickItems.push(r.data);
-        }
+            return null;
+        });
+        return r;
     },
-    
-    getAutoCreateNativeIOS : function()
+    /**
+     * show a specific panel
+     * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
+     * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
+     */
+    showPanel : function (pan)
     {
-        var cfg = {
-            cls: 'form-group' //input-group,
-        };
-        
-        var combobox =  {
-            tag: 'select',
-            cls : 'roo-ios-select'
-        };
-        
-        if (this.name) {
-            combobox.name = this.name;
+        if(this.transition || typeof(pan) == 'undefined'){
+            Roo.log("waiting for the transitionend");
+            return false;
         }
         
-        if (this.disabled) {
-            combobox.disabled = true;
+        if (typeof(pan) == 'number') {
+            pan = this.tabs[pan];
         }
         
-        var settings = this;
-        
-        ['xs','sm','md','lg'].map(function(size){
-            if (settings[size]) {
-                cfg.cls += ' col-' + size + '-' + settings[size];
-            }
-        });
+        if (typeof(pan) == 'string') {
+            pan = this.getPanelByName(pan);
+        }
         
-        cfg.cn = combobox;
+        var cur = this.getActivePanel();
         
-        return cfg;
+        if(!pan || !cur){
+            Roo.log('pan or acitve pan is undefined');
+            return false;
+        }
         
-    },
-    
-    initIOSView : function()
-    {
-        this.store.on('load', this.onIOSViewLoad, this);
+        if (pan.tabId == this.getActivePanel().tabId) {
+            return true;
+        }
         
-        return;
-    },
-    
-    onIOSViewLoad : function()
-    {
-        if(this.store.getCount() < 1){
-            return;
+        if (false === cur.fireEvent('beforedeactivate')) {
+            return false;
         }
         
-        this.clearIOSView();
+        if(this.bullets > 0 && !Roo.isTouch){
+            this.setActiveBullet(this.indexOfPanel(pan));
+        }
         
-        if(this.allowBlank) {
-            
-            var default_text = '-- SELECT --';
-            
-            if(this.placeholder.length){
-                default_text = this.placeholder;
-            }
+        if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
             
-            if(this.emptyTitle.length){
-                default_text += ' - ' + this.emptyTitle + ' -';
-            }
+            //class="carousel-item carousel-item-next carousel-item-left"
             
-            var opt = this.inputEl().createChild({
-                tag: 'option',
-                value : 0,
-                html : default_text
-            });
+            this.transition = true;
+            var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
+            var lr = dir == 'next' ? 'left' : 'right';
+            pan.el.addClass(dir); // or prev
+            pan.el.addClass('carousel-item-' + dir); // or prev
+            pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
+            cur.el.addClass(lr); // or right
+            pan.el.addClass(lr);
+            cur.el.addClass('carousel-item-' +lr); // or right
+            pan.el.addClass('carousel-item-' +lr);
             
-            var o = {};
-            o[this.valueField] = 0;
-            o[this.displayField] = default_text;
             
-            this.ios_options.push({
-                data : o,
-                el : opt
-            });
+            var _this = this;
+            cur.el.on('transitionend', function() {
+                Roo.log("trans end?");
+                
+                pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
+                pan.setActive(true);
+                
+                cur.el.removeClass([lr, 'carousel-item-' + lr]);
+                cur.setActive(false);
+                
+                _this.transition = false;
+                
+            }, this, { single:  true } );
             
+            return true;
         }
         
-        this.store.data.each(function(d, rowIndex){
-            
-            var html = '';
-            
-            if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
-                html = d.data[this.displayField];
-            }
-            
-            var value = '';
-            
-            if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
-                value = d.data[this.valueField];
-            }
-            
-            var option = {
-                tag: 'option',
-                value : value,
-                html : html
-            };
-            
-            if(this.value == d.data[this.valueField]){
-                option['selected'] = true;
-            }
-            
-            var opt = this.inputEl().createChild(option);
-            
-            this.ios_options.push({
-                data : d.data,
-                el : opt
-            });
-            
-        }, this);
+        cur.setActive(false);
+        pan.setActive(true);
         
-        this.inputEl().on('change', function(){
-           this.fireEvent('select', this);
-        }, this);
+        return true;
+        
+    },
+    showPanelNext : function()
+    {
+        var i = this.indexOfPanel(this.getActivePanel());
+        
+        if (i >= this.tabs.length - 1 && !this.autoslide) {
+            return;
+        }
         
+        if (i >= this.tabs.length - 1 && this.autoslide) {
+            i = -1;
+        }
+        
+        this.showPanel(this.tabs[i+1]);
     },
     
-    clearIOSView: function()
+    showPanelPrev : function()
     {
-        this.inputEl().dom.innerHTML = '';
+        var i = this.indexOfPanel(this.getActivePanel());
         
-        this.ios_options = [];
+        if (i  < 1 && !this.autoslide) {
+            return;
+        }
+        
+        if (i < 1 && this.autoslide) {
+            i = this.tabs.length;
+        }
+        
+        this.showPanel(this.tabs[i-1]);
     },
     
-    setIOSValue: function(v)
+    
+    addBullet: function()
     {
-        this.value = v;
-        
-        if(!this.ios_options){
+        if(!this.bullets || Roo.isTouch){
             return;
         }
+        var ctr = this.el.select('.carousel-bullets',true).first();
+        var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
+        var bullet = ctr.createChild({
+            cls : 'bullet bullet-' + i
+        },ctr.dom.lastChild);
         
-        Roo.each(this.ios_options, function(opts){
-           
-           opts.el.dom.removeAttribute('selected');
-           
-           if(opts.data[this.valueField] != v){
-               return;
-           }
-           
-           opts.el.dom.setAttribute('selected', true);
-           
-        }, this);
-    }
+        
+        var _this = this;
+        
+        bullet.on('click', (function(e, el, o, ii, t){
 
-    /** 
-    * @cfg {Boolean} grow 
-    * @hide 
-    */
-    /** 
-    * @cfg {Number} growMin 
-    * @hide 
-    */
-    /** 
-    * @cfg {Number} growMax 
-    * @hide 
-    */
-    /**
-     * @hide
-     * @method autoSize
-     */
-});
+            e.preventDefault();
 
-Roo.apply(Roo.bootstrap.ComboBox,  {
-    
-    header : {
-        tag: 'div',
-        cls: 'modal-header',
-        cn: [
-            {
-                tag: 'h4',
-                cls: 'modal-title'
+            this.showPanel(ii);
+
+            if(this.autoslide && this.slideFn){
+                clearInterval(this.slideFn);
+                this.slideFn = window.setInterval(function() {
+                    _this.showPanelNext();
+                }, this.timer);
             }
-        ]
+
+        }).createDelegate(this, [i, bullet], true));
+                
+        
     },
+     
+    setActiveBullet : function(i)
+    {
+        if(Roo.isTouch){
+            return;
+        }
+        
+        Roo.each(this.el.select('.bullet', true).elements, function(el){
+            el.removeClass('selected');
+        });
+
+        var bullet = this.el.select('.bullet-' + i, true).first();
+        
+        if(!bullet){
+            return;
+        }
+        
+        bullet.addClass('selected');
+    }
     
-    body : {
-        tag: 'div',
-        cls: 'modal-body',
-        cn: [
-            {
-                tag: 'ul',
-                cls: 'list-group'
-            }
-        ]
-    },
     
-    listItemRadio : {
-        tag: 'li',
-        cls: 'list-group-item',
-        cn: [
-            {
-                tag: 'span',
-                cls: 'roo-combobox-list-group-item-value'
-            },
-            {
-                tag: 'div',
-                cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
-                cn: [
-                    {
-                        tag: 'input',
-                        type: 'radio'
-                    },
-                    {
-                        tag: 'label'
-                    }
-                ]
-            }
-        ]
-    },
+  
+});
+
+
+Roo.apply(Roo.bootstrap.TabGroup, {
     
-    listItemCheckbox : {
-        tag: 'li',
-        cls: 'list-group-item',
-        cn: [
-            {
-                tag: 'span',
-                cls: 'roo-combobox-list-group-item-value'
-            },
-            {
-                tag: 'div',
-                cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
-                cn: [
-                    {
-                        tag: 'input',
-                        type: 'checkbox'
-                    },
-                    {
-                        tag: 'label'
-                    }
-                ]
-            }
-        ]
+    groups: {},
+     /**
+    * register a Navigation Group
+    * @param {Roo.bootstrap.nav.Group} the navgroup to add
+    */
+    register : function(navgrp)
+    {
+        this.groups[navgrp.navId] = navgrp;
+       
     },
+    /**
+    * fetch a Navigation Group based on the navigation ID
+    * if one does not exist , it will get created.
+    * @param {string} the navgroup to add
+    * @returns {Roo.bootstrap.nav.Group} the navgroup 
+    */
+    get: function(navId) {
+        if (typeof(this.groups[navId]) == 'undefined') {
+            this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
+        }
+        return this.groups[navId] ;
+    }
+    
     
-    emptyResult : {
-        tag: 'div',
-        cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
-    },
     
-    footer : {
-        tag: 'div',
-        cls: 'modal-footer',
-        cn: [
-            {
-                tag: 'div',
-                cls: 'row',
-                cn: [
-                    {
-                        tag: 'div',
-                        cls: 'col-xs-6 text-left',
-                        cn: {
-                            tag: 'button',
-                            cls: 'btn btn-danger roo-touch-view-cancel',
-                            html: 'Cancel'
-                        }
-                    },
-                    {
-                        tag: 'div',
-                        cls: 'col-xs-6 text-right',
-                        cn: {
-                            tag: 'button',
-                            cls: 'btn btn-success roo-touch-view-ok',
-                            html: 'OK'
-                        }
-                    }
-                ]
-            }
-        ]
-        
-    }
 });
 
-Roo.apply(Roo.bootstrap.ComboBox,  {
-    
-    touchViewTemplate : {
-        tag: 'div',
-        cls: 'modal fade roo-combobox-touch-view',
-        cn: [
-            {
-                tag: 'div',
-                cls: 'modal-dialog',
-                style : 'position:fixed', // we have to fix position....
-                cn: [
-                    {
-                        tag: 'div',
-                        cls: 'modal-content',
-                        cn: [
-                            Roo.bootstrap.ComboBox.header,
-                            Roo.bootstrap.ComboBox.body,
-                            Roo.bootstrap.ComboBox.footer
-                        ]
-                    }
-                ]
-            }
-        ]
-    }
-});/*
- * 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.
+ /*
+ * - LGPL
  *
- * Fork - LGPL
- * <script type="text/javascript">
+ * TabPanel
+ * 
  */
 
 /**
- * @class Roo.View
- * @extends Roo.util.Observable
- * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
- * This class also supports single and multi selection modes. <br>
- * Create a data model bound view:
- <pre><code>
- var store = new Roo.data.Store(...);
-
- var view = new Roo.View({
-    el : "my-element",
-    tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
-    singleSelect: true,
-    selectedClass: "ydataview-selected",
-    store: store
- });
-
- // listen for node click?
- view.on("click", function(vw, index, node, e){
- alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
- });
-
- // load XML data
- dataModel.load("foobar.xml");
- </code></pre>
- For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
- * <br><br>
- * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
- * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
+ * @class Roo.bootstrap.TabPanel
+ * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Component
+ * Bootstrap TabPanel class
+ * @cfg {Boolean} active panel active
+ * @cfg {String} html panel content
+ * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
+ * @cfg {String} navId The Roo.bootstrap.nav.Group which triggers show hide ()
+ * @cfg {String} href click to link..
+ * @cfg {Boolean} touchSlide if swiping slides tab to next panel (default off)
  * 
- * Note: old style constructor is still suported (container, template, config)
  * 
  * @constructor
- * Create a new View
+ * Create a new TabPanel
  * @param {Object} config The config object
- * 
  */
-Roo.View = function(config, depreciated_tpl, depreciated_config){
-    
-    this.parent = false;
-    
-    if (typeof(depreciated_tpl) == 'undefined') {
-        // new way.. - universal constructor.
-        Roo.apply(this, config);
-        this.el  = Roo.get(this.el);
-    } else {
-        // old format..
-        this.el  = Roo.get(config);
-        this.tpl = depreciated_tpl;
-        Roo.apply(this, depreciated_config);
-    }
-    this.wrapEl  = this.el.wrap().wrap();
-    ///this.el = this.wrapEla.appendChild(document.createElement("div"));
-    
-    
-    if(typeof(this.tpl) == "string"){
-        this.tpl = new Roo.Template(this.tpl);
-    } else {
-        // support xtype ctors..
-        this.tpl = new Roo.factory(this.tpl, Roo);
-    }
-    
-    
-    this.tpl.compile();
-    
-    /** @private */
+
+Roo.bootstrap.TabPanel = function(config){
+    Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
     this.addEvents({
         /**
-         * @event beforeclick
-         * Fires before a click is processed. Returns false to cancel the default action.
-         * @param {Roo.View} this
-         * @param {Number} index The index of the target node
-         * @param {HTMLElement} node The target node
-         * @param {Roo.EventObject} e The raw event object
-         */
-            "beforeclick" : true,
-        /**
-         * @event click
-         * Fires when a template node is clicked.
-         * @param {Roo.View} this
-         * @param {Number} index The index of the target node
-         * @param {HTMLElement} node The target node
-         * @param {Roo.EventObject} e The raw event object
-         */
-            "click" : true,
-        /**
-         * @event dblclick
-         * Fires when a template node is double clicked.
-         * @param {Roo.View} this
-         * @param {Number} index The index of the target node
-         * @param {HTMLElement} node The target node
-         * @param {Roo.EventObject} e The raw event object
-         */
-            "dblclick" : true,
-        /**
-         * @event contextmenu
-         * Fires when a template node is right clicked.
-         * @param {Roo.View} this
-         * @param {Number} index The index of the target node
-         * @param {HTMLElement} node The target node
-         * @param {Roo.EventObject} e The raw event object
-         */
-            "contextmenu" : true,
-        /**
-         * @event selectionchange
-         * Fires when the selected nodes change.
-         * @param {Roo.View} this
-         * @param {Array} selections Array of the selected nodes
-         */
-            "selectionchange" : true,
-    
-        /**
-         * @event beforeselect
-         * Fires before a selection is made. If any handlers return false, the selection is cancelled.
-         * @param {Roo.View} this
-         * @param {HTMLElement} node The node to be selected
-         * @param {Array} selections Array of currently selected nodes
+            * @event changed
+            * Fires when the active status changes
+            * @param {Roo.bootstrap.TabPanel} this
+            * @param {Boolean} state the new state
+           
          */
-            "beforeselect" : true,
+        'changed': true,
         /**
-         * @event preparedata
-         * Fires on every row to render, to allow you to change the data.
-         * @param {Roo.View} this
-         * @param {Object} data to be rendered (change this)
+            * @event beforedeactivate
+            * Fires before a tab is de-activated - can be used to do validation on a form.
+            * @param {Roo.bootstrap.TabPanel} this
+            * @return {Boolean} false if there is an error
+           
          */
-          "preparedata" : true
-          
-          
-        });
-
-
-
-    this.el.on({
-        "click": this.onClick,
-        "dblclick": this.onDblClick,
-        "contextmenu": this.onContextMenu,
-        scope:this
-    });
-
-    this.selections = [];
-    this.nodes = [];
-    this.cmp = new Roo.CompositeElementLite([]);
-    if(this.store){
-        this.store = Roo.factory(this.store, Roo.data);
-        this.setStore(this.store, true);
-    }
-    
-    if ( this.footer && this.footer.xtype) {
-           
-         var fctr = this.wrapEl.appendChild(document.createElement("div"));
-        
-        this.footer.dataSource = this.store;
-        this.footer.container = fctr;
-        this.footer = Roo.factory(this.footer, Roo);
-        fctr.insertFirst(this.el);
-        
-        // this is a bit insane - as the paging toolbar seems to detach the el..
-//        dom.parentNode.parentNode.parentNode
-         // they get detached?
-    }
-    
-    
-    Roo.View.superclass.constructor.call(this);
-    
-    
-};
-
-Roo.extend(Roo.View, Roo.util.Observable, {
-    
-     /**
-     * @cfg {Roo.data.Store} store Data store to load data from.
-     */
-    store : false,
-    
-    /**
-     * @cfg {String|Roo.Element} el The container element.
-     */
-    el : '',
-    
-    /**
-     * @cfg {String|Roo.Template} tpl The template used by this View 
-     */
-    tpl : false,
-    /**
-     * @cfg {String} dataName the named area of the template to use as the data area
-     *                          Works with domtemplates roo-name="name"
-     */
-    dataName: false,
-    /**
-     * @cfg {String} selectedClass The css class to add to selected nodes
-     */
-    selectedClass : "x-view-selected",
-     /**
-     * @cfg {String} emptyText The empty text to show when nothing is loaded.
-     */
-    emptyText : "",
-    
-    /**
-     * @cfg {String} text to display on mask (default Loading)
-     */
-    mask : false,
-    /**
-     * @cfg {Boolean} multiSelect Allow multiple selection
-     */
-    multiSelect : false,
-    /**
-     * @cfg {Boolean} singleSelect Allow single selection
-     */
-    singleSelect:  false,
-    
-    /**
-     * @cfg {Boolean} toggleSelect - selecting 
-     */
-    toggleSelect : false,
-    
-    /**
-     * @cfg {Boolean} tickable - selecting 
-     */
-    tickable : false,
-    
-    /**
-     * Returns the element this view is bound to.
-     * @return {Roo.Element}
-     */
-    getEl : function(){
-        return this.wrapEl;
-    },
-    
-    
-
-    /**
-     * Refreshes the view. - called by datachanged on the store. - do not call directly.
-     */
-    refresh : function(){
-        //Roo.log('refresh');
-        var t = this.tpl;
-        
-        // if we are using something like 'domtemplate', then
-        // the what gets used is:
-        // t.applySubtemplate(NAME, data, wrapping data..)
-        // the outer template then get' applied with
-        //     the store 'extra data'
-        // and the body get's added to the
-        //      roo-name="data" node?
-        //      <span class='roo-tpl-{name}'></span> ?????
-        
+        'beforedeactivate': true
+     });
+    
+    this.tabId = this.tabId || Roo.id();
+  
+};
+
+Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
+    
+    active: false,
+    html: false,
+    tabId: false,
+    navId : false,
+    href : '',
+    touchSlide : false,
+    getAutoCreate : function(){
         
+       
+       var cfg = {
+            tag: 'div',
+            // item is needed for carousel - not sure if it has any effect otherwise
+            cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
+            html: this.html || ''
+        };
         
-        this.clearSelections();
-        this.el.update("");
-        var html = [];
-        var records = this.store.getRange();
-        if(records.length < 1) {
-            
-            // is this valid??  = should it render a template??
-            
-            this.el.update(this.emptyText);
-            return;
+        if(this.active){
+            cfg.cls += ' active';
         }
-        var el = this.el;
-        if (this.dataName) {
-            this.el.update(t.apply(this.store.meta)); //????
-            el = this.el.child('.roo-tpl-' + this.dataName);
+        
+        if(this.tabId){
+            cfg.tabId = this.tabId;
         }
         
-        for(var i = 0, len = records.length; i < len; i++){
-            var data = this.prepareData(records[i].data, i, records[i]);
-            this.fireEvent("preparedata", this, data, i, records[i]);
+       
+        
+        return cfg;
+    },
+    
+    initEvents:  function()
+    {
+        var p = this.parent();
+        
+        this.navId = this.navId || p.navId;
+        
+        if (typeof(this.navId) != 'undefined') {
+            // not really needed.. but just in case.. parent should be a NavGroup.
+            var tg = Roo.bootstrap.TabGroup.get(this.navId);
             
-            var d = Roo.apply({}, data);
+            tg.register(this);
             
-            if(this.tickable){
-                Roo.apply(d, {'roo-id' : Roo.id()});
-                
-                var _this = this;
+            var i = tg.tabs.length - 1;
             
-                Roo.each(this.parent.item, function(item){
-                    if(item[_this.parent.valueField] != data[_this.parent.valueField]){
-                        return;
-                    }
-                    Roo.apply(d, {'roo-data-checked' : 'checked'});
-                });
+            if(this.active && tg.bullets > 0 && i < tg.bullets){
+                tg.setActiveBullet(i);
             }
-            
-            html[html.length] = Roo.util.Format.trim(
-                this.dataName ?
-                    t.applySubtemplate(this.dataName, d, this.store.meta) :
-                    t.apply(d)
-            );
         }
         
+        this.el.on('click', this.onClick, this);
         
+        if(Roo.isTouch && this.touchSlide){
+            this.el.on("touchstart", this.onTouchStart, this);
+            this.el.on("touchmove", this.onTouchMove, this);
+            this.el.on("touchend", this.onTouchEnd, this);
+        }
         
-        el.update(html.join(""));
-        this.nodes = el.dom.childNodes;
-        this.updateIndexes(0);
     },
     
-
-    /**
-     * Function to override to reformat the data that is sent to
-     * the template for each node.
-     * DEPRICATED - use the preparedata event handler.
-     * @param {Array/Object} data The raw data (array of colData for a data model bound view or
-     * a JSON object for an UpdateManager bound view).
-     */
-    prepareData : function(data, index, record)
+    onRender : function(ct, position)
     {
-        this.fireEvent("preparedata", this, data, index, record);
-        return data;
-    },
-
-    onUpdate : function(ds, record){
-        // Roo.log('on update');   
-        this.clearSelections();
-        var index = this.store.indexOf(record);
-        var n = this.nodes[index];
-        this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
-        n.parentNode.removeChild(n);
-        this.updateIndexes(index, index);
+        Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
     },
-
-    
     
-// --------- FIXME     
-    onAdd : function(ds, records, index)
+    setActive : function(state)
     {
-        //Roo.log(['on Add', ds, records, index] );        
-        this.clearSelections();
-        if(this.nodes.length == 0){
-            this.refresh();
-            return;
-        }
-        var n = this.nodes[index];
-        for(var i = 0, len = records.length; i < len; i++){
-            var d = this.prepareData(records[i].data, i, records[i]);
-            if(n){
-                this.tpl.insertBefore(n, d);
-            }else{
-                
-                this.tpl.append(this.el, d);
-            }
-        }
-        this.updateIndexes(index);
-    },
-
-    onRemove : function(ds, record, index){
-       // Roo.log('onRemove');
-        this.clearSelections();
-        var el = this.dataName  ?
-            this.el.child('.roo-tpl-' + this.dataName) :
-            this.el; 
+        Roo.log("panel - set active " + this.tabId + "=" + state);
         
-        el.dom.removeChild(this.nodes[index]);
-        this.updateIndexes(index);
-    },
-
-    /**
-     * Refresh an individual node.
-     * @param {Number} index
-     */
-    refreshNode : function(index){
-        this.onUpdate(this.store, this.store.getAt(index));
-    },
-
-    updateIndexes : function(startIndex, endIndex){
-        var ns = this.nodes;
-        startIndex = startIndex || 0;
-        endIndex = endIndex || ns.length - 1;
-        for(var i = startIndex; i <= endIndex; i++){
-            ns[i].nodeIndex = i;
+        this.active = state;
+        if (!state) {
+            this.el.removeClass('active');
+            
+        } else  if (!this.el.hasClass('active')) {
+            this.el.addClass('active');
         }
+        
+        this.fireEvent('changed', this, state);
     },
-
-    /**
-     * Changes the data store this view uses and refresh the view.
-     * @param {Store} store
-     */
-    setStore : function(store, initial){
-        if(!initial && this.store){
-            this.store.un("datachanged", this.refresh);
-            this.store.un("add", this.onAdd);
-            this.store.un("remove", this.onRemove);
-            this.store.un("update", this.onUpdate);
-            this.store.un("clear", this.refresh);
-            this.store.un("beforeload", this.onBeforeLoad);
-            this.store.un("load", this.onLoad);
-            this.store.un("loadexception", this.onLoad);
-        }
-        if(store){
-          
-            store.on("datachanged", this.refresh, this);
-            store.on("add", this.onAdd, this);
-            store.on("remove", this.onRemove, this);
-            store.on("update", this.onUpdate, this);
-            store.on("clear", this.refresh, this);
-            store.on("beforeload", this.onBeforeLoad, this);
-            store.on("load", this.onLoad, this);
-            store.on("loadexception", this.onLoad, this);
-        }
+    
+    onClick : function(e)
+    {
+        e.preventDefault();
         
-        if(store){
-            this.refresh();
+        if(!this.href.length){
+            return;
         }
+        
+        window.location.href = this.href;
     },
-    /**
-     * onbeforeLoad - masks the loading area.
-     *
-     */
-    onBeforeLoad : function(store,opts)
+    
+    startX : 0,
+    startY : 0,
+    endX : 0,
+    endY : 0,
+    swiping : false,
+    
+    onTouchStart : function(e)
     {
-         //Roo.log('onBeforeLoad');   
-        if (!opts.add) {
-            this.el.update("");
-        }
-        this.el.mask(this.mask ? this.mask : "Loading" ); 
+        this.swiping = false;
+        
+        this.startX = e.browserEvent.touches[0].clientX;
+        this.startY = e.browserEvent.touches[0].clientY;
     },
-    onLoad : function ()
+    
+    onTouchMove : function(e)
     {
-        this.el.unmask();
+        this.swiping = true;
+        
+        this.endX = e.browserEvent.touches[0].clientX;
+        this.endY = e.browserEvent.touches[0].clientY;
     },
     
-
-    /**
-     * Returns the template node the passed child belongs to or null if it doesn't belong to one.
-     * @param {HTMLElement} node
-     * @return {HTMLElement} The template node
-     */
-    findItemFromChild : function(node){
-        var el = this.dataName  ?
-            this.el.child('.roo-tpl-' + this.dataName,true) :
-            this.el.dom; 
+    onTouchEnd : function(e)
+    {
+        if(!this.swiping){
+            this.onClick(e);
+            return;
+        }
         
-        if(!node || node.parentNode == el){
-                   return node;
-           }
-           var p = node.parentNode;
-           while(p && p != el){
-            if(p.parentNode == el){
-               return p;
-            }
-            p = p.parentNode;
+        var tabGroup = this.parent();
+        
+        if(this.endX > this.startX){ // swiping right
+            tabGroup.showPanelPrev();
+            return;
         }
-           return null;
-    },
-
-    /** @ignore */
-    onClick : function(e){
-        var item = this.findItemFromChild(e.getTarget());
-        if(item){
-            var index = this.indexOf(item);
-            if(this.onItemClick(item, index, e) !== false){
-                this.fireEvent("click", this, index, item, e);
-            }
-        }else{
-            this.clearSelections();
+        
+        if(this.startX > this.endX){ // swiping left
+            tabGroup.showPanelNext();
+            return;
         }
-    },
+    }
+    
+    
+});
 
-    /** @ignore */
-    onContextMenu : function(e){
-        var item = this.findItemFromChild(e.getTarget());
-        if(item){
-            this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
-        }
-    },
 
-    /** @ignore */
-    onDblClick : function(e){
-        var item = this.findItemFromChild(e.getTarget());
-        if(item){
-            this.fireEvent("dblclick", this, this.indexOf(item), item, e);
-        }
-    },
+ /*
+ * - LGPL
+ *
+ * DateField
+ * 
+ */
 
-    onItemClick : function(item, index, e)
-    {
-        if(this.fireEvent("beforeclick", this, index, item, e) === false){
-            return false;
-        }
-        if (this.toggleSelect) {
-            var m = this.isSelected(item) ? 'unselect' : 'select';
-            //Roo.log(m);
-            var _t = this;
-            _t[m](item, true, false);
-            return true;
-        }
-        if(this.multiSelect || this.singleSelect){
-            if(this.multiSelect && e.shiftKey && this.lastSelection){
-                this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
-            }else{
-                this.select(item, this.multiSelect && e.ctrlKey);
-                this.lastSelection = item;
-            }
-            
-            if(!this.tickable){
-                e.preventDefault();
-            }
-            
-        }
-        return true;
-    },
+/**
+ * @class Roo.bootstrap.form.DateField
+ * @extends Roo.bootstrap.form.Input
+ * Bootstrap DateField class
+ * @cfg {Number} weekStart default 0
+ * @cfg {String} viewMode default empty, (months|years)
+ * @cfg {String} minViewMode default empty, (months|years)
+ * @cfg {Number} startDate default -Infinity
+ * @cfg {Number} endDate default Infinity
+ * @cfg {Boolean} todayHighlight default false
+ * @cfg {Boolean} todayBtn default false
+ * @cfg {Boolean} calendarWeeks default false
+ * @cfg {Object} daysOfWeekDisabled default empty
+ * @cfg {Boolean} singleMode default false (true | false)
+ * 
+ * @cfg {Boolean} keyboardNavigation default true
+ * @cfg {String} language default en
+ * 
+ * @constructor
+ * Create a new DateField
+ * @param {Object} config The config object
+ */
 
-    /**
-     * Get the number of selected nodes.
-     * @return {Number}
-     */
-    getSelectionCount : function(){
-        return this.selections.length;
-    },
+Roo.bootstrap.form.DateField = function(config){
+    Roo.bootstrap.form.DateField.superclass.constructor.call(this, config);
+     this.addEvents({
+            /**
+             * @event show
+             * Fires when this field show.
+             * @param {Roo.bootstrap.form.DateField} this
+             * @param {Mixed} date The date value
+             */
+            show : true,
+            /**
+             * @event show
+             * Fires when this field hide.
+             * @param {Roo.bootstrap.form.DateField} this
+             * @param {Mixed} date The date value
+             */
+            hide : true,
+            /**
+             * @event select
+             * Fires when select a date.
+             * @param {Roo.bootstrap.form.DateField} this
+             * @param {Mixed} date The date value
+             */
+            select : true,
+            /**
+             * @event beforeselect
+             * Fires when before select a date.
+             * @param {Roo.bootstrap.form.DateField} this
+             * @param {Mixed} date The date value
+             */
+            beforeselect : true
+        });
+};
 
+Roo.extend(Roo.bootstrap.form.DateField, Roo.bootstrap.form.Input,  {
+    
     /**
-     * Get the currently selected nodes.
-     * @return {Array} An array of HTMLElements
+     * @cfg {String} format
+     * The default date format string which can be overriden for localization support.  The format must be
+     * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
      */
-    getSelectedNodes : function(){
-        return this.selections;
-    },
-
+    format : "m/d/y",
     /**
-     * Get the indexes of the selected nodes.
-     * @return {Array}
+     * @cfg {String} altFormats
+     * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
+     * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
      */
-    getSelectedIndexes : function(){
-        var indexes = [], s = this.selections;
-        for(var i = 0, len = s.length; i < len; i++){
-            indexes.push(s[i].nodeIndex);
-        }
-        return indexes;
+    altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
+    
+    weekStart : 0,
+    
+    viewMode : '',
+    
+    minViewMode : '',
+    
+    todayHighlight : false,
+    
+    todayBtn: false,
+    
+    language: 'en',
+    
+    keyboardNavigation: true,
+    
+    calendarWeeks: false,
+    
+    startDate: -Infinity,
+    
+    endDate: Infinity,
+    
+    daysOfWeekDisabled: [],
+    
+    _events: [],
+    
+    singleMode : false,
+    
+    UTCDate: function()
+    {
+        return new Date(Date.UTC.apply(Date, arguments));
     },
-
-    /**
-     * Clear all selections
-     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
-     */
-    clearSelections : function(suppressEvent){
-        if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
-            this.cmp.elements = this.selections;
-            this.cmp.removeClass(this.selectedClass);
-            this.selections = [];
-            if(!suppressEvent){
-                this.fireEvent("selectionchange", this, this.selections);
-            }
-        }
+    
+    UTCToday: function()
+    {
+        var today = new Date();
+        return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
     },
-
-    /**
-     * Returns true if the passed node is selected
-     * @param {HTMLElement/Number} node The node or node index
-     * @return {Boolean}
-     */
-    isSelected : function(node){
-        var s = this.selections;
-        if(s.length < 1){
-            return false;
-        }
-        node = this.getNode(node);
-        return s.indexOf(node) !== -1;
+    
+    getDate: function() {
+            var d = this.getUTCDate();
+            return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
     },
-
-    /**
-     * Selects nodes.
-     * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
-     * @param {Boolean} keepExisting (optional) true to keep existing selections
-     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
-     */
-    select : function(nodeInfo, keepExisting, suppressEvent){
-        if(nodeInfo instanceof Array){
-            if(!keepExisting){
-                this.clearSelections(true);
-            }
-            for(var i = 0, len = nodeInfo.length; i < len; i++){
-                this.select(nodeInfo[i], true, true);
+    
+    getUTCDate: function() {
+            return this.date;
+    },
+    
+    setDate: function(d) {
+            this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
+    },
+    
+    setUTCDate: function(d) {
+            this.date = d;
+            this.setValue(this.formatDate(this.date));
+    },
+        
+    onRender: function(ct, position)
+    {
+        
+        Roo.bootstrap.form.DateField.superclass.onRender.call(this, ct, position);
+        
+        this.language = this.language || 'en';
+        this.language = this.language in Roo.bootstrap.form.DateField.dates ? this.language : this.language.split('-')[0];
+        this.language = this.language in Roo.bootstrap.form.DateField.dates ? this.language : "en";
+        
+        this.isRTL = Roo.bootstrap.form.DateField.dates[this.language].rtl || false;
+        this.format = this.format || 'm/d/y';
+        this.isInline = false;
+        this.isInput = true;
+        this.component = this.el.select('.add-on', true).first() || false;
+        this.component = (this.component && this.component.length === 0) ? false : this.component;
+        this.hasInput = this.component && this.inputEl().length;
+        
+        if (typeof(this.minViewMode === 'string')) {
+            switch (this.minViewMode) {
+                case 'months':
+                    this.minViewMode = 1;
+                    break;
+                case 'years':
+                    this.minViewMode = 2;
+                    break;
+                default:
+                    this.minViewMode = 0;
+                    break;
             }
-            return;
-        } 
-        var node = this.getNode(nodeInfo);
-        if(!node || this.isSelected(node)){
-            return; // already selected.
-        }
-        if(!keepExisting){
-            this.clearSelections(true);
         }
         
-        if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
-            Roo.fly(node).addClass(this.selectedClass);
-            this.selections.push(node);
-            if(!suppressEvent){
-                this.fireEvent("selectionchange", this, this.selections);
+        if (typeof(this.viewMode === 'string')) {
+            switch (this.viewMode) {
+                case 'months':
+                    this.viewMode = 1;
+                    break;
+                case 'years':
+                    this.viewMode = 2;
+                    break;
+                default:
+                    this.viewMode = 0;
+                    break;
             }
         }
+                
+        this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.form.DateField.template);
         
+//        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.form.DateField.template);
         
-    },
-      /**
-     * Unselects nodes.
-     * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
-     * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
-     * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
-     */
-    unselect : function(nodeInfo, keepExisting, suppressEvent)
-    {
-        if(nodeInfo instanceof Array){
-            Roo.each(this.selections, function(s) {
-                this.unselect(s, nodeInfo);
-            }, this);
-            return;
-        }
-        var node = this.getNode(nodeInfo);
-        if(!node || !this.isSelected(node)){
-            //Roo.log("not selected");
-            return; // not selected.
+        this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        
+        this.picker().on('mousedown', this.onMousedown, this);
+        this.picker().on('click', this.onClick, this);
+        
+        this.picker().addClass('datepicker-dropdown');
+        
+        this.startViewMode = this.viewMode;
+        
+        if(this.singleMode){
+            Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
+                v.setVisibilityMode(Roo.Element.DISPLAY);
+                v.hide();
+            });
+            
+            Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
+                v.setStyle('width', '189px');
+            });
         }
-        // fireevent???
-        var ns = [];
-        Roo.each(this.selections, function(s) {
-            if (s == node ) {
-                Roo.fly(node).removeClass(this.selectedClass);
-
+        
+        Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
+            if(!this.calendarWeeks){
+                v.remove();
                 return;
             }
-            ns.push(s);
-        },this);
+            
+            v.dom.innerHTML = Roo.bootstrap.form.DateField.dates[this.language].today;
+            v.attr('colspan', function(i, val){
+                return parseInt(val) + 1;
+            });
+        });
+                       
         
-        this.selections= ns;
-        this.fireEvent("selectionchange", this, this.selections);
-    },
-
-    /**
-     * Gets a template node.
-     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
-     * @return {HTMLElement} The node or null if it wasn't found
-     */
-    getNode : function(nodeInfo){
-        if(typeof nodeInfo == "string"){
-            return document.getElementById(nodeInfo);
-        }else if(typeof nodeInfo == "number"){
-            return this.nodes[nodeInfo];
+        this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
+        
+        this.setStartDate(this.startDate);
+        this.setEndDate(this.endDate);
+        
+        this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
+        
+        this.fillDow();
+        this.fillMonths();
+        this.update();
+        this.showMode();
+        
+        if(this.isInline) {
+            this.showPopup();
         }
-        return nodeInfo;
     },
-
-    /**
-     * Gets a range template nodes.
-     * @param {Number} startIndex
-     * @param {Number} endIndex
-     * @return {Array} An array of nodes
-     */
-    getNodes : function(start, end){
-        var ns = this.nodes;
-        start = start || 0;
-        end = typeof end == "undefined" ? ns.length - 1 : end;
-        var nodes = [];
-        if(start <= end){
-            for(var i = start; i <= end; i++){
-                nodes.push(ns[i]);
-            }
-        } else{
-            for(var i = start; i >= end; i--){
-                nodes.push(ns[i]);
-            }
-        }
-        return nodes;
+    
+    picker : function()
+    {
+        return this.pickerEl;
+//        return this.el.select('.datepicker', true).first();
     },
-
-    /**
-     * Finds the index of the passed node
-     * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
-     * @return {Number} The index of the node or -1
-     */
-    indexOf : function(node){
-        node = this.getNode(node);
-        if(typeof node.nodeIndex == "number"){
-            return node.nodeIndex;
+    
+    fillDow: function()
+    {
+        var dowCnt = this.weekStart;
+        
+        var dow = {
+            tag: 'tr',
+            cn: [
+                
+            ]
+        };
+        
+        if(this.calendarWeeks){
+            dow.cn.push({
+                tag: 'th',
+                cls: 'cw',
+                html: '&nbsp;'
+            })
         }
-        var ns = this.nodes;
-        for(var i = 0, len = ns.length; i < len; i++){
-            if(ns[i] == node){
-                return i;
-            }
+        
+        while (dowCnt < this.weekStart + 7) {
+            dow.cn.push({
+                tag: 'th',
+                cls: 'dow',
+                html: Roo.bootstrap.form.DateField.dates[this.language].daysMin[(dowCnt++)%7]
+            });
         }
-        return -1;
-    }
-});
-/*
- * - LGPL
- *
- * based on jquery fullcalendar
- * 
- */
-
-Roo.bootstrap = Roo.bootstrap || {};
-/**
- * @class Roo.bootstrap.Calendar
- * @extends Roo.bootstrap.Component
- * Bootstrap Calendar class
- * @cfg {Boolean} loadMask (true|false) default false
- * @cfg {Object} header generate the user specific header of the calendar, default false
-
- * @constructor
- * Create a new Container
- * @param {Object} config The config object
- */
-
-
-
-Roo.bootstrap.Calendar = function(config){
-    Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
-     this.addEvents({
-        /**
-            * @event select
-            * Fires when a date is selected
-            * @param {DatePicker} this
-            * @param {Date} date The selected date
-            */
-        'select': true,
-        /**
-            * @event monthchange
-            * Fires when the displayed month changes 
-            * @param {DatePicker} this
-            * @param {Date} date The selected month
-            */
-        'monthchange': true,
-        /**
-            * @event evententer
-            * Fires when mouse over an event
-            * @param {Calendar} this
-            * @param {event} Event
-            */
-        'evententer': true,
-        /**
-            * @event eventleave
-            * Fires when the mouse leaves an
-            * @param {Calendar} this
-            * @param {event}
-            */
-        'eventleave': true,
-        /**
-            * @event eventclick
-            * Fires when the mouse click an
-            * @param {Calendar} this
-            * @param {event}
-            */
-        'eventclick': true
         
-    });
-
-};
-
-Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
+        this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
+    },
     
-     /**
-     * @cfg {Number} startDay
-     * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
-     */
-    startDay : 0,
+    fillMonths: function()
+    {    
+        var i = 0;
+        var months = this.picker().select('>.datepicker-months td', true).first();
+        
+        months.dom.innerHTML = '';
+        
+        while (i < 12) {
+            var month = {
+                tag: 'span',
+                cls: 'month',
+                html: Roo.bootstrap.form.DateField.dates[this.language].monthsShort[i++]
+            };
+            
+            months.createChild(month);
+        }
+        
+    },
     
-    loadMask : false,
+    update: function()
+    {
+        this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
+        
+        if (this.date < this.startDate) {
+            this.viewDate = new Date(this.startDate);
+        } else if (this.date > this.endDate) {
+            this.viewDate = new Date(this.endDate);
+        } else {
+            this.viewDate = new Date(this.date);
+        }
+        
+        this.fill();
+    },
     
-    header : false,
-      
-    getAutoCreate : function(){
+    fill: function() 
+    {
+        var d = new Date(this.viewDate),
+                year = d.getUTCFullYear(),
+                month = d.getUTCMonth(),
+                startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
+                startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
+                endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
+                endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
+                currentDate = this.date && this.date.valueOf(),
+                today = this.UTCToday();
         
+        this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.form.DateField.dates[this.language].months[month]+' '+year;
         
-        var fc_button = function(name, corner, style, content ) {
-            return Roo.apply({},{
-                tag : 'span',
-                cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
-                         (corner.length ?
-                            'fc-corner-' + corner.split(' ').join(' fc-corner-') :
-                            ''
-                        ),
-                html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
-                unselectable: 'on'
-            });
-        };
+//        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.form.DateField.dates[this.language].today;
         
-        var header = {};
+//        this.picker.select('>tfoot th.today').
+//                                             .text(dates[this.language].today)
+//                                             .toggle(this.todayBtn !== false);
+    
+        this.updateNavArrows();
+        this.fillMonths();
+                                                
+        var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
         
-        if(!this.header){
-            header = {
-                tag : 'table',
-                cls : 'fc-header',
-                style : 'width:100%',
-                cn : [
-                    {
-                        tag: 'tr',
-                        cn : [
-                            {
-                                tag : 'td',
-                                cls : 'fc-header-left',
-                                cn : [
-                                    fc_button('prev', 'left', 'arrow', '&#8249;' ),
-                                    fc_button('next', 'right', 'arrow', '&#8250;' ),
-                                    { tag: 'span', cls: 'fc-header-space' },
-                                    fc_button('today', 'left right', '', 'today' )  // neds state disabled..
-
-
-                                ]
-                            },
-
-                            {
-                                tag : 'td',
-                                cls : 'fc-header-center',
-                                cn : [
-                                    {
-                                        tag: 'span',
-                                        cls: 'fc-header-title',
-                                        cn : {
-                                            tag: 'H2',
-                                            html : 'month / year'
-                                        }
-                                    }
-
-                                ]
-                            },
-                            {
-                                tag : 'td',
-                                cls : 'fc-header-right',
-                                cn : [
-                              /*      fc_button('month', 'left', '', 'month' ),
-                                    fc_button('week', '', '', 'week' ),
-                                    fc_button('day', 'right', '', 'day' )
-                                */    
-
-                                ]
-                            }
-
-                        ]
-                    }
-                ]
-            };
-        }
+        day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
+         
+        prevMonth.setUTCDate(day);
         
-        header = this.header;
+        prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
         
-       
-        var cal_heads = function() {
-            var ret = [];
-            // fixme - handle this.
+        var nextMonth = new Date(prevMonth);
+        
+        nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
+        
+        nextMonth = nextMonth.valueOf();
+        
+        var fillMonths = false;
+        
+        this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
+        
+        while(prevMonth.valueOf() <= nextMonth) {
+            var clsName = '';
             
-            for (var i =0; i < Date.dayNames.length; i++) {
-                var d = Date.dayNames[i];
-                ret.push({
-                    tag: 'th',
-                    cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
-                    html : d.substring(0,3)
-                });
+            if (prevMonth.getUTCDay() === this.weekStart) {
+                if(fillMonths){
+                    this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
+                }
+                    
+                fillMonths = {
+                    tag: 'tr',
+                    cn: []
+                };
                 
+                if(this.calendarWeeks){
+                    // ISO 8601: First week contains first thursday.
+                    // ISO also states week starts on Monday, but we can be more abstract here.
+                    var
+                    // Start of current week: based on weekstart/current date
+                    ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
+                    // Thursday of this week
+                    th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
+                    // First Thursday of year, year from thursday
+                    yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
+                    // Calendar week: ms between thursdays, div ms per day, div 7 days
+                    calWeek =  (th - yth) / 864e5 / 7 + 1;
+                    
+                    fillMonths.cn.push({
+                        tag: 'td',
+                        cls: 'cw',
+                        html: calWeek
+                    });
+                }
             }
-            ret[0].cls += ' fc-first';
-            ret[6].cls += ' fc-last';
-            return ret;
-        };
-        var cal_cell = function(n) {
-            return  {
+            
+            if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
+                clsName += ' old';
+            } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
+                clsName += ' new';
+            }
+            if (this.todayHighlight &&
+                prevMonth.getUTCFullYear() == today.getFullYear() &&
+                prevMonth.getUTCMonth() == today.getMonth() &&
+                prevMonth.getUTCDate() == today.getDate()) {
+                clsName += ' today';
+            }
+            
+            if (currentDate && prevMonth.valueOf() === currentDate) {
+                clsName += ' active';
+            }
+            
+            if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
+                    this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
+                    clsName += ' disabled';
+            }
+            
+            fillMonths.cn.push({
                 tag: 'td',
-                cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
-                cn : [
-                    {
-                        cn : [
-                            {
-                                cls: 'fc-day-number',
-                                html: 'D'
-                            },
-                            {
-                                cls: 'fc-day-content',
-                             
-                                cn : [
-                                     {
-                                        style: 'position: relative;' // height: 17px;
-                                    }
-                                ]
-                            }
-                            
-                            
-                        ]
-                    }
-                ]
-                
+                cls: 'day ' + clsName,
+                html: prevMonth.getDate()
+            });
+            
+            prevMonth.setDate(prevMonth.getDate()+1);
+        }
+          
+        var currentYear = this.date && this.date.getUTCFullYear();
+        var currentMonth = this.date && this.date.getUTCMonth();
+        
+        this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
+        
+        Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
+            v.removeClass('active');
+            
+            if(currentYear === year && k === currentMonth){
+                v.addClass('active');
             }
-        };
-        var cal_rows = function() {
             
-            var ret = [];
-            for (var r = 0; r < 6; r++) {
-                var row= {
-                    tag : 'tr',
-                    cls : 'fc-week',
-                    cn : []
-                };
-                
-                for (var i =0; i < Date.dayNames.length; i++) {
-                    var d = Date.dayNames[i];
-                    row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
-
-                }
-                row.cn[0].cls+=' fc-first';
-                row.cn[0].cn[0].style = 'min-height:90px';
-                row.cn[6].cls+=' fc-last';
-                ret.push(row);
-                
+            if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
+                v.addClass('disabled');
             }
-            ret[0].cls += ' fc-first';
-            ret[4].cls += ' fc-prev-last';
-            ret[5].cls += ' fc-last';
-            return ret;
             
-        };
+        });
         
-        var cal_table = {
-            tag: 'table',
-            cls: 'fc-border-separate',
-            style : 'width:100%',
-            cellspacing  : 0,
-            cn : [
-                { 
-                    tag: 'thead',
-                    cn : [
-                        { 
-                            tag: 'tr',
-                            cls : 'fc-first fc-last',
-                            cn : cal_heads()
-                        }
-                    ]
-                },
-                { 
-                    tag: 'tbody',
-                    cn : cal_rows()
-                }
-                  
-            ]
-        };
-         
-         var cfg = {
-            cls : 'fc fc-ltr',
-            cn : [
-                header,
-                {
-                    cls : 'fc-content',
-                    style : "position: relative;",
-                    cn : [
-                        {
-                            cls : 'fc-view fc-view-month fc-grid',
-                            style : 'position: relative',
-                            unselectable : 'on',
-                            cn : [
-                                {
-                                    cls : 'fc-event-container',
-                                    style : 'position:absolute;z-index:8;top:0;left:0;'
-                                },
-                                cal_table
-                            ]
-                        }
-                    ]
-    
-                }
-           ] 
-            
-        };
         
-         
+        year = parseInt(year/10, 10) * 10;
         
-        return cfg;
+        this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
+        
+        this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
+        
+        year -= 1;
+        for (var i = -1; i < 11; i++) {
+            this.picker().select('>.datepicker-years tbody td',true).first().createChild({
+                tag: 'span',
+                cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
+                html: year
+            });
+            
+            year += 1;
+        }
     },
     
-    
-    initEvents : function()
+    showMode: function(dir) 
     {
-        if(!this.store){
-            throw "can not find store for calendar";
+        if (dir) {
+            this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
         }
         
-        var mark = {
-            tag: "div",
-            cls:"x-dlg-mask",
-            style: "text-align:center",
-            cn: [
-                {
-                    tag: "div",
-                    style: "background-color:white;width:50%;margin:250 auto",
-                    cn: [
-                        {
-                            tag: "img",
-                            src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
-                        },
-                        {
-                            tag: "span",
-                            html: "Loading"
-                        }
-                        
-                    ]
-                }
-            ]
-        };
-        this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
-        
-        var size = this.el.select('.fc-content', true).first().getSize();
-        this.maskEl.setSize(size.width, size.height);
-        this.maskEl.enableDisplayMode("block");
-        if(!this.loadMask){
-            this.maskEl.hide();
+        Roo.each(this.picker().select('>div',true).elements, function(v){
+            v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+            v.hide();
+        });
+        this.picker().select('>.datepicker-'+Roo.bootstrap.form.DateField.modes[this.viewMode].clsName, true).first().show();
+    },
+    
+    place: function()
+    {
+        if(this.isInline) {
+            return;
         }
         
-        this.store = Roo.factory(this.store, Roo.data);
-        this.store.on('load', this.onLoad, this);
-        this.store.on('beforeload', this.onBeforeLoad, this);
-        
-        this.resize();
-        
-        this.cells = this.el.select('.fc-day',true);
-        //Roo.log(this.cells);
-        this.textNodes = this.el.query('.fc-day-number');
-        this.cells.addClassOnOver('fc-state-hover');
+        this.picker().removeClass(['bottom', 'top']);
         
-        this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
-        this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
-        this.el.select('.fc-button-today',true).on('click', this.showToday, this);
-        this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
+        if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
+            /*
+             * place to the top of element!
+             *
+             */
+            
+            this.picker().addClass('top');
+            this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
+            
+            return;
+        }
         
-        this.on('monthchange', this.onMonthChange, this);
+        this.picker().addClass('bottom');
         
-        this.update(new Date().clearTime());
+        this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
     },
     
-    resize : function() {
-        var sz  = this.el.getSize();
-        
-        this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
-        this.el.select('.fc-day-content div',true).setHeight(34);
+    parseDate : function(value)
+    {
+        if(!value || value instanceof Date){
+            return value;
+        }
+        var v = Date.parseDate(value, this.format);
+        if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
+            v = Date.parseDate(value, 'Y-m-d');
+        }
+        if(!v && this.altFormats){
+            if(!this.altFormatsArray){
+                this.altFormatsArray = this.altFormats.split("|");
+            }
+            for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
+                v = Date.parseDate(value, this.altFormatsArray[i]);
+            }
+        }
+        return v;
     },
     
-    
-    // private
-    showPrevMonth : function(e){
-        this.update(this.activeDate.add("mo", -1));
-    },
-    showToday : function(e){
-        this.update(new Date().clearTime());
-    },
-    // private
-    showNextMonth : function(e){
-        this.update(this.activeDate.add("mo", 1));
-    },
-
-    // private
-    showPrevYear : function(){
-        this.update(this.activeDate.add("y", -1));
+    formatDate : function(date, fmt)
+    {   
+        return (!date || !(date instanceof Date)) ?
+        date : date.dateFormat(fmt || this.format);
     },
-
-    // private
-    showNextYear : function(){
-        this.update(this.activeDate.add("y", 1));
+    
+    onFocus : function()
+    {
+        Roo.bootstrap.form.DateField.superclass.onFocus.call(this);
+        this.showPopup();
     },
-
     
-   // private
-    update : function(date)
+    onBlur : function()
     {
-        var vd = this.activeDate;
-        this.activeDate = date;
-//        if(vd && this.el){
-//            var t = date.getTime();
-//            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
-//                Roo.log('using add remove');
-//                
-//                this.fireEvent('monthchange', this, date);
-//                
-//                this.cells.removeClass("fc-state-highlight");
-//                this.cells.each(function(c){
-//                   if(c.dateValue == t){
-//                       c.addClass("fc-state-highlight");
-//                       setTimeout(function(){
-//                            try{c.dom.firstChild.focus();}catch(e){}
-//                       }, 50);
-//                       return false;
-//                   }
-//                   return true;
-//                });
-//                return;
-//            }
-//        }
+        Roo.bootstrap.form.DateField.superclass.onBlur.call(this);
         
-        var days = date.getDaysInMonth();
+        var d = this.inputEl().getValue();
         
-        var firstOfMonth = date.getFirstDateOfMonth();
-        var startingPos = firstOfMonth.getDay()-this.startDay;
+        this.setValue(d);
+                
+        this.hidePopup();
+    },
+    
+    showPopup : function()
+    {
+        this.picker().show();
+        this.update();
+        this.place();
         
-        if(startingPos < this.startDay){
-            startingPos += 7;
+        this.fireEvent('showpopup', this, this.date);
+    },
+    
+    hidePopup : function()
+    {
+        if(this.isInline) {
+            return;
         }
+        this.picker().hide();
+        this.viewMode = this.startViewMode;
+        this.showMode();
         
-        var pm = date.add(Date.MONTH, -1);
-        var prevStart = pm.getDaysInMonth()-startingPos;
-//        
-        this.cells = this.el.select('.fc-day',true);
-        this.textNodes = this.el.query('.fc-day-number');
-        this.cells.addClassOnOver('fc-state-hover');
-        
-        var cells = this.cells.elements;
-        var textEls = this.textNodes;
-        
-        Roo.each(cells, function(cell){
-            cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
-        });
+        this.fireEvent('hidepopup', this, this.date);
         
-        days += startingPos;
+    },
+    
+    onMousedown: function(e)
+    {
+        e.stopPropagation();
+        e.preventDefault();
+    },
+    
+    keyup: function(e)
+    {
+        Roo.bootstrap.form.DateField.superclass.keyup.call(this);
+        this.update();
+    },
 
-        // convert everything to numbers so it's fast
-        var day = 86400000;
-        var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
-        //Roo.log(d);
-        //Roo.log(pm);
-        //Roo.log(prevStart);
-        
-        var today = new Date().clearTime().getTime();
-        var sel = date.clearTime().getTime();
-        var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
-        var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
-        var ddMatch = this.disabledDatesRE;
-        var ddText = this.disabledDatesText;
-        var ddays = this.disabledDays ? this.disabledDays.join("") : false;
-        var ddaysText = this.disabledDaysText;
-        var format = this.format;
+    setValue: function(v)
+    {
+        if(this.fireEvent('beforeselect', this, v) !== false){
+            var d = new Date(this.parseDate(v) ).clearTime();
         
-        var setCellClass = function(cal, cell){
-            cell.row = 0;
-            cell.events = [];
-            cell.more = [];
-            //Roo.log('set Cell Class');
-            cell.title = "";
-            var t = d.getTime();
-            
-            //Roo.log(d);
-            
-            cell.dateValue = t;
-            if(t == today){
-                cell.className += " fc-today";
-                cell.className += " fc-state-highlight";
-                cell.title = cal.todayText;
-            }
-            if(t == sel){
-                // disable highlight in other month..
-                //cell.className += " fc-state-highlight";
-                
-            }
-            // disabling
-            if(t < min) {
-                cell.className = " fc-state-disabled";
-                cell.title = cal.minText;
-                return;
-            }
-            if(t > max) {
-                cell.className = " fc-state-disabled";
-                cell.title = cal.maxText;
+            if(isNaN(d.getTime())){
+                this.date = this.viewDate = '';
+                Roo.bootstrap.form.DateField.superclass.setValue.call(this, '');
                 return;
             }
-            if(ddays){
-                if(ddays.indexOf(d.getDay()) != -1){
-                    cell.title = ddaysText;
-                    cell.className = " fc-state-disabled";
-                }
-            }
-            if(ddMatch && format){
-                var fvalue = d.dateFormat(format);
-                if(ddMatch.test(fvalue)){
-                    cell.title = ddText.replace("%0", fvalue);
-                    cell.className = " fc-state-disabled";
-                }
-            }
-            
-            if (!cell.initialClassName) {
-                cell.initialClassName = cell.dom.className;
-            }
-            
-            cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
-        };
 
-        var i = 0;
-        
-        for(; i < startingPos; i++) {
-            textEls[i].innerHTML = (++prevStart);
-            d.setDate(d.getDate()+1);
-            
-            cells[i].className = "fc-past fc-other-month";
-            setCellClass(this, cells[i]);
-        }
-        
-        var intDay = 0;
-        
-        for(; i < days; i++){
-            intDay = i - startingPos + 1;
-            textEls[i].innerHTML = (intDay);
-            d.setDate(d.getDate()+1);
-            
-            cells[i].className = ''; // "x-date-active";
-            setCellClass(this, cells[i]);
+            v = this.formatDate(d);
+
+            Roo.bootstrap.form.DateField.superclass.setValue.call(this, v);
+
+            this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
+
+            this.update();
+
+            this.fireEvent('select', this, this.date);
         }
-        var extraDays = 0;
-        
-        for(; i < 42; i++) {
-            textEls[i].innerHTML = (++extraDays);
-            d.setDate(d.getDate()+1);
-            
-            cells[i].className = "fc-future fc-other-month";
-            setCellClass(this, cells[i]);
+    },
+    
+    getValue: function()
+    {
+        return this.formatDate(this.date);
+    },
+    
+    fireKey: function(e)
+    {
+        if (!this.picker().isVisible()){
+            if (e.keyCode == 27) { // allow escape to hide and re-show picker
+                this.showPopup();
+            }
+            return;
         }
         
-        this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
+        var dateChanged = false,
+        dir, day, month,
+        newDate, newViewDate;
         
-        var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
+        switch(e.keyCode){
+            case 27: // escape
+                this.hidePopup();
+                e.preventDefault();
+                break;
+            case 37: // left
+            case 39: // right
+                if (!this.keyboardNavigation) {
+                    break;
+                }
+                dir = e.keyCode == 37 ? -1 : 1;
+                
+                if (e.ctrlKey){
+                    newDate = this.moveYear(this.date, dir);
+                    newViewDate = this.moveYear(this.viewDate, dir);
+                } else if (e.shiftKey){
+                    newDate = this.moveMonth(this.date, dir);
+                    newViewDate = this.moveMonth(this.viewDate, dir);
+                } else {
+                    newDate = new Date(this.date);
+                    newDate.setUTCDate(this.date.getUTCDate() + dir);
+                    newViewDate = new Date(this.viewDate);
+                    newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
+                }
+                if (this.dateWithinRange(newDate)){
+                    this.date = newDate;
+                    this.viewDate = newViewDate;
+                    this.setValue(this.formatDate(this.date));
+//                    this.update();
+                    e.preventDefault();
+                    dateChanged = true;
+                }
+                break;
+            case 38: // up
+            case 40: // down
+                if (!this.keyboardNavigation) {
+                    break;
+                }
+                dir = e.keyCode == 38 ? -1 : 1;
+                if (e.ctrlKey){
+                    newDate = this.moveYear(this.date, dir);
+                    newViewDate = this.moveYear(this.viewDate, dir);
+                } else if (e.shiftKey){
+                    newDate = this.moveMonth(this.date, dir);
+                    newViewDate = this.moveMonth(this.viewDate, dir);
+                } else {
+                    newDate = new Date(this.date);
+                    newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
+                    newViewDate = new Date(this.viewDate);
+                    newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
+                }
+                if (this.dateWithinRange(newDate)){
+                    this.date = newDate;
+                    this.viewDate = newViewDate;
+                    this.setValue(this.formatDate(this.date));
+//                    this.update();
+                    e.preventDefault();
+                    dateChanged = true;
+                }
+                break;
+            case 13: // enter
+                this.setValue(this.formatDate(this.date));
+                this.hidePopup();
+                e.preventDefault();
+                break;
+            case 9: // tab
+                this.setValue(this.formatDate(this.date));
+                this.hidePopup();
+                break;
+            case 16: // shift
+            case 17: // ctrl
+            case 18: // alt
+                break;
+            default :
+                this.hidePopup();
+                
+        }
+    },
+    
+    
+    onClick: function(e) 
+    {
+        e.stopPropagation();
+        e.preventDefault();
         
-        this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
-        this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
+        var target = e.getTarget();
         
-        if(totalRows != 6){
-            this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
-            this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
+        if(target.nodeName.toLowerCase() === 'i'){
+            target = Roo.get(target).dom.parentNode;
         }
         
-        this.fireEvent('monthchange', this, date);
-        
+        var nodeName = target.nodeName;
+        var className = target.className;
+        var html = target.innerHTML;
+        //Roo.log(nodeName);
         
-        /*
-        if(!this.internalRender){
-            var main = this.el.dom.firstChild;
-            var w = main.offsetWidth;
-            this.el.setWidth(w + this.el.getBorderWidth("lr"));
-            Roo.fly(main).setWidth(w);
-            this.internalRender = true;
-            // opera does not respect the auto grow header center column
-            // then, after it gets a width opera refuses to recalculate
-            // without a second pass
-            if(Roo.isOpera && !this.secondPass){
-                main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
-                this.secondPass = true;
-                this.update.defer(10, this, [date]);
-            }
+        switch(nodeName.toLowerCase()) {
+            case 'th':
+                switch(className) {
+                    case 'switch':
+                        this.showMode(1);
+                        break;
+                    case 'prev':
+                    case 'next':
+                        var dir = Roo.bootstrap.form.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
+                        switch(this.viewMode){
+                                case 0:
+                                        this.viewDate = this.moveMonth(this.viewDate, dir);
+                                        break;
+                                case 1:
+                                case 2:
+                                        this.viewDate = this.moveYear(this.viewDate, dir);
+                                        break;
+                        }
+                        this.fill();
+                        break;
+                    case 'today':
+                        var date = new Date();
+                        this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
+//                        this.fill()
+                        this.setValue(this.formatDate(this.date));
+                        
+                        this.hidePopup();
+                        break;
+                }
+                break;
+            case 'span':
+                if (className.indexOf('disabled') < 0) {
+                if (!this.viewDate) {
+                    this.viewDate = new Date();
+                }
+                this.viewDate.setUTCDate(1);
+                    if (className.indexOf('month') > -1) {
+                        this.viewDate.setUTCMonth(Roo.bootstrap.form.DateField.dates[this.language].monthsShort.indexOf(html));
+                    } else {
+                        var year = parseInt(html, 10) || 0;
+                        this.viewDate.setUTCFullYear(year);
+                        
+                    }
+                    
+                    if(this.singleMode){
+                        this.setValue(this.formatDate(this.viewDate));
+                        this.hidePopup();
+                        return;
+                    }
+                    
+                    this.showMode(-1);
+                    this.fill();
+                }
+                break;
+                
+            case 'td':
+                //Roo.log(className);
+                if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
+                    var day = parseInt(html, 10) || 1;
+                    var year =  (this.viewDate || new Date()).getUTCFullYear(),
+                        month = (this.viewDate || new Date()).getUTCMonth();
+
+                    if (className.indexOf('old') > -1) {
+                        if(month === 0 ){
+                            month = 11;
+                            year -= 1;
+                        }else{
+                            month -= 1;
+                        }
+                    } else if (className.indexOf('new') > -1) {
+                        if (month == 11) {
+                            month = 0;
+                            year += 1;
+                        } else {
+                            month += 1;
+                        }
+                    }
+                    //Roo.log([year,month,day]);
+                    this.date = this.UTCDate(year, month, day,0,0,0,0);
+                    this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
+//                    this.fill();
+                    //Roo.log(this.formatDate(this.date));
+                    this.setValue(this.formatDate(this.date));
+                    this.hidePopup();
+                }
+                break;
         }
-        */
-        
     },
     
-    findCell : function(dt) {
-        dt = dt.clearTime().getTime();
-        var ret = false;
-        this.cells.each(function(c){
-            //Roo.log("check " +c.dateValue + '?=' + dt);
-            if(c.dateValue == dt){
-                ret = c;
-                return false;
-            }
-            return true;
-        });
-        
-        return ret;
+    setStartDate: function(startDate)
+    {
+        this.startDate = startDate || -Infinity;
+        if (this.startDate !== -Infinity) {
+            this.startDate = this.parseDate(this.startDate);
+        }
+        this.update();
+        this.updateNavArrows();
     },
-    
-    findCells : function(ev) {
-        var s = ev.start.clone().clearTime().getTime();
-       // Roo.log(s);
-        var e= ev.end.clone().clearTime().getTime();
-       // Roo.log(e);
-        var ret = [];
-        this.cells.each(function(c){
-             ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
-            
-            if(c.dateValue > e){
-                return ;
-            }
-            if(c.dateValue < s){
-                return ;
-            }
-            ret.push(c);
-        });
-        
-        return ret;    
+
+    setEndDate: function(endDate)
+    {
+        this.endDate = endDate || Infinity;
+        if (this.endDate !== Infinity) {
+            this.endDate = this.parseDate(this.endDate);
+        }
+        this.update();
+        this.updateNavArrows();
     },
     
-//    findBestRow: function(cells)
-//    {
-//        var ret = 0;
-//        
-//        for (var i =0 ; i < cells.length;i++) {
-//            ret  = Math.max(cells[i].rows || 0,ret);
-//        }
-//        return ret;
-//        
-//    },
-    
-    
-    addItem : function(ev)
+    setDaysOfWeekDisabled: function(daysOfWeekDisabled)
     {
-        // look for vertical location slot in
-        var cells = this.findCells(ev);
-        
-//        ev.row = this.findBestRow(cells);
-        
-        // work out the location.
-        
-        var crow = false;
-        var rows = [];
-        for(var i =0; i < cells.length; i++) {
-            
-            cells[i].row = cells[0].row;
-            
-            if(i == 0){
-                cells[i].row = cells[i].row + 1;
-            }
-            
-            if (!crow) {
-                crow = {
-                    start : cells[i],
-                    end :  cells[i]
-                };
-                continue;
-            }
-            if (crow.start.getY() == cells[i].getY()) {
-                // on same row.
-                crow.end = cells[i];
-                continue;
-            }
-            // different row.
-            rows.push(crow);
-            crow = {
-                start: cells[i],
-                end : cells[i]
-            };
-            
+        this.daysOfWeekDisabled = daysOfWeekDisabled || [];
+        if (typeof(this.daysOfWeekDisabled) !== 'object') {
+            this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
         }
-        
-        rows.push(crow);
-        ev.els = [];
-        ev.rows = rows;
-        ev.cells = cells;
-        
-        cells[0].events.push(ev);
-        
-        this.calevents.push(ev);
+        this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
+            return parseInt(d, 10);
+        });
+        this.update();
+        this.updateNavArrows();
     },
     
-    clearEvents: function() {
-        
-        if(!this.calevents){
+    updateNavArrows: function() 
+    {
+        if(this.singleMode){
             return;
         }
         
-        Roo.each(this.cells.elements, function(c){
-            c.row = 0;
-            c.events = [];
-            c.more = [];
-        });
-        
-        Roo.each(this.calevents, function(e) {
-            Roo.each(e.els, function(el) {
-                el.un('mouseenter' ,this.onEventEnter, this);
-                el.un('mouseleave' ,this.onEventLeave, this);
-                el.remove();
-            },this);
-        },this);
+        var d = new Date(this.viewDate),
+        year = d.getUTCFullYear(),
+        month = d.getUTCMonth();
         
-        Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
-            e.remove();
+        Roo.each(this.picker().select('.prev', true).elements, function(v){
+            v.show();
+            switch (this.viewMode) {
+                case 0:
+
+                    if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
+                        v.hide();
+                    }
+                    break;
+                case 1:
+                case 2:
+                    if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
+                        v.hide();
+                    }
+                    break;
+            }
         });
         
+        Roo.each(this.picker().select('.next', true).elements, function(v){
+            v.show();
+            switch (this.viewMode) {
+                case 0:
+
+                    if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
+                        v.hide();
+                    }
+                    break;
+                case 1:
+                case 2:
+                    if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
+                        v.hide();
+                    }
+                    break;
+            }
+        })
     },
     
-    renderEvents: function()
-    {   
-        var _this = this;
-        
-        this.cells.each(function(c) {
-            
-            if(c.row < 5){
-                return;
+    moveMonth: function(date, dir)
+    {
+        if (!dir) {
+            return date;
+        }
+        var new_date = new Date(date.valueOf()),
+        day = new_date.getUTCDate(),
+        month = new_date.getUTCMonth(),
+        mag = Math.abs(dir),
+        new_month, test;
+        dir = dir > 0 ? 1 : -1;
+        if (mag == 1){
+            test = dir == -1
+            // If going back one month, make sure month is not current month
+            // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
+            ? function(){
+                return new_date.getUTCMonth() == month;
             }
-            
-            var ev = c.events;
-            
-            var r = 4;
-            if(c.row != c.events.length){
-                r = 4 - (4 - (c.row - c.events.length));
+            // If going forward one month, make sure month is as expected
+            // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
+            : function(){
+                return new_date.getUTCMonth() != new_month;
+            };
+            new_month = month + dir;
+            new_date.setUTCMonth(new_month);
+            // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
+            if (new_month < 0 || new_month > 11) {
+                new_month = (new_month + 12) % 12;
             }
-            
-            c.events = ev.slice(0, r);
-            c.more = ev.slice(r);
-            
-            if(c.more.length && c.more.length == 1){
-                c.events.push(c.more.pop());
+        } else {
+            // For magnitudes >1, move one month at a time...
+            for (var i=0; i<mag; i++) {
+                // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
+                new_date = this.moveMonth(new_date, dir);
             }
-            
-            c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
-            
-        });
-            
-        this.cells.each(function(c) {
-            
-            c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
-            
-            
-            for (var e = 0; e < c.events.length; e++){
-                var ev = c.events[e];
-                var rows = ev.rows;
-                
-                for(var i = 0; i < rows.length; i++) {
-                
-                    // how many rows should it span..
-
-                    var  cfg = {
-                        cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
-                        style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
-
-                        unselectable : "on",
-                        cn : [
-                            {
-                                cls: 'fc-event-inner',
-                                cn : [
-    //                                {
-    //                                  tag:'span',
-    //                                  cls: 'fc-event-time',
-    //                                  html : cells.length > 1 ? '' : ev.time
-    //                                },
-                                    {
-                                      tag:'span',
-                                      cls: 'fc-event-title',
-                                      html : String.format('{0}', ev.title)
-                                    }
-
-
-                                ]
-                            },
-                            {
-                                cls: 'ui-resizable-handle ui-resizable-e',
-                                html : '&nbsp;&nbsp;&nbsp'
-                            }
-
-                        ]
-                    };
-
-                    if (i == 0) {
-                        cfg.cls += ' fc-event-start';
-                    }
-                    if ((i+1) == rows.length) {
-                        cfg.cls += ' fc-event-end';
-                    }
-
-                    var ctr = _this.el.select('.fc-event-container',true).first();
-                    var cg = ctr.createChild(cfg);
-
-                    var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
-                    var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
+            // ...then reset the day, keeping it in the new month
+            new_month = new_date.getUTCMonth();
+            new_date.setUTCDate(day);
+            test = function(){
+                return new_month != new_date.getUTCMonth();
+            };
+        }
+        // Common date-resetting loop -- if date is beyond end of month, make it
+        // end of month
+        while (test()){
+            new_date.setUTCDate(--day);
+            new_date.setUTCMonth(new_month);
+        }
+        return new_date;
+    },
 
-                    var r = (c.more.length) ? 1 : 0;
-                    cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
-                    cg.setWidth(ebox.right - sbox.x -2);
+    moveYear: function(date, dir)
+    {
+        return this.moveMonth(date, dir*12);
+    },
 
-                    cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
-                    cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
-                    cg.on('click', _this.onEventClick, _this, ev);
+    dateWithinRange: function(date)
+    {
+        return date >= this.startDate && date <= this.endDate;
+    },
 
-                    ev.els.push(cg);
-                    
-                }
-                
+    
+    remove: function() 
+    {
+        this.picker().remove();
+    },
+    
+    validateValue : function(value)
+    {
+        if(this.getVisibilityEl().hasClass('hidden')){
+            return true;
+        }
+        
+        if(value.length < 1)  {
+            if(this.allowBlank){
+                return true;
             }
-            
-            
-            if(c.more.length){
-                var  cfg = {
-                    cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
-                    style : 'position: absolute',
-                    unselectable : "on",
-                    cn : [
-                        {
-                            cls: 'fc-event-inner',
-                            cn : [
-                                {
-                                  tag:'span',
-                                  cls: 'fc-event-title',
-                                  html : 'More'
-                                }
-
-
-                            ]
-                        },
-                        {
-                            cls: 'ui-resizable-handle ui-resizable-e',
-                            html : '&nbsp;&nbsp;&nbsp'
-                        }
-
-                    ]
-                };
-
-                var ctr = _this.el.select('.fc-event-container',true).first();
-                var cg = ctr.createChild(cfg);
-
-                var sbox = c.select('.fc-day-content',true).first().getBox();
-                var ebox = c.select('.fc-day-content',true).first().getBox();
-                //Roo.log(cg);
-                cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
-                cg.setWidth(ebox.right - sbox.x -2);
-
-                cg.on('click', _this.onMoreEventClick, _this, c.more);
-                
+            return false;
+        }
+        
+        if(value.length < this.minLength){
+            return false;
+        }
+        if(value.length > this.maxLength){
+            return false;
+        }
+        if(this.vtype){
+            var vt = Roo.form.VTypes;
+            if(!vt[this.vtype](value, this)){
+                return false;
             }
-            
-        });
+        }
+        if(typeof this.validator == "function"){
+            var msg = this.validator(value);
+            if(msg !== true){
+                return false;
+            }
+        }
+        
+        if(this.regex && !this.regex.test(value)){
+            return false;
+        }
         
+        if(typeof(this.parseDate(value)) == 'undefined'){
+            return false;
+        }
+        
+        if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
+            return false;
+        }      
+        
+        if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
+            return false;
+        } 
         
         
+        return true;
     },
     
-    onEventEnter: function (e, el,event,d) {
-        this.fireEvent('evententer', this, el, event);
+    reset : function()
+    {
+        this.date = this.viewDate = '';
+        
+        Roo.bootstrap.form.DateField.superclass.setValue.call(this, '');
+    }
+   
+});
+
+Roo.apply(Roo.bootstrap.form.DateField,  {
+    
+    head : {
+        tag: 'thead',
+        cn: [
+        {
+            tag: 'tr',
+            cn: [
+            {
+                tag: 'th',
+                cls: 'prev',
+                html: '<i class="fa fa-arrow-left"/>'
+            },
+            {
+                tag: 'th',
+                cls: 'switch',
+                colspan: '5'
+            },
+            {
+                tag: 'th',
+                cls: 'next',
+                html: '<i class="fa fa-arrow-right"/>'
+            }
+
+            ]
+        }
+        ]
     },
     
-    onEventLeave: function (e, el,event,d) {
-        this.fireEvent('eventleave', this, el, event);
+    content : {
+        tag: 'tbody',
+        cn: [
+        {
+            tag: 'tr',
+            cn: [
+            {
+                tag: 'td',
+                colspan: '7'
+            }
+            ]
+        }
+        ]
     },
     
-    onEventClick: function (e, el,event,d) {
-        this.fireEvent('eventclick', this, el, event);
+    footer : {
+        tag: 'tfoot',
+        cn: [
+        {
+            tag: 'tr',
+            cn: [
+            {
+                tag: 'th',
+                colspan: '7',
+                cls: 'today'
+            }
+                    
+            ]
+        }
+        ]
     },
     
-    onMonthChange: function () {
-        this.store.load();
+    dates:{
+        en: {
+            days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
+            daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
+            daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
+            months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+            monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+            today: "Today"
+        }
     },
     
-    onMoreEventClick: function(e, el, more)
+    modes: [
     {
-        var _this = this;
-        
-        this.calpopover.placement = 'right';
-        this.calpopover.setTitle('More');
-        
-        this.calpopover.setContent('');
-        
-        var ctr = this.calpopover.el.select('.popover-content', true).first();
-        
-        Roo.each(more, function(m){
-            var cfg = {
-                cls : 'fc-event-hori fc-event-draggable',
-                html : m.title
-            };
-            var cg = ctr.createChild(cfg);
-            
-            cg.on('click', _this.onEventClick, _this, m);
-        });
-        
-        this.calpopover.show(el);
-        
-        
+        clsName: 'days',
+        navFnc: 'Month',
+        navStep: 1
     },
-    
-    onLoad: function () 
-    {   
-        this.calevents = [];
-        var cal = this;
-        
-        if(this.store.getCount() > 0){
-            this.store.data.each(function(d){
-               cal.addItem({
-                    id : d.data.id,
-                    start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
-                    end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
-                    time : d.data.start_time,
-                    title : d.data.title,
-                    description : d.data.description,
-                    venue : d.data.venue
-                });
-            });
-        }
-        
-        this.renderEvents();
-        
-        if(this.calevents.length && this.loadMask){
-            this.maskEl.hide();
-        }
+    {
+        clsName: 'months',
+        navFnc: 'FullYear',
+        navStep: 1
     },
-    
-    onBeforeLoad: function()
     {
-        this.clearEvents();
-        if(this.loadMask){
-            this.maskEl.show();
+        clsName: 'years',
+        navFnc: 'FullYear',
+        navStep: 10
+    }]
+});
+
+Roo.apply(Roo.bootstrap.form.DateField,  {
+  
+    template : {
+        tag: 'div',
+        cls: 'datepicker dropdown-menu roo-dynamic shadow',
+        cn: [
+        {
+            tag: 'div',
+            cls: 'datepicker-days',
+            cn: [
+            {
+                tag: 'table',
+                cls: 'table-condensed',
+                cn:[
+                Roo.bootstrap.form.DateField.head,
+                {
+                    tag: 'tbody'
+                },
+                Roo.bootstrap.form.DateField.footer
+                ]
+            }
+            ]
+        },
+        {
+            tag: 'div',
+            cls: 'datepicker-months',
+            cn: [
+            {
+                tag: 'table',
+                cls: 'table-condensed',
+                cn:[
+                Roo.bootstrap.form.DateField.head,
+                Roo.bootstrap.form.DateField.content,
+                Roo.bootstrap.form.DateField.footer
+                ]
+            }
+            ]
+        },
+        {
+            tag: 'div',
+            cls: 'datepicker-years',
+            cn: [
+            {
+                tag: 'table',
+                cls: 'table-condensed',
+                cn:[
+                Roo.bootstrap.form.DateField.head,
+                Roo.bootstrap.form.DateField.content,
+                Roo.bootstrap.form.DateField.footer
+                ]
+            }
+            ]
         }
+        ]
     }
 });
 
  
+
  /*
  * - LGPL
  *
- * element
+ * TimeField
  * 
  */
 
 /**
- * @class Roo.bootstrap.Popover
- * @extends Roo.bootstrap.Component
- * Bootstrap Popover class
- * @cfg {String} html contents of the popover   (or false to use children..)
- * @cfg {String} title of popover (or false to hide)
- * @cfg {String} placement how it is placed
- * @cfg {String} trigger click || hover (or false to trigger manually)
- * @cfg {String} over what (parent or false to trigger manually.)
- * @cfg {Number} delay - delay before showing
+ * @class Roo.bootstrap.form.TimeField
+ * @extends Roo.bootstrap.form.Input
+ * Bootstrap DateField class
+ * 
+ * 
  * @constructor
- * Create a new Popover
+ * Create a new TimeField
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.Popover = function(config){
-    Roo.bootstrap.Popover.superclass.constructor.call(this, config);
-    
+Roo.bootstrap.form.TimeField = function(config){
+    Roo.bootstrap.form.TimeField.superclass.constructor.call(this, config);
     this.addEvents({
-        // raw events
-         /**
-         * @event show
-         * After the popover show
-         * 
-         * @param {Roo.bootstrap.Popover} this
-         */
-        "show" : true,
-        /**
-         * @event hide
-         * After the popover hide
-         * 
-         * @param {Roo.bootstrap.Popover} this
-         */
-        "hide" : true
-    });
+            /**
+             * @event show
+             * Fires when this field show.
+             * @param {Roo.bootstrap.form.DateField} thisthis
+             * @param {Mixed} date The date value
+             */
+            show : true,
+            /**
+             * @event show
+             * Fires when this field hide.
+             * @param {Roo.bootstrap.form.DateField} this
+             * @param {Mixed} date The date value
+             */
+            hide : true,
+            /**
+             * @event select
+             * Fires when select a date.
+             * @param {Roo.bootstrap.form.DateField} this
+             * @param {Mixed} date The date value
+             */
+            select : true
+        });
 };
 
-Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.form.TimeField, Roo.bootstrap.form.Input,  {
     
-    title: 'Fill in a title',
-    html: false,
-    
-    placement : 'right',
-    trigger : 'hover', // hover
+    /**
+     * @cfg {String} format
+     * The default time format string which can be overriden for localization support.  The format must be
+     * valid according to {@link Date#parseDate} (defaults to 'H:i').
+     */
+    format : "H:i",
+
+    getAutoCreate : function()
+    {
+        this.after = '<i class="fa far fa-clock"></i>';
+        return Roo.bootstrap.form.TimeField.superclass.getAutoCreate.call(this);
+        
+         
+    },
+    onRender: function(ct, position)
+    {
+        
+        Roo.bootstrap.form.TimeField.superclass.onRender.call(this, ct, position);
+                
+        this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.form.TimeField.template);
+        
+        this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        
+        this.pop = this.picker().select('>.datepicker-time',true).first();
+        this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        
+        this.picker().on('mousedown', this.onMousedown, this);
+        this.picker().on('click', this.onClick, this);
+        
+        this.picker().addClass('datepicker-dropdown');
     
-    delay : 0,
+        this.fillTime();
+        this.update();
+            
+        this.pop.select('.hours-up', true).first().on('click', this.onIncrementHours, this);
+        this.pop.select('.hours-down', true).first().on('click', this.onDecrementHours, this);
+        this.pop.select('.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
+        this.pop.select('.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
+        this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
+        this.pop.select('button.ok', true).first().on('click', this.setTime, this);
+
+    },
     
-    over: 'parent',
+    fireKey: function(e){
+        if (!this.picker().isVisible()){
+            if (e.keyCode == 27) { // allow escape to hide and re-show picker
+                this.show();
+            }
+            return;
+        }
+
+        e.preventDefault();
+        
+        switch(e.keyCode){
+            case 27: // escape
+                this.hide();
+                break;
+            case 37: // left
+            case 39: // right
+                this.onTogglePeriod();
+                break;
+            case 38: // up
+                this.onIncrementMinutes();
+                break;
+            case 40: // down
+                this.onDecrementMinutes();
+                break;
+            case 13: // enter
+            case 9: // tab
+                this.setTime();
+                break;
+        }
+    },
     
-    can_build_overlaid : false,
+    onClick: function(e) {
+        e.stopPropagation();
+        e.preventDefault();
+    },
     
-    getChildContainer : function()
+    picker : function()
     {
-        return this.el.select('.popover-content',true).first();
+        return this.pickerEl;
     },
     
-    getAutoCreate : function(){
-         
-        var cfg = {
-           cls : 'popover roo-dynamic',
-           style: 'display:block',
-           cn : [
+    fillTime: function()
+    {    
+        var time = this.pop.select('tbody', true).first();
+        
+        time.dom.innerHTML = '';
+        
+        time.createChild({
+            tag: 'tr',
+            cn: [
                 {
-                    cls : 'arrow'
+                    tag: 'td',
+                    cn: [
+                        {
+                            tag: 'a',
+                            href: '#',
+                            cls: 'btn',
+                            cn: [
+                                {
+                                    tag: 'i',
+                                    cls: 'hours-up fa fas fa-chevron-up'
+                                }
+                            ]
+                        } 
+                    ]
                 },
                 {
-                    cls : 'popover-inner',
-                    cn : [
-                        {
-                            tag: 'h3',
-                            cls: 'popover-title popover-header',
-                            html : this.title
-                        },
+                    tag: 'td',
+                    cls: 'separator'
+                },
+                {
+                    tag: 'td',
+                    cn: [
                         {
-                            cls : 'popover-content popover-body',
-                            html : this.html
+                            tag: 'a',
+                            href: '#',
+                            cls: 'btn',
+                            cn: [
+                                {
+                                    tag: 'i',
+                                    cls: 'minutes-up fa fas fa-chevron-up'
+                                }
+                            ]
                         }
                     ]
-                    
+                },
+                {
+                    tag: 'td',
+                    cls: 'separator'
                 }
-           ]
-        };
+            ]
+        });
         
-        return cfg;
-    },
-    setTitle: function(str)
-    {
-        this.title = str;
-        this.el.select('.popover-title',true).first().dom.innerHTML = str;
-    },
-    setContent: function(str)
-    {
-        this.html = str;
-        this.el.select('.popover-content',true).first().dom.innerHTML = str;
-    },
-    // as it get's added to the bottom of the page.
-    onRender : function(ct, position)
-    {
-        Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
-        if(!this.el){
-            var cfg = Roo.apply({},  this.getAutoCreate());
-            cfg.id = Roo.id();
-            
-            if (this.cls) {
-                cfg.cls += ' ' + this.cls;
-            }
-            if (this.style) {
-                cfg.style = this.style;
-            }
-            //Roo.log("adding to ");
-            this.el = Roo.get(document.body).createChild(cfg, position);
-//            Roo.log(this.el);
-        }
-        this.initEvents();
-    },
-    
-    initEvents : function()
-    {
-        this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
-        this.el.enableDisplayMode('block');
-        this.el.hide();
-        if (this.over === false) {
-            return; 
-        }
-        if (this.triggers === false) {
-            return;
-        }
-        var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
-        var triggers = this.trigger ? this.trigger.split(' ') : [];
-        Roo.each(triggers, function(trigger) {
+        time.createChild({
+            tag: 'tr',
+            cn: [
+                {
+                    tag: 'td',
+                    cn: [
+                        {
+                            tag: 'span',
+                            cls: 'timepicker-hour',
+                            html: '00'
+                        }  
+                    ]
+                },
+                {
+                    tag: 'td',
+                    cls: 'separator',
+                    html: ':'
+                },
+                {
+                    tag: 'td',
+                    cn: [
+                        {
+                            tag: 'span',
+                            cls: 'timepicker-minute',
+                            html: '00'
+                        }  
+                    ]
+                },
+                {
+                    tag: 'td',
+                    cls: 'separator'
+                },
+                {
+                    tag: 'td',
+                    cn: [
+                        {
+                            tag: 'button',
+                            type: 'button',
+                            cls: 'btn btn-primary period',
+                            html: 'AM'
+                            
+                        }
+                    ]
+                }
+            ]
+        });
         
-            if (trigger == 'click') {
-                on_el.on('click', this.toggle, this);
-            } else if (trigger != 'manual') {
-                var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
-                var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
-      
-                on_el.on(eventIn  ,this.enter, this);
-                on_el.on(eventOut, this.leave, this);
-            }
-        }, this);
+        time.createChild({
+            tag: 'tr',
+            cn: [
+                {
+                    tag: 'td',
+                    cn: [
+                        {
+                            tag: 'a',
+                            href: '#',
+                            cls: 'btn',
+                            cn: [
+                                {
+                                    tag: 'span',
+                                    cls: 'hours-down fa fas fa-chevron-down'
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    tag: 'td',
+                    cls: 'separator'
+                },
+                {
+                    tag: 'td',
+                    cn: [
+                        {
+                            tag: 'a',
+                            href: '#',
+                            cls: 'btn',
+                            cn: [
+                                {
+                                    tag: 'span',
+                                    cls: 'minutes-down fa fas fa-chevron-down'
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    tag: 'td',
+                    cls: 'separator'
+                }
+            ]
+        });
         
     },
     
-    
-    // private
-    timeout : null,
-    hoverState : null,
-    
-    toggle : function () {
-        this.hoverState == 'in' ? this.leave() : this.enter();
-    },
-    
-    enter : function () {
+    update: function()
+    {
         
-        clearTimeout(this.timeout);
-    
-        this.hoverState = 'in';
-    
-        if (!this.delay || !this.delay.show) {
-            this.show();
-            return;
-        }
-        var _t = this;
-        this.timeout = setTimeout(function () {
-            if (_t.hoverState == 'in') {
-                _t.show();
-            }
-        }, this.delay.show)
-    },
-    
-    leave : function() {
-        clearTimeout(this.timeout);
-    
-        this.hoverState = 'out';
-    
-        if (!this.delay || !this.delay.hide) {
-            this.hide();
-            return;
-        }
-        var _t = this;
-        this.timeout = setTimeout(function () {
-            if (_t.hoverState == 'out') {
-                _t.hide();
-            }
-        }, this.delay.hide)
+        this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
+        
+        this.fill();
     },
     
-    show : function (on_el)
+    fill: function() 
     {
-        if (!on_el) {
-            on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
-        }
+        var hours = this.time.getHours();
+        var minutes = this.time.getMinutes();
+        var period = 'AM';
         
-        // set content.
-        this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
-        if (this.html !== false) {
-            this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
-        }
-        this.el.removeClass([
-            'fade','top','bottom', 'left', 'right','in',
-            'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
-        ]);
-        if (!this.title.length) {
-            this.el.select('.popover-title',true).hide();
+        if(hours > 11){
+            period = 'PM';
         }
         
-        var placement = typeof this.placement == 'function' ?
-            this.placement.call(this, this.el, on_el) :
-            this.placement;
-            
-        var autoToken = /\s?auto?\s?/i;
-        var autoPlace = autoToken.test(placement);
-        if (autoPlace) {
-            placement = placement.replace(autoToken, '') || 'top';
+        if(hours == 0){
+            hours = 12;
         }
         
-        //this.el.detach()
-        //this.el.setXY([0,0]);
-        this.el.show();
-        this.el.dom.style.display='block';
-        this.el.addClass(placement);
         
-        //this.el.appendTo(on_el);
+        if(hours > 12){
+            hours = hours - 12;
+        }
         
-        var p = this.getPosition();
-        var box = this.el.getBox();
+        if(hours < 10){
+            hours = '0' + hours;
+        }
         
-        if (autoPlace) {
-            // fixme..
+        if(minutes < 10){
+            minutes = '0' + minutes;
         }
-        var align = Roo.bootstrap.Popover.alignment[placement];
         
-//        Roo.log(align);
-        this.el.alignTo(on_el, align[0],align[1]);
-        //var arrow = this.el.select('.arrow',true).first();
-        //arrow.set(align[2], 
+        this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
+        this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
+        this.pop.select('button', true).first().dom.innerHTML = period;
         
-        this.el.addClass('in');
+    },
+    
+    place: function()
+    {   
+        this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
         
+        var cls = ['bottom'];
         
-        if (this.el.hasClass('fade')) {
-            // fade it?
+        if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
+            cls.pop();
+            cls.push('top');
         }
         
-        this.hoverState = 'in';
+        cls.push('right');
         
-        this.fireEvent('show', this);
+        if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
+            cls.pop();
+            cls.push('left');
+        }
+        //this.picker().setXY(20000,20000);
+        this.picker().addClass(cls.join('-'));
+        
+        var _this = this;
+        
+        Roo.each(cls, function(c){
+            if(c == 'bottom'){
+                (function() {
+                 //  
+                }).defer(200);
+                 _this.picker().alignTo(_this.inputEl(),   "tr-br", [0, 10], false);
+                //_this.picker().setTop(_this.inputEl().getHeight());
+                return;
+            }
+            if(c == 'top'){
+                 _this.picker().alignTo(_this.inputEl(),   "br-tr", [0, 10], false);
+                
+                //_this.picker().setTop(0 - _this.picker().getHeight());
+                return;
+            }
+            /*
+            if(c == 'left'){
+                _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
+                return;
+            }
+            if(c == 'right'){
+                _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
+                return;
+            }
+            */
+        });
         
     },
-    hide : function()
+  
+    onFocus : function()
     {
-        this.el.setXY([0,0]);
-        this.el.removeClass('in');
-        this.el.hide();
-        this.hoverState = null;
-        
-        this.fireEvent('hide', this);
-    }
+        Roo.bootstrap.form.TimeField.superclass.onFocus.call(this);
+        this.show();
+    },
     
-});
-
-Roo.bootstrap.Popover.alignment = {
-    'left' : ['r-l', [-10,0], 'right bs-popover-right'],
-    'right' : ['l-r', [10,0], 'left bs-popover-left'],
-    'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
-    'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
-};
-
- /*
- * - LGPL
- *
- * Progress
- * 
- */
-
-/**
- * @class Roo.bootstrap.Progress
- * @extends Roo.bootstrap.Component
- * Bootstrap Progress class
- * @cfg {Boolean} striped striped of the progress bar
- * @cfg {Boolean} active animated of the progress bar
- * 
- * 
- * @constructor
- * Create a new Progress
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.Progress = function(config){
-    Roo.bootstrap.Progress.superclass.constructor.call(this, config);
-};
-
-Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
+    onBlur : function()
+    {
+        Roo.bootstrap.form.TimeField.superclass.onBlur.call(this);
+        this.hide();
+    },
     
-    striped : false,
-    active: false,
+    show : function()
+    {
+        this.picker().show();
+        this.pop.show();
+        this.update();
+        this.place();
+        
+        this.fireEvent('show', this, this.date);
+    },
     
-    getAutoCreate : function(){
-        var cfg = {
-            tag: 'div',
-            cls: 'progress'
-        };
+    hide : function()
+    {
+        this.picker().hide();
+        this.pop.hide();
         
+        this.fireEvent('hide', this, this.date);
+    },
+    
+    setTime : function()
+    {
+        this.hide();
+        this.setValue(this.time.format(this.format));
         
-        if(this.striped){
-            cfg.cls += ' progress-striped';
-        }
-      
-        if(this.active){
-            cfg.cls += ' active';
-        }
+        this.fireEvent('select', this, this.date);
         
         
-        return cfg;
-    }
-   
-});
-
-
- /*
- * - LGPL
- *
- * ProgressBar
- * 
- */
-
-/**
- * @class Roo.bootstrap.ProgressBar
- * @extends Roo.bootstrap.Component
- * Bootstrap ProgressBar class
- * @cfg {Number} aria_valuenow aria-value now
- * @cfg {Number} aria_valuemin aria-value min
- * @cfg {Number} aria_valuemax aria-value max
- * @cfg {String} label label for the progress bar
- * @cfg {String} panel (success | info | warning | danger )
- * @cfg {String} role role of the progress bar
- * @cfg {String} sr_only text
- * 
- * 
- * @constructor
- * Create a new ProgressBar
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.ProgressBar = function(config){
-    Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
-};
-
-Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
+    },
     
-    aria_valuenow : 0,
-    aria_valuemin : 0,
-    aria_valuemax : 100,
-    label : false,
-    panel : false,
-    role : false,
-    sr_only: false,
+    onMousedown: function(e){
+        e.stopPropagation();
+        e.preventDefault();
+    },
     
-    getAutoCreate : function()
+    onIncrementHours: function()
     {
+        Roo.log('onIncrementHours');
+        this.time = this.time.add(Date.HOUR, 1);
+        this.update();
         
-        var cfg = {
-            tag: 'div',
-            cls: 'progress-bar',
-            style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
-        };
-        
-        if(this.sr_only){
-            cfg.cn = {
-                tag: 'span',
-                cls: 'sr-only',
-                html: this.sr_only
-            }
-        }
-        
-        if(this.role){
-            cfg.role = this.role;
-        }
-        
-        if(this.aria_valuenow){
-            cfg['aria-valuenow'] = this.aria_valuenow;
-        }
-        
-        if(this.aria_valuemin){
-            cfg['aria-valuemin'] = this.aria_valuemin;
-        }
-        
-        if(this.aria_valuemax){
-            cfg['aria-valuemax'] = this.aria_valuemax;
-        }
-        
-        if(this.label && !this.sr_only){
-            cfg.html = this.label;
-        }
-        
-        if(this.panel){
-            cfg.cls += ' progress-bar-' + this.panel;
-        }
-        
-        return cfg;
     },
     
-    update : function(aria_valuenow)
+    onDecrementHours: function()
     {
-        this.aria_valuenow = aria_valuenow;
-        
-        this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
+        Roo.log('onDecrementHours');
+        this.time = this.time.add(Date.HOUR, -1);
+        this.update();
+    },
+    
+    onIncrementMinutes: function()
+    {
+        Roo.log('onIncrementMinutes');
+        this.time = this.time.add(Date.MINUTE, 1);
+        this.update();
+    },
+    
+    onDecrementMinutes: function()
+    {
+        Roo.log('onDecrementMinutes');
+        this.time = this.time.add(Date.MINUTE, -1);
+        this.update();
+    },
+    
+    onTogglePeriod: function()
+    {
+        Roo.log('onTogglePeriod');
+        this.time = this.time.add(Date.HOUR, 12);
+        this.update();
     }
+    
    
 });
+
+Roo.apply(Roo.bootstrap.form.TimeField,  {
+  
+    template : {
+        tag: 'div',
+        cls: 'datepicker dropdown-menu',
+        cn: [
+            {
+                tag: 'div',
+                cls: 'datepicker-time',
+                cn: [
+                {
+                    tag: 'table',
+                    cls: 'table-condensed',
+                    cn:[
+                        {
+                            tag: 'tbody',
+                            cn: [
+                                {
+                                    tag: 'tr',
+                                    cn: [
+                                    {
+                                        tag: 'td',
+                                        colspan: '7'
+                                    }
+                                    ]
+                                }
+                            ]
+                        },
+                        {
+                            tag: 'tfoot',
+                            cn: [
+                                {
+                                    tag: 'tr',
+                                    cn: [
+                                    {
+                                        tag: 'th',
+                                        colspan: '7',
+                                        cls: '',
+                                        cn: [
+                                            {
+                                                tag: 'button',
+                                                cls: 'btn btn-info ok',
+                                                html: 'OK'
+                                            }
+                                        ]
+                                    }
+                    
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
+                }
+                ]
+            }
+        ]
+    }
+});
 
  
 
  /*
  * - LGPL
  *
- * column
+ * MonthField
  * 
  */
 
 /**
- * @class Roo.bootstrap.TabGroup
- * @extends Roo.bootstrap.Column
- * Bootstrap Column class
- * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
- * @cfg {Boolean} carousel true to make the group behave like a carousel
- * @cfg {Boolean} bullets show bullets for the panels
- * @cfg {Boolean} autoslide (true|false) auto slide .. default false
- * @cfg {Number} timer auto slide timer .. default 0 millisecond
- * @cfg {Boolean} showarrow (true|false) show arrow default true
+ * @class Roo.bootstrap.form.MonthField
+ * @extends Roo.bootstrap.form.Input
+ * Bootstrap MonthField class
+ * 
+ * @cfg {String} language default en
  * 
  * @constructor
- * Create a new TabGroup
+ * Create a new MonthField
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.TabGroup = function(config){
-    Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
-    if (!this.navId) {
-        this.navId = Roo.id();
-    }
-    this.tabs = [];
-    Roo.bootstrap.TabGroup.register(this);
+Roo.bootstrap.form.MonthField = function(config){
+    Roo.bootstrap.form.MonthField.superclass.constructor.call(this, config);
     
+    this.addEvents({
+        /**
+         * @event show
+         * Fires when this field show.
+         * @param {Roo.bootstrap.form.MonthField} this
+         * @param {Mixed} date The date value
+         */
+        show : true,
+        /**
+         * @event show
+         * Fires when this field hide.
+         * @param {Roo.bootstrap.form.MonthField} this
+         * @param {Mixed} date The date value
+         */
+        hide : true,
+        /**
+         * @event select
+         * Fires when select a date.
+         * @param {Roo.bootstrap.form.MonthField} this
+         * @param {String} oldvalue The old value
+         * @param {String} newvalue The new value
+         */
+        select : true
+    });
 };
 
-Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
-    
-    carousel : false,
-    transition : false,
-    bullets : 0,
-    timer : 0,
-    autoslide : false,
-    slideFn : false,
-    slideOnTouch : false,
-    showarrow : true,
+Roo.extend(Roo.bootstrap.form.MonthField, Roo.bootstrap.form.Input,  {
     
-    getAutoCreate : function()
+    onRender: function(ct, position)
     {
-        var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
         
-        cfg.cls += ' tab-content';
+        Roo.bootstrap.form.MonthField.superclass.onRender.call(this, ct, position);
         
-        if (this.carousel) {
-            cfg.cls += ' carousel slide';
-            
-            cfg.cn = [{
-               cls : 'carousel-inner',
-               cn : []
-            }];
+        this.language = this.language || 'en';
+        this.language = this.language in Roo.bootstrap.form.MonthField.dates ? this.language : this.language.split('-')[0];
+        this.language = this.language in Roo.bootstrap.form.MonthField.dates ? this.language : "en";
         
-            if(this.bullets  && !Roo.isTouch){
-                
-                var bullets = {
-                    cls : 'carousel-bullets',
-                    cn : []
-                };
-               
-                if(this.bullets_cls){
-                    bullets.cls = bullets.cls + ' ' + this.bullets_cls;
-                }
-                
-                bullets.cn.push({
-                    cls : 'clear'
-                });
-                
-                cfg.cn[0].cn.push(bullets);
-            }
-            
-            if(this.showarrow){
-                cfg.cn[0].cn.push({
-                    tag : 'div',
-                    class : 'carousel-arrow',
-                    cn : [
-                        {
-                            tag : 'div',
-                            class : 'carousel-prev',
-                            cn : [
-                                {
-                                    tag : 'i',
-                                    class : 'fa fa-chevron-left'
-                                }
-                            ]
-                        },
-                        {
-                            tag : 'div',
-                            class : 'carousel-next',
-                            cn : [
-                                {
-                                    tag : 'i',
-                                    class : 'fa fa-chevron-right'
-                                }
-                            ]
-                        }
-                    ]
-                });
-            }
-            
+        this.isRTL = Roo.bootstrap.form.MonthField.dates[this.language].rtl || false;
+        this.isInline = false;
+        this.isInput = true;
+        this.component = this.el.select('.add-on', true).first() || false;
+        this.component = (this.component && this.component.length === 0) ? false : this.component;
+        this.hasInput = this.component && this.inputEL().length;
+        
+        this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.form.MonthField.template);
+        
+        this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        
+        this.picker().on('mousedown', this.onMousedown, this);
+        this.picker().on('click', this.onClick, this);
+        
+        this.picker().addClass('datepicker-dropdown');
+        
+        Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
+            v.setStyle('width', '189px');
+        });
+        
+        this.fillMonths();
+        
+        this.update();
+        
+        if(this.isInline) {
+            this.show();
         }
         
-        return cfg;
     },
     
-    initEvents:  function()
-    {
-//        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
-//            this.el.on("touchstart", this.onTouchStart, this);
-//        }
+    setValue: function(v, suppressEvent)
+    {   
+        var o = this.getValue();
         
-        if(this.autoslide){
-            var _this = this;
-            
-            this.slideFn = window.setInterval(function() {
-                _this.showPanelNext();
-            }, this.timer);
-        }
+        Roo.bootstrap.form.MonthField.superclass.setValue.call(this, v);
         
-        if(this.showarrow){
-            this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
-            this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
+        this.update();
+
+        if(suppressEvent !== true){
+            this.fireEvent('select', this, o, v);
         }
         
-        
-    },
-    
-//    onTouchStart : function(e, el, o)
-//    {
-//        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
-//            return;
-//        }
-//        
-//        this.showPanelNext();
-//    },
-    
-    
-    getChildContainer : function()
-    {
-        return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
     },
     
-    /**
-    * register a Navigation item
-    * @param {Roo.bootstrap.NavItem} the navitem to add
-    */
-    register : function(item)
+    getValue: function()
     {
-        this.tabs.push( item);
-        item.navId = this.navId; // not really needed..
-        this.addBullet();
-    
+        return this.value;
     },
     
-    getActivePanel : function()
-    {
-        var r = false;
-        Roo.each(this.tabs, function(t) {
-            if (t.active) {
-                r = t;
-                return false;
-            }
-            return null;
-        });
-        return r;
-        
-    },
-    getPanelByName : function(n)
-    {
-        var r = false;
-        Roo.each(this.tabs, function(t) {
-            if (t.tabId == n) {
-                r = t;
-                return false;
-            }
-            return null;
-        });
-        return r;
-    },
-    indexOfPanel : function(p)
-    {
-        var r = false;
-        Roo.each(this.tabs, function(t,i) {
-            if (t.tabId == p.tabId) {
-                r = i;
-                return false;
-            }
-            return null;
-        });
-        return r;
-    },
-    /**
-     * show a specific panel
-     * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
-     * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
-     */
-    showPanel : function (pan)
+    onClick: function(e) 
     {
-        if(this.transition || typeof(pan) == 'undefined'){
-            Roo.log("waiting for the transitionend");
-            return false;
-        }
+        e.stopPropagation();
+        e.preventDefault();
         
-        if (typeof(pan) == 'number') {
-            pan = this.tabs[pan];
-        }
+        var target = e.getTarget();
         
-        if (typeof(pan) == 'string') {
-            pan = this.getPanelByName(pan);
+        if(target.nodeName.toLowerCase() === 'i'){
+            target = Roo.get(target).dom.parentNode;
         }
         
-        var cur = this.getActivePanel();
+        var nodeName = target.nodeName;
+        var className = target.className;
+        var html = target.innerHTML;
         
-        if(!pan || !cur){
-            Roo.log('pan or acitve pan is undefined');
-            return false;
+        if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
+            return;
         }
         
-        if (pan.tabId == this.getActivePanel().tabId) {
-            return true;
-        }
+        this.vIndex = Roo.bootstrap.form.MonthField.dates[this.language].monthsShort.indexOf(html);
         
-        if (false === cur.fireEvent('beforedeactivate')) {
-            return false;
-        }
+        this.setValue(Roo.bootstrap.form.MonthField.dates[this.language].months[this.vIndex]);
         
-        if(this.bullets > 0 && !Roo.isTouch){
-            this.setActiveBullet(this.indexOfPanel(pan));
-        }
+        this.hide();
+                        
+    },
+    
+    picker : function()
+    {
+        return this.pickerEl;
+    },
+    
+    fillMonths: function()
+    {    
+        var i = 0;
+        var months = this.picker().select('>.datepicker-months td', true).first();
         
-        if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
-            
-            //class="carousel-item carousel-item-next carousel-item-left"
-            
-            this.transition = true;
-            var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
-            var lr = dir == 'next' ? 'left' : 'right';
-            pan.el.addClass(dir); // or prev
-            pan.el.addClass('carousel-item-' + dir); // or prev
-            pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
-            cur.el.addClass(lr); // or right
-            pan.el.addClass(lr);
-            cur.el.addClass('carousel-item-' +lr); // or right
-            pan.el.addClass('carousel-item-' +lr);
-            
-            
-            var _this = this;
-            cur.el.on('transitionend', function() {
-                Roo.log("trans end?");
-                
-                pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
-                pan.setActive(true);
-                
-                cur.el.removeClass([lr, 'carousel-item-' + lr]);
-                cur.setActive(false);
-                
-                _this.transition = false;
-                
-            }, this, { single:  true } );
+        months.dom.innerHTML = '';
+        
+        while (i < 12) {
+            var month = {
+                tag: 'span',
+                cls: 'month',
+                html: Roo.bootstrap.form.MonthField.dates[this.language].monthsShort[i++]
+            };
             
-            return true;
+            months.createChild(month);
         }
         
-        cur.setActive(false);
-        pan.setActive(true);
-        
-        return true;
-        
     },
-    showPanelNext : function()
+    
+    update: function()
     {
-        var i = this.indexOfPanel(this.getActivePanel());
-        
-        if (i >= this.tabs.length - 1 && !this.autoslide) {
-            return;
-        }
+        var _this = this;
         
-        if (i >= this.tabs.length - 1 && this.autoslide) {
-            i = -1;
+        if(typeof(this.vIndex) == 'undefined' && this.value.length){
+            this.vIndex = Roo.bootstrap.form.MonthField.dates[this.language].months.indexOf(this.value);
         }
         
-        this.showPanel(this.tabs[i+1]);
+        Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
+            e.removeClass('active');
+            
+            if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
+                e.addClass('active');
+            }
+        })
     },
     
-    showPanelPrev : function()
+    place: function()
     {
-        var i = this.indexOfPanel(this.getActivePanel());
-        
-        if (i  < 1 && !this.autoslide) {
+        if(this.isInline) {
             return;
         }
         
-        if (i < 1 && this.autoslide) {
-            i = this.tabs.length;
+        this.picker().removeClass(['bottom', 'top']);
+        
+        if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
+            /*
+             * place to the top of element!
+             *
+             */
+            
+            this.picker().addClass('top');
+            this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
+            
+            return;
         }
         
-        this.showPanel(this.tabs[i-1]);
+        this.picker().addClass('bottom');
+        
+        this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
     },
     
+    onFocus : function()
+    {
+        Roo.bootstrap.form.MonthField.superclass.onFocus.call(this);
+        this.show();
+    },
     
-    addBullet: function()
+    onBlur : function()
     {
-        if(!this.bullets || Roo.isTouch){
-            return;
-        }
-        var ctr = this.el.select('.carousel-bullets',true).first();
-        var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
-        var bullet = ctr.createChild({
-            cls : 'bullet bullet-' + i
-        },ctr.dom.lastChild);
+        Roo.bootstrap.form.MonthField.superclass.onBlur.call(this);
         
+        var d = this.inputEl().getValue();
         
-        var _this = this;
-        
-        bullet.on('click', (function(e, el, o, ii, t){
-
-            e.preventDefault();
-
-            this.showPanel(ii);
-
-            if(this.autoslide && this.slideFn){
-                clearInterval(this.slideFn);
-                this.slideFn = window.setInterval(function() {
-                    _this.showPanelNext();
-                }, this.timer);
-            }
-
-        }).createDelegate(this, [i, bullet], true));
+        this.setValue(d);
                 
+        this.hide();
+    },
+    
+    show : function()
+    {
+        this.picker().show();
+        this.picker().select('>.datepicker-months', true).first().show();
+        this.update();
+        this.place();
         
+        this.fireEvent('show', this, this.date);
     },
-     
-    setActiveBullet : function(i)
+    
+    hide : function()
     {
-        if(Roo.isTouch){
+        if(this.isInline) {
             return;
         }
+        this.picker().hide();
+        this.fireEvent('hide', this, this.date);
         
-        Roo.each(this.el.select('.bullet', true).elements, function(el){
-            el.removeClass('selected');
-        });
+    },
+    
+    onMousedown: function(e)
+    {
+        e.stopPropagation();
+        e.preventDefault();
+    },
+    
+    keyup: function(e)
+    {
+        Roo.bootstrap.form.MonthField.superclass.keyup.call(this);
+        this.update();
+    },
 
-        var bullet = this.el.select('.bullet-' + i, true).first();
-        
-        if(!bullet){
+    fireKey: function(e)
+    {
+        if (!this.picker().isVisible()){
+            if (e.keyCode == 27)   {// allow escape to hide and re-show picker
+                this.show();
+            }
             return;
         }
         
-        bullet.addClass('selected');
-    }
-    
+        var dir;
+        
+        switch(e.keyCode){
+            case 27: // escape
+                this.hide();
+                e.preventDefault();
+                break;
+            case 37: // left
+            case 39: // right
+                dir = e.keyCode == 37 ? -1 : 1;
+                
+                this.vIndex = this.vIndex + dir;
+                
+                if(this.vIndex < 0){
+                    this.vIndex = 0;
+                }
+                
+                if(this.vIndex > 11){
+                    this.vIndex = 11;
+                }
+                
+                if(isNaN(this.vIndex)){
+                    this.vIndex = 0;
+                }
+                
+                this.setValue(Roo.bootstrap.form.MonthField.dates[this.language].months[this.vIndex]);
+                
+                break;
+            case 38: // up
+            case 40: // down
+                
+                dir = e.keyCode == 38 ? -1 : 1;
+                
+                this.vIndex = this.vIndex + dir * 4;
+                
+                if(this.vIndex < 0){
+                    this.vIndex = 0;
+                }
+                
+                if(this.vIndex > 11){
+                    this.vIndex = 11;
+                }
+                
+                if(isNaN(this.vIndex)){
+                    this.vIndex = 0;
+                }
+                
+                this.setValue(Roo.bootstrap.form.MonthField.dates[this.language].months[this.vIndex]);
+                break;
+                
+            case 13: // enter
+                
+                if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
+                    this.setValue(Roo.bootstrap.form.MonthField.dates[this.language].months[this.vIndex]);
+                }
+                
+                this.hide();
+                e.preventDefault();
+                break;
+            case 9: // tab
+                if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
+                    this.setValue(Roo.bootstrap.form.MonthField.dates[this.language].months[this.vIndex]);
+                }
+                this.hide();
+                break;
+            case 16: // shift
+            case 17: // ctrl
+            case 18: // alt
+                break;
+            default :
+                this.hide();
+                
+        }
+    },
     
-  
+    remove: function() 
+    {
+        this.picker().remove();
+    }
+   
 });
 
-
-Roo.apply(Roo.bootstrap.TabGroup, {
+Roo.apply(Roo.bootstrap.form.MonthField,  {
     
-    groups: {},
-     /**
-    * register a Navigation Group
-    * @param {Roo.bootstrap.NavGroup} the navgroup to add
-    */
-    register : function(navgrp)
-    {
-        this.groups[navgrp.navId] = navgrp;
-       
+    content : {
+        tag: 'tbody',
+        cn: [
+        {
+            tag: 'tr',
+            cn: [
+            {
+                tag: 'td',
+                colspan: '7'
+            }
+            ]
+        }
+        ]
     },
-    /**
-    * fetch a Navigation Group based on the navigation ID
-    * if one does not exist , it will get created.
-    * @param {string} the navgroup to add
-    * @returns {Roo.bootstrap.NavGroup} the navgroup 
-    */
-    get: function(navId) {
-        if (typeof(this.groups[navId]) == 'undefined') {
-            this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
+    
+    dates:{
+        en: {
+            months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+            monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
         }
-        return this.groups[navId] ;
     }
-    
-    
-    
 });
 
+Roo.apply(Roo.bootstrap.form.MonthField,  {
+  
+    template : {
+        tag: 'div',
+        cls: 'datepicker dropdown-menu roo-dynamic',
+        cn: [
+            {
+                tag: 'div',
+                cls: 'datepicker-months',
+                cn: [
+                {
+                    tag: 'table',
+                    cls: 'table-condensed',
+                    cn:[
+                        Roo.bootstrap.form.DateField.content
+                    ]
+                }
+                ]
+            }
+        ]
+    }
+});
+
+
  /*
  * - LGPL
  *
- * TabPanel
+ * CheckBox
  * 
  */
 
 /**
- * @class Roo.bootstrap.TabPanel
- * @extends Roo.bootstrap.Component
- * Bootstrap TabPanel class
- * @cfg {Boolean} active panel active
- * @cfg {String} html panel content
- * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
- * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
- * @cfg {String} href click to link..
+ * @class Roo.bootstrap.form.CheckBox
+ * @extends Roo.bootstrap.form.Input
+ * Bootstrap CheckBox class
  * 
+ * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
+ * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
+ * @cfg {String} boxLabel The text that appears beside the checkbox
+ * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
+ * @cfg {Boolean} checked initnal the element
+ * @cfg {Boolean} inline inline the element (default false)
+ * @cfg {String} groupId the checkbox group id // normal just use for checkbox
+ * @cfg {String} tooltip label tooltip
  * 
  * @constructor
- * Create a new TabPanel
+ * Create a new CheckBox
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.TabPanel = function(config){
-    Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
+Roo.bootstrap.form.CheckBox = function(config){
+    Roo.bootstrap.form.CheckBox.superclass.constructor.call(this, config);
+   
     this.addEvents({
         /**
-            * @event changed
-            * Fires when the active status changes
-            * @param {Roo.bootstrap.TabPanel} this
-            * @param {Boolean} state the new state
-           
-         */
-        'changed': true,
-        /**
-            * @event beforedeactivate
-            * Fires before a tab is de-activated - can be used to do validation on a form.
-            * @param {Roo.bootstrap.TabPanel} this
-            * @return {Boolean} false if there is an error
-           
-         */
-        'beforedeactivate': true
-     });
+        * @event check
+        * Fires when the element is checked or unchecked.
+        * @param {Roo.bootstrap.form.CheckBox} this This input
+        * @param {Boolean} checked The new checked value
+        */
+       check : true,
+       /**
+        * @event click
+        * Fires when the element is click.
+        * @param {Roo.bootstrap.form.CheckBox} this This input
+        */
+       click : true
+    });
     
-    this.tabId = this.tabId || Roo.id();
-  
 };
 
-Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.form.CheckBox, Roo.bootstrap.form.Input,  {
+  
+    inputType: 'checkbox',
+    inputValue: 1,
+    valueOff: 0,
+    boxLabel: false,
+    checked: false,
+    weight : false,
+    inline: false,
+    tooltip : '',
     
-    active: false,
-    html: false,
-    tabId: false,
-    navId : false,
-    href : '',
+    // checkbox success does not make any sense really.. 
+    invalidClass : "",
+    validClass : "",
     
-    getAutoCreate : function(){
+    
+    getAutoCreate : function()
+    {
+        var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
         
-       
-       var cfg = {
-            tag: 'div',
-            // item is needed for carousel - not sure if it has any effect otherwise
-            cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
-            html: this.html || ''
-        };
+        var id = Roo.id();
         
-        if(this.active){
-            cfg.cls += ' active';
+        var cfg = {};
+        
+        cfg.cls = 'form-group form-check ' + this.inputType; //input-group
+        
+        if(this.inline){
+            cfg.cls += ' ' + this.inputType + '-inline  form-check-inline';
         }
         
-        if(this.tabId){
-            cfg.tabId = this.tabId;
+        var input =  {
+            tag: 'input',
+            id : id,
+            type : this.inputType,
+            value : this.inputValue,
+            cls : 'roo-' + this.inputType, //'form-box',
+            placeholder : this.placeholder || ''
+            
+        };
+        
+        if(this.inputType != 'radio'){
+            var hidden =  {
+                tag: 'input',
+                type : 'hidden',
+                cls : 'roo-hidden-value',
+                value : this.checked ? this.inputValue : this.valueOff
+            };
         }
         
-       
+            
+        if (this.weight) { // Validity check?
+            cfg.cls += " " + this.inputType + "-" + this.weight;
+        }
         
-        return cfg;
-    },
-    
-    initEvents:  function()
-    {
-        var p = this.parent();
+        if (this.disabled) {
+            input.disabled=true;
+        }
         
-        this.navId = this.navId || p.navId;
+        if(this.checked){
+            input.checked = this.checked;
+        }
         
-        if (typeof(this.navId) != 'undefined') {
-            // not really needed.. but just in case.. parent should be a NavGroup.
-            var tg = Roo.bootstrap.TabGroup.get(this.navId);
-            
-            tg.register(this);
+        if (this.name) {
             
-            var i = tg.tabs.length - 1;
+            input.name = this.name;
             
-            if(this.active && tg.bullets > 0 && i < tg.bullets){
-                tg.setActiveBullet(i);
+            if(this.inputType != 'radio'){
+                hidden.name = this.name;
+                input.name = '_hidden_' + this.name;
             }
         }
         
-        this.el.on('click', this.onClick, this);
-        
-        if(Roo.isTouch){
-            this.el.on("touchstart", this.onTouchStart, this);
-            this.el.on("touchmove", this.onTouchMove, this);
-            this.el.on("touchend", this.onTouchEnd, this);
+        if (this.size) {
+            input.cls += ' input-' + this.size;
         }
         
-    },
-    
-    onRender : function(ct, position)
-    {
-        Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
-    },
-    
-    setActive : function(state)
-    {
-        Roo.log("panel - set active " + this.tabId + "=" + state);
+        var settings=this;
         
-        this.active = state;
-        if (!state) {
-            this.el.removeClass('active');
+        ['xs','sm','md','lg'].map(function(size){
+            if (settings[size]) {
+                cfg.cls += ' col-' + size + '-' + settings[size];
+            }
+        });
+        
+        var inputblock = input;
+         
+        if (this.before || this.after) {
+            
+            inputblock = {
+                cls : 'input-group',
+                cn :  [] 
+            };
+            
+            if (this.before) {
+                inputblock.cn.push({
+                    tag :'span',
+                    cls : 'input-group-addon',
+                    html : this.before
+                });
+            }
+            
+            inputblock.cn.push(input);
+            
+            if(this.inputType != 'radio'){
+                inputblock.cn.push(hidden);
+            }
+            
+            if (this.after) {
+                inputblock.cn.push({
+                    tag :'span',
+                    cls : 'input-group-addon',
+                    html : this.after
+                });
+            }
             
-        } else  if (!this.el.hasClass('active')) {
-            this.el.addClass('active');
         }
+        var boxLabelCfg = false;
         
-        this.fireEvent('changed', this, state);
-    },
-    
-    onClick : function(e)
-    {
-        e.preventDefault();
-        
-        if(!this.href.length){
-            return;
+        if(this.boxLabel){
+           
+            boxLabelCfg = {
+                tag: 'label',
+                //'for': id, // box label is handled by onclick - so no for...
+                cls: 'box-label',
+                html: this.boxLabel
+            };
+            if(this.tooltip){
+                boxLabelCfg.tooltip = this.tooltip;
+            }
+             
         }
         
-        window.location.href = this.href;
-    },
-    
-    startX : 0,
-    startY : 0,
-    endX : 0,
-    endY : 0,
-    swiping : false,
-    
-    onTouchStart : function(e)
-    {
-        this.swiping = false;
-        
-        this.startX = e.browserEvent.touches[0].clientX;
-        this.startY = e.browserEvent.touches[0].clientY;
-    },
-    
-    onTouchMove : function(e)
-    {
-        this.swiping = true;
         
-        this.endX = e.browserEvent.touches[0].clientX;
-        this.endY = e.browserEvent.touches[0].clientY;
-    },
-    
-    onTouchEnd : function(e)
-    {
-        if(!this.swiping){
-            this.onClick(e);
-            return;
+        if (align ==='left' && this.fieldLabel.length) {
+//                Roo.log("left and has label");
+            cfg.cn = [
+                {
+                    tag: 'label',
+                    'for' :  id,
+                    cls : 'control-label',
+                    html : this.fieldLabel
+                },
+                {
+                    cls : "", 
+                    cn: [
+                        inputblock
+                    ]
+                }
+            ];
+            
+            if (boxLabelCfg) {
+                cfg.cn[1].cn.push(boxLabelCfg);
+            }
+            
+            if(this.labelWidth > 12){
+                cfg.cn[0].style = "width: " + this.labelWidth + 'px';
+            }
+            
+            if(this.labelWidth < 13 && this.labelmd == 0){
+                this.labelmd = this.labelWidth;
+            }
+            
+            if(this.labellg > 0){
+                cfg.cn[0].cls += ' col-lg-' + this.labellg;
+                cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
+            }
+            
+            if(this.labelmd > 0){
+                cfg.cn[0].cls += ' col-md-' + this.labelmd;
+                cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
+            }
+            
+            if(this.labelsm > 0){
+                cfg.cn[0].cls += ' col-sm-' + this.labelsm;
+                cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
+            }
+            
+            if(this.labelxs > 0){
+                cfg.cn[0].cls += ' col-xs-' + this.labelxs;
+                cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
+            }
+            
+        } else if ( this.fieldLabel.length) {
+//                Roo.log(" label");
+                cfg.cn = [
+                   
+                    {
+                        tag: this.boxLabel ? 'span' : 'label',
+                        'for': id,
+                        cls: 'control-label box-input-label',
+                        //cls : 'input-group-addon',
+                        html : this.fieldLabel
+                    },
+                    
+                    inputblock
+                    
+                ];
+                if (boxLabelCfg) {
+                    cfg.cn.push(boxLabelCfg);
+                }
+
+        } else {
+            
+//                Roo.log(" no label && no align");
+                cfg.cn = [  inputblock ] ;
+                if (boxLabelCfg) {
+                    cfg.cn.push(boxLabelCfg);
+                }
+
+                
         }
         
-        var tabGroup = this.parent();
+       
         
-        if(this.endX > this.startX){ // swiping right
-            tabGroup.showPanelPrev();
-            return;
+        if(this.inputType != 'radio'){
+            cfg.cn.push(hidden);
         }
         
-        if(this.startX > this.endX){ // swiping left
-            tabGroup.showPanelNext();
-            return;
-        }
-    }
-    
-    
-});
-
-
- /*
- * - LGPL
- *
- * DateField
- * 
- */
-
-/**
- * @class Roo.bootstrap.DateField
- * @extends Roo.bootstrap.Input
- * Bootstrap DateField class
- * @cfg {Number} weekStart default 0
- * @cfg {String} viewMode default empty, (months|years)
- * @cfg {String} minViewMode default empty, (months|years)
- * @cfg {Number} startDate default -Infinity
- * @cfg {Number} endDate default Infinity
- * @cfg {Boolean} todayHighlight default false
- * @cfg {Boolean} todayBtn default false
- * @cfg {Boolean} calendarWeeks default false
- * @cfg {Object} daysOfWeekDisabled default empty
- * @cfg {Boolean} singleMode default false (true | false)
- * 
- * @cfg {Boolean} keyboardNavigation default true
- * @cfg {String} language default en
- * 
- * @constructor
- * Create a new DateField
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.DateField = function(config){
-    Roo.bootstrap.DateField.superclass.constructor.call(this, config);
-     this.addEvents({
-            /**
-             * @event show
-             * Fires when this field show.
-             * @param {Roo.bootstrap.DateField} this
-             * @param {Mixed} date The date value
-             */
-            show : true,
-            /**
-             * @event show
-             * Fires when this field hide.
-             * @param {Roo.bootstrap.DateField} this
-             * @param {Mixed} date The date value
-             */
-            hide : true,
-            /**
-             * @event select
-             * Fires when select a date.
-             * @param {Roo.bootstrap.DateField} this
-             * @param {Mixed} date The date value
-             */
-            select : true,
-            /**
-             * @event beforeselect
-             * Fires when before select a date.
-             * @param {Roo.bootstrap.DateField} this
-             * @param {Mixed} date The date value
-             */
-            beforeselect : true
-        });
-};
-
-Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
+        return cfg;
+        
+    },
     
     /**
-     * @cfg {String} format
-     * The default date format string which can be overriden for localization support.  The format must be
-     * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
-     */
-    format : "m/d/y",
-    /**
-     * @cfg {String} altFormats
-     * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
-     * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
+     * return the real input element.
      */
-    altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
-    
-    weekStart : 0,
-    
-    viewMode : '',
-    
-    minViewMode : '',
-    
-    todayHighlight : false,
-    
-    todayBtn: false,
-    
-    language: 'en',
-    
-    keyboardNavigation: true,
-    
-    calendarWeeks: false,
-    
-    startDate: -Infinity,
-    
-    endDate: Infinity,
-    
-    daysOfWeekDisabled: [],
-    
-    _events: [],
-    
-    singleMode : false,
-    
-    UTCDate: function()
+    inputEl: function ()
     {
-        return new Date(Date.UTC.apply(Date, arguments));
+        return this.el.select('input.roo-' + this.inputType,true).first();
     },
-    
-    UTCToday: function()
+    hiddenEl: function ()
     {
-        var today = new Date();
-        return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
+        return this.el.select('input.roo-hidden-value',true).first();
     },
     
-    getDate: function() {
-            var d = this.getUTCDate();
-            return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
+    labelEl: function()
+    {
+        return this.el.select('label.control-label',true).first();
     },
+    /* depricated... */
     
-    getUTCDate: function() {
-            return this.date;
+    label: function()
+    {
+        return this.labelEl();
     },
     
-    setDate: function(d) {
-            this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
+    boxLabelEl: function()
+    {
+        return this.el.select('label.box-label',true).first();
     },
     
-    setUTCDate: function(d) {
-            this.date = d;
-            this.setValue(this.formatDate(this.date));
-    },
-        
-    onRender: function(ct, position)
+    initEvents : function()
     {
+//        Roo.bootstrap.form.CheckBox.superclass.initEvents.call(this);
         
-        Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
+        this.inputEl().on('click', this.onClick,  this);
         
-        this.language = this.language || 'en';
-        this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
-        this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
+        if (this.boxLabel) { 
+            this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
+        }
         
-        this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
-        this.format = this.format || 'm/d/y';
-        this.isInline = false;
-        this.isInput = true;
-        this.component = this.el.select('.add-on', true).first() || false;
-        this.component = (this.component && this.component.length === 0) ? false : this.component;
-        this.hasInput = this.component && this.inputEl().length;
+        this.startValue = this.getValue();
         
-        if (typeof(this.minViewMode === 'string')) {
-            switch (this.minViewMode) {
-                case 'months':
-                    this.minViewMode = 1;
-                    break;
-                case 'years':
-                    this.minViewMode = 2;
-                    break;
-                default:
-                    this.minViewMode = 0;
-                    break;
-            }
+        if(this.groupId){
+            Roo.bootstrap.form.CheckBox.register(this);
         }
-        
-        if (typeof(this.viewMode === 'string')) {
-            switch (this.viewMode) {
-                case 'months':
-                    this.viewMode = 1;
-                    break;
-                case 'years':
-                    this.viewMode = 2;
-                    break;
-                default:
-                    this.viewMode = 0;
-                    break;
-            }
+    },
+    
+    onClick : function(e)
+    {   
+        if(this.fireEvent('click', this, e) !== false){
+            this.setChecked(!this.checked);
         }
-                
-        this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
-        
-//        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
-        
-        this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
-        
-        this.picker().on('mousedown', this.onMousedown, this);
-        this.picker().on('click', this.onClick, this);
-        
-        this.picker().addClass('datepicker-dropdown');
         
-        this.startViewMode = this.viewMode;
-        
-        if(this.singleMode){
-            Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
-                v.setVisibilityMode(Roo.Element.DISPLAY);
-                v.hide();
-            });
+    },
+    
+    setChecked : function(state,suppressEvent)
+    {
+        this.startValue = this.getValue();
+
+        if(this.inputType == 'radio'){
             
-            Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
-                v.setStyle('width', '189px');
+            Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+                e.dom.checked = false;
             });
-        }
-        
-        Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
-            if(!this.calendarWeeks){
-                v.remove();
-                return;
+            
+            this.inputEl().dom.checked = true;
+            
+            this.inputEl().dom.value = this.inputValue;
+            
+            if(suppressEvent !== true){
+                this.fireEvent('check', this, true);
             }
             
-            v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
-            v.attr('colspan', function(i, val){
-                return parseInt(val) + 1;
-            });
-        });
-                       
+            this.validate();
+            
+            return;
+        }
         
-        this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
+        this.checked = state;
         
-        this.setStartDate(this.startDate);
-        this.setEndDate(this.endDate);
+        this.inputEl().dom.checked = state;
         
-        this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
         
-        this.fillDow();
-        this.fillMonths();
-        this.update();
-        this.showMode();
+        this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
         
-        if(this.isInline) {
-            this.showPopup();
+        if(suppressEvent !== true){
+            this.fireEvent('check', this, state);
         }
+        
+        this.validate();
     },
     
-    picker : function()
+    getValue : function()
     {
-        return this.pickerEl;
-//        return this.el.select('.datepicker', true).first();
+        if(this.inputType == 'radio'){
+            return this.getGroupValue();
+        }
+        
+        return this.hiddenEl().dom.value;
+        
     },
     
-    fillDow: function()
+    getGroupValue : function()
     {
-        var dowCnt = this.weekStart;
-        
-        var dow = {
-            tag: 'tr',
-            cn: [
-                
-            ]
-        };
-        
-        if(this.calendarWeeks){
-            dow.cn.push({
-                tag: 'th',
-                cls: 'cw',
-                html: '&nbsp;'
-            })
+        if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
+            return '';
         }
         
-        while (dowCnt < this.weekStart + 7) {
-            dow.cn.push({
-                tag: 'th',
-                cls: 'dow',
-                html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
-            });
+        return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
+    },
+    
+    setValue : function(v,suppressEvent)
+    {
+        if(this.inputType == 'radio'){
+            this.setGroupValue(v, suppressEvent);
+            return;
         }
         
-        this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
+        this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
+        
+        this.validate();
     },
     
-    fillMonths: function()
-    {    
-        var i = 0;
-        var months = this.picker().select('>.datepicker-months td', true).first();
-        
-        months.dom.innerHTML = '';
+    setGroupValue : function(v, suppressEvent)
+    {
+        this.startValue = this.getValue();
         
-        while (i < 12) {
-            var month = {
-                tag: 'span',
-                cls: 'month',
-                html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
-            };
+        Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+            e.dom.checked = false;
             
-            months.createChild(month);
+            if(e.dom.value == v){
+                e.dom.checked = true;
+            }
+        });
+        
+        if(suppressEvent !== true){
+            this.fireEvent('check', this, true);
         }
+
+        this.validate();
         
+        return;
     },
     
-    update: function()
+    validate : function()
     {
-        this.date = (typeof(this.date) === 'undefined' || ((typeof(this.date) === 'string') && !this.date.length)) ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
+        if(this.getVisibilityEl().hasClass('hidden')){
+            return true;
+        }
         
-        if (this.date < this.startDate) {
-            this.viewDate = new Date(this.startDate);
-        } else if (this.date > this.endDate) {
-            this.viewDate = new Date(this.endDate);
-        } else {
-            this.viewDate = new Date(this.date);
+        if(
+                this.disabled || 
+                (this.inputType == 'radio' && this.validateRadio()) ||
+                (this.inputType == 'checkbox' && this.validateCheckbox())
+        ){
+            this.markValid();
+            return true;
         }
         
-        this.fill();
+        this.markInvalid();
+        return false;
     },
     
-    fill: function() 
+    validateRadio : function()
     {
-        var d = new Date(this.viewDate),
-                year = d.getUTCFullYear(),
-                month = d.getUTCMonth(),
-                startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
-                startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
-                endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
-                endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
-                currentDate = this.date && this.date.valueOf(),
-                today = this.UTCToday();
+        if(this.getVisibilityEl().hasClass('hidden')){
+            return true;
+        }
         
-        this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
+        if(this.allowBlank){
+            return true;
+        }
         
-//        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
+        var valid = false;
         
-//        this.picker.select('>tfoot th.today').
-//                                             .text(dates[this.language].today)
-//                                             .toggle(this.todayBtn !== false);
+        Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+            if(!e.dom.checked){
+                return;
+            }
+            
+            valid = true;
+            
+            return false;
+        });
+        
+        return valid;
+    },
     
-        this.updateNavArrows();
-        this.fillMonths();
-                                                
-        var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
+    validateCheckbox : function()
+    {
+        if(!this.groupId){
+            return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
+            //return (this.getValue() == this.inputValue) ? true : false;
+        }
         
-        day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
-         
-        prevMonth.setUTCDate(day);
+        var group = Roo.bootstrap.form.CheckBox.get(this.groupId);
         
-        prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
+        if(!group){
+            return false;
+        }
         
-        var nextMonth = new Date(prevMonth);
+        var r = false;
         
-        nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
+        for(var i in group){
+            if(group[i].el.isVisible(true)){
+                r = false;
+                break;
+            }
+            
+            r = true;
+        }
         
-        nextMonth = nextMonth.valueOf();
+        for(var i in group){
+            if(r){
+                break;
+            }
+            
+            r = (group[i].getValue() == group[i].inputValue) ? true : false;
+        }
         
-        var fillMonths = false;
+        return r;
+    },
+    
+    /**
+     * Mark this field as valid
+     */
+    markValid : function()
+    {
+        var _this = this;
         
-        this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
+        this.fireEvent('valid', this);
         
-        while(prevMonth.valueOf() <= nextMonth) {
-            var clsName = '';
-            
-            if (prevMonth.getUTCDay() === this.weekStart) {
-                if(fillMonths){
-                    this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
-                }
-                    
-                fillMonths = {
-                    tag: 'tr',
-                    cn: []
-                };
-                
-                if(this.calendarWeeks){
-                    // ISO 8601: First week contains first thursday.
-                    // ISO also states week starts on Monday, but we can be more abstract here.
-                    var
-                    // Start of current week: based on weekstart/current date
-                    ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
-                    // Thursday of this week
-                    th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
-                    // First Thursday of year, year from thursday
-                    yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
-                    // Calendar week: ms between thursdays, div ms per day, div 7 days
-                    calWeek =  (th - yth) / 864e5 / 7 + 1;
-                    
-                    fillMonths.cn.push({
-                        tag: 'td',
-                        cls: 'cw',
-                        html: calWeek
-                    });
+        var label = Roo.bootstrap.form.FieldLabel.get(this.name + '-group');
+        
+        if(this.groupId){
+            label = Roo.bootstrap.form.FieldLabel.get(this.groupId + '-group');
+        }
+        
+        if(label){
+            label.markValid();
+        }
+
+        if(this.inputType == 'radio'){
+            Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+                var fg = e.findParent('.form-group', false, true);
+                if (Roo.bootstrap.version == 3) {
+                    fg.removeClass([_this.invalidClass, _this.validClass]);
+                    fg.addClass(_this.validClass);
+                } else {
+                    fg.removeClass(['is-valid', 'is-invalid']);
+                    fg.addClass('is-valid');
                 }
-            }
+            });
             
-            if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
-                clsName += ' old';
-            } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
-                clsName += ' new';
-            }
-            if (this.todayHighlight &&
-                prevMonth.getUTCFullYear() == today.getFullYear() &&
-                prevMonth.getUTCMonth() == today.getMonth() &&
-                prevMonth.getUTCDate() == today.getDate()) {
-                clsName += ' today';
+            return;
+        }
+
+        if(!this.groupId){
+            var fg = this.el.findParent('.form-group', false, true);
+            if (Roo.bootstrap.version == 3) {
+                fg.removeClass([this.invalidClass, this.validClass]);
+                fg.addClass(this.validClass);
+            } else {
+                fg.removeClass(['is-valid', 'is-invalid']);
+                fg.addClass('is-valid');
             }
-            
-            if (currentDate && prevMonth.valueOf() === currentDate) {
-                clsName += ' active';
+            return;
+        }
+        
+        var group = Roo.bootstrap.form.CheckBox.get(this.groupId);
+        
+        if(!group){
+            return;
+        }
+        
+        for(var i in group){
+            var fg = group[i].el.findParent('.form-group', false, true);
+            if (Roo.bootstrap.version == 3) {
+                fg.removeClass([this.invalidClass, this.validClass]);
+                fg.addClass(this.validClass);
+            } else {
+                fg.removeClass(['is-valid', 'is-invalid']);
+                fg.addClass('is-valid');
             }
+        }
+    },
+    
+     /**
+     * Mark this field as invalid
+     * @param {String} msg The validation message
+     */
+    markInvalid : function(msg)
+    {
+        if(this.allowBlank){
+            return;
+        }
+        
+        var _this = this;
+        
+        this.fireEvent('invalid', this, msg);
+        
+        var label = Roo.bootstrap.form.FieldLabel.get(this.name + '-group');
+        
+        if(this.groupId){
+            label = Roo.bootstrap.form.FieldLabel.get(this.groupId + '-group');
+        }
+        
+        if(label){
+            label.markInvalid();
+        }
             
-            if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
-                    this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
-                    clsName += ' disabled';
-            }
+        if(this.inputType == 'radio'){
             
-            fillMonths.cn.push({
-                tag: 'td',
-                cls: 'day ' + clsName,
-                html: prevMonth.getDate()
+            Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+                var fg = e.findParent('.form-group', false, true);
+                if (Roo.bootstrap.version == 3) {
+                    fg.removeClass([_this.invalidClass, _this.validClass]);
+                    fg.addClass(_this.invalidClass);
+                } else {
+                    fg.removeClass(['is-invalid', 'is-valid']);
+                    fg.addClass('is-invalid');
+                }
             });
             
-            prevMonth.setDate(prevMonth.getDate()+1);
+            return;
         }
-          
-        var currentYear = this.date && this.date.getUTCFullYear();
-        var currentMonth = this.date && this.date.getUTCMonth();
-        
-        this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
         
-        Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
-            v.removeClass('active');
-            
-            if(currentYear === year && k === currentMonth){
-                v.addClass('active');
-            }
-            
-            if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
-                v.addClass('disabled');
+        if(!this.groupId){
+            var fg = this.el.findParent('.form-group', false, true);
+            if (Roo.bootstrap.version == 3) {
+                fg.removeClass([_this.invalidClass, _this.validClass]);
+                fg.addClass(_this.invalidClass);
+            } else {
+                fg.removeClass(['is-invalid', 'is-valid']);
+                fg.addClass('is-invalid');
             }
-            
-        });
+            return;
+        }
         
+        var group = Roo.bootstrap.form.CheckBox.get(this.groupId);
         
-        year = parseInt(year/10, 10) * 10;
+        if(!group){
+            return;
+        }
         
-        this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
+        for(var i in group){
+            var fg = group[i].el.findParent('.form-group', false, true);
+            if (Roo.bootstrap.version == 3) {
+                fg.removeClass([_this.invalidClass, _this.validClass]);
+                fg.addClass(_this.invalidClass);
+            } else {
+                fg.removeClass(['is-invalid', 'is-valid']);
+                fg.addClass('is-invalid');
+            }
+        }
         
-        this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
+    },
+    
+    clearInvalid : function()
+    {
+        Roo.bootstrap.form.Input.prototype.clearInvalid.call(this);
         
-        year -= 1;
-        for (var i = -1; i < 11; i++) {
-            this.picker().select('>.datepicker-years tbody td',true).first().createChild({
-                tag: 'span',
-                cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
-                html: year
-            });
-            
-            year += 1;
+        // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
+        
+        var label = Roo.bootstrap.form.FieldLabel.get(this.name + '-group');
+        
+        if (label && label.iconEl) {
+            label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
+            label.iconEl.removeClass(['is-invalid', 'is-valid']);
         }
     },
     
-    showMode: function(dir) 
+    disable : function()
     {
-        if (dir) {
-            this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
+        if(this.inputType != 'radio'){
+            Roo.bootstrap.form.CheckBox.superclass.disable.call(this);
+            return;
         }
         
-        Roo.each(this.picker().select('>div',true).elements, function(v){
-            v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
-            v.hide();
-        });
-        this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
+        var _this = this;
+        
+        if(this.rendered){
+            Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+                _this.getActionEl().addClass(this.disabledClass);
+                e.dom.disabled = true;
+            });
+        }
+        
+        this.disabled = true;
+        this.fireEvent("disable", this);
+        return this;
     },
-    
-    place: function()
+
+    enable : function()
     {
-        if(this.isInline) {
+        if(this.inputType != 'radio'){
+            Roo.bootstrap.form.CheckBox.superclass.enable.call(this);
             return;
         }
         
-        this.picker().removeClass(['bottom', 'top']);
+        var _this = this;
         
-        if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
-            /*
-             * place to the top of element!
-             *
-             */
-            
-            this.picker().addClass('top');
-            this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
-            
-            return;
+        if(this.rendered){
+            Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
+                _this.getActionEl().removeClass(this.disabledClass);
+                e.dom.disabled = false;
+            });
         }
         
-        this.picker().addClass('bottom');
+        this.disabled = false;
+        this.fireEvent("enable", this);
+        return this;
+    },
+    
+    setBoxLabel : function(v)
+    {
+        this.boxLabel = v;
         
-        this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
+        if(this.rendered){
+            this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
+        }
+    }
+
+});
+
+Roo.apply(Roo.bootstrap.form.CheckBox, {
+    
+    groups: {},
+    
+     /**
+    * register a CheckBox Group
+    * @param {Roo.bootstrap.form.CheckBox} the CheckBox to add
+    */
+    register : function(checkbox)
+    {
+        if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
+            this.groups[checkbox.groupId] = {};
+        }
+        
+        if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
+            return;
+        }
+        
+        this.groups[checkbox.groupId][checkbox.name] = checkbox;
+       
     },
+    /**
+    * fetch a CheckBox Group based on the group ID
+    * @param {string} the group ID
+    * @returns {Roo.bootstrap.form.CheckBox} the CheckBox group
+    */
+    get: function(groupId) {
+        if (typeof(this.groups[groupId]) == 'undefined') {
+            return false;
+        }
+        
+        return this.groups[groupId] ;
+    }
+    
+    
+});
+/*
+ * - LGPL
+ *
+ * RadioItem
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.form.Radio
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Radio class
+ * @cfg {String} boxLabel - the label associated
+ * @cfg {String} value - the value of radio
+ * 
+ * @constructor
+ * Create a new Radio
+ * @param {Object} config The config object
+ */
+Roo.bootstrap.form.Radio = function(config){
+    Roo.bootstrap.form.Radio.superclass.constructor.call(this, config);
+    
+};
+
+Roo.extend(Roo.bootstrap.form.Radio, Roo.bootstrap.Component, {
     
-    parseDate : function(value)
-    {
-        if(!value || value instanceof Date){
-            return value;
-        }
-        var v = Date.parseDate(value, this.format);
-        if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
-            v = Date.parseDate(value, 'Y-m-d');
-        }
-        if(!v && this.altFormats){
-            if(!this.altFormatsArray){
-                this.altFormatsArray = this.altFormats.split("|");
-            }
-            for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
-                v = Date.parseDate(value, this.altFormatsArray[i]);
-            }
-        }
-        return v;
-    },
+    boxLabel : '',
     
-    formatDate : function(date, fmt)
-    {   
-        return (!date || !(date instanceof Date)) ?
-        date : date.dateFormat(fmt || this.format);
-    },
+    value : '',
     
-    onFocus : function()
+    getAutoCreate : function()
     {
-        Roo.bootstrap.DateField.superclass.onFocus.call(this);
-        this.showPopup();
+        var cfg = {
+            tag : 'div',
+            cls : 'form-group radio',
+            cn : [
+                {
+                    tag : 'label',
+                    cls : 'box-label',
+                    html : this.boxLabel
+                }
+            ]
+        };
+        
+        return cfg;
     },
     
-    onBlur : function()
+    initEvents : function() 
     {
-        Roo.bootstrap.DateField.superclass.onBlur.call(this);
+        this.parent().register(this);
         
-        var d = this.inputEl().getValue();
+        this.el.on('click', this.onClick, this);
         
-        this.setValue(d);
-                
-        this.hidePopup();
     },
     
-    showPopup : function()
+    onClick : function(e)
     {
-        this.picker().show();
-        this.update();
-        this.place();
-        
-        this.fireEvent('showpopup', this, this.date);
+        if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
+            this.setChecked(true);
+        }
     },
     
-    hidePopup : function()
+    setChecked : function(state, suppressEvent)
     {
-        if(this.isInline) {
-            return;
-        }
-        this.picker().hide();
-        this.viewMode = this.startViewMode;
-        this.showMode();
-        
-        this.fireEvent('hidepopup', this, this.date);
+        this.parent().setValue(this.value, suppressEvent);
         
     },
     
-    onMousedown: function(e)
+    setBoxLabel : function(v)
     {
-        e.stopPropagation();
-        e.preventDefault();
-    },
+        this.boxLabel = v;
+        
+        if(this.rendered){
+            this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
+        }
+    }
     
-    keyup: function(e)
-    {
-        Roo.bootstrap.DateField.superclass.keyup.call(this);
-        this.update();
+});
+
+ /*
+ * - LGPL
+ *
+ * Input
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.form.SecurePass
+ * @extends Roo.bootstrap.form.Input
+ * Bootstrap SecurePass class
+ *
+ * 
+ * @constructor
+ * Create a new SecurePass
+ * @param {Object} config The config object
+ */
+Roo.bootstrap.form.SecurePass = function (config) {
+    // these go here, so the translation tool can replace them..
+    this.errors = {
+        PwdEmpty: "Please type a password, and then retype it to confirm.",
+        PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
+        PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
+        PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
+        IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
+        FNInPwd: "Your password can't contain your first name. Please type a different password.",
+        LNInPwd: "Your password can't contain your last name. Please type a different password.",
+        TooWeak: "Your password is Too Weak."
     },
+    this.meterLabel = "Password strength:";
+    this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
+    this.meterClass = [
+        "roo-password-meter-tooweak", 
+        "roo-password-meter-weak", 
+        "roo-password-meter-medium", 
+        "roo-password-meter-strong", 
+        "roo-password-meter-grey"
+    ];
+    
+    this.errors = {};
+    
+    Roo.bootstrap.form.SecurePass.superclass.constructor.call(this, config);
+}
 
-    setValue: function(v)
+Roo.extend(Roo.bootstrap.form.SecurePass, Roo.bootstrap.form.Input, {
+    /**
+     * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
+     * {
+     *  PwdEmpty: "Please type a password, and then retype it to confirm.",
+     *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
+     *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
+     *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
+     *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
+     *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
+     *  LNInPwd: "Your password can't contain your last name. Please type a different password."
+     * })
+     */
+    // private
+    
+    meterWidth: 300,
+    errorMsg :'',    
+    errors: false,
+    imageRoot: '/',
+    /**
+     * @cfg {String/Object} Label for the strength meter (defaults to
+     * 'Password strength:')
+     */
+    // private
+    meterLabel: '',
+    /**
+     * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
+     * ['Weak', 'Medium', 'Strong'])
+     */
+    // private    
+    pwdStrengths: false,    
+    // private
+    strength: 0,
+    // private
+    _lastPwd: null,
+    // private
+    kCapitalLetter: 0,
+    kSmallLetter: 1,
+    kDigit: 2,
+    kPunctuation: 3,
+    
+    insecure: false,
+    // private
+    initEvents: function ()
     {
-        if(this.fireEvent('beforeselect', this, v) !== false){
-            var d = new Date(this.parseDate(v) ).clearTime();
-        
-            if(isNaN(d.getTime())){
-                this.date = this.viewDate = '';
-                Roo.bootstrap.DateField.superclass.setValue.call(this, '');
-                return;
-            }
+        Roo.bootstrap.form.SecurePass.superclass.initEvents.call(this);
 
-            v = this.formatDate(d);
-
-            Roo.bootstrap.DateField.superclass.setValue.call(this, v);
+        if (this.el.is('input[type=password]') && Roo.isSafari) {
+            this.el.on('keydown', this.SafariOnKeyDown, this);
+        }
 
-            this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
+        this.el.on('keyup', this.checkStrength, this, {buffer: 50});
+    },
+    // private
+    onRender: function (ct, position)
+    {
+        Roo.bootstrap.form.SecurePass.superclass.onRender.call(this, ct, position);
+        this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
+        this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
 
-            this.update();
+        this.trigger.createChild({
+                  cn: [
+                    {
+                    //id: 'PwdMeter',
+                    tag: 'div',
+                    cls: 'roo-password-meter-grey col-xs-12',
+                    style: {
+                        //width: 0,
+                        //width: this.meterWidth + 'px'                                                
+                        }
+                    },
+                    {                           
+                        cls: 'roo-password-meter-text'                          
+                    }
+                ]            
+        });
 
-            this.fireEvent('select', this, this.date);
+         
+        if (this.hideTrigger) {
+            this.trigger.setDisplayed(false);
         }
+        this.setSize(this.width || '', this.height || '');
     },
-    
-    getValue: function()
+    // private
+    onDestroy: function ()
     {
-        return this.formatDate(this.date);
+        if (this.trigger) {
+            this.trigger.removeAllListeners();
+            this.trigger.remove();
+        }
+        if (this.wrap) {
+            this.wrap.remove();
+        }
+        Roo.bootstrap.form.TriggerField.superclass.onDestroy.call(this);
     },
-    
-    fireKey: function(e)
+    // private
+    checkStrength: function ()
     {
-        if (!this.picker().isVisible()){
-            if (e.keyCode == 27) { // allow escape to hide and re-show picker
-                this.showPopup();
-            }
+        var pwd = this.inputEl().getValue();
+        if (pwd == this._lastPwd) {
             return;
         }
+
+        var strength;
+        if (this.ClientSideStrongPassword(pwd)) {
+            strength = 3;
+        } else if (this.ClientSideMediumPassword(pwd)) {
+            strength = 2;
+        } else if (this.ClientSideWeakPassword(pwd)) {
+            strength = 1;
+        } else {
+            strength = 0;
+        }
         
-        var dateChanged = false,
-        dir, day, month,
-        newDate, newViewDate;
+        Roo.log('strength1: ' + strength);
         
-        switch(e.keyCode){
-            case 27: // escape
-                this.hidePopup();
-                e.preventDefault();
-                break;
-            case 37: // left
-            case 39: // right
-                if (!this.keyboardNavigation) {
-                    break;
-                }
-                dir = e.keyCode == 37 ? -1 : 1;
+        //var pm = this.trigger.child('div/div/div').dom;
+        var pm = this.trigger.child('div/div');
+        pm.removeClass(this.meterClass);
+        pm.addClass(this.meterClass[strength]);
                 
-                if (e.ctrlKey){
-                    newDate = this.moveYear(this.date, dir);
-                    newViewDate = this.moveYear(this.viewDate, dir);
-                } else if (e.shiftKey){
-                    newDate = this.moveMonth(this.date, dir);
-                    newViewDate = this.moveMonth(this.viewDate, dir);
-                } else {
-                    newDate = new Date(this.date);
-                    newDate.setUTCDate(this.date.getUTCDate() + dir);
-                    newViewDate = new Date(this.viewDate);
-                    newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
-                }
-                if (this.dateWithinRange(newDate)){
-                    this.date = newDate;
-                    this.viewDate = newViewDate;
-                    this.setValue(this.formatDate(this.date));
-//                    this.update();
-                    e.preventDefault();
-                    dateChanged = true;
-                }
-                break;
-            case 38: // up
-            case 40: // down
-                if (!this.keyboardNavigation) {
-                    break;
-                }
-                dir = e.keyCode == 38 ? -1 : 1;
-                if (e.ctrlKey){
-                    newDate = this.moveYear(this.date, dir);
-                    newViewDate = this.moveYear(this.viewDate, dir);
-                } else if (e.shiftKey){
-                    newDate = this.moveMonth(this.date, dir);
-                    newViewDate = this.moveMonth(this.viewDate, dir);
-                } else {
-                    newDate = new Date(this.date);
-                    newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
-                    newViewDate = new Date(this.viewDate);
-                    newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
-                }
-                if (this.dateWithinRange(newDate)){
-                    this.date = newDate;
-                    this.viewDate = newViewDate;
-                    this.setValue(this.formatDate(this.date));
-//                    this.update();
-                    e.preventDefault();
-                    dateChanged = true;
-                }
-                break;
-            case 13: // enter
-                this.setValue(this.formatDate(this.date));
-                this.hidePopup();
-                e.preventDefault();
-                break;
-            case 9: // tab
-                this.setValue(this.formatDate(this.date));
-                this.hidePopup();
-                break;
-            case 16: // shift
-            case 17: // ctrl
-            case 18: // alt
-                break;
-            default :
-                this.hidePopup();
+        
+        var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
                 
-        }
+        pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
+        
+        this._lastPwd = pwd;
     },
-    
-    
-    onClick: function(e) 
+    reset: function ()
     {
-        e.stopPropagation();
-        e.preventDefault();
+        Roo.bootstrap.form.SecurePass.superclass.reset.call(this);
         
-        var target = e.getTarget();
+        this._lastPwd = '';
         
-        if(target.nodeName.toLowerCase() === 'i'){
-            target = Roo.get(target).dom.parentNode;
+        var pm = this.trigger.child('div/div');
+        pm.removeClass(this.meterClass);
+        pm.addClass('roo-password-meter-grey');        
+        
+        
+        var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
+        
+        pt.innerHTML = '';
+        this.inputEl().dom.type='password';
+    },
+    // private
+    validateValue: function (value)
+    {
+        if (!Roo.bootstrap.form.SecurePass.superclass.validateValue.call(this, value)) {
+            return false;
+        }
+        if (value.length == 0) {
+            if (this.allowBlank) {
+                this.clearInvalid();
+                return true;
+            }
+
+            this.markInvalid(this.errors.PwdEmpty);
+            this.errorMsg = this.errors.PwdEmpty;
+            return false;
         }
         
-        var nodeName = target.nodeName;
-        var className = target.className;
-        var html = target.innerHTML;
-        //Roo.log(nodeName);
+        if(this.insecure){
+            return true;
+        }
         
-        switch(nodeName.toLowerCase()) {
-            case 'th':
-                switch(className) {
-                    case 'switch':
-                        this.showMode(1);
-                        break;
-                    case 'prev':
-                    case 'next':
-                        var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
-                        switch(this.viewMode){
-                                case 0:
-                                        this.viewDate = this.moveMonth(this.viewDate, dir);
-                                        break;
-                                case 1:
-                                case 2:
-                                        this.viewDate = this.moveYear(this.viewDate, dir);
-                                        break;
-                        }
-                        this.fill();
-                        break;
-                    case 'today':
-                        var date = new Date();
-                        this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
-//                        this.fill()
-                        this.setValue(this.formatDate(this.date));
-                        
-                        this.hidePopup();
-                        break;
-                }
-                break;
-            case 'span':
-                if (className.indexOf('disabled') < 0) {
-                    this.viewDate.setUTCDate(1);
-                    if (className.indexOf('month') > -1) {
-                        this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
-                    } else {
-                        var year = parseInt(html, 10) || 0;
-                        this.viewDate.setUTCFullYear(year);
-                        
-                    }
-                    
-                    if(this.singleMode){
-                        this.setValue(this.formatDate(this.viewDate));
-                        this.hidePopup();
-                        return;
-                    }
-                    
-                    this.showMode(-1);
-                    this.fill();
-                }
-                break;
-                
-            case 'td':
-                //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();
+        if (!value.match(/[\x21-\x7e]+/)) {
+            this.markInvalid(this.errors.PwdBadChar);
+            this.errorMsg = this.errors.PwdBadChar;
+            return false;
+        }
+        if (value.length < 6) {
+            this.markInvalid(this.errors.PwdShort);
+            this.errorMsg = this.errors.PwdShort;
+            return false;
+        }
+        if (value.length > 16) {
+            this.markInvalid(this.errors.PwdLong);
+            this.errorMsg = this.errors.PwdLong;
+            return false;
+        }
+        var strength;
+        if (this.ClientSideStrongPassword(value)) {
+            strength = 3;
+        } else if (this.ClientSideMediumPassword(value)) {
+            strength = 2;
+        } else if (this.ClientSideWeakPassword(value)) {
+            strength = 1;
+        } else {
+            strength = 0;
+        }
 
-                    if (className.indexOf('old') > -1) {
-                        if(month === 0 ){
-                            month = 11;
-                            year -= 1;
-                        }else{
-                            month -= 1;
-                        }
-                    } else if (className.indexOf('new') > -1) {
-                        if (month == 11) {
-                            month = 0;
-                            year += 1;
-                        } else {
-                            month += 1;
-                        }
-                    }
-                    //Roo.log([year,month,day]);
-                    this.date = this.UTCDate(year, month, day,0,0,0,0);
-                    this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
-//                    this.fill();
-                    //Roo.log(this.formatDate(this.date));
-                    this.setValue(this.formatDate(this.date));
-                    this.hidePopup();
+        
+        if (strength < 2) {
+            //this.markInvalid(this.errors.TooWeak);
+            this.errorMsg = this.errors.TooWeak;
+            //return false;
+        }
+        
+        
+        console.log('strength2: ' + strength);
+        
+        //var pm = this.trigger.child('div/div/div').dom;
+        
+        var pm = this.trigger.child('div/div');
+        pm.removeClass(this.meterClass);
+        pm.addClass(this.meterClass[strength]);
+                
+        var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
+                
+        pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
+        
+        this.errorMsg = ''; 
+        return true;
+    },
+    // private
+    CharacterSetChecks: function (type)
+    {
+        this.type = type;
+        this.fResult = false;
+    },
+    // private
+    isctype: function (character, type)
+    {
+        switch (type) {  
+            case this.kCapitalLetter:
+                if (character >= 'A' && character <= 'Z') {
+                    return true;
                 }
                 break;
+            
+            case this.kSmallLetter:
+                if (character >= 'a' && character <= 'z') {
+                    return true;
+                }
+                break;
+            
+            case this.kDigit:
+                if (character >= '0' && character <= '9') {
+                    return true;
+                }
+                break;
+            
+            case this.kPunctuation:
+                if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
+                    return true;
+                }
+                break;
+            
+            default:
+                return false;
         }
-    },
-    
-    setStartDate: function(startDate)
-    {
-        this.startDate = startDate || -Infinity;
-        if (this.startDate !== -Infinity) {
-            this.startDate = this.parseDate(this.startDate);
-        }
-        this.update();
-        this.updateNavArrows();
-    },
 
-    setEndDate: function(endDate)
-    {
-        this.endDate = endDate || Infinity;
-        if (this.endDate !== Infinity) {
-            this.endDate = this.parseDate(this.endDate);
-        }
-        this.update();
-        this.updateNavArrows();
     },
-    
-    setDaysOfWeekDisabled: function(daysOfWeekDisabled)
+    // private
+    IsLongEnough: function (pwd, size)
     {
-        this.daysOfWeekDisabled = daysOfWeekDisabled || [];
-        if (typeof(this.daysOfWeekDisabled) !== 'object') {
-            this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
-        }
-        this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
-            return parseInt(d, 10);
-        });
-        this.update();
-        this.updateNavArrows();
+        return !(pwd == null || isNaN(size) || pwd.length < size);
     },
-    
-    updateNavArrows: function() 
+    // private
+    SpansEnoughCharacterSets: function (word, nb)
     {
-        if(this.singleMode){
-            return;
+        if (!this.IsLongEnough(word, nb))
+        {
+            return false;
         }
-        
-        var d = new Date(this.viewDate),
-        year = d.getUTCFullYear(),
-        month = d.getUTCMonth();
-        
-        Roo.each(this.picker().select('.prev', true).elements, function(v){
-            v.show();
-            switch (this.viewMode) {
-                case 0:
 
-                    if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
-                        v.hide();
-                    }
-                    break;
-                case 1:
-                case 2:
-                    if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
-                        v.hide();
-                    }
-                    break;
-            }
-        });
+        var characterSetChecks = new Array(
+            new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
+            new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
+        );
         
-        Roo.each(this.picker().select('.next', true).elements, function(v){
-            v.show();
-            switch (this.viewMode) {
-                case 0:
-
-                    if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
-                        v.hide();
-                    }
-                    break;
-                case 1:
-                case 2:
-                    if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
-                        v.hide();
-                    }
+        for (var index = 0; index < word.length; ++index) {
+            for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
+                if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
+                    characterSetChecks[nCharSet].fResult = true;
                     break;
+                }
             }
-        })
-    },
-    
-    moveMonth: function(date, dir)
-    {
-        if (!dir) {
-            return date;
         }
-        var new_date = new Date(date.valueOf()),
-        day = new_date.getUTCDate(),
-        month = new_date.getUTCMonth(),
-        mag = Math.abs(dir),
-        new_month, test;
-        dir = dir > 0 ? 1 : -1;
-        if (mag == 1){
-            test = dir == -1
-            // If going back one month, make sure month is not current month
-            // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
-            ? function(){
-                return new_date.getUTCMonth() == month;
-            }
-            // If going forward one month, make sure month is as expected
-            // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
-            : function(){
-                return new_date.getUTCMonth() != new_month;
-            };
-            new_month = month + dir;
-            new_date.setUTCMonth(new_month);
-            // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
-            if (new_month < 0 || new_month > 11) {
-                new_month = (new_month + 12) % 12;
-            }
-        } else {
-            // For magnitudes >1, move one month at a time...
-            for (var i=0; i<mag; i++) {
-                // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
-                new_date = this.moveMonth(new_date, dir);
+
+        var nCharSets = 0;
+        for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
+            if (characterSetChecks[nCharSet].fResult) {
+                ++nCharSets;
             }
-            // ...then reset the day, keeping it in the new month
-            new_month = new_date.getUTCMonth();
-            new_date.setUTCDate(day);
-            test = function(){
-                return new_month != new_date.getUTCMonth();
-            };
         }
-        // Common date-resetting loop -- if date is beyond end of month, make it
-        // end of month
-        while (test()){
-            new_date.setUTCDate(--day);
-            new_date.setUTCMonth(new_month);
+
+        if (nCharSets < nb) {
+            return false;
         }
-        return new_date;
+        return true;
     },
-
-    moveYear: function(date, dir)
+    // private
+    ClientSideStrongPassword: function (pwd)
     {
-        return this.moveMonth(date, dir*12);
+        return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
     },
-
-    dateWithinRange: function(date)
+    // private
+    ClientSideMediumPassword: function (pwd)
     {
-        return date >= this.startDate && date <= this.endDate;
+        return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
     },
+    // private
+    ClientSideWeakPassword: function (pwd)
+    {
+        return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
+    }
+          
+});
+Roo.htmleditor = {};
+/**
+ * @class Roo.htmleditor.Filter
+ * Base Class for filtering htmleditor stuff. - do not use this directly - extend it.
+ * @cfg {DomElement} node The node to iterate and filter
+ * @cfg {boolean|String|Array} tag Tags to replace 
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
+
+
+
+Roo.htmleditor.Filter = function(cfg) {
+    Roo.apply(this.cfg);
+    // this does not actually call walk as it's really just a abstract class
+}
 
+
+Roo.htmleditor.Filter.prototype = {
     
-    remove: function() 
+    node: false,
+    
+    tag: false,
+
+    // overrride to do replace comments.
+    replaceComment : false,
+    
+    // overrride to do replace or do stuff with tags..
+    replaceTag : false,
+    
+    walk : function(dom)
     {
-        this.picker().remove();
-    },
+        Roo.each( Array.from(dom.childNodes), function( e ) {
+            switch(true) {
+                
+                case e.nodeType == 8 &&  this.replaceComment  !== false: // comment
+                    this.replaceComment(e);
+                    return;
+                
+                case e.nodeType != 1: //not a node.
+                    return;
+                
+                case this.tag === true: // everything
+                case e.tagName.indexOf(":") > -1 && typeof(this.tag) == 'object' && this.tag.indexOf(":") > -1:
+                case e.tagName.indexOf(":") > -1 && typeof(this.tag) == 'string' && this.tag == ":":
+                case typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1: // array and it matches.
+                case typeof(this.tag) == 'string' && this.tag == e.tagName: // array and it matches.
+                    if (this.replaceTag && false === this.replaceTag(e)) {
+                        return;
+                    }
+                    if (e.hasChildNodes()) {
+                        this.walk(e);
+                    }
+                    return;
+                
+                default:    // tags .. that do not match.
+                    if (e.hasChildNodes()) {
+                        this.walk(e);
+                    }
+            }
+            
+        }, this);
+        
+    }
+}; 
+
+/**
+ * @class Roo.htmleditor.FilterAttributes
+ * clean attributes and  styles including http:// etc.. in attribute
+ * @constructor
+* Run a new Attribute Filter
+* @param {Object} config Configuration options
+ */
+Roo.htmleditor.FilterAttributes = function(cfg)
+{
+    Roo.apply(this, cfg);
+    this.attrib_black = this.attrib_black || [];
+    this.attrib_white = this.attrib_white || [];
+
+    this.attrib_clean = this.attrib_clean || [];
+    this.style_white = this.style_white || [];
+    this.style_black = this.style_black || [];
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterAttributes, Roo.htmleditor.Filter,
+{
+    tag: true, // all tags
     
-    validateValue : function(value)
+    attrib_black : false, // array
+    attrib_clean : false,
+    attrib_white : false,
+
+    style_white : false,
+    style_black : false,
+     
+     
+    replaceTag : function(node)
     {
-        if(this.getVisibilityEl().hasClass('hidden')){
+        if (!node.attributes || !node.attributes.length) {
             return true;
         }
         
-        if(value.length < 1)  {
-            if(this.allowBlank){
-                return true;
+        for (var i = node.attributes.length-1; i > -1 ; i--) {
+            var a = node.attributes[i];
+            //console.log(a);
+            if (this.attrib_white.length && this.attrib_white.indexOf(a.name.toLowerCase()) < 0) {
+                node.removeAttribute(a.name);
+                continue;
             }
-            return false;
+            
+            
+            
+            if (a.name.toLowerCase().substr(0,2)=='on')  {
+                node.removeAttribute(a.name);
+                continue;
+            }
+            
+            
+            if (this.attrib_black.indexOf(a.name.toLowerCase()) > -1) {
+                node.removeAttribute(a.name);
+                continue;
+            }
+            if (this.attrib_clean.indexOf(a.name.toLowerCase()) > -1) {
+                this.cleanAttr(node,a.name,a.value); // fixme..
+                continue;
+            }
+            if (a.name == 'style') {
+                this.cleanStyle(node,a.name,a.value);
+                continue;
+            }
+            /// clean up MS crap..
+            // tecnically this should be a list of valid class'es..
+            
+            
+            if (a.name == 'class') {
+                if (a.value.match(/^Mso/)) {
+                    node.removeAttribute('class');
+                }
+                
+                if (a.value.match(/^body$/)) {
+                    node.removeAttribute('class');
+                }
+                continue;
+            }
+            
+            
+            // style cleanup!?
+            // class cleanup?
+            
         }
+        return true; // clean children
+    },
         
-        if(value.length < this.minLength){
-            return false;
+    cleanAttr: function(node, n,v)
+    {
+        
+        if (v.match(/^\./) || v.match(/^\//)) {
+            return;
         }
-        if(value.length > this.maxLength){
-            return false;
+        if (v.match(/^(http|https):\/\//)
+            || v.match(/^mailto:/) 
+            || v.match(/^ftp:/)
+            || v.match(/^data:/)
+            ) {
+            return;
         }
-        if(this.vtype){
-            var vt = Roo.form.VTypes;
-            if(!vt[this.vtype](value, this)){
-                return false;
-            }
+        if (v.match(/^#/)) {
+            return;
         }
-        if(typeof this.validator == "function"){
-            var msg = this.validator(value);
-            if(msg !== true){
-                return false;
-            }
+        if (v.match(/^\{/)) { // allow template editing.
+            return;
         }
+//            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
+        node.removeAttribute(n);
         
-        if(this.regex && !this.regex.test(value)){
-            return false;
+    },
+    cleanStyle : function(node,  n,v)
+    {
+        if (v.match(/expression/)) { //XSS?? should we even bother..
+            node.removeAttribute(n);
+            return;
         }
         
-        if(typeof(this.parseDate(value)) == 'undefined'){
-            return false;
+        var parts = v.split(/;/);
+        var clean = [];
+        
+        Roo.each(parts, function(p) {
+            p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
+            if (!p.length) {
+                return true;
+            }
+            var l = p.split(':').shift().replace(/\s+/g,'');
+            l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
+            
+            if ( this.style_black.length && (this.style_black.indexOf(l) > -1 || this.style_black.indexOf(l.toLowerCase()) > -1)) {
+                return true;
+            }
+            //Roo.log()
+            // only allow 'c whitelisted system attributes'
+            if ( this.style_white.length &&  style_white.indexOf(l) < 0 && style_white.indexOf(l.toLowerCase()) < 0 ) {
+                return true;
+            }
+            
+            
+            clean.push(p);
+            return true;
+        },this);
+        if (clean.length) { 
+            node.setAttribute(n, clean.join(';'));
+        } else {
+            node.removeAttribute(n);
         }
         
-        if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
-            return false;
-        }      
+    }
         
-        if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
-            return false;
-        } 
         
         
-        return true;
-    },
     
-    reset : function()
+});/**
+ * @class Roo.htmleditor.FilterBlack
+ * remove blacklisted elements.
+ * @constructor
+ * Run a new Blacklisted Filter
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.FilterBlack = function(cfg)
+{
+    Roo.apply(this, cfg);
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterBlack, Roo.htmleditor.Filter,
+{
+    tag : true, // all elements.
+   
+    replaceTag : function(n)
     {
-        this.date = this.viewDate = '';
-        
-        Roo.bootstrap.DateField.superclass.setValue.call(this, '');
+        n.parentNode.removeChild(n);
     }
-   
 });
+/**
+ * @class Roo.htmleditor.FilterComment
+ * remove comments.
+ * @constructor
+* Run a new Comments Filter
+* @param {Object} config Configuration options
+ */
+Roo.htmleditor.FilterComment = function(cfg)
+{
+    this.walk(cfg.node);
+}
 
-Roo.apply(Roo.bootstrap.DateField,  {
-    
-    head : {
-        tag: 'thead',
-        cn: [
-        {
-            tag: 'tr',
-            cn: [
-            {
-                tag: 'th',
-                cls: 'prev',
-                html: '<i class="fa fa-arrow-left"/>'
-            },
-            {
-                tag: 'th',
-                cls: 'switch',
-                colspan: '5'
-            },
-            {
-                tag: 'th',
-                cls: 'next',
-                html: '<i class="fa fa-arrow-right"/>'
-            }
+Roo.extend(Roo.htmleditor.FilterComment, Roo.htmleditor.Filter,
+{
+  
+    replaceComment : function(n)
+    {
+        n.parentNode.removeChild(n);
+    }
+});/**
+ * @class Roo.htmleditor.FilterKeepChildren
+ * remove tags but keep children
+ * @constructor
+ * Run a new Keep Children Filter
+ * @param {Object} config Configuration options
+ */
 
-            ]
-        }
-        ]
-    },
+Roo.htmleditor.FilterKeepChildren = function(cfg)
+{
+    Roo.apply(this, cfg);
+    if (this.tag === false) {
+        return; // dont walk.. (you can use this to use this just to do a child removal on a single tag )
+    }
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterKeepChildren, Roo.htmleditor.FilterBlack,
+{
     
-    content : {
-        tag: 'tbody',
-        cn: [
-        {
-            tag: 'tr',
-            cn: [
-            {
-                tag: 'td',
-                colspan: '7'
+  
+    replaceTag : function(node)
+    {
+        // walk children...
+        //Roo.log(node);
+        var ar = Array.from(node.childNodes);
+        //remove first..
+        for (var i = 0; i < ar.length; i++) {
+            if (ar[i].nodeType == 1) {
+                if (
+                    (typeof(this.tag) == 'object' && this.tag.indexOf(ar[i].tagName) > -1)
+                    || // array and it matches
+                    (typeof(this.tag) == 'string' && this.tag == ar[i].tagName)
+                ) {
+                    this.replaceTag(ar[i]); // child is blacklisted as well...
+                    continue;
+                }
             }
-            ]
-        }
-        ]
-    },
-    
-    footer : {
-        tag: 'tfoot',
-        cn: [
-        {
-            tag: 'tr',
-            cn: [
-            {
-                tag: 'th',
-                colspan: '7',
-                cls: 'today'
+        }  
+        ar = Array.from(node.childNodes);
+        for (var i = 0; i < ar.length; i++) {
+         
+            node.removeChild(ar[i]);
+            // what if we need to walk these???
+            node.parentNode.insertBefore(ar[i], node);
+            if (this.tag !== false) {
+                this.walk(ar[i]);
+                
             }
-                    
-            ]
         }
-        ]
-    },
+        node.parentNode.removeChild(node);
+        return false; // don't walk children
+        
+        
+    }
+});/**
+ * @class Roo.htmleditor.FilterParagraph
+ * paragraphs cause a nightmare for shared content - this filter is designed to be called ? at various points when editing
+ * like on 'push' to remove the <p> tags and replace them with line breaks.
+ * @constructor
+ * Run a new Paragraph Filter
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.FilterParagraph = function(cfg)
+{
+    // no need to apply config.
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterParagraph, Roo.htmleditor.Filter,
+{
     
-    dates:{
-        en: {
-            days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
-            daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
-            daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
-            months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
-            monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
-            today: "Today"
-        }
-    },
+     
+    tag : 'P',
     
-    modes: [
-    {
-        clsName: 'days',
-        navFnc: 'Month',
-        navStep: 1
-    },
-    {
-        clsName: 'months',
-        navFnc: 'FullYear',
-        navStep: 1
-    },
-    {
-        clsName: 'years',
-        navFnc: 'FullYear',
-        navStep: 10
-    }]
-});
-
-Roo.apply(Roo.bootstrap.DateField,  {
-  
-    template : {
-        tag: 'div',
-        cls: 'datepicker dropdown-menu roo-dynamic',
-        cn: [
-        {
-            tag: 'div',
-            cls: 'datepicker-days',
-            cn: [
-            {
-                tag: 'table',
-                cls: 'table-condensed',
-                cn:[
-                Roo.bootstrap.DateField.head,
-                {
-                    tag: 'tbody'
-                },
-                Roo.bootstrap.DateField.footer
-                ]
-            }
-            ]
-        },
-        {
-            tag: 'div',
-            cls: 'datepicker-months',
-            cn: [
-            {
-                tag: 'table',
-                cls: 'table-condensed',
-                cn:[
-                Roo.bootstrap.DateField.head,
-                Roo.bootstrap.DateField.content,
-                Roo.bootstrap.DateField.footer
-                ]
-            }
-            ]
-        },
-        {
-            tag: 'div',
-            cls: 'datepicker-years',
-            cn: [
-            {
-                tag: 'table',
-                cls: 'table-condensed',
-                cn:[
-                Roo.bootstrap.DateField.head,
-                Roo.bootstrap.DateField.content,
-                Roo.bootstrap.DateField.footer
-                ]
-            }
-            ]
+     
+    replaceTag : function(node)
+    {
+        
+        if (node.childNodes.length == 1 &&
+            node.childNodes[0].nodeType == 3 &&
+            node.childNodes[0].textContent.trim().length < 1
+            ) {
+            // remove and replace with '<BR>';
+            node.parentNode.replaceChild(node.ownerDocument.createElement('BR'),node);
+            return false; // no need to walk..
         }
-        ]
+        var ar = Array.from(node.childNodes);
+        for (var i = 0; i < ar.length; i++) {
+            node.removeChild(ar[i]);
+            // what if we need to walk these???
+            node.parentNode.insertBefore(ar[i], node);
+        }
+        // now what about this?
+        // <p> &nbsp; </p>
+        
+        // double BR.
+        node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
+        node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
+        node.parentNode.removeChild(node);
+        
+        return false;
+
     }
-});
+    
+});/**
+ * @class Roo.htmleditor.FilterSpan
+ * filter span's with no attributes out..
+ * @constructor
+ * Run a new Span Filter
+ * @param {Object} config Configuration options
+ */
 
+Roo.htmleditor.FilterSpan = function(cfg)
+{
+    // no need to apply config.
+    this.walk(cfg.node);
+}
 
- /*
- * - LGPL
- *
- * TimeField
+Roo.extend(Roo.htmleditor.FilterSpan, Roo.htmleditor.FilterKeepChildren,
+{
+     
+    tag : 'SPAN',
+     
+    replaceTag : function(node)
+    {
+        if (node.attributes && node.attributes.length > 0) {
+            return true; // walk if there are any.
+        }
+        Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this, node);
+        return false;
+     
+    }
+    
+});/**
+ * @class Roo.htmleditor.FilterTableWidth
+  try and remove table width data - as that frequently messes up other stuff.
  * 
+ *      was cleanTableWidths.
+ *
+ * Quite often pasting from word etc.. results in tables with column and widths.
+ * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
+ *
+ * @constructor
+ * Run a new Table Filter
+ * @param {Object} config Configuration options
  */
 
-/**
- * @class Roo.bootstrap.TimeField
- * @extends Roo.bootstrap.Input
- * Bootstrap DateField class
- * 
+Roo.htmleditor.FilterTableWidth = function(cfg)
+{
+    // no need to apply config.
+    this.tag = ['TABLE', 'TD', 'TR', 'TH', 'THEAD', 'TBODY' ];
+    this.walk(cfg.node);
+}
+
+Roo.extend(Roo.htmleditor.FilterTableWidth, Roo.htmleditor.Filter,
+{
+     
+     
+    
+    replaceTag: function(node) {
+        
+        
+      
+        if (node.hasAttribute('width')) {
+            node.removeAttribute('width');
+        }
+        
+         
+        if (node.hasAttribute("style")) {
+            // pretty basic...
+            
+            var styles = node.getAttribute("style").split(";");
+            var nstyle = [];
+            Roo.each(styles, function(s) {
+                if (!s.match(/:/)) {
+                    return;
+                }
+                var kv = s.split(":");
+                if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
+                    return;
+                }
+                // what ever is left... we allow.
+                nstyle.push(s);
+            });
+            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
+            if (!nstyle.length) {
+                node.removeAttribute('style');
+            }
+        }
+        
+        return true; // continue doing children..
+    }
+});/**
+ * @class Roo.htmleditor.FilterWord
+ * try and clean up all the mess that Word generates.
  * 
+ * This is the 'nice version' - see 'Heavy' that white lists a very short list of elements, and multi-filters 
  * @constructor
- * Create a new TimeField
- * @param {Object} config The config object
+ * Run a new Span Filter
+ * @param {Object} config Configuration options
  */
 
-Roo.bootstrap.TimeField = function(config){
-    Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
-    this.addEvents({
-            /**
-             * @event show
-             * Fires when this field show.
-             * @param {Roo.bootstrap.DateField} thisthis
-             * @param {Mixed} date The date value
-             */
-            show : true,
-            /**
-             * @event show
-             * Fires when this field hide.
-             * @param {Roo.bootstrap.DateField} this
-             * @param {Mixed} date The date value
-             */
-            hide : true,
-            /**
-             * @event select
-             * Fires when select a date.
-             * @param {Roo.bootstrap.DateField} this
-             * @param {Mixed} date The date value
-             */
-            select : true
-        });
-};
+Roo.htmleditor.FilterWord = function(cfg)
+{
+    // no need to apply config.
+    this.replaceDocBullets(cfg.node);
+    
+    // this is disabled as the removal is done by other filters;
+   // this.walk(cfg.node);
+    
+    
+}
 
-Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
+Roo.extend(Roo.htmleditor.FilterWord, Roo.htmleditor.Filter,
+{
+    tag: true,
+     
     
     /**
-     * @cfg {String} format
-     * The default time format string which can be overriden for localization support.  The format must be
-     * valid according to {@link Date#parseDate} (defaults to 'H:i').
+     * Clean up MS wordisms...
      */
-    format : "H:i",
-       
-    onRender: function(ct, position)
+    replaceTag : function(node)
     {
+         
+        // no idea what this does - span with text, replaceds with just text.
+        if(
+                node.nodeName == 'SPAN' &&
+                !node.hasAttributes() &&
+                node.childNodes.length == 1 &&
+                node.firstChild.nodeName == "#text"  
+        ) {
+            var textNode = node.firstChild;
+            node.removeChild(textNode);
+            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
+                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
+            }
+            node.parentNode.insertBefore(textNode, node);
+            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
+                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
+            }
+            
+            node.parentNode.removeChild(node);
+            return false; // dont do chidren - we have remove our node - so no need to do chdhilren?
+        }
         
-        Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
-                
-        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
-        
-        this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
-        
-        this.pop = this.picker().select('>.datepicker-time',true).first();
-        this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
-        
-        this.picker().on('mousedown', this.onMousedown, this);
-        this.picker().on('click', this.onClick, this);
+   
         
-        this.picker().addClass('datepicker-dropdown');
-    
-        this.fillTime();
-        this.update();
+        if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
+            node.parentNode.removeChild(node);
+            return false; // dont do chidlren
+        }
+        //Roo.log(node.tagName);
+        // remove - but keep children..
+        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
+            //Roo.log('-- removed');
+            while (node.childNodes.length) {
+                var cn = node.childNodes[0];
+                node.removeChild(cn);
+                node.parentNode.insertBefore(cn, node);
+                // move node to parent - and clean it..
+                if (cn.nodeType == 1) {
+                    this.replaceTag(cn);
+                }
+                
+            }
+            node.parentNode.removeChild(node);
+            /// no need to iterate chidlren = it's got none..
+            //this.iterateChildren(node, this.cleanWord);
+            return false; // no need to iterate children.
+        }
+        // clean styles
+        if (node.className.length) {
             
-        this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
-        this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
-        this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
-        this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
-        this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
-        this.pop.select('button.ok', true).first().on('click', this.setTime, this);
-
-    },
-    
-    fireKey: function(e){
-        if (!this.picker().isVisible()){
-            if (e.keyCode == 27) { // allow escape to hide and re-show picker
-                this.show();
+            var cn = node.className.split(/\W+/);
+            var cna = [];
+            Roo.each(cn, function(cls) {
+                if (cls.match(/Mso[a-zA-Z]+/)) {
+                    return;
+                }
+                cna.push(cls);
+            });
+            node.className = cna.length ? cna.join(' ') : '';
+            if (!cna.length) {
+                node.removeAttribute("class");
             }
-            return;
         }
-
-        e.preventDefault();
         
-        switch(e.keyCode){
-            case 27: // escape
-                this.hide();
-                break;
-            case 37: // left
-            case 39: // right
-                this.onTogglePeriod();
-                break;
-            case 38: // up
-                this.onIncrementMinutes();
-                break;
-            case 40: // down
-                this.onDecrementMinutes();
-                break;
-            case 13: // enter
-            case 9: // tab
-                this.setTime();
-                break;
+        if (node.hasAttribute("lang")) {
+            node.removeAttribute("lang");
         }
-    },
-    
-    onClick: function(e) {
-        e.stopPropagation();
-        e.preventDefault();
-    },
-    
-    picker : function()
-    {
-        return this.el.select('.datepicker', true).first();
-    },
-    
-    fillTime: function()
-    {    
-        var time = this.pop.select('tbody', true).first();
-        
-        time.dom.innerHTML = '';
         
-        time.createChild({
-            tag: 'tr',
-            cn: [
-                {
-                    tag: 'td',
-                    cn: [
-                        {
-                            tag: 'a',
-                            href: '#',
-                            cls: 'btn',
-                            cn: [
-                                {
-                                    tag: 'span',
-                                    cls: 'hours-up glyphicon glyphicon-chevron-up'
-                                }
-                            ]
-                        } 
-                    ]
-                },
-                {
-                    tag: 'td',
-                    cls: 'separator'
-                },
-                {
-                    tag: 'td',
-                    cn: [
-                        {
-                            tag: 'a',
-                            href: '#',
-                            cls: 'btn',
-                            cn: [
-                                {
-                                    tag: 'span',
-                                    cls: 'minutes-up glyphicon glyphicon-chevron-up'
-                                }
-                            ]
-                        }
-                    ]
-                },
-                {
-                    tag: 'td',
-                    cls: 'separator'
+        if (node.hasAttribute("style")) {
+            
+            var styles = node.getAttribute("style").split(";");
+            var nstyle = [];
+            Roo.each(styles, function(s) {
+                if (!s.match(/:/)) {
+                    return;
                 }
-            ]
-        });
-        
-        time.createChild({
-            tag: 'tr',
-            cn: [
-                {
-                    tag: 'td',
-                    cn: [
-                        {
-                            tag: 'span',
-                            cls: 'timepicker-hour',
-                            html: '00'
-                        }  
-                    ]
-                },
-                {
-                    tag: 'td',
-                    cls: 'separator',
-                    html: ':'
-                },
-                {
-                    tag: 'td',
-                    cn: [
-                        {
-                            tag: 'span',
-                            cls: 'timepicker-minute',
-                            html: '00'
-                        }  
-                    ]
-                },
-                {
-                    tag: 'td',
-                    cls: 'separator'
-                },
-                {
-                    tag: 'td',
-                    cn: [
-                        {
-                            tag: 'button',
-                            type: 'button',
-                            cls: 'btn btn-primary period',
-                            html: 'AM'
-                            
-                        }
-                    ]
+                var kv = s.split(":");
+                if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
+                    return;
                 }
-            ]
-        });
+                // what ever is left... we allow.
+                nstyle.push(s);
+            });
+            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
+            if (!nstyle.length) {
+                node.removeAttribute('style');
+            }
+        }
+        return true; // do children
+        
         
-        time.createChild({
-            tag: 'tr',
-            cn: [
-                {
-                    tag: 'td',
-                    cn: [
-                        {
-                            tag: 'a',
-                            href: '#',
-                            cls: 'btn',
-                            cn: [
-                                {
-                                    tag: 'span',
-                                    cls: 'hours-down glyphicon glyphicon-chevron-down'
-                                }
-                            ]
-                        }
-                    ]
-                },
-                {
-                    tag: 'td',
-                    cls: 'separator'
-                },
-                {
-                    tag: 'td',
-                    cn: [
-                        {
-                            tag: 'a',
-                            href: '#',
-                            cls: 'btn',
-                            cn: [
-                                {
-                                    tag: 'span',
-                                    cls: 'minutes-down glyphicon glyphicon-chevron-down'
-                                }
-                            ]
-                        }
-                    ]
-                },
-                {
-                    tag: 'td',
-                    cls: 'separator'
-                }
-            ]
-        });
         
     },
     
-    update: function()
+    styleToObject: function(node)
     {
-        
-        this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
-        
-        this.fill();
+        var styles = (node.getAttribute("style") || '').split(";");
+        var ret = {};
+        Roo.each(styles, function(s) {
+            if (!s.match(/:/)) {
+                return;
+            }
+            var kv = s.split(":");
+             
+            // what ever is left... we allow.
+            ret[kv[0].trim()] = kv[1];
+        });
+        return ret;
     },
     
-    fill: function() 
+    
+    replaceDocBullets : function(doc)
     {
-        var hours = this.time.getHours();
-        var minutes = this.time.getMinutes();
-        var period = 'AM';
-        
-        if(hours > 11){
-            period = 'PM';
-        }
+        // this is a bit odd - but it appears some indents use ql-indent-1
+        //Roo.log(doc.innerHTML);
         
-        if(hours == 0){
-            hours = 12;
+        var listpara = doc.getElementsByClassName('MsoListParagraphCxSpFirst');
+        for( var i = 0; i < listpara.length; i ++) {
+            listpara.item(i).className = "MsoListParagraph";
         }
-        
-        
-        if(hours > 12){
-            hours = hours - 12;
+        // this is a bit hacky - we had one word document where h2 had a miso-list attribute.
+        var htwo = doc.getElementsByTagName('h2');
+        for( var i = 0; i < htwo.length; i ++) {
+            if (htwo.item(i).getAttribute('style').match(/mso-list:/)) {
+                htwo.item(i).className = "MsoListParagraph";
+            }
         }
         
-        if(hours < 10){
-            hours = '0' + hours;
+        listpara = doc.getElementsByClassName('ql-indent-1');
+        while(listpara.length) {
+            this.replaceDocBullet(listpara.item(0));
         }
-        
-        if(minutes < 10){
-            minutes = '0' + minutes;
+        listpara = doc.getElementsByClassName('MsoListParagraph');
+        while(listpara.length) {
+            this.replaceDocBullet(listpara.item(0));
         }
-        
-        this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
-        this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
-        this.pop.select('button', true).first().dom.innerHTML = period;
-        
+      
     },
     
-    place: function()
-    {   
-        this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
-        
-        var cls = ['bottom'];
-        
-        if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
-            cls.pop();
-            cls.push('top');
-        }
-        
-        cls.push('right');
-        
-        if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
-            cls.pop();
-            cls.push('left');
+    replaceDocBullet : function(p)
+    {
+        // gather all the siblings.
+        var ns = p,
+            parent = p.parentNode,
+            doc = parent.ownerDocument,
+            items = [];
+            
+            
+        while (ns) {
+            if (ns.nodeType != 1) {
+                ns = ns.nextSibling;
+                continue;
+            }
+            if (!ns.className.match(/(MsoListParagraph|ql-indent-1)/i)) {
+                break;
+            }
+            items.push(ns);
+            ns = ns.nextSibling;
         }
         
-        this.picker().addClass(cls.join('-'));
         
-        var _this = this;
+        var ul = parent.ownerDocument.createElement('ul'); // what about number lists...
+        parent.insertBefore(ul, p);
+        var lvl = 0;
+        var stack = [ ul ];
+        var last_li = false;
         
-        Roo.each(cls, function(c){
-            if(c == 'bottom'){
-                _this.picker().setTop(_this.inputEl().getHeight());
-                return;
-            }
-            if(c == 'top'){
-                _this.picker().setTop(0 - _this.picker().getHeight());
-                return;
+        items.forEach(function(n, ipos) {
+            //Roo.log("got innertHMLT=" + n.innerHTML);
+            
+            var spans = n.getElementsByTagName('span');
+            if (!spans.length) {
+                //Roo.log("No spans found");
+
+                parent.removeChild(n);
+                return; // skip it...
             }
+           
+                
             
-            if(c == 'left'){
-                _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
-                return;
+            var style = {};
+            for(var i = 0; i < spans.length; i++) {
+            
+                style = this.styleToObject(spans[i]);
+                if (typeof(style['mso-list']) == 'undefined') {
+                    continue;
+                }
+                
+                spans[i].parentNode.removeChild(spans[i]); // remove the fake bullet.
+                break;
             }
-            if(c == 'right'){
-                _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
+            //Roo.log("NOW GOT innertHMLT=" + n.innerHTML);
+            style = this.styleToObject(n); // mo-list is from the parent node.
+            if (typeof(style['mso-list']) == 'undefined') {
+                //Roo.log("parent is missing level");
+                parent.removeChild(n);
                 return;
             }
-        });
-        
-    },
-  
-    onFocus : function()
-    {
-        Roo.bootstrap.TimeField.superclass.onFocus.call(this);
-        this.show();
-    },
-    
-    onBlur : function()
-    {
-        Roo.bootstrap.TimeField.superclass.onBlur.call(this);
-        this.hide();
-    },
-    
-    show : function()
-    {
-        this.picker().show();
-        this.pop.show();
-        this.update();
-        this.place();
-        
-        this.fireEvent('show', this, this.date);
-    },
-    
-    hide : function()
-    {
-        this.picker().hide();
-        this.pop.hide();
+            
+            var nlvl =   (style['mso-list'].split(' ')[1].replace(/level/,'') *1) - 1  ;
+            
+            
+            
+            if (nlvl > lvl) {
+                //new indent
+                var nul = doc.createElement('ul'); // what about number lists...
+                if (!last_li) {
+                    last_li = doc.createElement('li');
+                    stack[lvl].appendChild(last_li);
+                }
+                last_li.appendChild(nul);
+                stack[nlvl] = nul;
+                
+            }
+            lvl = nlvl;
+            
+            var nli = stack[nlvl].appendChild(doc.createElement('li'));
+            last_li = nli;
+            nli.innerHTML = n.innerHTML;
+            //Roo.log("innerHTML = " + n.innerHTML);
+            parent.removeChild(n);
+            
+            // copy children of p into nli
+            /*while(n.firstChild) {
+                var fc = n.firstChild;
+                n.removeChild(fc);
+                nli.appendChild(fc);
+            }*/
+             
+            
+        },this);
         
-        this.fireEvent('hide', this, this.date);
-    },
-    
-    setTime : function()
-    {
-        this.hide();
-        this.setValue(this.time.format(this.format));
         
-        this.fireEvent('select', this, this.date);
         
         
-    },
+    }
     
-    onMousedown: function(e){
-        e.stopPropagation();
-        e.preventDefault();
-    },
     
-    onIncrementHours: function()
-    {
-        Roo.log('onIncrementHours');
-        this.time = this.time.add(Date.HOUR, 1);
-        this.update();
-        
-    },
     
-    onDecrementHours: function()
-    {
-        Roo.log('onDecrementHours');
-        this.time = this.time.add(Date.HOUR, -1);
-        this.update();
-    },
+});
+/**
+ * @class Roo.htmleditor.FilterStyleToTag
+ * part of the word stuff... - certain 'styles' should be converted to tags.
+ * eg.
+ *   font-weight: bold -> bold
+ *   ?? super / subscrit etc..
+ * 
+ * @constructor
+* Run a new style to tag filter.
+* @param {Object} config Configuration options
+ */
+Roo.htmleditor.FilterStyleToTag = function(cfg)
+{
     
-    onIncrementMinutes: function()
-    {
-        Roo.log('onIncrementMinutes');
-        this.time = this.time.add(Date.MINUTE, 1);
-        this.update();
-    },
+    this.tags = {
+        B  : [ 'fontWeight' , 'bold'],
+        I :  [ 'fontStyle' , 'italic'],
+        //pre :  [ 'font-style' , 'italic'],
+        // h1.. h6 ?? font-size?
+        SUP : [ 'verticalAlign' , 'super' ],
+        SUB : [ 'verticalAlign' , 'sub' ]
+        
+        
+    };
     
-    onDecrementMinutes: function()
-    {
-        Roo.log('onDecrementMinutes');
-        this.time = this.time.add(Date.MINUTE, -1);
-        this.update();
-    },
+    Roo.apply(this, cfg);
+     
     
-    onTogglePeriod: function()
-    {
-        Roo.log('onTogglePeriod');
-        this.time = this.time.add(Date.HOUR, 12);
-        this.update();
-    }
+    this.walk(cfg.node);
     
-   
-});
-
-Roo.apply(Roo.bootstrap.TimeField,  {
     
-    content : {
-        tag: 'tbody',
-        cn: [
-            {
-                tag: 'tr',
-                cn: [
-                {
-                    tag: 'td',
-                    colspan: '7'
-                }
-                ]
-            }
-        ]
-    },
     
-    footer : {
-        tag: 'tfoot',
-        cn: [
-            {
-                tag: 'tr',
-                cn: [
-                {
-                    tag: 'th',
-                    colspan: '7',
-                    cls: '',
-                    cn: [
-                        {
-                            tag: 'button',
-                            cls: 'btn btn-info ok',
-                            html: 'OK'
-                        }
-                    ]
-                }
+}
 
-                ]
-            }
-        ]
-    }
-});
 
-Roo.apply(Roo.bootstrap.TimeField,  {
-  
-    template : {
-        tag: 'div',
-        cls: 'datepicker dropdown-menu',
-        cn: [
-            {
-                tag: 'div',
-                cls: 'datepicker-time',
-                cn: [
-                {
-                    tag: 'table',
-                    cls: 'table-condensed',
-                    cn:[
-                    Roo.bootstrap.TimeField.content,
-                    Roo.bootstrap.TimeField.footer
-                    ]
-                }
-                ]
+Roo.extend(Roo.htmleditor.FilterStyleToTag, Roo.htmleditor.Filter,
+{
+    tag: true, // all tags
+    
+    tags : false,
+    
+    
+    replaceTag : function(node)
+    {
+        
+        
+        if (node.getAttribute("style") === null) {
+            return true;
+        }
+        var inject = [];
+        for (var k in this.tags) {
+            if (node.style[this.tags[k][0]] == this.tags[k][1]) {
+                inject.push(k);
+                node.style.removeProperty(this.tags[k][0]);
             }
-        ]
+        }
+        if (!inject.length) {
+            return true; 
+        }
+        var cn = Array.from(node.childNodes);
+        var nn = node;
+        Roo.each(inject, function(t) {
+            var nc = node.ownerDocument.createElement(t);
+            nn.appendChild(nc);
+            nn = nc;
+        });
+        for(var i = 0;i < cn.length;cn++) {
+            node.removeChild(cn[i]);
+            nn.appendChild(cn[i]);
+        }
+        return true /// iterate thru
     }
-});
-
-
- /*
- * - LGPL
- *
- * MonthField
- * 
- */
-
-/**
- * @class Roo.bootstrap.MonthField
- * @extends Roo.bootstrap.Input
- * Bootstrap MonthField class
- * 
- * @cfg {String} language default en
- * 
+    
+})/**
+ * @class Roo.htmleditor.FilterLongBr
+ * BR/BR/BR - keep a maximum of 2...
  * @constructor
- * Create a new MonthField
- * @param {Object} config The config object
+ * Run a new Long BR Filter
+ * @param {Object} config Configuration options
  */
 
-Roo.bootstrap.MonthField = function(config){
-    Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
-    
-    this.addEvents({
-        /**
-         * @event show
-         * Fires when this field show.
-         * @param {Roo.bootstrap.MonthField} this
-         * @param {Mixed} date The date value
-         */
-        show : true,
-        /**
-         * @event show
-         * Fires when this field hide.
-         * @param {Roo.bootstrap.MonthField} this
-         * @param {Mixed} date The date value
-         */
-        hide : true,
-        /**
-         * @event select
-         * Fires when select a date.
-         * @param {Roo.bootstrap.MonthField} this
-         * @param {String} oldvalue The old value
-         * @param {String} newvalue The new value
-         */
-        select : true
-    });
-};
+Roo.htmleditor.FilterLongBr = function(cfg)
+{
+    // no need to apply config.
+    this.walk(cfg.node);
+}
 
-Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
+Roo.extend(Roo.htmleditor.FilterLongBr, Roo.htmleditor.Filter,
+{
     
-    onRender: function(ct, position)
+     
+    tag : 'BR',
+    
+     
+    replaceTag : function(node)
     {
         
-        Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
-        
-        this.language = this.language || 'en';
-        this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
-        this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
-        
-        this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
-        this.isInline = false;
-        this.isInput = true;
-        this.component = this.el.select('.add-on', true).first() || false;
-        this.component = (this.component && this.component.length === 0) ? false : this.component;
-        this.hasInput = this.component && this.inputEL().length;
+        var ps = node.nextSibling;
+        while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
+            ps = ps.nextSibling;
+        }
         
-        this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
+        if (!ps &&  [ 'TD', 'TH', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(node.parentNode.tagName) > -1) { 
+            node.parentNode.removeChild(node); // remove last BR inside one fo these tags
+            return false;
+        }
         
-        this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
+        if (!ps || ps.nodeType != 1) {
+            return false;
+        }
         
-        this.picker().on('mousedown', this.onMousedown, this);
-        this.picker().on('click', this.onClick, this);
+        if (!ps || ps.tagName != 'BR') {
+           
+            return false;
+        }
         
-        this.picker().addClass('datepicker-dropdown');
         
-        Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
-            v.setStyle('width', '189px');
-        });
         
-        this.fillMonths();
         
-        this.update();
         
-        if(this.isInline) {
-            this.show();
+        if (!node.previousSibling) {
+            return false;
         }
+        var ps = node.previousSibling;
         
-    },
-    
-    setValue: function(v, suppressEvent)
-    {   
-        var o = this.getValue();
+        while (ps && ps.nodeType == 3 && ps.nodeValue.trim().length < 1) {
+            ps = ps.previousSibling;
+        }
+        if (!ps || ps.nodeType != 1) {
+            return false;
+        }
+        // if header or BR before.. then it's a candidate for removal.. - as we only want '2' of these..
+        if (!ps || [ 'BR', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' ].indexOf(ps.tagName) < 0) {
+            return false;
+        }
         
-        Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
+        node.parentNode.removeChild(node); // remove me...
         
-        this.update();
+        return false; // no need to do children
 
-        if(suppressEvent !== true){
-            this.fireEvent('select', this, o, v);
-        }
-        
-    },
+    }
     
-    getValue: function()
-    {
-        return this.value;
-    },
+}); 
+
+/**
+ * @class Roo.htmleditor.FilterBlock
+ * removes id / data-block and contenteditable that are associated with blocks
+ * usage should be done on a cloned copy of the dom
+ * @constructor
+* Run a new Attribute Filter { node : xxxx }}
+* @param {Object} config Configuration options
+ */
+Roo.htmleditor.FilterBlock = function(cfg)
+{
+    Roo.apply(this, cfg);
+    var qa = cfg.node.querySelectorAll;
+    this.removeAttributes('data-block');
+    this.removeAttributes('contenteditable');
+    this.removeAttributes('id');
     
-    onClick: function(e) 
+}
+
+Roo.apply(Roo.htmleditor.FilterBlock.prototype,
+{
+    node: true, // all tags
+     
+     
+    removeAttributes : function(attr)
     {
-        e.stopPropagation();
-        e.preventDefault();
-        
-        var target = e.getTarget();
-        
-        if(target.nodeName.toLowerCase() === 'i'){
-            target = Roo.get(target).dom.parentNode;
-        }
-        
-        var nodeName = target.nodeName;
-        var className = target.className;
-        var html = target.innerHTML;
-        
-        if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
-            return;
+        var ar = this.node.querySelectorAll('*[' + attr + ']');
+        for (var i =0;i<ar.length;i++) {
+            ar[i].removeAttribute(attr);
         }
+    }
         
-        this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
         
-        this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
         
-        this.hide();
-                        
-    },
     
-    picker : function()
-    {
-        return this.pickerEl;
-    },
+});
+/**
+ * @class Roo.htmleditor.KeyEnter
+ * Handle Enter press..
+ * @cfg {Roo.HtmlEditorCore} core the editor.
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
+
+
+
+
+
+Roo.htmleditor.KeyEnter = function(cfg) {
+    Roo.apply(this, cfg);
+    // this does not actually call walk as it's really just a abstract class
+    Roo.get(this.core.doc.body).on('keypress', this.keypress, this);
+}
+
+//Roo.htmleditor.KeyEnter.i = 0;
+
+
+Roo.htmleditor.KeyEnter.prototype = {
     
-    fillMonths: function()
-    {    
-        var i = 0;
-        var months = this.picker().select('>.datepicker-months td', true).first();
-        
-        months.dom.innerHTML = '';
-        
-        while (i < 12) {
-            var month = {
-                tag: 'span',
-                cls: 'month',
-                html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
-            };
-            
-            months.createChild(month);
-        }
-        
-    },
+    core : false,
     
-    update: function()
+    keypress : function(e)
     {
-        var _this = this;
-        
-        if(typeof(this.vIndex) == 'undefined' && this.value.length){
-            this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
+        if (e.charCode != 13 && e.charCode != 10) {
+            Roo.log([e.charCode,e]);
+            return true;
         }
-        
-        Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
-            e.removeClass('active');
-            
-            if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
-                e.addClass('active');
-            }
-        })
-    },
+        e.preventDefault();
+        // https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
+        var doc = this.core.doc;
+          //add a new line
+       
     
-    place: function()
-    {
-        if(this.isInline) {
-            return;
-        }
-        
-        this.picker().removeClass(['bottom', 'top']);
-        
-        if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
-            /*
-             * place to the top of element!
-             *
-             */
-            
-            this.picker().addClass('top');
-            this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
+        var sel = this.core.getSelection();
+        var range = sel.getRangeAt(0);
+        var n = range.commonAncestorContainer;
+        var pc = range.closest([ 'ol', 'ul']);
+        var pli = range.closest('li');
+        if (!pc || e.ctrlKey) {
+            // on it list, or ctrl pressed.
+            if (!e.ctrlKey) {
+                sel.insertNode('br', 'after'); 
+            } else {
+                // only do this if we have ctrl key..
+                var br = doc.createElement('br');
+                br.className = 'clear';
+                br.setAttribute('style', 'clear: both');
+                sel.insertNode(br, 'after'); 
+            }
             
-            return;
+         
+            this.core.undoManager.addEvent();
+            this.core.fireEditorEvent(e);
+            return false;
         }
         
-        this.picker().addClass('bottom');
-        
-        this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
-    },
+        // deal with <li> insetion
+        if (pli.innerText.trim() == '' &&
+            pli.previousSibling &&
+            pli.previousSibling.nodeName == 'LI' &&
+            pli.previousSibling.innerText.trim() ==  '') {
+            pli.parentNode.removeChild(pli.previousSibling);
+            sel.cursorAfter(pc);
+            this.core.undoManager.addEvent();
+            this.core.fireEditorEvent(e);
+            return false;
+        }
     
-    onFocus : function()
-    {
-        Roo.bootstrap.MonthField.superclass.onFocus.call(this);
-        this.show();
-    },
+        var li = doc.createElement('LI');
+        li.innerHTML = '&nbsp;';
+        if (!pli || !pli.firstSibling) {
+            pc.appendChild(li);
+        } else {
+            pli.parentNode.insertBefore(li, pli.firstSibling);
+        }
+        sel.cursorText (li.firstChild);
+      
+        this.core.undoManager.addEvent();
+        this.core.fireEditorEvent(e);
+
+        return false;
+        
     
-    onBlur : function()
-    {
-        Roo.bootstrap.MonthField.superclass.onBlur.call(this);
         
-        var d = this.inputEl().getValue();
         
-        this.setValue(d);
-                
-        this.hide();
-    },
+         
+    }
+};
+     
+/**
+ * @class Roo.htmleditor.Block
+ * Base class for html editor blocks - do not use it directly .. extend it..
+ * @cfg {DomElement} node The node to apply stuff to.
+ * @cfg {String} friendly_name the name that appears in the context bar about this block
+ * @cfg {Object} Context menu - see Roo.form.HtmlEditor.ToolbarContext
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.Block  = function(cfg)
+{
+    // do nothing .. should not be called really.
+}
+/**
+ * factory method to get the block from an element (using cache if necessary)
+ * @static
+ * @param {HtmlElement} the dom element
+ */
+Roo.htmleditor.Block.factory = function(node)
+{
+    var cc = Roo.htmleditor.Block.cache;
+    var id = Roo.get(node).id;
+    if (typeof(cc[id]) != 'undefined' && (!cc[id].node || cc[id].node.closest('body'))) {
+        Roo.htmleditor.Block.cache[id].readElement(node);
+        return Roo.htmleditor.Block.cache[id];
+    }
+    var db  = node.getAttribute('data-block');
+    if (!db) {
+        db = node.nodeName.toLowerCase().toUpperCaseFirst();
+    }
+    var cls = Roo.htmleditor['Block' + db];
+    if (typeof(cls) == 'undefined') {
+        //Roo.log(node.getAttribute('data-block'));
+        Roo.log("OOps missing block : " + 'Block' + db);
+        return false;
+    }
+    Roo.htmleditor.Block.cache[id] = new cls({ node: node });
+    return Roo.htmleditor.Block.cache[id];  /// should trigger update element
+};
+
+/**
+ * initalize all Elements from content that are 'blockable'
+ * @static
+ * @param the body element
+ */
+Roo.htmleditor.Block.initAll = function(body, type)
+{
+    if (typeof(type) == 'undefined') {
+        var ia = Roo.htmleditor.Block.initAll;
+        ia(body,'table');
+        ia(body,'td');
+        ia(body,'figure');
+        return;
+    }
+    Roo.each(Roo.get(body).query(type), function(e) {
+        Roo.htmleditor.Block.factory(e);    
+    },this);
+};
+// question goes here... do we need to clear out this cache sometimes?
+// or show we make it relivant to the htmleditor.
+Roo.htmleditor.Block.cache = {};
+
+Roo.htmleditor.Block.prototype = {
     
-    show : function()
-    {
-        this.picker().show();
-        this.picker().select('>.datepicker-months', true).first().show();
-        this.update();
-        this.place();
-        
-        this.fireEvent('show', this, this.date);
-    },
+    node : false,
     
-    hide : function()
-    {
-        if(this.isInline) {
-            return;
-        }
-        this.picker().hide();
-        this.fireEvent('hide', this, this.date);
-        
-    },
+     // used by context menu
+    friendly_name : 'Based Block',
     
-    onMousedown: function(e)
+    // text for button to delete this element
+    deleteTitle : false,
+    
+    context : false,
+    /**
+     * Update a node with values from this object
+     * @param {DomElement} node
+     */
+    updateElement : function(node)
     {
-        e.stopPropagation();
-        e.preventDefault();
+        Roo.DomHelper.update(node === undefined ? this.node : node, this.toObject());
     },
-    
-    keyup: function(e)
+     /**
+     * convert to plain HTML for calling insertAtCursor..
+     */
+    toHTML : function()
     {
-        Roo.bootstrap.MonthField.superclass.keyup.call(this);
-        this.update();
+        return Roo.DomHelper.markup(this.toObject());
     },
-
-    fireKey: function(e)
+    /**
+     * used by readEleemnt to extract data from a node
+     * may need improving as it's pretty basic
+     
+     * @param {DomElement} node
+     * @param {String} tag - tag to find, eg. IMG ?? might be better to use DomQuery ?
+     * @param {String} attribute (use html - for contents, style for using next param as style, or false to return the node)
+     * @param {String} style the style property - eg. text-align
+     */
+    getVal : function(node, tag, attr, style)
     {
-        if (!this.picker().isVisible()){
-            if (e.keyCode == 27)   {// allow escape to hide and re-show picker
-                this.show();
-            }
-            return;
+        var n = node;
+        if (tag !== true && n.tagName != tag.toUpperCase()) {
+            // in theory we could do figure[3] << 3rd figure? or some more complex search..?
+            // but kiss for now.
+            n = node.getElementsByTagName(tag).item(0);
         }
-        
-        var dir;
-        
-        switch(e.keyCode){
-            case 27: // escape
-                this.hide();
-                e.preventDefault();
-                break;
-            case 37: // left
-            case 39: // right
-                dir = e.keyCode == 37 ? -1 : 1;
-                
-                this.vIndex = this.vIndex + dir;
-                
-                if(this.vIndex < 0){
-                    this.vIndex = 0;
-                }
-                
-                if(this.vIndex > 11){
-                    this.vIndex = 11;
-                }
-                
-                if(isNaN(this.vIndex)){
-                    this.vIndex = 0;
-                }
-                
-                this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
-                
-                break;
-            case 38: // up
-            case 40: // down
-                
-                dir = e.keyCode == 38 ? -1 : 1;
-                
-                this.vIndex = this.vIndex + dir * 4;
-                
-                if(this.vIndex < 0){
-                    this.vIndex = 0;
-                }
-                
-                if(this.vIndex > 11){
-                    this.vIndex = 11;
-                }
-                
-                if(isNaN(this.vIndex)){
-                    this.vIndex = 0;
-                }
-                
-                this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
-                break;
-                
-            case 13: // enter
-                
-                if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
-                    this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
-                }
-                
-                this.hide();
-                e.preventDefault();
-                break;
-            case 9: // tab
-                if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
-                    this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
-                }
-                this.hide();
-                break;
-            case 16: // shift
-            case 17: // ctrl
-            case 18: // alt
-                break;
-            default :
-                this.hide();
-                
+        if (!n) {
+            return '';
+        }
+        if (attr === false) {
+            return n;
+        }
+        if (attr == 'html') {
+            return n.innerHTML;
+        }
+        if (attr == 'style') {
+            return n.style[style]; 
         }
+        
+        return n.hasAttribute(attr) ? n.getAttribute(attr) : '';
+            
     },
-    
-    remove: function() 
+    /**
+     * create a DomHelper friendly object - for use with 
+     * Roo.DomHelper.markup / overwrite / etc..
+     * (override this)
+     */
+    toObject : function()
     {
-        this.picker().remove();
-    }
-   
-});
-
-Roo.apply(Roo.bootstrap.MonthField,  {
-    
-    content : {
-        tag: 'tbody',
-        cn: [
-        {
-            tag: 'tr',
-            cn: [
-            {
-                tag: 'td',
-                colspan: '7'
-            }
-            ]
-        }
-        ]
+        return {};
     },
+      /**
+     * Read a node that has a 'data-block' property - and extract the values from it.
+     * @param {DomElement} node - the node
+     */
+    readElement : function(node)
+    {
+        
+    } 
     
-    dates:{
-        en: {
-            months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
-            monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
-        }
-    }
-});
-
-Roo.apply(Roo.bootstrap.MonthField,  {
-  
-    template : {
-        tag: 'div',
-        cls: 'datepicker dropdown-menu roo-dynamic',
-        cn: [
-            {
-                tag: 'div',
-                cls: 'datepicker-months',
-                cn: [
-                {
-                    tag: 'table',
-                    cls: 'table-condensed',
-                    cn:[
-                        Roo.bootstrap.DateField.content
-                    ]
-                }
-                ]
-            }
-        ]
-    }
-});
-
+    
+};
 
  
- /*
- * - LGPL
- *
- * CheckBox
- * 
- */
 
 /**
- * @class Roo.bootstrap.CheckBox
- * @extends Roo.bootstrap.Input
- * Bootstrap CheckBox class
- * 
- * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
- * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
- * @cfg {String} boxLabel The text that appears beside the checkbox
- * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
- * @cfg {Boolean} checked initnal the element
- * @cfg {Boolean} inline inline the element (default false)
- * @cfg {String} groupId the checkbox group id // normal just use for checkbox
- * @cfg {String} tooltip label tooltip
+ * @class Roo.htmleditor.BlockFigure
+ * Block that has an image and a figcaption
+ * @cfg {String} image_src the url for the image
+ * @cfg {String} align (left|right) alignment for the block default left
+ * @cfg {String} caption the text to appear below  (and in the alt tag)
+ * @cfg {String} caption_display (block|none) display or not the caption
+ * @cfg {String|number} image_width the width of the image number or %?
+ * @cfg {String|number} image_height the height of the image number or %?
  * 
  * @constructor
- * Create a new CheckBox
- * @param {Object} config The config object
+ * Create a new Filter.
+ * @param {Object} config Configuration options
  */
 
-Roo.bootstrap.CheckBox = function(config){
-    Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
-   
-    this.addEvents({
-        /**
-        * @event check
-        * Fires when the element is checked or unchecked.
-        * @param {Roo.bootstrap.CheckBox} this This input
-        * @param {Boolean} checked The new checked value
-        */
-       check : true,
-       /**
-        * @event click
-        * Fires when the element is click.
-        * @param {Roo.bootstrap.CheckBox} this This input
-        */
-       click : true
-    });
+Roo.htmleditor.BlockFigure = function(cfg)
+{
+    if (cfg.node) {
+        this.readElement(cfg.node);
+        this.updateElement(cfg.node);
+    }
+    Roo.apply(this, cfg);
+}
+Roo.extend(Roo.htmleditor.BlockFigure, Roo.htmleditor.Block, {
     
-};
-
-Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
-  
-    inputType: 'checkbox',
-    inputValue: 1,
-    valueOff: 0,
-    boxLabel: false,
-    checked: false,
-    weight : false,
-    inline: false,
-    tooltip : '',
+    // setable values.
+    image_src: '',
+    align: 'center',
+    caption : '',
+    caption_display : 'block',
+    width : '100%',
+    cls : '',
+    href: '',
+    video_url : '',
     
-    // checkbox success does not make any sense really.. 
-    invalidClass : "",
-    validClass : "",
+    // margin: '2%', not used
+    
+    text_align: 'left', //   (left|right) alignment for the text caption default left. - not used at present
+
     
+    // used by context menu
+    friendly_name : 'Image with caption',
+    deleteTitle : "Delete Image and Caption",
     
-    getAutoCreate : function()
+    contextMenu : function(toolbar)
     {
-        var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
-        
-        var id = Roo.id();
-        
-        var cfg = {};
-        
-        cfg.cls = 'form-group form-check ' + this.inputType; //input-group
-        
-        if(this.inline){
-            cfg.cls += ' ' + this.inputType + '-inline  form-check-inline';
-        }
         
-        var input =  {
-            tag: 'input',
-            id : id,
-            type : this.inputType,
-            value : this.inputValue,
-            cls : 'roo-' + this.inputType, //'form-box',
-            placeholder : this.placeholder || ''
-            
+        var block = function() {
+            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
         };
         
-        if(this.inputType != 'radio'){
-            var hidden =  {
-                tag: 'input',
-                type : 'hidden',
-                cls : 'roo-hidden-value',
-                value : this.checked ? this.inputValue : this.valueOff
-            };
-        }
         
-            
-        if (this.weight) { // Validity check?
-            cfg.cls += " " + this.inputType + "-" + this.weight;
-        }
+        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
         
-        if (this.disabled) {
-            input.disabled=true;
-        }
+        var syncValue = toolbar.editorcore.syncValue;
         
-        if(this.checked){
-            input.checked = this.checked;
-        }
+        var fields = {};
         
-        if (this.name) {
+        return [
+             {
+                xtype : 'TextItem',
+                text : "Source: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+            {
+                xtype : 'Button',
+                text: 'Change Image URL',
+                 
+                listeners : {
+                    click: function (btn, state)
+                    {
+                        var b = block();
+                        
+                        Roo.MessageBox.show({
+                            title : "Image Source URL",
+                            msg : "Enter the url for the image",
+                            buttons: Roo.MessageBox.OKCANCEL,
+                            fn: function(btn, val){
+                                if (btn != 'ok') {
+                                    return;
+                                }
+                                b.image_src = val;
+                                b.updateElement();
+                                syncValue();
+                                toolbar.editorcore.onEditorEvent();
+                            },
+                            minWidth:250,
+                            prompt:true,
+                            //multiline: multiline,
+                            modal : true,
+                            value : b.image_src
+                        });
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+         
+            {
+                xtype : 'Button',
+                text: 'Change Link URL',
+                 
+                listeners : {
+                    click: function (btn, state)
+                    {
+                        var b = block();
+                        
+                        Roo.MessageBox.show({
+                            title : "Link URL",
+                            msg : "Enter the url for the link - leave blank to have no link",
+                            buttons: Roo.MessageBox.OKCANCEL,
+                            fn: function(btn, val){
+                                if (btn != 'ok') {
+                                    return;
+                                }
+                                b.href = val;
+                                b.updateElement();
+                                syncValue();
+                                toolbar.editorcore.onEditorEvent();
+                            },
+                            minWidth:250,
+                            prompt:true,
+                            //multiline: multiline,
+                            modal : true,
+                            value : b.href
+                        });
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'Button',
+                text: 'Show Video URL',
+                 
+                listeners : {
+                    click: function (btn, state)
+                    {
+                        Roo.MessageBox.alert("Video URL",
+                            block().video_url == '' ? 'This image is not linked ot a video' :
+                                'The image is linked to: <a target="_new" href="' + block().video_url + '">' + block().video_url + '</a>');
+                    }
+                },
+                xns : rooui.Toolbar
+            },
             
-            input.name = this.name;
             
-            if(this.inputType != 'radio'){
-                hidden.name = this.name;
-                input.name = '_hidden_' + this.name;
+            {
+                xtype : 'TextItem',
+                text : "Width: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+            {
+                xtype : 'ComboBox',
+                allowBlank : false,
+                displayField : 'val',
+                editable : true,
+                listWidth : 100,
+                triggerAction : 'all',
+                typeAhead : true,
+                valueField : 'val',
+                width : 70,
+                name : 'width',
+                listeners : {
+                    select : function (combo, r, index)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        var b = block();
+                        b.width = r.get('val');
+                        b.updateElement();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.form,
+                store : {
+                    xtype : 'SimpleStore',
+                    data : [
+                        ['100%'],
+                        ['80%'],
+                        ['50%'],
+                        ['20%'],
+                        ['10%']
+                    ],
+                    fields : [ 'val'],
+                    xns : Roo.data
+                }
+            },
+            {
+                xtype : 'TextItem',
+                text : "Align: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+            {
+                xtype : 'ComboBox',
+                allowBlank : false,
+                displayField : 'val',
+                editable : true,
+                listWidth : 100,
+                triggerAction : 'all',
+                typeAhead : true,
+                valueField : 'val',
+                width : 70,
+                name : 'align',
+                listeners : {
+                    select : function (combo, r, index)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        var b = block();
+                        b.align = r.get('val');
+                        b.updateElement();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.form,
+                store : {
+                    xtype : 'SimpleStore',
+                    data : [
+                        ['left'],
+                        ['right'],
+                        ['center']
+                    ],
+                    fields : [ 'val'],
+                    xns : Roo.data
+                }
+            },
+            
+            
+            {
+                xtype : 'Button',
+                text: 'Hide Caption',
+                name : 'caption_display',
+                pressed : false,
+                enableToggle : true,
+                setValue : function(v) {
+                    // this trigger toggle.
+                     
+                    this.setText(v ? "Hide Caption" : "Show Caption");
+                    this.setPressed(v != 'block');
+                },
+                listeners : {
+                    toggle: function (btn, state)
+                    {
+                        var b  = block();
+                        b.caption_display = b.caption_display == 'block' ? 'none' : 'block';
+                        this.setText(b.caption_display == 'block' ? "Hide Caption" : "Show Caption");
+                        b.updateElement();
+                        syncValue();
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
             }
-        }
+        ];
         
-        if (this.size) {
-            input.cls += ' input-' + this.size;
-        }
+    },
+    /**
+     * create a DomHelper friendly object - for use with
+     * Roo.DomHelper.markup / overwrite / etc..
+     */
+    toObject : function()
+    {
+        var d = document.createElement('div');
+        d.innerHTML = this.caption;
         
-        var settings=this;
+        var m = this.width != '100%' && this.align == 'center' ? '0 auto' : 0; 
         
-        ['xs','sm','md','lg'].map(function(size){
-            if (settings[size]) {
-                cfg.cls += ' col-' + size + '-' + settings[size];
+        var iw = this.align == 'center' ? this.width : '100%';
+        var img =   {
+            tag : 'img',
+            contenteditable : 'false',
+            src : this.image_src,
+            alt : d.innerText.replace(/\n/g, " ").replace(/\s+/g, ' ').trim(), // removeHTML and reduce spaces..
+            style: {
+                width : iw,
+                maxWidth : iw + ' !important', // this is not getting rendered?
+                margin : m  
+                
             }
-        });
-        
-        var inputblock = input;
-         
-        if (this.before || this.after) {
-            
-            inputblock = {
-                cls : 'input-group',
-                cn :  [] 
+        };
+        /*
+        '<div class="{0}" width="420" height="315" src="{1}" frameborder="0" allowfullscreen>' +
+                    '<a href="{2}">' + 
+                        '<img class="{0}-thumbnail" src="{3}/Images/{4}/{5}#image-{4}" />' + 
+                    '</a>' + 
+                '</div>',
+        */
+                
+        if (this.href.length > 0) {
+            img = {
+                tag : 'a',
+                href: this.href,
+                contenteditable : 'true',
+                cn : [
+                    img
+                ]
             };
-            
-            if (this.before) {
-                inputblock.cn.push({
-                    tag :'span',
-                    cls : 'input-group-addon',
-                    html : this.before
-                });
-            }
-            
-            inputblock.cn.push(input);
-            
-            if(this.inputType != 'radio'){
-                inputblock.cn.push(hidden);
-            }
-            
-            if (this.after) {
-                inputblock.cn.push({
-                    tag :'span',
-                    cls : 'input-group-addon',
-                    html : this.after
-                });
-            }
-            
         }
-        var boxLabelCfg = false;
         
-        if(this.boxLabel){
-           
-            boxLabelCfg = {
-                tag: 'label',
-                //'for': id, // box label is handled by onclick - so no for...
-                cls: 'box-label',
-                html: this.boxLabel
+        
+        if (this.video_url.length > 0) {
+            img = {
+                tag : 'div',
+                cls : this.cls,
+                frameborder : 0,
+                allowfullscreen : true,
+                width : 420,  // these are for video tricks - that we replace the outer
+                height : 315,
+                src : this.video_url,
+                cn : [
+                    img
+                ]
             };
-            if(this.tooltip){
-                boxLabelCfg.tooltip = this.tooltip;
-            }
-             
         }
+        // we remove caption totally if its hidden... - will delete data.. but otherwise we end up with fake caption
+        var captionhtml = this.caption_display == 'none' ? '' : (this.caption.length ? this.caption : "Caption");
         
-        
-        if (align ==='left' && this.fieldLabel.length) {
-//                Roo.log("left and has label");
-            cfg.cn = [
-                {
-                    tag: 'label',
-                    'for' :  id,
-                    cls : 'control-label',
-                    html : this.fieldLabel
-                },
-                {
-                    cls : "", 
-                    cn: [
-                        inputblock
-                    ]
-                }
-            ];
-            
-            if (boxLabelCfg) {
-                cfg.cn[1].cn.push(boxLabelCfg);
-            }
-            
-            if(this.labelWidth > 12){
-                cfg.cn[0].style = "width: " + this.labelWidth + 'px';
-            }
-            
-            if(this.labelWidth < 13 && this.labelmd == 0){
-                this.labelmd = this.labelWidth;
-            }
-            
-            if(this.labellg > 0){
-                cfg.cn[0].cls += ' col-lg-' + this.labellg;
-                cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
-            }
-            
-            if(this.labelmd > 0){
-                cfg.cn[0].cls += ' col-md-' + this.labelmd;
-                cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
-            }
-            
-            if(this.labelsm > 0){
-                cfg.cn[0].cls += ' col-sm-' + this.labelsm;
-                cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
-            }
-            
-            if(this.labelxs > 0){
-                cfg.cn[0].cls += ' col-xs-' + this.labelxs;
-                cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
-            }
+  
+        var ret =   {
+            tag: 'figure',
+            'data-block' : 'Figure',
+            'data-width' : this.width, 
+            contenteditable : 'false',
+            
+            style : {
+                display: 'block',
+                float :  this.align ,
+                maxWidth :  this.align == 'center' ? '100% !important' : (this.width + ' !important'),
+                width : this.align == 'center' ? '100%' : this.width,
+                margin:  '0px',
+                padding: this.align == 'center' ? '0' : '0 10px' ,
+                textAlign : this.align   // seems to work for email..
+                
+            },
+           
             
-        } else if ( this.fieldLabel.length) {
-//                Roo.log(" label");
-                cfg.cn = [
-                   
-                    {
-                        tag: this.boxLabel ? 'span' : 'label',
-                        'for': id,
-                        cls: 'control-label box-input-label',
-                        //cls : 'input-group-addon',
-                        html : this.fieldLabel
-                    },
+            align : this.align,
+            cn : [
+                img,
+              
+                {
+                    tag: 'figcaption',
+                    'data-display' : this.caption_display,
+                    style : {
+                        textAlign : 'left',
+                        fontSize : '16px',
+                        lineHeight : '24px',
+                        display : this.caption_display,
+                        maxWidth : (this.align == 'center' ?  this.width : '100%' ) + ' !important',
+                        margin: m,
+                        width: this.align == 'center' ?  this.width : '100%' 
                     
-                    inputblock
+                         
+                    },
+                    cls : this.cls.length > 0 ? (this.cls  + '-thumbnail' ) : '',
+                    cn : [
+                        {
+                            tag: 'div',
+                            style  : {
+                                marginTop : '16px',
+                                textAlign : 'left'
+                            },
+                            align: 'left',
+                            cn : [
+                                {
+                                    // we can not rely on yahoo syndication to use CSS elements - so have to use  '<i>' to encase stuff.
+                                    tag : 'i',
+                                    contenteditable : true,
+                                    html : captionhtml
+                                }
+                                
+                            ]
+                        }
+                        
+                    ]
                     
-                ];
-                if (boxLabelCfg) {
-                    cfg.cn.push(boxLabelCfg);
-                }
-
-        } else {
-            
-//                Roo.log(" no label && no align");
-                cfg.cn = [  inputblock ] ;
-                if (boxLabelCfg) {
-                    cfg.cn.push(boxLabelCfg);
                 }
-
-                
-        }
+            ]
+        };
+        return ret;
+         
+    },
+    
+    readElement : function(node)
+    {
+        // this should not really come from the link...
+        this.video_url = this.getVal(node, 'div', 'src');
+        this.cls = this.getVal(node, 'div', 'class');
+        this.href = this.getVal(node, 'a', 'href');
         
-       
         
-        if(this.inputType != 'radio'){
-            cfg.cn.push(hidden);
+        this.image_src = this.getVal(node, 'img', 'src');
+         
+        this.align = this.getVal(node, 'figure', 'align');
+        var figcaption = this.getVal(node, 'figcaption', false);
+        if (figcaption !== '') {
+            this.caption = this.getVal(figcaption, 'i', 'html');
         }
         
-        return cfg;
+
+        this.caption_display = this.getVal(node, 'figcaption', 'data-display');
+        //this.text_align = this.getVal(node, 'figcaption', 'style','text-align');
+        this.width = this.getVal(node, true, 'data-width');
+        //this.margin = this.getVal(node, 'figure', 'style', 'margin');
         
     },
-    
-    /**
-     * return the real input element.
-     */
-    inputEl: function ()
-    {
-        return this.el.select('input.roo-' + this.inputType,true).first();
-    },
-    hiddenEl: function ()
-    {
-        return this.el.select('input.roo-hidden-value',true).first();
-    },
-    
-    labelEl: function()
+    removeNode : function()
     {
-        return this.el.select('label.control-label',true).first();
-    },
-    /* depricated... */
+        return this.node;
+    }
     
-    label: function()
-    {
-        return this.labelEl();
-    },
+  
+   
+     
     
-    boxLabelEl: function()
-    {
-        return this.el.select('label.box-label',true).first();
-    },
     
-    initEvents : function()
-    {
-//        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
-        
-        this.inputEl().on('click', this.onClick,  this);
-        
-        if (this.boxLabel) { 
-            this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
-        }
-        
-        this.startValue = this.getValue();
-        
-        if(this.groupId){
-            Roo.bootstrap.CheckBox.register(this);
-        }
-    },
     
-    onClick : function(e)
-    {   
-        if(this.fireEvent('click', this, e) !== false){
-            this.setChecked(!this.checked);
-        }
-        
-    },
     
-    setChecked : function(state,suppressEvent)
-    {
-        this.startValue = this.getValue();
+})
 
-        if(this.inputType == 'radio'){
-            
-            Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
-                e.dom.checked = false;
-            });
-            
-            this.inputEl().dom.checked = true;
-            
-            this.inputEl().dom.value = this.inputValue;
-            
-            if(suppressEvent !== true){
-                this.fireEvent('check', this, true);
+
+/**
+ * @class Roo.htmleditor.BlockTable
+ * Block that manages a table
+ * 
+ * @constructor
+ * Create a new Filter.
+ * @param {Object} config Configuration options
+ */
+
+Roo.htmleditor.BlockTable = function(cfg)
+{
+    if (cfg.node) {
+        this.readElement(cfg.node);
+        this.updateElement(cfg.node);
+    }
+    Roo.apply(this, cfg);
+    if (!cfg.node) {
+        this.rows = [];
+        for(var r = 0; r < this.no_row; r++) {
+            this.rows[r] = [];
+            for(var c = 0; c < this.no_col; c++) {
+                this.rows[r][c] = this.emptyCell();
             }
-            
-            this.validate();
-            
-            return;
         }
+    }
+    
+    
+}
+Roo.extend(Roo.htmleditor.BlockTable, Roo.htmleditor.Block, {
+    rows : false,
+    no_col : 1,
+    no_row : 1,
+    
+    
+    width: '100%',
+    
+    // used by context menu
+    friendly_name : 'Table',
+    deleteTitle : 'Delete Table',
+    // context menu is drawn once..
+    
+    contextMenu : function(toolbar)
+    {
         
-        this.checked = state;
+        var block = function() {
+            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
+        };
         
-        this.inputEl().dom.checked = state;
         
+        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
         
-        this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
+        var syncValue = toolbar.editorcore.syncValue;
         
-        if(suppressEvent !== true){
-            this.fireEvent('check', this, state);
-        }
+        var fields = {};
+        
+        return [
+            {
+                xtype : 'TextItem',
+                text : "Width: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+            {
+                xtype : 'ComboBox',
+                allowBlank : false,
+                displayField : 'val',
+                editable : true,
+                listWidth : 100,
+                triggerAction : 'all',
+                typeAhead : true,
+                valueField : 'val',
+                width : 100,
+                name : 'width',
+                listeners : {
+                    select : function (combo, r, index)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        var b = block();
+                        b.width = r.get('val');
+                        b.updateElement();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.form,
+                store : {
+                    xtype : 'SimpleStore',
+                    data : [
+                        ['100%'],
+                        ['auto']
+                    ],
+                    fields : [ 'val'],
+                    xns : Roo.data
+                }
+            },
+            // -------- Cols
+            
+            {
+                xtype : 'TextItem',
+                text : "Columns: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+         
+            {
+                xtype : 'Button',
+                text: '-',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        block().removeColumn();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'Button',
+                text: '+',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        block().addColumn();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            // -------- ROWS
+            {
+                xtype : 'TextItem',
+                text : "Rows: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+         
+            {
+                xtype : 'Button',
+                text: '-',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        block().removeRow();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'Button',
+                text: '+',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        block().addRow();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            // -------- ROWS
+            {
+                xtype : 'Button',
+                text: 'Reset Column Widths',
+                listeners : {
+                    
+                    click : function (_self, e)
+                    {
+                        block().resetWidths();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            } 
+            
+            
+            
+        ];
         
-        this.validate();
     },
     
-    getValue : function()
-    {
-        if(this.inputType == 'radio'){
-            return this.getGroupValue();
-        }
-        
-        return this.hiddenEl().dom.value;
-        
-    },
     
-    getGroupValue : function()
+  /**
+     * create a DomHelper friendly object - for use with
+     * Roo.DomHelper.markup / overwrite / etc..
+     * ?? should it be called with option to hide all editing features?
+     */
+    toObject : function()
     {
-        if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
-            return '';
-        }
         
-        return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
-    },
-    
-    setValue : function(v,suppressEvent)
-    {
-        if(this.inputType == 'radio'){
-            this.setGroupValue(v, suppressEvent);
-            return;
-        }
+        var ret = {
+            tag : 'table',
+            contenteditable : 'false', // this stops cell selection from picking the table.
+            'data-block' : 'Table',
+            style : {
+                width:  this.width,
+                border : 'solid 1px #000', // ??? hard coded?
+                'border-collapse' : 'collapse' 
+            },
+            cn : [
+                { tag : 'tbody' , cn : [] }
+            ]
+        };
         
-        this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
+        // do we have a head = not really 
+        var ncols = 0;
+        Roo.each(this.rows, function( row ) {
+            var tr = {
+                tag: 'tr',
+                style : {
+                    margin: '6px',
+                    border : 'solid 1px #000',
+                    textAlign : 'left' 
+                },
+                cn : [ ]
+            };
+            
+            ret.cn[0].cn.push(tr);
+            // does the row have any properties? ?? height?
+            var nc = 0;
+            Roo.each(row, function( cell ) {
+                
+                var td = {
+                    tag : 'td',
+                    contenteditable :  'true',
+                    'data-block' : 'Td',
+                    html : cell.html,
+                    style : cell.style
+                };
+                if (cell.colspan > 1) {
+                    td.colspan = cell.colspan ;
+                    nc += cell.colspan;
+                } else {
+                    nc++;
+                }
+                if (cell.rowspan > 1) {
+                    td.rowspan = cell.rowspan ;
+                }
+                
+                
+                // widths ?
+                tr.cn.push(td);
+                    
+                
+            }, this);
+            ncols = Math.max(nc, ncols);
+            
+            
+        }, this);
+        // add the header row..
         
-        this.validate();
+        ncols++;
+         
+        
+        return ret;
+         
     },
     
-    setGroupValue : function(v, suppressEvent)
+    readElement : function(node)
     {
-        this.startValue = this.getValue();
+        node  = node ? node : this.node ;
+        this.width = this.getVal(node, true, 'style', 'width') || '100%';
         
-        Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
-            e.dom.checked = false;
+        this.rows = [];
+        this.no_row = 0;
+        var trs = Array.from(node.rows);
+        trs.forEach(function(tr) {
+            var row =  [];
+            this.rows.push(row);
             
-            if(e.dom.value == v){
-                e.dom.checked = true;
-            }
-        });
+            this.no_row++;
+            var no_column = 0;
+            Array.from(tr.cells).forEach(function(td) {
+                
+                var add = {
+                    colspan : td.hasAttribute('colspan') ? td.getAttribute('colspan')*1 : 1,
+                    rowspan : td.hasAttribute('rowspan') ? td.getAttribute('rowspan')*1 : 1,
+                    style : td.hasAttribute('style') ? td.getAttribute('style') : '',
+                    html : td.innerHTML
+                };
+                no_column += add.colspan;
+                     
+                
+                row.push(add);
+                
+                
+            },this);
+            this.no_col = Math.max(this.no_col, no_column);
+            
+            
+        },this);
         
-        if(suppressEvent !== true){
-            this.fireEvent('check', this, true);
-        }
-
-        this.validate();
         
-        return;
     },
-    
-    validate : function()
+    normalizeRows: function()
     {
-        if(this.getVisibilityEl().hasClass('hidden')){
-            return true;
-        }
-        
-        if(
-                this.disabled || 
-                (this.inputType == 'radio' && this.validateRadio()) ||
-                (this.inputType == 'checkbox' && this.validateCheckbox())
-        ){
-            this.markValid();
-            return true;
-        }
-        
-        this.markInvalid();
-        return false;
+        var ret= [];
+        var rid = -1;
+        this.rows.forEach(function(row) {
+            rid++;
+            ret[rid] = [];
+            row = this.normalizeRow(row);
+            var cid = 0;
+            row.forEach(function(c) {
+                while (typeof(ret[rid][cid]) != 'undefined') {
+                    cid++;
+                }
+                if (typeof(ret[rid]) == 'undefined') {
+                    ret[rid] = [];
+                }
+                ret[rid][cid] = c;
+                c.row = rid;
+                c.col = cid;
+                if (c.rowspan < 2) {
+                    return;
+                }
+                
+                for(var i = 1 ;i < c.rowspan; i++) {
+                    if (typeof(ret[rid+i]) == 'undefined') {
+                        ret[rid+i] = [];
+                    }
+                    ret[rid+i][cid] = c;
+                }
+            });
+        }, this);
+        return ret;
+    
     },
     
-    validateRadio : function()
+    normalizeRow: function(row)
     {
-        if(this.getVisibilityEl().hasClass('hidden')){
-            return true;
-        }
-        
-        if(this.allowBlank){
-            return true;
-        }
-        
-        var valid = false;
-        
-        Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
-            if(!e.dom.checked){
+        var ret= [];
+        row.forEach(function(c) {
+            if (c.colspan < 2) {
+                ret.push(c);
                 return;
             }
-            
-            valid = true;
-            
-            return false;
+            for(var i =0 ;i < c.colspan; i++) {
+                ret.push(c);
+            }
         });
-        
-        return valid;
+        return ret;
+    
     },
     
-    validateCheckbox : function()
+    deleteColumn : function(sel)
     {
-        if(!this.groupId){
-            return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
-            //return (this.getValue() == this.inputValue) ? true : false;
-        }
-        
-        var group = Roo.bootstrap.CheckBox.get(this.groupId);
-        
-        if(!group){
-            return false;
+        if (!sel || sel.type != 'col') {
+            return;
         }
-        
-        var r = false;
-        
-        for(var i in group){
-            if(group[i].el.isVisible(true)){
-                r = false;
-                break;
-            }
-            
-            r = true;
+        if (this.no_col < 2) {
+            return;
         }
         
-        for(var i in group){
-            if(r){
-                break;
+        this.rows.forEach(function(row) {
+            var cols = this.normalizeRow(row);
+            var col = cols[sel.col];
+            if (col.colspan > 1) {
+                col.colspan --;
+            } else {
+                row.remove(col);
             }
             
-            r = (group[i].getValue() == group[i].inputValue) ? true : false;
-        }
+        }, this);
+        this.no_col--;
         
-        return r;
+    },
+    removeColumn : function()
+    {
+        this.deleteColumn({
+            type: 'col',
+            col : this.no_col-1
+        });
+        this.updateElement();
     },
     
-    /**
-     * Mark this field as valid
-     */
-    markValid : function()
+     
+    addColumn : function()
     {
-        var _this = this;
-        
-        this.fireEvent('valid', this);
-        
-        var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
-        
-        if(this.groupId){
-            label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
-        }
-        
-        if(label){
-            label.markValid();
-        }
-
-        if(this.inputType == 'radio'){
-            Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
-                var fg = e.findParent('.form-group', false, true);
-                if (Roo.bootstrap.version == 3) {
-                    fg.removeClass([_this.invalidClass, _this.validClass]);
-                    fg.addClass(_this.validClass);
-                } else {
-                    fg.removeClass(['is-valid', 'is-invalid']);
-                    fg.addClass('is-valid');
-                }
-            });
-            
-            return;
-        }
-
-        if(!this.groupId){
-            var fg = this.el.findParent('.form-group', false, true);
-            if (Roo.bootstrap.version == 3) {
-                fg.removeClass([this.invalidClass, this.validClass]);
-                fg.addClass(this.validClass);
-            } else {
-                fg.removeClass(['is-valid', 'is-invalid']);
-                fg.addClass('is-valid');
-            }
-            return;
-        }
-        
-        var group = Roo.bootstrap.CheckBox.get(this.groupId);
-        
-        if(!group){
-            return;
-        }
         
-        for(var i in group){
-            var fg = group[i].el.findParent('.form-group', false, true);
-            if (Roo.bootstrap.version == 3) {
-                fg.removeClass([this.invalidClass, this.validClass]);
-                fg.addClass(this.validClass);
-            } else {
-                fg.removeClass(['is-valid', 'is-invalid']);
-                fg.addClass('is-valid');
-            }
-        }
+        this.rows.forEach(function(row) {
+            row.push(this.emptyCell());
+           
+        }, this);
+        this.updateElement();
     },
     
-     /**
-     * Mark this field as invalid
-     * @param {String} msg The validation message
-     */
-    markInvalid : function(msg)
+    deleteRow : function(sel)
     {
-        if(this.allowBlank){
+        if (!sel || sel.type != 'row') {
             return;
         }
         
-        var _this = this;
-        
-        this.fireEvent('invalid', this, msg);
+        if (this.no_row < 2) {
+            return;
+        }
         
-        var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
+        var rows = this.normalizeRows();
         
-        if(this.groupId){
-            label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
-        }
         
-        if(label){
-            label.markInvalid();
-        }
-            
-        if(this.inputType == 'radio'){
+        rows[sel.row].forEach(function(col) {
+            if (col.rowspan > 1) {
+                col.rowspan--;
+            } else {
+                col.remove = 1; // flage it as removed.
+            }
             
-            Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
-                var fg = e.findParent('.form-group', false, true);
-                if (Roo.bootstrap.version == 3) {
-                    fg.removeClass([_this.invalidClass, _this.validClass]);
-                    fg.addClass(_this.invalidClass);
-                } else {
-                    fg.removeClass(['is-invalid', 'is-valid']);
-                    fg.addClass('is-invalid');
+        }, this);
+        var newrows = [];
+        this.rows.forEach(function(row) {
+            newrow = [];
+            row.forEach(function(c) {
+                if (typeof(c.remove) == 'undefined') {
+                    newrow.push(c);
                 }
+                
             });
-            
-            return;
-        }
-        
-        if(!this.groupId){
-            var fg = this.el.findParent('.form-group', false, true);
-            if (Roo.bootstrap.version == 3) {
-                fg.removeClass([_this.invalidClass, _this.validClass]);
-                fg.addClass(_this.invalidClass);
-            } else {
-                fg.removeClass(['is-invalid', 'is-valid']);
-                fg.addClass('is-invalid');
+            if (newrow.length > 0) {
+                newrows.push(row);
             }
-            return;
-        }
+        });
+        this.rows =  newrows;
         
-        var group = Roo.bootstrap.CheckBox.get(this.groupId);
         
-        if(!group){
-            return;
-        }
         
-        for(var i in group){
-            var fg = group[i].el.findParent('.form-group', false, true);
-            if (Roo.bootstrap.version == 3) {
-                fg.removeClass([_this.invalidClass, _this.validClass]);
-                fg.addClass(_this.invalidClass);
-            } else {
-                fg.removeClass(['is-invalid', 'is-valid']);
-                fg.addClass('is-invalid');
-            }
-        }
+        this.no_row--;
+        this.updateElement();
         
     },
-    
-    clearInvalid : function()
+    removeRow : function()
     {
-        Roo.bootstrap.Input.prototype.clearInvalid.call(this);
-        
-        // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
-        
-        var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
+        this.deleteRow({
+            type: 'row',
+            row : this.no_row-1
+        });
         
-        if (label && label.iconEl) {
-            label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
-            label.iconEl.removeClass(['is-invalid', 'is-valid']);
-        }
     },
     
-    disable : function()
+     
+    addRow : function()
     {
-        if(this.inputType != 'radio'){
-            Roo.bootstrap.CheckBox.superclass.disable.call(this);
-            return;
-        }
-        
-        var _this = this;
         
-        if(this.rendered){
-            Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
-                _this.getActionEl().addClass(this.disabledClass);
-                e.dom.disabled = true;
-            });
+        var row = [];
+        for (var i = 0; i < this.no_col; i++ ) {
+            
+            row.push(this.emptyCell());
+           
         }
+        this.rows.push(row);
+        this.updateElement();
         
-        this.disabled = true;
-        this.fireEvent("disable", this);
-        return this;
     },
-
-    enable : function()
-    {
-        if(this.inputType != 'radio'){
-            Roo.bootstrap.CheckBox.superclass.enable.call(this);
-            return;
-        }
-        
-        var _this = this;
-        
-        if(this.rendered){
-            Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
-                _this.getActionEl().removeClass(this.disabledClass);
-                e.dom.disabled = false;
-            });
-        }
+     
+    // the default cell object... at present...
+    emptyCell : function() {
+        return (new Roo.htmleditor.BlockTd({})).toObject();
         
-        this.disabled = false;
-        this.fireEvent("enable", this);
-        return this;
+     
     },
     
-    setBoxLabel : function(v)
+    removeNode : function()
     {
-        this.boxLabel = v;
-        
-        if(this.rendered){
-            this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
-        }
-    }
-
-});
-
-Roo.apply(Roo.bootstrap.CheckBox, {
+        return this.node;
+    },
     
-    groups: {},
     
-     /**
-    * register a CheckBox Group
-    * @param {Roo.bootstrap.CheckBox} the CheckBox to add
-    */
-    register : function(checkbox)
+    
+    resetWidths : function()
     {
-        if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
-            this.groups[checkbox.groupId] = {};
-        }
-        
-        if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
-            return;
-        }
-        
-        this.groups[checkbox.groupId][checkbox.name] = checkbox;
-       
-    },
-    /**
-    * fetch a CheckBox Group based on the group ID
-    * @param {string} the group ID
-    * @returns {Roo.bootstrap.CheckBox} the CheckBox group
-    */
-    get: function(groupId) {
-        if (typeof(this.groups[groupId]) == 'undefined') {
-            return false;
-        }
-        
-        return this.groups[groupId] ;
+        Array.from(this.node.getElementsByTagName('td')).forEach(function(n) {
+            var nn = Roo.htmleditor.Block.factory(n);
+            nn.width = '';
+            nn.updateElement(n);
+        });
     }
     
     
-});
-/*
- * - LGPL
+    
+    
+})
+
+/**
+ *
+ * editing a TD?
+ *
+ * since selections really work on the table cell, then editing really should work from there
+ *
+ * The original plan was to support merging etc... - but that may not be needed yet..
+ *
+ * So this simple version will support:
+ *   add/remove cols
+ *   adjust the width +/-
+ *   reset the width...
+ *   
  *
- * RadioItem
- * 
  */
 
+
+
 /**
- * @class Roo.bootstrap.Radio
- * @extends Roo.bootstrap.Component
- * Bootstrap Radio class
- * @cfg {String} boxLabel - the label associated
- * @cfg {String} value - the value of radio
+ * @class Roo.htmleditor.BlockTable
+ * Block that manages a table
  * 
  * @constructor
- * Create a new Radio
- * @param {Object} config The config object
+ * Create a new Filter.
+ * @param {Object} config Configuration options
  */
-Roo.bootstrap.Radio = function(config){
-    Roo.bootstrap.Radio.superclass.constructor.call(this, config);
-    
-};
 
-Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
+Roo.htmleditor.BlockTd = function(cfg)
+{
+    if (cfg.node) {
+        this.readElement(cfg.node);
+        this.updateElement(cfg.node);
+    }
+    Roo.apply(this, cfg);
+     
     
-    boxLabel : '',
     
-    value : '',
+}
+Roo.extend(Roo.htmleditor.BlockTd, Roo.htmleditor.Block, {
+    node : false,
+    
+    width: '',
+    textAlign : 'left',
+    valign : 'top',
+    
+    colspan : 1,
+    rowspan : 1,
+    
+    
+    // used by context menu
+    friendly_name : 'Table Cell',
+    deleteTitle : false, // use our customer delete
+    
+    // context menu is drawn once..
+    
+    contextMenu : function(toolbar)
+    {
+        
+        var cell = function() {
+            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode);
+        };
+        
+        var table = function() {
+            return Roo.htmleditor.Block.factory(toolbar.tb.selectedNode.closest('table'));
+        };
+        
+        var lr = false;
+        var saveSel = function()
+        {
+            lr = toolbar.editorcore.getSelection().getRangeAt(0);
+        }
+        var restoreSel = function()
+        {
+            if (lr) {
+                (function() {
+                    toolbar.editorcore.focus();
+                    var cr = toolbar.editorcore.getSelection();
+                    cr.removeAllRanges();
+                    cr.addRange(lr);
+                    toolbar.editorcore.onEditorEvent();
+                }).defer(10, this);
+                
+                
+            }
+        }
+        
+        var rooui =  typeof(Roo.bootstrap) == 'undefined' ? Roo : Roo.bootstrap;
+        
+        var syncValue = toolbar.editorcore.syncValue;
+        
+        var fields = {};
+        
+        return [
+            {
+                xtype : 'Button',
+                text : 'Edit Table',
+                listeners : {
+                    click : function() {
+                        var t = toolbar.tb.selectedNode.closest('table');
+                        toolbar.editorcore.selectNode(t);
+                        toolbar.editorcore.onEditorEvent();                        
+                    }
+                }
+                
+            },
+              
+           
+             
+            {
+                xtype : 'TextItem',
+                text : "Column Width: ",
+                 xns : rooui.Toolbar 
+               
+            },
+            {
+                xtype : 'Button',
+                text: '-',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        cell().shrinkColumn();
+                        syncValue();
+                         toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'Button',
+                text: '+',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        cell().growColumn();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            
+            {
+                xtype : 'TextItem',
+                text : "Vertical Align: ",
+                xns : rooui.Toolbar  //Boostrap?
+            },
+            {
+                xtype : 'ComboBox',
+                allowBlank : false,
+                displayField : 'val',
+                editable : true,
+                listWidth : 100,
+                triggerAction : 'all',
+                typeAhead : true,
+                valueField : 'val',
+                width : 100,
+                name : 'valign',
+                listeners : {
+                    select : function (combo, r, index)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        var b = cell();
+                        b.valign = r.get('val');
+                        b.updateElement();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.form,
+                store : {
+                    xtype : 'SimpleStore',
+                    data : [
+                        ['top'],
+                        ['middle'],
+                        ['bottom'] // there are afew more... 
+                    ],
+                    fields : [ 'val'],
+                    xns : Roo.data
+                }
+            },
+            
+            {
+                xtype : 'TextItem',
+                text : "Merge Cells: ",
+                 xns : rooui.Toolbar 
+               
+            },
+            
+            
+            {
+                xtype : 'Button',
+                text: 'Right',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        cell().mergeRight();
+                        //block().growColumn();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+             
+            {
+                xtype : 'Button',
+                text: 'Below',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        cell().mergeBelow();
+                        //block().growColumn();
+                        syncValue();
+                        toolbar.editorcore.onEditorEvent();
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'TextItem',
+                text : "| ",
+                 xns : rooui.Toolbar 
+               
+            },
+            
+            {
+                xtype : 'Button',
+                text: 'Split',
+                listeners : {
+                    click : function (_self, e)
+                    {
+                        //toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        cell().split();
+                        syncValue();
+                        toolbar.editorcore.selectNode(toolbar.tb.selectedNode);
+                        toolbar.editorcore.onEditorEvent();
+                                             
+                    }
+                },
+                xns : rooui.Toolbar
+            },
+            {
+                xtype : 'Fill',
+                xns : rooui.Toolbar 
+               
+            },
+        
+          
+            {
+                xtype : 'Button',
+                text: 'Delete',
+                 
+                xns : rooui.Toolbar,
+                menu : {
+                    xtype : 'Menu',
+                    xns : rooui.menu,
+                    items : [
+                        {
+                            xtype : 'Item',
+                            html: 'Column',
+                            listeners : {
+                                click : function (_self, e)
+                                {
+                                    var t = table();
+                                    
+                                    cell().deleteColumn();
+                                    syncValue();
+                                    toolbar.editorcore.selectNode(t.node);
+                                    toolbar.editorcore.onEditorEvent();   
+                                }
+                            },
+                            xns : rooui.menu
+                        },
+                        {
+                            xtype : 'Item',
+                            html: 'Row',
+                            listeners : {
+                                click : function (_self, e)
+                                {
+                                    var t = table();
+                                    cell().deleteRow();
+                                    syncValue();
+                                    
+                                    toolbar.editorcore.selectNode(t.node);
+                                    toolbar.editorcore.onEditorEvent();   
+                                                         
+                                }
+                            },
+                            xns : rooui.menu
+                        },
+                       {
+                            xtype : 'Separator',
+                            xns : rooui.menu
+                        },
+                        {
+                            xtype : 'Item',
+                            html: 'Table',
+                            listeners : {
+                                click : function (_self, e)
+                                {
+                                    var t = table();
+                                    var nn = t.node.nextSibling || t.node.previousSibling;
+                                    t.node.parentNode.removeChild(t.node);
+                                    if (nn) { 
+                                        toolbar.editorcore.selectNode(nn, true);
+                                    }
+                                    toolbar.editorcore.onEditorEvent();   
+                                                         
+                                }
+                            },
+                            xns : rooui.menu
+                        }
+                    ]
+                }
+            }
+            
+            // align... << fixme
+            
+        ];
+        
+    },
+    
     
-    getAutoCreate : function()
+  /**
+     * create a DomHelper friendly object - for use with
+     * Roo.DomHelper.markup / overwrite / etc..
+     * ?? should it be called with option to hide all editing features?
+     */
+ /**
+     * create a DomHelper friendly object - for use with
+     * Roo.DomHelper.markup / overwrite / etc..
+     * ?? should it be called with option to hide all editing features?
+     */
+    toObject : function()
     {
-        var cfg = {
-            tag : 'div',
-            cls : 'form-group radio',
-            cn : [
-                {
-                    tag : 'label',
-                    cls : 'box-label',
-                    html : this.boxLabel
-                }
-            ]
+        
+        var ret = {
+            tag : 'td',
+            contenteditable : 'true', // this stops cell selection from picking the table.
+            'data-block' : 'Td',
+            valign : this.valign,
+            style : {  
+                'text-align' :  this.textAlign,
+                border : 'solid 1px rgb(0, 0, 0)', // ??? hard coded?
+                'border-collapse' : 'collapse',
+                padding : '6px', // 8 for desktop / 4 for mobile
+                'vertical-align': this.valign
+            },
+            html : this.html
         };
+        if (this.width != '') {
+            ret.width = this.width;
+            ret.style.width = this.width;
+        }
         
-        return cfg;
+        
+        if (this.colspan > 1) {
+            ret.colspan = this.colspan ;
+        } 
+        if (this.rowspan > 1) {
+            ret.rowspan = this.rowspan ;
+        }
+        
+           
+        
+        return ret;
+         
     },
     
-    initEvents : function() 
+    readElement : function(node)
     {
-        this.parent().register(this);
+        node  = node ? node : this.node ;
+        this.width = node.style.width;
+        this.colspan = Math.max(1,1*node.getAttribute('colspan'));
+        this.rowspan = Math.max(1,1*node.getAttribute('rowspan'));
+        this.html = node.innerHTML;
         
-        this.el.on('click', this.onClick, this);
         
     },
-    
-    onClick : function(e)
-    {
-        if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
-            this.setChecked(true);
-        }
+     
+    // the default cell object... at present...
+    emptyCell : function() {
+        return {
+            colspan :  1,
+            rowspan :  1,
+            textAlign : 'left',
+            html : "&nbsp;" // is this going to be editable now?
+        };
+     
     },
     
-    setChecked : function(state, suppressEvent)
+    removeNode : function()
     {
-        this.parent().setValue(this.value, suppressEvent);
-        
+        return this.node.closest('table');
+         
     },
     
-    setBoxLabel : function(v)
+    cellData : false,
+    
+    colWidths : false,
+    
+    toTableArray  : function()
     {
-        this.boxLabel = v;
+        var ret = [];
+        var tab = this.node.closest('tr').closest('table');
+        Array.from(tab.rows).forEach(function(r, ri){
+            ret[ri] = [];
+        });
+        var rn = 0;
+        this.colWidths = [];
+        var all_auto = true;
+        Array.from(tab.rows).forEach(function(r, ri){
+            
+            var cn = 0;
+            Array.from(r.cells).forEach(function(ce, ci){
+                var c =  {
+                    cell : ce,
+                    row : rn,
+                    col: cn,
+                    colspan : ce.colSpan,
+                    rowspan : ce.rowSpan
+                };
+                if (ce.isEqualNode(this.node)) {
+                    this.cellData = c;
+                }
+                // if we have been filled up by a row?
+                if (typeof(ret[rn][cn]) != 'undefined') {
+                    while(typeof(ret[rn][cn]) != 'undefined') {
+                        cn++;
+                    }
+                    c.col = cn;
+                }
+                
+                if (typeof(this.colWidths[cn]) == 'undefined') {
+                    this.colWidths[cn] =   ce.style.width;
+                    if (this.colWidths[cn] != '') {
+                        all_auto = false;
+                    }
+                }
+                
+                
+                if (c.colspan < 2 && c.rowspan < 2 ) {
+                    ret[rn][cn] = c;
+                    cn++;
+                    return;
+                }
+                for(var j = 0; j < c.rowspan; j++) {
+                    if (typeof(ret[rn+j]) == 'undefined') {
+                        continue; // we have a problem..
+                    }
+                    ret[rn+j][cn] = c;
+                    for(var i = 0; i < c.colspan; i++) {
+                        ret[rn+j][cn+i] = c;
+                    }
+                }
+                
+                cn += c.colspan;
+            }, this);
+            rn++;
+        }, this);
         
-        if(this.rendered){
-            this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
+        // initalize widths.?
+        // either all widths or no widths..
+        if (all_auto) {
+            this.colWidths[0] = false; // no widths flag.
         }
-    }
-    
-});
-
- /*
- * - LGPL
- *
- * Input
- * 
- */
-
-/**
- * @class Roo.bootstrap.SecurePass
- * @extends Roo.bootstrap.Input
- * Bootstrap SecurePass class
- *
- * 
- * @constructor
- * Create a new SecurePass
- * @param {Object} config The config object
- */
-Roo.bootstrap.SecurePass = function (config) {
-    // these go here, so the translation tool can replace them..
-    this.errors = {
-        PwdEmpty: "Please type a password, and then retype it to confirm.",
-        PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
-        PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
-        PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
-        IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
-        FNInPwd: "Your password can't contain your first name. Please type a different password.",
-        LNInPwd: "Your password can't contain your last name. Please type a different password.",
-        TooWeak: "Your password is Too Weak."
+        
+        
+        return ret;
+        
     },
-    this.meterLabel = "Password strength:";
-    this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
-    this.meterClass = [
-        "roo-password-meter-tooweak", 
-        "roo-password-meter-weak", 
-        "roo-password-meter-medium", 
-        "roo-password-meter-strong", 
-        "roo-password-meter-grey"
-    ];
     
-    this.errors = {};
     
-    Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
-}
-
-Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
-    /**
-     * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
-     * {
-     *  PwdEmpty: "Please type a password, and then retype it to confirm.",
-     *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
-     *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
-     *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
-     *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
-     *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
-     *  LNInPwd: "Your password can't contain your last name. Please type a different password."
-     * })
-     */
-    // private
     
-    meterWidth: 300,
-    errorMsg :'',    
-    errors: false,
-    imageRoot: '/',
-    /**
-     * @cfg {String/Object} Label for the strength meter (defaults to
-     * 'Password strength:')
-     */
-    // private
-    meterLabel: '',
-    /**
-     * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
-     * ['Weak', 'Medium', 'Strong'])
-     */
-    // private    
-    pwdStrengths: false,    
-    // private
-    strength: 0,
-    // private
-    _lastPwd: null,
-    // private
-    kCapitalLetter: 0,
-    kSmallLetter: 1,
-    kDigit: 2,
-    kPunctuation: 3,
     
-    insecure: false,
-    // private
-    initEvents: function ()
-    {
-        Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
-
-        if (this.el.is('input[type=password]') && Roo.isSafari) {
-            this.el.on('keydown', this.SafariOnKeyDown, this);
-        }
-
-        this.el.on('keyup', this.checkStrength, this, {buffer: 50});
-    },
-    // private
-    onRender: function (ct, position)
+    mergeRight: function()
     {
-        Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
-        this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
-        this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
-
-        this.trigger.createChild({
-                  cn: [
-                    {
-                    //id: 'PwdMeter',
-                    tag: 'div',
-                    cls: 'roo-password-meter-grey col-xs-12',
-                    style: {
-                        //width: 0,
-                        //width: this.meterWidth + 'px'                                                
-                        }
-                    },
-                    {                           
-                        cls: 'roo-password-meter-text'                          
-                    }
-                ]            
-        });
-
          
-        if (this.hideTrigger) {
-            this.trigger.setDisplayed(false);
-        }
-        this.setSize(this.width || '', this.height || '');
-    },
-    // private
-    onDestroy: function ()
-    {
-        if (this.trigger) {
-            this.trigger.removeAllListeners();
-            this.trigger.remove();
-        }
-        if (this.wrap) {
-            this.wrap.remove();
+        // get the contents of the next cell along..
+        var tr = this.node.closest('tr');
+        var i = Array.prototype.indexOf.call(tr.childNodes, this.node);
+        if (i >= tr.childNodes.length - 1) {
+            return; // no cells on right to merge with.
         }
-        Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
-    },
-    // private
-    checkStrength: function ()
-    {
-        var pwd = this.inputEl().getValue();
-        if (pwd == this._lastPwd) {
-            return;
+        var table = this.toTableArray();
+        
+        if (typeof(table[this.cellData.row][this.cellData.col+this.cellData.colspan]) == 'undefined') {
+            return; // nothing right?
         }
-
-        var strength;
-        if (this.ClientSideStrongPassword(pwd)) {
-            strength = 3;
-        } else if (this.ClientSideMediumPassword(pwd)) {
-            strength = 2;
-        } else if (this.ClientSideWeakPassword(pwd)) {
-            strength = 1;
-        } else {
-            strength = 0;
+        var rc = table[this.cellData.row][this.cellData.col+this.cellData.colspan];
+        // right cell - must be same rowspan and on the same row.
+        if (rc.rowspan != this.cellData.rowspan || rc.row != this.cellData.row) {
+            return; // right hand side is not same rowspan.
         }
         
-        Roo.log('strength1: ' + strength);
-        
-        //var pm = this.trigger.child('div/div/div').dom;
-        var pm = this.trigger.child('div/div');
-        pm.removeClass(this.meterClass);
-        pm.addClass(this.meterClass[strength]);
-                
-        
-        var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
-                
-        pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
-        
-        this._lastPwd = pwd;
-    },
-    reset: function ()
-    {
-        Roo.bootstrap.SecurePass.superclass.reset.call(this);
-        
-        this._lastPwd = '';
-        
-        var pm = this.trigger.child('div/div');
-        pm.removeClass(this.meterClass);
-        pm.addClass('roo-password-meter-grey');        
-        
         
-        var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
         
-        pt.innerHTML = '';
-        this.inputEl().dom.type='password';
+        this.node.innerHTML += ' ' + rc.cell.innerHTML;
+        tr.removeChild(rc.cell);
+        this.colspan += rc.colspan;
+        this.node.setAttribute('colspan', this.colspan);
+
     },
-    // private
-    validateValue: function (value)
+    
+    
+    mergeBelow : function()
     {
-        
-        if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
-            return false;
-        }
-        if (value.length == 0) {
-            if (this.allowBlank) {
-                this.clearInvalid();
-                return true;
-            }
-
-            this.markInvalid(this.errors.PwdEmpty);
-            this.errorMsg = this.errors.PwdEmpty;
-            return false;
+        var table = this.toTableArray();
+        if (typeof(table[this.cellData.row+this.cellData.rowspan]) == 'undefined') {
+            return; // no row below
         }
-        
-        if(this.insecure){
-            return true;
+        if (typeof(table[this.cellData.row+this.cellData.rowspan][this.cellData.col]) == 'undefined') {
+            return; // nothing right?
         }
+        var rc = table[this.cellData.row+this.cellData.rowspan][this.cellData.col];
         
-        if ('[\x21-\x7e]*'.match(value)) {
-            this.markInvalid(this.errors.PwdBadChar);
-            this.errorMsg = this.errors.PwdBadChar;
-            return false;
-        }
-        if (value.length < 6) {
-            this.markInvalid(this.errors.PwdShort);
-            this.errorMsg = this.errors.PwdShort;
-            return false;
+        if (rc.colspan != this.cellData.colspan || rc.col != this.cellData.col) {
+            return; // right hand side is not same rowspan.
         }
-        if (value.length > 16) {
-            this.markInvalid(this.errors.PwdLong);
-            this.errorMsg = this.errors.PwdLong;
-            return false;
-        }
-        var strength;
-        if (this.ClientSideStrongPassword(value)) {
-            strength = 3;
-        } else if (this.ClientSideMediumPassword(value)) {
-            strength = 2;
-        } else if (this.ClientSideWeakPassword(value)) {
-            strength = 1;
-        } else {
-            strength = 0;
+        this.node.innerHTML =  this.node.innerHTML + rc.cell.innerHTML ;
+        rc.cell.parentNode.removeChild(rc.cell);
+        this.rowspan += rc.rowspan;
+        this.node.setAttribute('rowspan', this.rowspan);
+    },
+    
+    split: function()
+    {
+        if (this.node.rowSpan < 2 && this.node.colSpan < 2) {
+            return;
         }
-
+        var table = this.toTableArray();
+        var cd = this.cellData;
+        this.rowspan = 1;
+        this.colspan = 1;
         
-        if (strength < 2) {
-            //this.markInvalid(this.errors.TooWeak);
-            this.errorMsg = this.errors.TooWeak;
-            //return false;
+        for(var r = cd.row; r < cd.row + cd.rowspan; r++) {
+            
+            
+            
+            for(var c = cd.col; c < cd.col + cd.colspan; c++) {
+                if (r == cd.row && c == cd.col) {
+                    this.node.removeAttribute('rowspan');
+                    this.node.removeAttribute('colspan');
+                    continue;
+                }
+                 
+                var ntd = this.node.cloneNode(); // which col/row should be 0..
+                ntd.removeAttribute('id'); //
+                //ntd.style.width  = '';
+                ntd.innerHTML = '';
+                table[r][c] = { cell : ntd, col : c, row: r , colspan : 1 , rowspan : 1   };
+            }
+            
         }
+        this.redrawAllCells(table);
         
+         
         
-        console.log('strength2: ' + strength);
-        
-        //var pm = this.trigger.child('div/div/div').dom;
-        
-        var pm = this.trigger.child('div/div');
-        pm.removeClass(this.meterClass);
-        pm.addClass(this.meterClass[strength]);
-                
-        var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
-                
-        pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
-        
-        this.errorMsg = ''; 
-        return true;
-    },
-    // private
-    CharacterSetChecks: function (type)
-    {
-        this.type = type;
-        this.fResult = false;
     },
-    // private
-    isctype: function (character, type)
+    
+    
+    
+    redrawAllCells: function(table)
     {
-        switch (type) {  
-            case this.kCapitalLetter:
-                if (character >= 'A' && character <= 'Z') {
-                    return true;
-                }
-                break;
-            
-            case this.kSmallLetter:
-                if (character >= 'a' && character <= 'z') {
-                    return true;
-                }
-                break;
+        
+         
+        var tab = this.node.closest('tr').closest('table');
+        var ctr = tab.rows[0].parentNode;
+        Array.from(tab.rows).forEach(function(r, ri){
             
-            case this.kDigit:
-                if (character >= '0' && character <= '9') {
-                    return true;
-                }
-                break;
+            Array.from(r.cells).forEach(function(ce, ci){
+                ce.parentNode.removeChild(ce);
+            });
+            r.parentNode.removeChild(r);
+        });
+        for(var r = 0 ; r < table.length; r++) {
+            var re = tab.rows[r];
             
-            case this.kPunctuation:
-                if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
-                    return true;
+            var re = tab.ownerDocument.createElement('tr');
+            ctr.appendChild(re);
+            for(var c = 0 ; c < table[r].length; c++) {
+                if (table[r][c].cell === false) {
+                    continue;
                 }
-                break;
-            
-            default:
-                return false;
+                
+                re.appendChild(table[r][c].cell);
+                 
+                table[r][c].cell = false;
+            }
         }
-
+        
     },
-    // private
-    IsLongEnough: function (pwd, size)
+    updateWidths : function(table)
     {
-        return !(pwd == null || isNaN(size) || pwd.length < size);
+        for(var r = 0 ; r < table.length; r++) {
+           
+            for(var c = 0 ; c < table[r].length; c++) {
+                if (table[r][c].cell === false) {
+                    continue;
+                }
+                
+                if (this.colWidths[0] != false && table[r][c].colspan < 2) {
+                    var el = Roo.htmleditor.Block.factory(table[r][c].cell);
+                    el.width = Math.floor(this.colWidths[c])  +'%';
+                    el.updateElement(el.node);
+                }
+                table[r][c].cell = false; // done
+            }
+        }
     },
-    // private
-    SpansEnoughCharacterSets: function (word, nb)
+    normalizeWidths : function(table)
     {
-        if (!this.IsLongEnough(word, nb))
-        {
-            return false;
+    
+        if (this.colWidths[0] === false) {
+            var nw = 100.0 / this.colWidths.length;
+            this.colWidths.forEach(function(w,i) {
+                this.colWidths[i] = nw;
+            },this);
+            return;
         }
-
-        var characterSetChecks = new Array(
-            new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
-            new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
-        );
+    
+        var t = 0, missing = [];
         
-        for (var index = 0; index < word.length; ++index) {
-            for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
-                if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
-                    characterSetChecks[nCharSet].fResult = true;
-                    break;
-                }
-            }
-        }
-
-        var nCharSets = 0;
-        for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
-            if (characterSetChecks[nCharSet].fResult) {
-                ++nCharSets;
+        this.colWidths.forEach(function(w,i) {
+            //if you mix % and
+            this.colWidths[i] = this.colWidths[i] == '' ? 0 : (this.colWidths[i]+'').replace(/[^0-9]+/g,'')*1;
+            var add =  this.colWidths[i];
+            if (add > 0) {
+                t+=add;
+                return;
             }
+            missing.push(i);
+            
+            
+        },this);
+        var nc = this.colWidths.length;
+        if (missing.length) {
+            var mult = (nc - missing.length) / (1.0 * nc);
+            var t = mult * t;
+            var ew = (100 -t) / (1.0 * missing.length);
+            this.colWidths.forEach(function(w,i) {
+                if (w > 0) {
+                    this.colWidths[i] = w * mult;
+                    return;
+                }
+                
+                this.colWidths[i] = ew;
+            }, this);
+            // have to make up numbers..
+             
         }
-
-        if (nCharSets < nb) {
-            return false;
+        // now we should have all the widths..
+        
+    
+    },
+    
+    shrinkColumn : function()
+    {
+        var table = this.toTableArray();
+        this.normalizeWidths(table);
+        var col = this.cellData.col;
+        var nw = this.colWidths[col] * 0.8;
+        if (nw < 5) {
+            return;
         }
-        return true;
+        var otherAdd = (this.colWidths[col]  * 0.2) / (this.colWidths.length -1);
+        this.colWidths.forEach(function(w,i) {
+            if (i == col) {
+                 this.colWidths[i] = nw;
+                return;
+            }
+            this.colWidths[i] += otherAdd
+        }, this);
+        this.updateWidths(table);
+         
     },
-    // private
-    ClientSideStrongPassword: function (pwd)
+    growColumn : function()
     {
-        return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
+        var table = this.toTableArray();
+        this.normalizeWidths(table);
+        var col = this.cellData.col;
+        var nw = this.colWidths[col] * 1.2;
+        if (nw > 90) {
+            return;
+        }
+        var otherSub = (this.colWidths[col]  * 0.2) / (this.colWidths.length -1);
+        this.colWidths.forEach(function(w,i) {
+            if (i == col) {
+                this.colWidths[i] = nw;
+                return;
+            }
+            this.colWidths[i] -= otherSub
+        }, this);
+        this.updateWidths(table);
+         
     },
-    // private
-    ClientSideMediumPassword: function (pwd)
+    deleteRow : function()
     {
-        return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
+        // delete this rows 'tr'
+        // if any of the cells in this row have a rowspan > 1 && row!= this row..
+        // then reduce the rowspan.
+        var table = this.toTableArray();
+        // this.cellData.row;
+        for (var i =0;i< table[this.cellData.row].length ; i++) {
+            var c = table[this.cellData.row][i];
+            if (c.row != this.cellData.row) {
+                
+                c.rowspan--;
+                c.cell.setAttribute('rowspan', c.rowspan);
+                continue;
+            }
+            if (c.rowspan > 1) {
+                c.rowspan--;
+                c.cell.setAttribute('rowspan', c.rowspan);
+            }
+        }
+        table.splice(this.cellData.row,1);
+        this.redrawAllCells(table);
+        
     },
-    // private
-    ClientSideWeakPassword: function (pwd)
+    deleteColumn : function()
     {
-        return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
+        var table = this.toTableArray();
+        
+        for (var i =0;i< table.length ; i++) {
+            var c = table[i][this.cellData.col];
+            if (c.col != this.cellData.col) {
+                table[i][this.cellData.col].colspan--;
+            } else if (c.colspan > 1) {
+                c.colspan--;
+                c.cell.setAttribute('colspan', c.colspan);
+            }
+            table[i].splice(this.cellData.col,1);
+        }
+        
+        this.redrawAllCells(table);
     }
-          
-})//<script type="text/javascript">
+    
+    
+    
+    
+})
+
+//<script type="text/javascript">
 
 /*
  * Based  Ext JS Library 1.1.1
@@ -23617,7 +28876,8 @@ Roo.HtmlEditorCore = function(config){
          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
          * @param {Roo.HtmlEditorCore} this
          */
-        editorevent: true
+        editorevent: true 
+         
         
     });
     
@@ -23653,13 +28913,32 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      * @cfg {Number} width (in pixels)
      */   
     width: 500,
+     /**
+     * @cfg {boolean} autoClean - default true - loading and saving will remove quite a bit of formating,
+     *         if you are doing an email editor, this probably needs disabling, it's designed
+     */
+    autoClean: true,
     
+    /**
+     * @cfg {boolean} enableBlocks - default true - if the block editor (table and figure should be enabled)
+     */
+    enableBlocks : true,
     /**
      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
      * 
      */
     stylesheets: false,
+     /**
+     * @cfg {String} language default en - language of text (usefull for rtl languages)
+     * 
+     */
+    language: 'en',
     
+    /**
+     * @cfg {boolean} allowComments - default false - allow comments in HTML source
+     *          - by default they are stripped - if you are editing email you may need this.
+     */
+    allowComments: false,
     // id of frame..
     frameId: false,
     
@@ -23681,6 +28960,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      
     bodyCls : '',
 
+    
+    undoManager : false,
     /**
      * Protected method that will not generally be called directly. It
      * is called when the editor initializes the iframe with HTML contents. Override this method if you
@@ -23706,23 +28987,29 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                 st = '<style type="text/css">' +
                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
                    '</style>';
-        } else { 
-            st = '<style type="text/css">' +
-                    this.stylesheets +
-                '</style>';
+        } else {
+            for (var i in this.stylesheets) {
+                if (typeof(this.stylesheets[i]) != 'string') {
+                    continue;
+                }
+                st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
+            }
+            
         }
         
         st +=  '<style type="text/css">' +
             'IMG { cursor: pointer } ' +
         '</style>';
-
-        var cls = 'roo-htmleditor-body';
+        
+        st += '<meta name="google" content="notranslate">';
+        
+        var cls = 'notranslate roo-htmleditor-body';
         
         if(this.bodyCls.length){
             cls += ' ' + this.bodyCls;
         }
         
-        return '<html><head>' + st  +
+        return '<html  class="notranslate" translate="no"><head>' + st  +
             //<style type="text/css">' +
             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
             //'</style>' +
@@ -23765,7 +29052,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         this.iframe = iframe.dom;
 
-         this.assignDocWin();
+        this.assignDocWin();
         
         this.doc.designMode = 'on';
        
@@ -23781,6 +29068,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                 if(this.doc.body || this.doc.readyState == 'complete'){
                     try {
                         this.doc.designMode="on";
+                        
                     } catch (e) {
                         return;
                     }
@@ -23828,10 +29116,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         if(this.sourceEditMode){
  
-            Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
+            Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']);     //FIXME - what's the BS styles for these
             
         }else{
-            Roo.get(this.iframe).removeClass(['x-hidden','hide']);
+            Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']);
             //this.iframe.className = '';
             this.deferFocus();
         }
@@ -23848,7 +29136,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      * @param {String} html The HTML to be cleaned
      * return {String} The cleaned HTML
      */
-    cleanHtml : function(html){
+    cleanHtml : function(html)
+    {
         html = String(html);
         if(html.length > 5){
             if(Roo.isSafari){ // strip safari nonsense
@@ -23866,11 +29155,40 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      * Protected method that will not generally be called directly. Syncs the contents
      * of the editor iframe with the textarea.
      */
-    syncValue : function(){
+    syncValue : function()
+    {
+        //Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)");
         if(this.initialized){
+            
+            if (this.undoManager) {
+                this.undoManager.addEvent();
+            }
+
+            
             var bd = (this.doc.body || this.doc.documentElement);
-            //this.cleanUpPaste(); -- this is done else where and causes havoc..
-            var html = bd.innerHTML;
+           
+            
+            var sel = this.win.getSelection();
+            
+            var div = document.createElement('div');
+            div.innerHTML = bd.innerHTML;
+            var gtx = div.getElementsByClassName('gtx-trans-icon'); // google translate - really annoying and difficult to get rid of.
+            if (gtx.length > 0) {
+                var rm = gtx.item(0).parentNode;
+                rm.parentNode.removeChild(rm);
+            }
+            
+           
+            if (this.enableBlocks) {
+                new Roo.htmleditor.FilterBlock({ node : div });
+            }
+            //?? tidy?
+            var tidy = new Roo.htmleditor.TidySerializer({
+                inner:  true
+            });
+            var html  = tidy.serialize(div);
+            
+            
             if(Roo.isSafari){
                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
@@ -23915,24 +29233,41 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     },
 
     /**
+     * TEXTAREA -> EDITABLE
      * Protected method that will not generally be called directly. Pushes the value of the textarea
      * into the iframe editor.
      */
-    pushValue : function(){
+    pushValue : function()
+    {
+        //Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)");
         if(this.initialized){
             var v = this.el.dom.value.trim();
             
-//            if(v.length < 1){
-//                v = '&#160;';
-//            }
             
             if(this.owner.fireEvent('beforepush', this, v) !== false){
                 var d = (this.doc.body || this.doc.documentElement);
                 d.innerHTML = v;
-                this.cleanUpPaste();
+                 
                 this.el.dom.value = d.innerHTML;
                 this.owner.fireEvent('push', this, v);
             }
+            if (this.autoClean) {
+                new Roo.htmleditor.FilterParagraph({node : this.doc.body}); // paragraphs
+                new Roo.htmleditor.FilterSpan({node : this.doc.body}); // empty spans
+            }
+            if (this.enableBlocks) {
+                Roo.htmleditor.Block.initAll(this.doc.body);
+            }
+            
+            this.updateLanguage();
+            
+            var lc = this.doc.body.lastChild;
+            if (lc && lc.nodeType == 1 && lc.getAttribute("contenteditable") == "false") {
+                // add an extra line at the end.
+                this.doc.body.appendChild(this.doc.createElement('br'));
+            }
+            
+            
         }
     },
 
@@ -23994,28 +29329,146 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
         //ss['background-attachment'] = 'fixed'; // w3c
         dbody.bgProperties = 'fixed'; // ie
+        dbody.setAttribute("translate", "no");
+        
         //Roo.DomHelper.applyStyles(dbody, ss);
         Roo.EventManager.on(this.doc, {
-            //'mousedown': this.onEditorEvent,
+             
             'mouseup': this.onEditorEvent,
             'dblclick': this.onEditorEvent,
             'click': this.onEditorEvent,
             'keyup': this.onEditorEvent,
+            
             buffer:100,
             scope: this
         });
+        Roo.EventManager.on(this.doc, {
+            'paste': this.onPasteEvent,
+            scope : this
+        });
         if(Roo.isGecko){
             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
         }
+        //??? needed???
         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
         }
         this.initialized = true;
 
+        
+        // initialize special key events - enter
+        new Roo.htmleditor.KeyEnter({core : this});
+        
+         
+        
         this.owner.fireEvent('initialize', this);
         this.pushValue();
     },
-
+    // this is to prevent a href clicks resulting in a redirect?
+   
+    onPasteEvent : function(e,v)
+    {
+        // I think we better assume paste is going to be a dirty load of rubish from word..
+        
+        // even pasting into a 'email version' of this widget will have to clean up that mess.
+        var cd = (e.browserEvent.clipboardData || window.clipboardData);
+        
+        // check what type of paste - if it's an image, then handle it differently.
+        if (cd.files && cd.files.length > 0) {
+            // pasting images?
+            var urlAPI = (window.createObjectURL && window) || 
+                (window.URL && URL.revokeObjectURL && URL) || 
+                (window.webkitURL && webkitURL);
+    
+            var url = urlAPI.createObjectURL( cd.files[0]);
+            this.insertAtCursor('<img src=" + url + ">');
+            return false;
+        }
+        if (cd.types.indexOf('text/html') < 0 ) {
+            return false;
+        }
+        var images = [];
+        var html = cd.getData('text/html'); // clipboard event
+        if (cd.types.indexOf('text/rtf') > -1) {
+            var parser = new Roo.rtf.Parser(cd.getData('text/rtf'));
+            images = parser.doc ? parser.doc.getElementsByType('pict') : [];
+        }
+        //Roo.log(images);
+        //Roo.log(imgs);
+        // fixme..
+        images = images.filter(function(g) { return !g.path.match(/^rtf\/(head|pgdsctbl|listtable|footerf)/); }) // ignore headers/footers etc.
+                       .map(function(g) { return g.toDataURL(); })
+                       .filter(function(g) { return g != 'about:blank'; });
+        
+        
+        html = this.cleanWordChars(html);
+        
+        var d = (new DOMParser().parseFromString(html, 'text/html')).body;
+        
+        
+        var sn = this.getParentElement();
+        // check if d contains a table, and prevent nesting??
+        //Roo.log(d.getElementsByTagName('table'));
+        //Roo.log(sn);
+        //Roo.log(sn.closest('table'));
+        if (d.getElementsByTagName('table').length && sn && sn.closest('table')) {
+            e.preventDefault();
+            this.insertAtCursor("You can not nest tables");
+            //Roo.log("prevent?"); // fixme - 
+            return false;
+        }
+        
+        if (images.length > 0) {
+            Roo.each(d.getElementsByTagName('img'), function(img, i) {
+                img.setAttribute('src', images[i]);
+            });
+        }
+        if (this.autoClean) {
+            new Roo.htmleditor.FilterWord({ node : d });
+            
+            new Roo.htmleditor.FilterStyleToTag({ node : d });
+            new Roo.htmleditor.FilterAttributes({
+                node : d,
+                attrib_white : ['href', 'src', 'name', 'align', 'colspan', 'rowspan', 'data-display', 'data-width'],
+                attrib_clean : ['href', 'src' ] 
+            });
+            new Roo.htmleditor.FilterBlack({ node : d, tag : this.black});
+            // should be fonts..
+            new Roo.htmleditor.FilterKeepChildren({node : d, tag : [ 'FONT', ':' ]} );
+            new Roo.htmleditor.FilterParagraph({ node : d });
+            new Roo.htmleditor.FilterSpan({ node : d });
+            new Roo.htmleditor.FilterLongBr({ node : d });
+            new Roo.htmleditor.FilterComment({ node : d });
+            
+            
+        }
+        if (this.enableBlocks) {
+                
+            Array.from(d.getElementsByTagName('img')).forEach(function(img) {
+                if (img.closest('figure')) { // assume!! that it's aready
+                    return;
+                }
+                var fig  = new Roo.htmleditor.BlockFigure({
+                    image_src  : img.src
+                });
+                fig.updateElement(img); // replace it..
+                
+            });
+        }
+        
+        
+        this.insertAtCursor(d.innerHTML.replace(/&nbsp;/g,' '));
+        if (this.enableBlocks) {
+            Roo.htmleditor.Block.initAll(this.doc.body);
+        }
+         
+        
+        e.preventDefault();
+        return false;
+        // default behaveiour should be our local cleanup paste? (optional?)
+        // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable..
+        //this.owner.fireEvent('paste', e, v);
+    },
     // private
     onDestroy : function(){
         
@@ -24037,7 +29490,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     onFirstFocus : function(){
         
         this.assignDocWin();
-        
+        this.undoManager = new Roo.lib.UndoManager(100,(this.doc.body || this.doc.documentElement));
         
         this.activated = true;
          
@@ -24082,10 +29535,48 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
 
     onEditorEvent : function(e)
     {
-        this.owner.fireEvent('editorevent', this, e);
+         
+        
+        if (e && (e.ctrlKey || e.metaKey) && e.keyCode === 90) {
+            return; // we do not handle this.. (undo manager does..)
+        }
+        // in theory this detects if the last element is not a br, then we try and do that.
+        // its so clicking in space at bottom triggers adding a br and moving the cursor.
+        if (e &&
+            e.target.nodeName == 'BODY' &&
+            e.type == "mouseup" &&
+            this.doc.body.lastChild
+           ) {
+            var lc = this.doc.body.lastChild;
+            // gtx-trans is google translate plugin adding crap.
+            while ((lc.nodeType == 3 && lc.nodeValue == '') || lc.id == 'gtx-trans') {
+                lc = lc.previousSibling;
+            }
+            if (lc.nodeType == 1 && lc.nodeName != 'BR') {
+            // if last element is <BR> - then dont do anything.
+            
+                var ns = this.doc.createElement('br');
+                this.doc.body.appendChild(ns);
+                range = this.doc.createRange();
+                range.setStartAfter(ns);
+                range.collapse(true);
+                var sel = this.win.getSelection();
+                sel.removeAllRanges();
+                sel.addRange(range);
+            }
+        }
+        
+        
+        
+        this.fireEditorEvent(e);
       //  this.updateToolbar();
         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
     },
+    
+    fireEditorEvent: function(e)
+    {
+        this.owner.fireEvent('editorevent', this, e);
+    },
 
     insertTag : function(tg)
     {
@@ -24107,7 +29598,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             
         }
         this.execCmd("formatblock",   tg);
-        
+        this.undoManager.addEvent(); 
     },
     
     insertText : function(txt)
@@ -24119,6 +29610,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                //alert(Sender.getAttribute('label'));
                
         range.insertNode(this.doc.createTextNode(txt));
+        this.undoManager.addEvent();
     } ,
     
      
@@ -24129,7 +29621,37 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
      * @param {String} cmd The Midas command
      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
      */
-    relayCmd : function(cmd, value){
+    relayCmd : function(cmd, value)
+    {
+        
+        switch (cmd) {
+            case 'justifyleft':
+            case 'justifyright':
+            case 'justifycenter':
+                // if we are in a cell, then we will adjust the
+                var n = this.getParentElement();
+                var td = n.closest('td');
+                if (td) {
+                    var bl = Roo.htmleditor.Block.factory(td);
+                    bl.textAlign = cmd.replace('justify','');
+                    bl.updateElement();
+                    this.owner.fireEvent('editorevent', this);
+                    return;
+                }
+                this.execCmd('styleWithCSS', true); // 
+                break;
+            case 'bold':
+            case 'italic':
+                // if there is no selection, then we insert, and set the curson inside it..
+                this.execCmd('styleWithCSS', false); 
+                break;
+                
+        
+            default:
+                break;
+        }
+        
+        
         this.win.focus();
         this.execCmd(cmd, value);
         this.owner.fireEvent('editorevent', this);
@@ -24162,20 +29684,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         if(!this.activated){
             return;
         }
-        /*
-        if(Roo.isIE){
-            this.win.focus();
-            var r = this.doc.selection.createRange();
-            if(r){
-                r.collapse(true);
-                r.pasteHTML(text);
-                this.syncValue();
-                this.deferFocus();
-            
-            }
-            return;
-        }
-        */
+         
         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
             this.win.focus();
             
@@ -24185,19 +29694,31 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             var win = this.win;
             
             if (win.getSelection && win.getSelection().getRangeAt) {
+                
+                // delete the existing?
+                
+                this.createRange(this.getSelection()).deleteContents();
                 range = win.getSelection().getRangeAt(0);
                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
                 range.insertNode(node);
+                range = range.cloneRange();
+                range.collapse(false);
+                 
+                win.getSelection().removeAllRanges();
+                win.getSelection().addRange(range);
+                
+                
+                
             } else if (win.document.selection && win.document.selection.createRange) {
                 // no firefox support
                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
                 win.document.selection.createRange().pasteHTML(txt);
+            
             } else {
                 // no firefox support
                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
                 this.execCmd('InsertHTML', txt);
             } 
-            
             this.syncValue();
             
             this.deferFocus();
@@ -24222,15 +29743,17 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                         cmd = 'underline';
                         break;
                     
-                    case 'v':
-                        this.cleanUpPaste.defer(100, this);
-                        return;
+                    //case 'v':
+                      //  this.cleanUpPaste.defer(100, this);
+                      //  return;
                         
                 }
                 if(cmd){
-                    this.win.focus();
-                    this.execCmd(cmd);
-                    this.deferFocus();
+                    
+                    this.relayCmd(cmd);
+                    //this.win.focus();
+                    //this.execCmd(cmd);
+                    //this.deferFocus();
                     e.preventDefault();
                 }
                 
@@ -24240,6 +29763,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
 
     // private
     fixKeys : function(){ // load time branching for fastest keydown performance
+        
+        
         if(Roo.isIE){
             return function(e){
                 var k = e.getKey(), r;
@@ -24253,23 +29778,25 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                     }
                     return;
                 }
-                
+                /// this is handled by Roo.htmleditor.KeyEnter
+                 /*
                 if(k == e.ENTER){
                     r = this.doc.selection.createRange();
                     if(r){
                         var target = r.parentElement();
                         if(!target || target.tagName.toLowerCase() != 'li'){
                             e.stopEvent();
-                            r.pasteHTML('<br />');
+                            r.pasteHTML('<br/>');
                             r.collapse(false);
                             r.select();
                         }
                     }
                 }
-                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
-                }
+                */
+                //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                //    this.cleanUpPaste.defer(100, this);
+                //    return;
+                //}
                 
                 
             };
@@ -24282,10 +29809,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
                     this.deferFocus();
                 }
-                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
-                }
+               
+                //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                //    this.cleanUpPaste.defer(100, this);
+                 //   return;
+                //}
                 
             };
         }else if(Roo.isSafari){
@@ -24298,10 +29826,12 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
                     this.deferFocus();
                     return;
                 }
-               if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
-                    this.cleanUpPaste.defer(100, this);
-                    return;
-                }
+                 this.mozKeyPress(e);
+                
+               //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
+                 //   this.cleanUpPaste.defer(100, this);
+                 //   return;
+               // }
                 
              };
         }
@@ -24331,7 +29861,27 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     getSelection : function() 
     {
         this.assignDocWin();
-        return Roo.isIE ? this.doc.selection : this.win.getSelection();
+        return Roo.lib.Selection.wrap(Roo.isIE ? this.doc.selection : this.win.getSelection(), this.doc);
+    },
+    /**
+     * Select a dom node
+     * @param {DomElement} node the node to select
+     */
+    selectNode : function(node, collapse)
+    {
+        var nodeRange = node.ownerDocument.createRange();
+        try {
+            nodeRange.selectNode(node);
+        } catch (e) {
+            nodeRange.selectNodeContents(node);
+        }
+        if (collapse === true) {
+            nodeRange.collapse(true);
+        }
+        //
+        var s = this.win.getSelection();
+        s.removeAllRanges();
+        s.addRange(nodeRange);
     },
     
     getSelectedNode: function() 
@@ -24340,8 +29890,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         // should we cache this!!!!
         
-        
-        
+         
          
         var range = this.createRange(this.getSelection()).cloneRange();
         
@@ -24405,6 +29954,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         return nodes[0];
     },
+    
+    
     createRange: function(sel)
     {
         // this has strange effects when using with 
@@ -24522,26 +30073,21 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         // fully contined.
         return 3;
     },
-
-    // private? - in a new class?
-    cleanUpPaste :  function()
-    {
-        // cleans up the whole document..
-        Roo.log('cleanuppaste');
-        
-        this.cleanUpChildren(this.doc.body);
-        var clean = this.cleanWordChars(this.doc.body.innerHTML);
-        if (clean != this.doc.body.innerHTML) {
-            this.doc.body.innerHTML = clean;
-        }
-        
-    },
-    
     cleanWordChars : function(input) {// change the chars to hex code
-        var he = Roo.HtmlEditorCore;
         
+       var swapCodes  = [ 
+            [    8211, "&#8211;" ], 
+            [    8212, "&#8212;" ], 
+            [    8216,  "'" ],  
+            [    8217, "'" ],  
+            [    8220, '"' ],  
+            [    8221, '"' ],  
+            [    8226, "*" ],  
+            [    8230, "..." ]
+        ]; 
         var output = input;
-        Roo.each(he.swapCodes, function(sw) { 
+        Roo.each(swapCodes, function(sw) { 
             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
             
             output = output.replace(swapper, sw[1]);
@@ -24550,482 +30096,61 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         return output;
     },
     
-    
-    cleanUpChildren : function (n)
-    {
-        if (!n.childNodes.length) {
-            return;
-        }
-        for (var i = n.childNodes.length-1; i > -1 ; i--) {
-           this.cleanUpChild(n.childNodes[i]);
-        }
-    },
-    
+     
     
         
     
     cleanUpChild : function (node)
     {
-        var ed = this;
-        //console.log(node);
-        if (node.nodeName == "#text") {
-            // clean up silly Windows -- stuff?
-            return; 
-        }
-        if (node.nodeName == "#comment") {
-            node.parentNode.removeChild(node);
-            // clean up silly Windows -- stuff?
-            return; 
-        }
-        var lcname = node.tagName.toLowerCase();
-        // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
-        // whitelist of tags..
-        
-        if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
-            // remove node.
-            node.parentNode.removeChild(node);
-            return;
-            
-        }
-        
-        var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
-        
-        // spans with no attributes - just remove them..
-        if ((!node.attributes || !node.attributes.length) && lcname == 'span') { 
-            remove_keep_children = true;
-        }
-        
-        // remove <a name=....> as rendering on yahoo mailer is borked with this.
-        // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
-        
-        //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
-        //    remove_keep_children = true;
-        //}
-        
-        if (remove_keep_children) {
-            this.cleanUpChildren(node);
-            // inserts everything just before this node...
-            while (node.childNodes.length) {
-                var cn = node.childNodes[0];
-                node.removeChild(cn);
-                node.parentNode.insertBefore(cn, node);
-            }
-            node.parentNode.removeChild(node);
-            return;
-        }
-        
-        if (!node.attributes || !node.attributes.length) {
-            
-          
-            
-            
-            this.cleanUpChildren(node);
-            return;
-        }
-        
-        function cleanAttr(n,v)
-        {
-            
-            if (v.match(/^\./) || v.match(/^\//)) {
-                return;
-            }
-            if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
-                return;
-            }
-            if (v.match(/^#/)) {
-                return;
-            }
-//            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
-            node.removeAttribute(n);
-            
-        }
-        
-        var cwhite = this.cwhite;
-        var cblack = this.cblack;
-            
-        function cleanStyle(n,v)
-        {
-            if (v.match(/expression/)) { //XSS?? should we even bother..
-                node.removeAttribute(n);
-                return;
-            }
-            
-            var parts = v.split(/;/);
-            var clean = [];
-            
-            Roo.each(parts, function(p) {
-                p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
-                if (!p.length) {
-                    return true;
-                }
-                var l = p.split(':').shift().replace(/\s+/g,'');
-                l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
-                
-                if ( cwhite.length && cblack.indexOf(l) > -1) {
-//                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
-                    //node.removeAttribute(n);
-                    return true;
-                }
-                //Roo.log()
-                // only allow 'c whitelisted system attributes'
-                if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
-//                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
-                    //node.removeAttribute(n);
-                    return true;
-                }
-                
-                
-                 
-                
-                clean.push(p);
-                return true;
-            });
-            if (clean.length) { 
-                node.setAttribute(n, clean.join(';'));
-            } else {
-                node.removeAttribute(n);
-            }
-            
-        }
-        
-        
-        for (var i = node.attributes.length-1; i > -1 ; i--) {
-            var a = node.attributes[i];
-            //console.log(a);
-            
-            if (a.name.toLowerCase().substr(0,2)=='on')  {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
-                node.removeAttribute(a.name);
-                continue;
-            }
-            if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
-                cleanAttr(a.name,a.value); // fixme..
-                continue;
-            }
-            if (a.name == 'style') {
-                cleanStyle(a.name,a.value);
-                continue;
-            }
-            /// clean up MS crap..
-            // tecnically this should be a list of valid class'es..
-            
-            
-            if (a.name == 'class') {
-                if (a.value.match(/^Mso/)) {
-                    node.removeAttribute('class');
-                }
-                
-                if (a.value.match(/^body$/)) {
-                    node.removeAttribute('class');
-                }
-                continue;
-            }
-            
-            // style cleanup!?
-            // class cleanup?
-            
-        }
-        
-        
-        this.cleanUpChildren(node);
         
+        new Roo.htmleditor.FilterComment({node : node});
+        new Roo.htmleditor.FilterAttributes({
+                node : node,
+                attrib_black : this.ablack,
+                attrib_clean : this.aclean,
+                style_white : this.cwhite,
+                style_black : this.cblack
+        });
+        new Roo.htmleditor.FilterBlack({ node : node, tag : this.black});
+        new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} );
+         
         
     },
     
     /**
      * Clean up MS wordisms...
+     * @deprecated - use filter directly
      */
     cleanWord : function(node)
     {
-        if (!node) {
-            this.cleanWord(this.doc.body);
-            return;
-        }
-        
-        if(
-                node.nodeName == 'SPAN' &&
-                !node.hasAttributes() &&
-                node.childNodes.length == 1 &&
-                node.firstChild.nodeName == "#text"  
-        ) {
-            var textNode = node.firstChild;
-            node.removeChild(textNode);
-            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
-                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
-            }
-            node.parentNode.insertBefore(textNode, node);
-            if (node.getAttribute('lang') != 'zh-CN') {   // do not space pad on chinese characters..
-                node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
-            }
-            node.parentNode.removeChild(node);
-        }
-        
-        if (node.nodeName == "#text") {
-            // clean up silly Windows -- stuff?
-            return; 
-        }
-        if (node.nodeName == "#comment") {
-            node.parentNode.removeChild(node);
-            // clean up silly Windows -- stuff?
-            return; 
-        }
-        
-        if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
-            node.parentNode.removeChild(node);
-            return;
-        }
-        //Roo.log(node.tagName);
-        // remove - but keep children..
-        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
-            //Roo.log('-- removed');
-            while (node.childNodes.length) {
-                var cn = node.childNodes[0];
-                node.removeChild(cn);
-                node.parentNode.insertBefore(cn, node);
-                // move node to parent - and clean it..
-                this.cleanWord(cn);
-            }
-            node.parentNode.removeChild(node);
-            /// no need to iterate chidlren = it's got none..
-            //this.iterateChildren(node, this.cleanWord);
-            return;
-        }
-        // clean styles
-        if (node.className.length) {
-            
-            var cn = node.className.split(/\W+/);
-            var cna = [];
-            Roo.each(cn, function(cls) {
-                if (cls.match(/Mso[a-zA-Z]+/)) {
-                    return;
-                }
-                cna.push(cls);
-            });
-            node.className = cna.length ? cna.join(' ') : '';
-            if (!cna.length) {
-                node.removeAttribute("class");
-            }
-        }
-        
-        if (node.hasAttribute("lang")) {
-            node.removeAttribute("lang");
-        }
-        
-        if (node.hasAttribute("style")) {
-            
-            var styles = node.getAttribute("style").split(";");
-            var nstyle = [];
-            Roo.each(styles, function(s) {
-                if (!s.match(/:/)) {
-                    return;
-                }
-                var kv = s.split(":");
-                if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
-                    return;
-                }
-                // what ever is left... we allow.
-                nstyle.push(s);
-            });
-            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
-            if (!nstyle.length) {
-                node.removeAttribute('style');
-            }
-        }
-        this.iterateChildren(node, this.cleanWord);
-        
-        
+        new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
+        new Roo.htmleditor.FilterKeepChildren({node : node ? node : this.doc.body, tag : [ 'FONT', ':' ]} );
         
     },
-    /**
-     * iterateChildren of a Node, calling fn each time, using this as the scole..
-     * @param {DomNode} node node to iterate children of.
-     * @param {Function} fn method of this class to call on each item.
-     */
-    iterateChildren : function(node, fn)
-    {
-        if (!node.childNodes.length) {
-                return;
-        }
-        for (var i = node.childNodes.length-1; i > -1 ; i--) {
-           fn.call(this, node.childNodes[i])
-        }
-    },
-    
+   
     
     /**
-     * cleanTableWidths.
-     *
-     * Quite often pasting from word etc.. results in tables with column and widths.
-     * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
-     *
+
+     * @deprecated - use filters
      */
     cleanTableWidths : function(node)
     {
-         
-         
-        if (!node) {
-            this.cleanTableWidths(this.doc.body);
-            return;
-        }
-        
-        // ignore list...
-        if (node.nodeName == "#text" || node.nodeName == "#comment") {
-            return; 
-        }
-        Roo.log(node.tagName);
-        if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
-            this.iterateChildren(node, this.cleanTableWidths);
-            return;
-        }
-        if (node.hasAttribute('width')) {
-            node.removeAttribute('width');
-        }
-        
-         
-        if (node.hasAttribute("style")) {
-            // pretty basic...
-            
-            var styles = node.getAttribute("style").split(";");
-            var nstyle = [];
-            Roo.each(styles, function(s) {
-                if (!s.match(/:/)) {
-                    return;
-                }
-                var kv = s.split(":");
-                if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
-                    return;
-                }
-                // what ever is left... we allow.
-                nstyle.push(s);
-            });
-            node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
-            if (!nstyle.length) {
-                node.removeAttribute('style');
-            }
-        }
-        
-        this.iterateChildren(node, this.cleanTableWidths);
-        
+        new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
         
     },
     
-    
-    
-    
-    domToHTML : function(currentElement, depth, nopadtext) {
-        
-        depth = depth || 0;
-        nopadtext = nopadtext || false;
-    
-        if (!currentElement) {
-            return this.domToHTML(this.doc.body);
-        }
-        
-        //Roo.log(currentElement);
-        var j;
-        var allText = false;
-        var nodeName = currentElement.nodeName;
-        var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
-        
-        if  (nodeName == '#text') {
-            
-            return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
-        }
-        
-        
-        var ret = '';
-        if (nodeName != 'BODY') {
-             
-            var i = 0;
-            // Prints the node tagName, such as <A>, <IMG>, etc
-            if (tagName) {
-                var attr = [];
-                for(i = 0; i < currentElement.attributes.length;i++) {
-                    // quoting?
-                    var aname = currentElement.attributes.item(i).name;
-                    if (!currentElement.attributes.item(i).value.length) {
-                        continue;
-                    }
-                    attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
-                }
-                
-                ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
-            } 
-            else {
-                
-                // eack
-            }
-        } else {
-            tagName = false;
-        }
-        if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
-            return ret;
-        }
-        if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
-            nopadtext = true;
-        }
-        
-        
-        // Traverse the tree
-        i = 0;
-        var currentElementChild = currentElement.childNodes.item(i);
-        var allText = true;
-        var innerHTML  = '';
-        lastnode = '';
-        while (currentElementChild) {
-            // Formatting code (indent the tree so it looks nice on the screen)
-            var nopad = nopadtext;
-            if (lastnode == 'SPAN') {
-                nopad  = true;
-            }
-            // text
-            if  (currentElementChild.nodeName == '#text') {
-                var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
-                toadd = nopadtext ? toadd : toadd.trim();
-                if (!nopad && toadd.length > 80) {
-                    innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
-                }
-                innerHTML  += toadd;
-                
-                i++;
-                currentElementChild = currentElement.childNodes.item(i);
-                lastNode = '';
-                continue;
-            }
-            allText = false;
-            
-            innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
-                
-            // Recursively traverse the tree structure of the child node
-            innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
-            lastnode = currentElementChild.nodeName;
-            i++;
-            currentElementChild=currentElement.childNodes.item(i);
-        }
-        
-        ret += innerHTML;
-        
-        if (!allText) {
-                // The remaining code is mostly for formatting the tree
-            ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
-        }
-        
-        
-        if (tagName) {
-            ret+= "</"+tagName+">";
-        }
-        return ret;
-        
-    },
+     
         
     applyBlacklists : function()
     {
         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
         
+        this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean :  Roo.HtmlEditorCore.aclean;
+        this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack :  Roo.HtmlEditorCore.ablack;
+        this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove :  Roo.HtmlEditorCore.tag_remove;
+        
         this.white = [];
         this.black = [];
         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
@@ -25143,6 +30268,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
     },
     
+    
+    updateLanguage : function()
+    {
+        if (!this.iframe || !this.iframe.contentDocument) {
+            return;
+        }
+        Roo.get(this.iframe.contentDocument.body).attr("lang", this.language);
+    },
+    
+    
     removeStylesheets : function()
     {
         var _this = this;
@@ -25207,36 +30342,40 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
 });
 
 Roo.HtmlEditorCore.white = [
-        'area', 'br', 'img', 'input', 'hr', 'wbr',
+        'AREA', 'BR', 'IMG', 'INPUT', 'HR', 'WBR',
         
-       'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
-       'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
-       'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
-       'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
-       'table',   'ul',         'xmp', 
+       'ADDRESS', 'BLOCKQUOTE', 'CENTER', 'DD',      'DIR',       'DIV', 
+       'DL',      'DT',         'H1',     'H2',      'H3',        'H4', 
+       'H5',      'H6',         'HR',     'ISINDEX', 'LISTING',   'MARQUEE', 
+       'MENU',    'MULTICOL',   'OL',     'P',       'PLAINTEXT', 'PRE', 
+       'TABLE',   'UL',         'XMP', 
        
-       'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
-      'thead',   'tr', 
+       'CAPTION', 'COL', 'COLGROUP', 'TBODY', 'TD', 'TFOOT', 'TH', 
+      'THEAD',   'TR', 
      
-      'dir', 'menu', 'ol', 'ul', 'dl',
+      'DIR', 'MENU', 'OL', 'UL', 'DL',
        
-      'embed',  'object'
+      'EMBED',  'OBJECT'
 ];
 
 
 Roo.HtmlEditorCore.black = [
     //    'embed',  'object', // enable - backend responsiblity to clean thiese
-        'applet', // 
-        'base',   'basefont', 'bgsound', 'blink',  'body', 
-        'frame',  'frameset', 'head',    'html',   'ilayer', 
-        'iframe', 'layer',  'link',     'meta',    'object',   
-        'script', 'style' ,'title',  'xml' // clean later..
+        'APPLET', // 
+        'BASE',   'BASEFONT', 'BGSOUND', 'BLINK',  'BODY', 
+        'FRAME',  'FRAMESET', 'HEAD',    'HTML',   'ILAYER', 
+        'IFRAME', 'LAYER',  'LINK',     'META',    'OBJECT',   
+        'SCRIPT', 'STYLE' ,'TITLE',  'XML',
+        //'FONT' // CLEAN LATER..
+        'COLGROUP', 'COL'   // messy tables.
+        
+        
 ];
-Roo.HtmlEditorCore.clean = [
-    'script', 'style', 'title', 'xml'
+Roo.HtmlEditorCore.clean = [ // ?? needed???
+     'SCRIPT', 'STYLE', 'TITLE', 'XML'
 ];
-Roo.HtmlEditorCore.remove = [
-    'font'
+Roo.HtmlEditorCore.tag_remove = [
+    'FONT', 'TBODY'  
 ];
 // attributes..
 
@@ -25267,16 +30406,7 @@ Roo.HtmlEditorCore.cblack= [
 ];
 
 
-Roo.HtmlEditorCore.swapCodes   =[ 
-    [    8211, "--" ], 
-    [    8212, "--" ], 
-    [    8216,  "'" ],  
-    [    8217, "'" ],  
-    [    8220, '"' ],  
-    [    8221, '"' ],  
-    [    8226, "*" ],  
-    [    8230, "..." ]
-]; 
+
 
     /*
  * - LGPL
@@ -25286,8 +30416,8 @@ Roo.HtmlEditorCore.swapCodes   =[
  */
 
 /**
- * @class Roo.bootstrap.HtmlEditor
- * @extends Roo.bootstrap.TextArea
+ * @class Roo.bootstrap.form.HtmlEditor
+ * @extends Roo.bootstrap.form.TextArea
  * Bootstrap HtmlEditor class
 
  * @constructor
@@ -25295,8 +30425,8 @@ Roo.HtmlEditorCore.swapCodes   =[
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.HtmlEditor = function(config){
-    Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
+Roo.bootstrap.form.HtmlEditor = function(config){
+    Roo.bootstrap.form.HtmlEditor.superclass.constructor.call(this, config);
     if (!this.toolbars) {
         this.toolbars = [];
     }
@@ -25381,7 +30511,7 @@ Roo.bootstrap.HtmlEditor = function(config){
 };
 
 
-Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
+Roo.extend(Roo.bootstrap.form.HtmlEditor, Roo.bootstrap.form.TextArea,  {
     
     
       /**
@@ -25445,20 +30575,20 @@ Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
         Roo.log('renewing');
         Roo.log("create toolbars");
         
-        this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
+        this.toolbars = [ new Roo.bootstrap.form.HtmlEditorToolbarStandard({editor: this} ) ];
         this.toolbars[0].render(this.toolbarContainer());
         
         return;
         
 //        if (!editor.toolbars || !editor.toolbars.length) {
-//            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
+//            editor.toolbars = [ new Roo.bootstrap.form.HtmlEditorToolbarStandard() ]; // can be empty?
 //        }
 //        
 //        for (var i =0 ; i < editor.toolbars.length;i++) {
 //            editor.toolbars[i] = Roo.factory(
 //                    typeof(editor.toolbars[i]) == 'string' ?
 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
-//                Roo.bootstrap.HtmlEditor);
+//                Roo.bootstrap.form.HtmlEditor);
 //            editor.toolbars[i].init(editor);
 //        }
     },
@@ -25469,7 +30599,7 @@ Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
     {
        // Roo.log("Call onRender: " + this.xtype);
         var _t = this;
-        Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
+        Roo.bootstrap.form.HtmlEditor.superclass.onRender.call(this, ct, position);
       
         this.wrap = this.inputEl().wrap({
             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
@@ -25511,7 +30641,7 @@ Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
     onResize : function(w, h)
     {
         Roo.log('resize: ' +w + ',' + h );
-        Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
+        Roo.bootstrap.form.HtmlEditor.superclass.onResize.apply(this, arguments);
         var ew = false;
         var eh = false;
         
@@ -25611,7 +30741,7 @@ Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
 //    clearInvalid : Roo.emptyFn,
 
     setValue : function(v){
-        Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
+        Roo.bootstrap.form.HtmlEditor.superclass.setValue.call(this, v);
         this.editorcore.pushValue();
     },
 
@@ -25713,18 +30843,20 @@ Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
    
    
       
-Roo.namespace('Roo.bootstrap.htmleditor');
+Roo.namespace('Roo.bootstrap.form.HtmlEditor');
 /**
- * @class Roo.bootstrap.HtmlEditorToolbar1
+ * @class Roo.bootstrap.form.HtmlEditorToolbarStandard
+ * @parent Roo.bootstrap.form.HtmlEditor
+ * @extends Roo.bootstrap.nav.Simplebar
  * Basic Toolbar
  * 
  * @example
  * Usage:
  *
- new Roo.bootstrap.HtmlEditor({
+ new Roo.bootstrap.form.HtmlEditor({
     ....
     toolbars : [
-        new Roo.bootstrap.HtmlEditorToolbar1({
+        new Roo.bootstrap.form.HtmlEditorToolbarStandard({
             disable : { fonts: 1 , format: 1, ..., ... , ...],
             btns : [ .... ]
         })
@@ -25739,7 +30871,7 @@ Roo.namespace('Roo.bootstrap.htmleditor');
  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
  */
  
-Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
+Roo.bootstrap.form.HtmlEditorToolbarStandard = function(config)
 {
     
     Roo.apply(this, config);
@@ -25751,7 +30883,7 @@ Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
         colors : true,
         specialElements : true
     });
-    Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
+    Roo.bootstrap.form.HtmlEditorToolbarStandard.superclass.constructor.call(this, config);
     
     this.editor = config.editor;
     this.editorcore = config.editor.editorcore;
@@ -25761,7 +30893,7 @@ Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
     // dont call parent... till later.
 }
-Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
+Roo.extend(Roo.bootstrap.form.HtmlEditorToolbarStandard, Roo.bootstrap.nav.Simplebar,  {
      
     bar : true,
     
@@ -25781,7 +30913,7 @@ Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,
     {
        // Roo.log("Call onRender: " + this.xtype);
         
-       Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
+       Roo.bootstrap.form.HtmlEditorToolbarStandard.superclass.onRender.call(this, ct, position);
        Roo.log(this.el);
        this.el.dom.style.marginBottom = '0';
        var _this = this;
@@ -25960,7 +31092,7 @@ Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,
         // hides menus... - so this cant be on a menu...
         Roo.bootstrap.MenuMgr.hideAll();
         */
-        Roo.bootstrap.MenuMgr.hideAll();
+        Roo.bootstrap.menu.Manager.hideAll();
         //this.editorsyncValue();
     },
     onFirstFocus: function() {
@@ -25998,553 +31130,102 @@ Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,
 
 
 
+/*
+ * - LGPL
+ */
 
 /**
- * @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.
+ * @class Roo.bootstrap.form.Markdown
+ * @extends Roo.bootstrap.form.TextArea
+ * Bootstrap Showdown editable area
+ * @cfg {string} content
+ * 
  * @constructor
+ * Create a new Showdown
  */
-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;
-    },
+Roo.bootstrap.form.Markdown = function(config){
+    Roo.bootstrap.form.Markdown.superclass.constructor.call(this, config);
+   
+};
 
-    /**
-     * Returns true if the selections are locked.
-     * @return {Boolean}
-     */
-    isLocked : function(){
-        return this.locked;
-    },
+Roo.extend(Roo.bootstrap.form.Markdown, Roo.bootstrap.form.TextArea,  {
     
+    editing :false,
     
-    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
+        Roo.bootstrap.form.TextArea.prototype.initEvents.call(this);
+        this.markdownEl = this.el.createChild({
+            cls : 'roo-markdown-area'
         });
-        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);
+        this.inputEl().addClass('d-none');
+        if (this.getValue() == '') {
+            this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
+            
+        } else {
+            this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
         }
+        this.markdownEl.on('click', this.toggleTextEdit, this);
+        this.on('blur', this.toggleTextEdit, this);
+        this.on('specialkey', this.resizeTextArea, this);
     },
-
-    /**
-     * 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)
+    
+    toggleTextEdit : function()
     {
-        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) {
+        var sh = this.markdownEl.getHeight();
+        this.inputEl().addClass('d-none');
+        this.markdownEl.addClass('d-none');
+        if (!this.editing) {
+            // show editor?
+            this.inputEl().setHeight(Math.min(500, Math.max(sh,(this.getValue().split("\n").length+1) * 30)));
+            this.inputEl().removeClass('d-none');
+            this.inputEl().focus();
+            this.editing = true;
             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){
-       
+        // show showdown...
+        this.updateMarkdown();
+        this.markdownEl.removeClass('d-none');
+        this.editing = false;
+        return;
     },
-    // private
-    handleMouseDown : function(e, t)
+    updateMarkdown : function()
     {
-           var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
-        if(this.isLocked() || rowIndex < 0 ){
+        if (this.getValue() == '') {
+            this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
             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);
         }
+        this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
     },
     
-    /**
-     * 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);
-        }
+    resizeTextArea: function () {
+        
+        var sh = 100;
+        Roo.log([sh, this.getValue().split("\n").length * 30]);
+        this.inputEl().setHeight(Math.min(500, Math.max(sh, (this.getValue().split("\n").length +1) * 30)));
     },
-
-    /**
-     * 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)
+    setValue : function(val)
     {
-           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);
+        Roo.bootstrap.form.TextArea.prototype.setValue.call(this,val);
+        if (!this.editing) {
+            this.updateMarkdown();
         }
+        
     },
-
-    /**
-     * Deselects a row.
-     * @param {Number} row The index of the row to deselect
-     */
-    deselectRow : function(index, preventViewNotify)
+    focus : function()
     {
-        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;
+        if (!this.editing) {
+            this.toggleTextEdit();
         }
         
-        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.
@@ -26557,7 +31238,7 @@ Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSe
  
 /**
  * @class Roo.bootstrap.PagingToolbar
- * @extends Roo.bootstrap.NavSimplebar
+ * @extends Roo.bootstrap.nav.Simplebar
  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
  * @constructor
  * Create a new PagingToolbar
@@ -26593,14 +31274,18 @@ Roo.bootstrap.PagingToolbar = function(config)
     if (Roo.bootstrap.version == 4) {
         this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
     } else {
-        this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
+        this.navgroup = new Roo.bootstrap.nav.Group({ cls: 'pagination' });
     }
     
 };
 
-Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
+Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.nav.Simplebar, {
     /**
-     * @cfg {Roo.data.Store} dataSource
+     * @cfg {Roo.bootstrap.Button} buttons[]
+     * Buttons for the toolbar
+     */
+     /**
+     * @cfg {Roo.data.Store} store
      * The underlying data store providing the paged data
      */
     /**
@@ -26772,7 +31457,7 @@ Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
     // private
     onLoad : function(ds, r, o)
     {
-        this.cursor = o.params.start ? o.params.start : 0;
+        this.cursor = o.params && o.params.start ? o.params.start : 0;
         
         var d = this.getPageData(),
             ap = d.activePage,
@@ -26800,8 +31485,14 @@ Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
     },
 
     // private
-    onLoadError : function(){
+    onLoadError : function(proxy, o){
         this.loading.enable();
+        if (this.ds.events.loadexception.listeners.length  < 2) {
+            // nothing has been assigned to loadexception except this...
+            // so 
+            Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
+
+        }
     },
 
     // private
@@ -27247,7 +31938,7 @@ Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
 });
 
  
-/*
+Roo.bootstrap.dash = {};/*
  * - LGPL
  *
  * numberBox
@@ -27385,6 +32076,7 @@ Roo.bootstrap.dash = Roo.bootstrap.dash || {};
 /**
  * @class Roo.bootstrap.dash.TabBox
  * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.dash.TabPane
  * Bootstrap TabBox class
  * @cfg {String} title Title of the TabBox
  * @cfg {String} icon Icon of the TabBox
@@ -27585,6 +32277,7 @@ Roo.bootstrap.dash = Roo.bootstrap.dash || {};
 /**
  * @class Roo.bootstrap.TabPane
  * @extends Roo.bootstrap.Component
+ * @children  Roo.bootstrap.Graph Roo.bootstrap.Column
  * Bootstrap TabPane class
  * @cfg {Boolean} active (false | true) Default false
  * @cfg {String} title title of panel
@@ -27658,409 +32351,6 @@ Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
  
 
 
- /*
- * - LGPL
- *
- * menu
- * 
- */
-Roo.bootstrap.menu = Roo.bootstrap.menu || {};
-
-/**
- * @class Roo.bootstrap.menu.Menu
- * @extends Roo.bootstrap.Component
- * Bootstrap Menu class - container for Menu
- * @cfg {String} html Text of the menu
- * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
- * @cfg {String} icon Font awesome icon
- * @cfg {String} pos Menu align to (top | bottom) default bottom
- * 
- * 
- * @constructor
- * Create a new Menu
- * @param {Object} config The config object
- */
-
-
-Roo.bootstrap.menu.Menu = function(config){
-    Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
-    
-    this.addEvents({
-        /**
-         * @event beforeshow
-         * Fires before this menu is displayed
-         * @param {Roo.bootstrap.menu.Menu} this
-         */
-        beforeshow : true,
-        /**
-         * @event beforehide
-         * Fires before this menu is hidden
-         * @param {Roo.bootstrap.menu.Menu} this
-         */
-        beforehide : true,
-        /**
-         * @event show
-         * Fires after this menu is displayed
-         * @param {Roo.bootstrap.menu.Menu} this
-         */
-        show : true,
-        /**
-         * @event hide
-         * Fires after this menu is hidden
-         * @param {Roo.bootstrap.menu.Menu} this
-         */
-        hide : true,
-        /**
-         * @event click
-         * Fires when this menu is clicked (or when the enter key is pressed while it is active)
-         * @param {Roo.bootstrap.menu.Menu} this
-         * @param {Roo.EventObject} e
-         */
-        click : true
-    });
-    
-};
-
-Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
-    
-    submenu : false,
-    html : '',
-    weight : 'default',
-    icon : false,
-    pos : 'bottom',
-    
-    
-    getChildContainer : function() {
-        if(this.isSubMenu){
-            return this.el;
-        }
-        
-        return this.el.select('ul.dropdown-menu', true).first();  
-    },
-    
-    getAutoCreate : function()
-    {
-        var text = [
-            {
-                tag : 'span',
-                cls : 'roo-menu-text',
-                html : this.html
-            }
-        ];
-        
-        if(this.icon){
-            text.unshift({
-                tag : 'i',
-                cls : 'fa ' + this.icon
-            })
-        }
-        
-        
-        var cfg = {
-            tag : 'div',
-            cls : 'btn-group',
-            cn : [
-                {
-                    tag : 'button',
-                    cls : 'dropdown-button btn btn-' + this.weight,
-                    cn : text
-                },
-                {
-                    tag : 'button',
-                    cls : 'dropdown-toggle btn btn-' + this.weight,
-                    cn : [
-                        {
-                            tag : 'span',
-                            cls : 'caret'
-                        }
-                    ]
-                },
-                {
-                    tag : 'ul',
-                    cls : 'dropdown-menu'
-                }
-            ]
-            
-        };
-        
-        if(this.pos == 'top'){
-            cfg.cls += ' dropup';
-        }
-        
-        if(this.isSubMenu){
-            cfg = {
-                tag : 'ul',
-                cls : 'dropdown-menu'
-            }
-        }
-       
-        return cfg;
-    },
-    
-    onRender : function(ct, position)
-    {
-        this.isSubMenu = ct.hasClass('dropdown-submenu');
-        
-        Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
-    },
-    
-    initEvents : function() 
-    {
-        if(this.isSubMenu){
-            return;
-        }
-        
-        this.hidden = true;
-        
-        this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
-        this.triggerEl.on('click', this.onTriggerPress, this);
-        
-        this.buttonEl = this.el.select('button.dropdown-button', true).first();
-        this.buttonEl.on('click', this.onClick, this);
-        
-    },
-    
-    list : function()
-    {
-        if(this.isSubMenu){
-            return this.el;
-        }
-        
-        return this.el.select('ul.dropdown-menu', true).first();
-    },
-    
-    onClick : function(e)
-    {
-        this.fireEvent("click", this, e);
-    },
-    
-    onTriggerPress  : function(e)
-    {   
-        if (this.isVisible()) {
-            this.hide();
-        } else {
-            this.show();
-        }
-    },
-    
-    isVisible : function(){
-        return !this.hidden;
-    },
-    
-    show : function()
-    {
-        this.fireEvent("beforeshow", this);
-        
-        this.hidden = false;
-        this.el.addClass('open');
-        
-        Roo.get(document).on("mouseup", this.onMouseUp, this);
-        
-        this.fireEvent("show", this);
-        
-        
-    },
-    
-    hide : function()
-    {
-        this.fireEvent("beforehide", this);
-        
-        this.hidden = true;
-        this.el.removeClass('open');
-        
-        Roo.get(document).un("mouseup", this.onMouseUp);
-        
-        this.fireEvent("hide", this);
-    },
-    
-    onMouseUp : function()
-    {
-        this.hide();
-    }
-    
-});
-
- /*
- * - LGPL
- *
- * menu item
- * 
- */
-Roo.bootstrap.menu = Roo.bootstrap.menu || {};
-
-/**
- * @class Roo.bootstrap.menu.Item
- * @extends Roo.bootstrap.Component
- * Bootstrap MenuItem class
- * @cfg {Boolean} submenu (true | false) default false
- * @cfg {String} html text of the item
- * @cfg {String} href the link
- * @cfg {Boolean} disable (true | false) default false
- * @cfg {Boolean} preventDefault (true | false) default true
- * @cfg {String} icon Font awesome icon
- * @cfg {String} pos Submenu align to (left | right) default right 
- * 
- * 
- * @constructor
- * Create a new Item
- * @param {Object} config The config object
- */
-
-
-Roo.bootstrap.menu.Item = function(config){
-    Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
-    this.addEvents({
-        /**
-         * @event mouseover
-         * Fires when the mouse is hovering over this menu
-         * @param {Roo.bootstrap.menu.Item} this
-         * @param {Roo.EventObject} e
-         */
-        mouseover : true,
-        /**
-         * @event mouseout
-         * Fires when the mouse exits this menu
-         * @param {Roo.bootstrap.menu.Item} this
-         * @param {Roo.EventObject} e
-         */
-        mouseout : true,
-        // raw events
-        /**
-         * @event click
-         * The raw click event for the entire grid.
-         * @param {Roo.EventObject} e
-         */
-        click : true
-    });
-};
-
-Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
-    
-    submenu : false,
-    href : '',
-    html : '',
-    preventDefault: true,
-    disable : false,
-    icon : false,
-    pos : 'right',
-    
-    getAutoCreate : function()
-    {
-        var text = [
-            {
-                tag : 'span',
-                cls : 'roo-menu-item-text',
-                html : this.html
-            }
-        ];
-        
-        if(this.icon){
-            text.unshift({
-                tag : 'i',
-                cls : 'fa ' + this.icon
-            })
-        }
-        
-        var cfg = {
-            tag : 'li',
-            cn : [
-                {
-                    tag : 'a',
-                    href : this.href || '#',
-                    cn : text
-                }
-            ]
-        };
-        
-        if(this.disable){
-            cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
-        }
-        
-        if(this.submenu){
-            cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
-            
-            if(this.pos == 'left'){
-                cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
-            }
-        }
-        
-        return cfg;
-    },
-    
-    initEvents : function() 
-    {
-        this.el.on('mouseover', this.onMouseOver, this);
-        this.el.on('mouseout', this.onMouseOut, this);
-        
-        this.el.select('a', true).first().on('click', this.onClick, this);
-        
-    },
-    
-    onClick : function(e)
-    {
-        if(this.preventDefault){
-            e.preventDefault();
-        }
-        
-        this.fireEvent("click", this, e);
-    },
-    
-    onMouseOver : function(e)
-    {
-        if(this.submenu && this.pos == 'left'){
-            this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
-        }
-        
-        this.fireEvent("mouseover", this, e);
-    },
-    
-    onMouseOut : function(e)
-    {
-        this.fireEvent("mouseout", this, e);
-    }
-});
-
-
- /*
- * - LGPL
- *
- * menu separator
- * 
- */
-Roo.bootstrap.menu = Roo.bootstrap.menu || {};
-
-/**
- * @class Roo.bootstrap.menu.Separator
- * @extends Roo.bootstrap.Component
- * Bootstrap Separator class
- * 
- * @constructor
- * Create a new Separator
- * @param {Object} config The config object
- */
-
-
-Roo.bootstrap.menu.Separator = function(config){
-    Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
-};
-
-Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
-    
-    getAutoCreate : function(){
-        var cfg = {
-            tag : 'li',
-            cls: 'divider'
-        };
-        
-        return cfg;
-    }
-   
-});
-
-
  /*
  * - LGPL
  *
@@ -28140,10 +32430,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;
             }
@@ -28157,7 +32456,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();
@@ -28220,11 +32519,11 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
     getAutoCreate : function(){
     
         var cfg = {
-           cls : 'tooltip',
+           cls : 'tooltip',   
            role : 'tooltip',
            cn : [
                 {
-                    cls : 'tooltip-arrow'
+                    cls : 'tooltip-arrow arrow'
                 },
                 {
                     cls : 'tooltip-inner'
@@ -28238,7 +32537,12 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
     {
         this.bindEl = el;
     },
-      
+    
+    initEvents : function()
+    {
+        this.arrowEl = this.el.select('.arrow', true).first();
+        this.innerEl = this.el.select('.tooltip-inner', true).first();
+    },
     
     enter : function () {
        
@@ -28292,7 +32596,8 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
         
         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
         
-        this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
+        this.el.removeClass(['fade','top','bottom', 'left', 'right','in',
+                             'bs-tooltip-top','bs-tooltip-bottom', 'bs-tooltip-left', 'bs-tooltip-right']);
         
         var placement = typeof this.placement == 'function' ?
             this.placement.call(this, this.el, on_el) :
@@ -28338,15 +32643,35 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
             }
             
             align = this.alignment[placement];
+            
+            this.arrowEl.setLeft((this.innerEl.getWidth()/2) - 5);
+            
         }
         
+        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], 
         
         this.el.addClass(placement);
+        this.el.addClass("bs-tooltip-"+ placement);
         
-        this.el.addClass('in fade');
+        this.el.addClass('in fade show');
         
         this.hoverState = null;
         
@@ -28354,6 +32679,10 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
             // fade it?
         }
         
+        
+        
+        
+        
     },
     hide : function()
     {
@@ -28362,7 +32691,7 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
             return;
         }
         //this.el.setXY([0,0]);
-        this.el.removeClass('in');
+        this.el.removeClass(['show', 'in']);
         //this.el.hide();
         
     }
@@ -28862,8 +33191,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
@@ -28881,7 +33213,10 @@ Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
     title: '',
     html: '',
     weight: false,
-    faicon: false,
+    fa: false,
+    faicon: false, // BC
+    close : false,
+    
     
     getAutoCreate : function()
     {
@@ -28890,6 +33225,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'
@@ -28911,6 +33253,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;
@@ -28922,45 +33267,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();   
@@ -31429,685 +35798,286 @@ Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
         
         image.on('click', this.onClick, this, file);
         
-        this.fireEvent('previewrendered', this, file);
-        
-        return file;
-        
-    },
-    
-    onPreviewLoad : function(file, image)
-    {
-        if(typeof(file.target) == 'undefined' || !file.target){
-            return;
-        }
-        
-        var width = image.dom.naturalWidth || image.dom.width;
-        var height = image.dom.naturalHeight || image.dom.height;
-        
-        if(!this.previewResize) {
-            return;
-        }
-        
-        if(width > height){
-            file.target.addClass('wide');
-            return;
-        }
-        
-        file.target.addClass('tall');
-        return;
-        
-    },
-    
-    uploadFromSource : function(file, crop)
-    {
-        this.xhr = new XMLHttpRequest();
-        
-        this.managerEl.createChild({
-            tag : 'div',
-            cls : 'roo-document-manager-loading',
-            cn : [
-                {
-                    tag : 'div',
-                    tooltip : file.name,
-                    cls : 'roo-document-manager-thumb',
-                    html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
-                }
-            ]
-
-        });
-
-        this.xhr.open(this.method, this.url, true);
-        
-        var headers = {
-            "Accept": "application/json",
-            "Cache-Control": "no-cache",
-            "X-Requested-With": "XMLHttpRequest"
-        };
-        
-        for (var headerName in headers) {
-            var headerValue = headers[headerName];
-            if (headerValue) {
-                this.xhr.setRequestHeader(headerName, headerValue);
-            }
-        }
-        
-        var _this = this;
-        
-        this.xhr.onload = function()
-        {
-            _this.xhrOnLoad(_this.xhr);
-        }
-        
-        this.xhr.onerror = function()
-        {
-            _this.xhrOnError(_this.xhr);
-        }
-        
-        var formData = new FormData();
-
-        formData.append('returnHTML', 'NO');
-        
-        formData.append('crop', crop);
-        
-        if(typeof(file.filename) != 'undefined'){
-            formData.append('filename', file.filename);
-        }
-        
-        if(typeof(file.mimetype) != 'undefined'){
-            formData.append('mimetype', file.mimetype);
-        }
-        
-        Roo.log(formData);
-        
-        if(this.fireEvent('prepare', this, formData) != false){
-            this.xhr.send(formData);
-        };
-    }
-});
-
-/*
-* Licence: LGPL
-*/
-
-/**
- * @class Roo.bootstrap.DocumentViewer
- * @extends Roo.bootstrap.Component
- * Bootstrap DocumentViewer class
- * @cfg {Boolean} showDownload (true|false) show download button (default true)
- * @cfg {Boolean} showTrash (true|false) show trash button (default true)
- * 
- * @constructor
- * Create a new DocumentViewer
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.DocumentViewer = function(config){
-    Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
-    
-    this.addEvents({
-        /**
-         * @event initial
-         * Fire after initEvent
-         * @param {Roo.bootstrap.DocumentViewer} this
-         */
-        "initial" : true,
-        /**
-         * @event click
-         * Fire after click
-         * @param {Roo.bootstrap.DocumentViewer} this
-         */
-        "click" : true,
-        /**
-         * @event download
-         * Fire after download button
-         * @param {Roo.bootstrap.DocumentViewer} this
-         */
-        "download" : true,
-        /**
-         * @event trash
-         * Fire after trash button
-         * @param {Roo.bootstrap.DocumentViewer} this
-         */
-        "trash" : true
-        
-    });
-};
-
-Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
-    
-    showDownload : true,
-    
-    showTrash : true,
-    
-    getAutoCreate : function()
-    {
-        var cfg = {
-            tag : 'div',
-            cls : 'roo-document-viewer',
-            cn : [
-                {
-                    tag : 'div',
-                    cls : 'roo-document-viewer-body',
-                    cn : [
-                        {
-                            tag : 'div',
-                            cls : 'roo-document-viewer-thumb',
-                            cn : [
-                                {
-                                    tag : 'img',
-                                    cls : 'roo-document-viewer-image'
-                                }
-                            ]
-                        }
-                    ]
-                },
-                {
-                    tag : 'div',
-                    cls : 'roo-document-viewer-footer',
-                    cn : {
-                        tag : 'div',
-                        cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
-                        cn : [
-                            {
-                                tag : 'div',
-                                cls : 'btn-group roo-document-viewer-download',
-                                cn : [
-                                    {
-                                        tag : 'button',
-                                        cls : 'btn btn-default',
-                                        html : '<i class="fa fa-download"></i>'
-                                    }
-                                ]
-                            },
-                            {
-                                tag : 'div',
-                                cls : 'btn-group roo-document-viewer-trash',
-                                cn : [
-                                    {
-                                        tag : 'button',
-                                        cls : 'btn btn-default',
-                                        html : '<i class="fa fa-trash"></i>'
-                                    }
-                                ]
-                            }
-                        ]
-                    }
-                }
-            ]
-        };
-        
-        return cfg;
-    },
-    
-    initEvents : function()
-    {
-        this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
-        this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
-        
-        this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
-        this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
-        
-        this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
-        this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
-        
-        this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
-        this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
-        
-        this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
-        this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
-        
-        this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
-        this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
-        
-        this.bodyEl.on('click', this.onClick, this);
-        this.downloadBtn.on('click', this.onDownload, this);
-        this.trashBtn.on('click', this.onTrash, this);
-        
-        this.downloadBtn.hide();
-        this.trashBtn.hide();
-        
-        if(this.showDownload){
-            this.downloadBtn.show();
-        }
-        
-        if(this.showTrash){
-            this.trashBtn.show();
-        }
-        
-        if(!this.showDownload && !this.showTrash) {
-            this.footerEl.hide();
-        }
-        
-    },
-    
-    initial : function()
-    {
-        this.fireEvent('initial', this);
-        
-    },
-    
-    onClick : function(e)
-    {
-        e.preventDefault();
-        
-        this.fireEvent('click', this);
-    },
-    
-    onDownload : function(e)
-    {
-        e.preventDefault();
-        
-        this.fireEvent('download', this);
-    },
-    
-    onTrash : function(e)
-    {
-        e.preventDefault();
-        
-        this.fireEvent('trash', this);
-    }
-    
-});
-/*
- * - LGPL
- *
- * nav progress bar
- * 
- */
-
-/**
- * @class Roo.bootstrap.NavProgressBar
- * @extends Roo.bootstrap.Component
- * Bootstrap NavProgressBar class
- * 
- * @constructor
- * Create a new nav progress bar
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.NavProgressBar = function(config){
-    Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
-
-    this.bullets = this.bullets || [];
-   
-//    Roo.bootstrap.NavProgressBar.register(this);
-     this.addEvents({
-        /**
-            * @event changed
-            * Fires when the active item changes
-            * @param {Roo.bootstrap.NavProgressBar} this
-            * @param {Roo.bootstrap.NavProgressItem} selected The item selected
-            * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
-         */
-        'changed': true
-     });
-    
-};
-
-Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
-    
-    bullets : [],
-    barItems : [],
-    
-    getAutoCreate : function()
-    {
-        var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
-        
-        cfg = {
-            tag : 'div',
-            cls : 'roo-navigation-bar-group',
-            cn : [
-                {
-                    tag : 'div',
-                    cls : 'roo-navigation-top-bar'
-                },
-                {
-                    tag : 'div',
-                    cls : 'roo-navigation-bullets-bar',
-                    cn : [
-                        {
-                            tag : 'ul',
-                            cls : 'roo-navigation-bar'
-                        }
-                    ]
-                },
-                
-                {
-                    tag : 'div',
-                    cls : 'roo-navigation-bottom-bar'
-                }
-            ]
-            
-        };
-        
-        return cfg;
-        
-    },
-    
-    initEvents: function() 
-    {
-        
-    },
-    
-    onRender : function(ct, position) 
-    {
-        Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
-        
-        if(this.bullets.length){
-            Roo.each(this.bullets, function(b){
-               this.addItem(b);
-            }, this);
-        }
-        
-        this.format();
-        
-    },
-    
-    addItem : function(cfg)
-    {
-        var item = new Roo.bootstrap.NavProgressItem(cfg);
-        
-        item.parentId = this.id;
-        item.render(this.el.select('.roo-navigation-bar', true).first(), null);
-        
-        if(cfg.html){
-            var top = new Roo.bootstrap.Element({
-                tag : 'div',
-                cls : 'roo-navigation-bar-text'
-            });
-            
-            var bottom = new Roo.bootstrap.Element({
-                tag : 'div',
-                cls : 'roo-navigation-bar-text'
-            });
-            
-            top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
-            bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
-            
-            var topText = new Roo.bootstrap.Element({
-                tag : 'span',
-                html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
-            });
-            
-            var bottomText = new Roo.bootstrap.Element({
-                tag : 'span',
-                html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
-            });
-            
-            topText.onRender(top.el, null);
-            bottomText.onRender(bottom.el, null);
-            
-            item.topEl = top;
-            item.bottomEl = bottom;
-        }
-        
-        this.barItems.push(item);
-        
-        return item;
-    },
-    
-    getActive : function()
-    {
-        var active = false;
-        
-        Roo.each(this.barItems, function(v){
-            
-            if (!v.isActive()) {
-                return;
-            }
-            
-            active = v;
-            return false;
-            
-        });
+        this.fireEvent('previewrendered', this, file);
+        
+        return file;
         
-        return active;
     },
     
-    setActiveItem : function(item)
+    onPreviewLoad : function(file, image)
     {
-        var prev = false;
+        if(typeof(file.target) == 'undefined' || !file.target){
+            return;
+        }
         
-        Roo.each(this.barItems, function(v){
-            if (v.rid == item.rid) {
-                return ;
-            }
-            
-            if (v.isActive()) {
-                v.setActive(false);
-                prev = v;
-            }
-        });
-
-        item.setActive(true);
+        var width = image.dom.naturalWidth || image.dom.width;
+        var height = image.dom.naturalHeight || image.dom.height;
+        
+        if(!this.previewResize) {
+            return;
+        }
+        
+        if(width > height){
+            file.target.addClass('wide');
+            return;
+        }
+        
+        file.target.addClass('tall');
+        return;
         
-        this.fireEvent('changed', this, item, prev);
     },
     
-    getBarItem: function(rid)
+    uploadFromSource : function(file, crop)
     {
-        var ret = false;
+        this.xhr = new XMLHttpRequest();
         
-        Roo.each(this.barItems, function(e) {
-            if (e.rid != rid) {
-                return;
-            }
-            
-            ret =  e;
-            return false;
+        this.managerEl.createChild({
+            tag : 'div',
+            cls : 'roo-document-manager-loading',
+            cn : [
+                {
+                    tag : 'div',
+                    tooltip : file.name,
+                    cls : 'roo-document-manager-thumb',
+                    html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
+                }
+            ]
+
         });
+
+        this.xhr.open(this.method, this.url, true);
         
-        return ret;
-    },
-    
-    indexOfItem : function(item)
-    {
-        var index = false;
+        var headers = {
+            "Accept": "application/json",
+            "Cache-Control": "no-cache",
+            "X-Requested-With": "XMLHttpRequest"
+        };
         
-        Roo.each(this.barItems, function(v, i){
-            
-            if (v.rid != item.rid) {
-                return;
+        for (var headerName in headers) {
+            var headerValue = headers[headerName];
+            if (headerValue) {
+                this.xhr.setRequestHeader(headerName, headerValue);
             }
-            
-            index = i;
-            return false
-        });
+        }
         
-        return index;
-    },
-    
-    setActiveNext : function()
-    {
-        var i = this.indexOfItem(this.getActive());
+        var _this = this;
         
-        if (i > this.barItems.length) {
-            return;
+        this.xhr.onload = function()
+        {
+            _this.xhrOnLoad(_this.xhr);
         }
         
-        this.setActiveItem(this.barItems[i+1]);
-    },
-    
-    setActivePrev : function()
-    {
-        var i = this.indexOfItem(this.getActive());
+        this.xhr.onerror = function()
+        {
+            _this.xhrOnError(_this.xhr);
+        }
         
-        if (i  < 1) {
-            return;
+        var formData = new FormData();
+
+        formData.append('returnHTML', 'NO');
+        
+        formData.append('crop', crop);
+        
+        if(typeof(file.filename) != 'undefined'){
+            formData.append('filename', file.filename);
         }
         
-        this.setActiveItem(this.barItems[i-1]);
-    },
-    
-    format : function()
-    {
-        if(!this.barItems.length){
-            return;
+        if(typeof(file.mimetype) != 'undefined'){
+            formData.append('mimetype', file.mimetype);
         }
-     
-        var width = 100 / this.barItems.length;
         
-        Roo.each(this.barItems, function(i){
-            i.el.setStyle('width', width + '%');
-            i.topEl.el.setStyle('width', width + '%');
-            i.bottomEl.el.setStyle('width', width + '%');
-        }, this);
+        Roo.log(formData);
         
+        if(this.fireEvent('prepare', this, formData) != false){
+            this.xhr.send(formData);
+        };
     }
-    
 });
+
 /*
- * - LGPL
- *
- * Nav Progress Item
- * 
- */
+* Licence: LGPL
+*/
 
 /**
- * @class Roo.bootstrap.NavProgressItem
+ * @class Roo.bootstrap.DocumentViewer
  * @extends Roo.bootstrap.Component
- * Bootstrap NavProgressItem class
- * @cfg {String} rid the reference id
- * @cfg {Boolean} active (true|false) Is item active default false
- * @cfg {Boolean} disabled (true|false) Is item active default false
- * @cfg {String} html
- * @cfg {String} position (top|bottom) text position default bottom
- * @cfg {String} icon show icon instead of number
+ * Bootstrap DocumentViewer class
+ * @cfg {Boolean} showDownload (true|false) show download button (default true)
+ * @cfg {Boolean} showTrash (true|false) show trash button (default true)
  * 
  * @constructor
- * Create a new NavProgressItem
+ * Create a new DocumentViewer
  * @param {Object} config The config object
  */
-Roo.bootstrap.NavProgressItem = function(config){
-    Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
+
+Roo.bootstrap.DocumentViewer = function(config){
+    Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
+    
     this.addEvents({
-        // raw events
+        /**
+         * @event initial
+         * Fire after initEvent
+         * @param {Roo.bootstrap.DocumentViewer} this
+         */
+        "initial" : true,
         /**
          * @event click
-         * The raw click event for the entire grid.
-         * @param {Roo.bootstrap.NavProgressItem} this
-         * @param {Roo.EventObject} e
+         * Fire after click
+         * @param {Roo.bootstrap.DocumentViewer} this
          */
-        "click" : true
+        "click" : true,
+        /**
+         * @event download
+         * Fire after download button
+         * @param {Roo.bootstrap.DocumentViewer} this
+         */
+        "download" : true,
+        /**
+         * @event trash
+         * Fire after trash button
+         * @param {Roo.bootstrap.DocumentViewer} this
+         */
+        "trash" : true
+        
     });
-   
 };
 
-Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
     
-    rid : '',
-    active : false,
-    disabled : false,
-    html : '',
-    position : 'bottom',
-    icon : false,
+    showDownload : true,
+    
+    showTrash : true,
     
     getAutoCreate : function()
     {
-        var iconCls = 'roo-navigation-bar-item-icon';
-        
-        iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
-        
         var cfg = {
-            tag: 'li',
-            cls: 'roo-navigation-bar-item',
+            tag : 'div',
+            cls : 'roo-document-viewer',
             cn : [
                 {
-                    tag : 'i',
-                    cls : iconCls
+                    tag : 'div',
+                    cls : 'roo-document-viewer-body',
+                    cn : [
+                        {
+                            tag : 'div',
+                            cls : 'roo-document-viewer-thumb',
+                            cn : [
+                                {
+                                    tag : 'img',
+                                    cls : 'roo-document-viewer-image'
+                                }
+                            ]
+                        }
+                    ]
+                },
+                {
+                    tag : 'div',
+                    cls : 'roo-document-viewer-footer',
+                    cn : {
+                        tag : 'div',
+                        cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
+                        cn : [
+                            {
+                                tag : 'div',
+                                cls : 'btn-group roo-document-viewer-download',
+                                cn : [
+                                    {
+                                        tag : 'button',
+                                        cls : 'btn btn-default',
+                                        html : '<i class="fa fa-download"></i>'
+                                    }
+                                ]
+                            },
+                            {
+                                tag : 'div',
+                                cls : 'btn-group roo-document-viewer-trash',
+                                cn : [
+                                    {
+                                        tag : 'button',
+                                        cls : 'btn btn-default',
+                                        html : '<i class="fa fa-trash"></i>'
+                                    }
+                                ]
+                            }
+                        ]
+                    }
                 }
             ]
         };
         
-        if(this.active){
-            cfg.cls += ' active';
-        }
-        if(this.disabled){
-            cfg.cls += ' disabled';
-        }
-        
         return cfg;
     },
     
-    disable : function()
-    {
-        this.setDisabled(true);
-    },
-    
-    enable : function()
-    {
-        this.setDisabled(false);
-    },
-    
-    initEvents: function() 
+    initEvents : function()
     {
-        this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
+        this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
+        this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
         
-        this.iconEl.on('click', this.onClick, this);
-    },
-    
-    onClick : function(e)
-    {
-        e.preventDefault();
+        this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
+        this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
         
-        if(this.disabled){
-            return;
+        this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
+        this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
+        
+        this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
+        this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
+        
+        this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
+        this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
+        
+        this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
+        this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
+        
+        this.bodyEl.on('click', this.onClick, this);
+        this.downloadBtn.on('click', this.onDownload, this);
+        this.trashBtn.on('click', this.onTrash, this);
+        
+        this.downloadBtn.hide();
+        this.trashBtn.hide();
+        
+        if(this.showDownload){
+            this.downloadBtn.show();
         }
         
-        if(this.fireEvent('click', this, e) === false){
-            return;
-        };
+        if(this.showTrash){
+            this.trashBtn.show();
+        }
+        
+        if(!this.showDownload && !this.showTrash) {
+            this.footerEl.hide();
+        }
         
-        this.parent().setActiveItem(this);
     },
     
-    isActive: function () 
+    initial : function()
     {
-        return this.active;
+        this.fireEvent('initial', this);
+        
     },
     
-    setActive : function(state)
+    onClick : function(e)
     {
-        if(this.active == state){
-            return;
-        }
-        
-        this.active = state;
-        
-        if (state) {
-            this.el.addClass('active');
-            return;
-        }
-        
-        this.el.removeClass('active');
+        e.preventDefault();
         
-        return;
+        this.fireEvent('click', this);
     },
     
-    setDisabled : function(state)
+    onDownload : function(e)
     {
-        if(this.disabled == state){
-            return;
-        }
-        
-        this.disabled = state;
-        
-        if (state) {
-            this.el.addClass('disabled');
-            return;
-        }
+        e.preventDefault();
         
-        this.el.removeClass('disabled');
+        this.fireEvent('download', this);
     },
     
-    tooltipEl : function()
+    onTrash : function(e)
     {
-        return this.el.select('.roo-navigation-bar-item-icon', true).first();;
+        e.preventDefault();
+        
+        this.fireEvent('trash', this);
     }
+    
 });
-
- /*
+/*
  * - LGPL
  *
  * FieldLabel
@@ -32115,7 +36085,7 @@ Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
  */
 
 /**
- * @class Roo.bootstrap.FieldLabel
+ * @class Roo.bootstrap.form.FieldLabel
  * @extends Roo.bootstrap.Component
  * Bootstrap FieldLabel class
  * @cfg {String} html contents of the element
@@ -32133,7 +36103,7 @@ Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.FieldLabel = function(config){
+Roo.bootstrap.form.FieldLabel = function(config){
     Roo.bootstrap.Element.superclass.constructor.call(this, config);
     
     this.addEvents({
@@ -32153,7 +36123,7 @@ Roo.bootstrap.FieldLabel = function(config){
         });
 };
 
-Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.form.FieldLabel, Roo.bootstrap.Component,  {
     
     tag: 'label',
     cls: '',
@@ -32222,7 +36192,7 @@ Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
             this.indicator.addClass('invisible');
         }
         
-        Roo.bootstrap.FieldLabel.register(this);
+        Roo.bootstrap.form.FieldLabel.register(this);
     },
     
     indicatorEl : function()
@@ -32283,13 +36253,13 @@ Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
    
 });
 
-Roo.apply(Roo.bootstrap.FieldLabel, {
+Roo.apply(Roo.bootstrap.form.FieldLabel, {
     
     groups: {},
     
      /**
     * register a FieldLabel Group
-    * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
+    * @param {Roo.bootstrap.form.FieldLabel} the FieldLabel to add
     */
     register : function(label)
     {
@@ -32303,7 +36273,7 @@ Roo.apply(Roo.bootstrap.FieldLabel, {
     /**
     * fetch a FieldLabel Group based on the target
     * @param {string} target
-    * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
+    * @returns {Roo.bootstrap.form.FieldLabel} the CheckBox group
     */
     get: function(target) {
         if (typeof(this.groups[target]) == 'undefined') {
@@ -32325,7 +36295,7 @@ Roo.apply(Roo.bootstrap.FieldLabel, {
 
 
 /**
- * @class Roo.bootstrap.DateSplitField
+ * @class Roo.bootstrap.form.DateSplitField
  * @extends Roo.bootstrap.Component
  * Bootstrap DateSplitField class
  * @cfg {string} fieldLabel - the label associated
@@ -32351,22 +36321,22 @@ Roo.apply(Roo.bootstrap.FieldLabel, {
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.DateSplitField = function(config){
-    Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
+Roo.bootstrap.form.DateSplitField = function(config){
+    Roo.bootstrap.form.DateSplitField.superclass.constructor.call(this, config);
     
     this.addEvents({
         // raw events
          /**
          * @event years
          * getting the data of years
-         * @param {Roo.bootstrap.DateSplitField} this
+         * @param {Roo.bootstrap.form.DateSplitField} this
          * @param {Object} years
          */
         "years" : true,
         /**
          * @event days
          * getting the data of days
-         * @param {Roo.bootstrap.DateSplitField} this
+         * @param {Roo.bootstrap.form.DateSplitField} this
          * @param {Object} days
          */
         "days" : true,
@@ -32386,7 +36356,7 @@ Roo.bootstrap.DateSplitField = function(config){
     });
 };
 
-Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
+Roo.extend(Roo.bootstrap.form.DateSplitField, Roo.bootstrap.Component,  {
     
     fieldLabel : '',
     labelAlign : 'top',
@@ -32492,11 +36462,11 @@ Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
     {
         var _this = this;
         
-        Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
+        Roo.bootstrap.DateSplitFiel.superclass.onRender.call(this, ct, position);
         
         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
         
-        this.dayField = new Roo.bootstrap.ComboBox({
+        this.dayField = new Roo.bootstrap.form.ComboBox({
             allowBlank : this.dayAllowBlank,
             alwaysQuery : true,
             displayField : 'value',
@@ -32528,7 +36498,7 @@ Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
 
         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
         
-        this.monthField = new Roo.bootstrap.MonthField({
+        this.monthField = new Roo.bootstrap.form.MonthField({
             after : '<i class=\"fa fa-calendar\"></i>',
             allowBlank : this.monthAllowBlank,
             placeholder : this.monthPlaceholder,
@@ -32550,7 +36520,7 @@ Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
         
         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
         
-        this.yearField = new Roo.bootstrap.ComboBox({
+        this.yearField = new Roo.bootstrap.form.ComboBox({
             allowBlank : this.yearAllowBlank,
             alwaysQuery : true,
             displayField : 'value',
@@ -32747,7 +36717,13 @@ Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
     
 });
 
- /**
+
+/**
+ * @class Roo.bootstrap.LayoutMasonry
+ * @extends Roo.bootstrap.Component
+ * @children Roo.bootstrap.Element Roo.bootstrap.Img Roo.bootstrap.MasonryBrick
+ * Bootstrap Layout Masonry class
  *
  * This is based on 
  * http://masonry.desandro.com
@@ -32755,15 +36731,7 @@ Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
  * The idea is to render all the bricks based on vertical width...
  *
  * The original code extends 'outlayer' - we might need to use that....
- * 
- */
 
-
-/**
- * @class Roo.bootstrap.LayoutMasonry
- * @extends Roo.bootstrap.Component
- * Bootstrap Layout Masonry class
- * 
  * @constructor
  * Create a new Element
  * @param {Object} config The config object
@@ -35334,8 +39302,8 @@ Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
  */
 
 /**
- * @class Roo.bootstrap.NumberField
- * @extends Roo.bootstrap.Input
+ * @class Roo.bootstrap.form.NumberField
+ * @extends Roo.bootstrap.form.Input
  * Bootstrap NumberField class
  * 
  * 
@@ -35346,11 +39314,11 @@ Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.NumberField = function(config){
-    Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
+Roo.bootstrap.form.NumberField = function(config){
+    Roo.bootstrap.form.NumberField.superclass.constructor.call(this, config);
 };
 
-Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
+Roo.extend(Roo.bootstrap.form.NumberField, Roo.bootstrap.form.Input, {
     
     /**
      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
@@ -35418,7 +39386,7 @@ Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
         
         this.name = '';
         
-        var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
+        var cfg = Roo.bootstrap.form.NumberField.superclass.getAutoCreate.call(this);
         
         this.name = hiddenInput.name;
         
@@ -35432,7 +39400,7 @@ Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
     // private
     initEvents : function()
     {   
-        Roo.bootstrap.NumberField.superclass.initEvents.call(this);
+        Roo.bootstrap.form.NumberField.superclass.initEvents.call(this);
         
         var allowed = "0123456789";
         
@@ -35479,7 +39447,7 @@ Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
     validateValue : function(value)
     {
         
-        if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
+        if(!Roo.bootstrap.form.NumberField.superclass.validateValue.call(this, value)){
             return false;
         }
         
@@ -35786,8 +39754,9 @@ Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
  */
 
 /**
- * @class Roo.bootstrap.RadioSet
- * @extends Roo.bootstrap.Input
+ * @class Roo.bootstrap.form.RadioSet
+ * @extends Roo.bootstrap.form.Input
+ * @children Roo.bootstrap.form.Radio
  * Bootstrap RadioSet class
  * @cfg {String} indicatorpos (left|right) default left
  * @cfg {Boolean} inline (true|false) inline the element (default true)
@@ -35797,27 +39766,27 @@ Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
  * @param {Object} config The config object
  */
 
-Roo.bootstrap.RadioSet = function(config){
+Roo.bootstrap.form.RadioSet = function(config){
     
-    Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
+    Roo.bootstrap.form.RadioSet.superclass.constructor.call(this, config);
     
     this.radioes = [];
     
-    Roo.bootstrap.RadioSet.register(this);
+    Roo.bootstrap.form.RadioSet.register(this);
     
     this.addEvents({
         /**
         * @event check
         * Fires when the element is checked or unchecked.
-        * @param {Roo.bootstrap.RadioSet} this This radio
-        * @param {Roo.bootstrap.Radio} item The checked item
+        * @param {Roo.bootstrap.form.RadioSet} this This radio
+        * @param {Roo.bootstrap.form.Radio} item The checked item
         */
        check : true,
        /**
         * @event click
         * Fires when the element is click.
-        * @param {Roo.bootstrap.RadioSet} this This radio set
-        * @param {Roo.bootstrap.Radio} item The checked item
+        * @param {Roo.bootstrap.form.RadioSet} this This radio set
+        * @param {Roo.bootstrap.form.Radio} item The checked item
         * @param {Roo.EventObject} e The event object
         */
        click : true
@@ -35825,7 +39794,7 @@ Roo.bootstrap.RadioSet = function(config){
     
 };
 
-Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
+Roo.extend(Roo.bootstrap.form.RadioSet, Roo.bootstrap.form.Input,  {
 
     radioes : false,
     
@@ -36101,7 +40070,7 @@ Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
     
 });
 
-Roo.apply(Roo.bootstrap.RadioSet, {
+Roo.apply(Roo.bootstrap.form.RadioSet, {
     
     groups: {},
     
@@ -36571,7 +40540,7 @@ Roo.bootstrap.SplitBar.TOP = 3;
  * @type Number
  */
 Roo.bootstrap.SplitBar.BOTTOM = 4;
-Roo.namespace("Roo.bootstrap.layout");/*
+/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -36585,10 +40554,13 @@ Roo.namespace("Roo.bootstrap.layout");/*
 /**
  * @class Roo.bootstrap.layout.Manager
  * @extends Roo.bootstrap.Component
+ * @abstract
  * Base class for layout managers.
  */
 Roo.bootstrap.layout.Manager = function(config)
 {
+    this.monitorWindowResize = true; // do this before we apply configuration.
+    
     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
 
 
@@ -36596,7 +40568,7 @@ Roo.bootstrap.layout.Manager = function(config)
 
 
     /** false to disable window resize monitoring @type Boolean */
-    this.monitorWindowResize = true;
+    
     this.regions = {};
     this.addEvents({
         /**
@@ -36773,6 +40745,8 @@ Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
 /**
  * @class Roo.bootstrap.layout.Border
  * @extends Roo.bootstrap.layout.Manager
+ * @children Roo.bootstrap.panel.Content Roo.bootstrap.panel.Nest Roo.bootstrap.panel.Grid
+ * @parent builder Roo.bootstrap.panel.Nest Roo.bootstrap.panel.Nest Roo.bootstrap.Modal
  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
  * please see: examples/bootstrap/nested.html<br><br>
  
@@ -36800,10 +40774,29 @@ Roo.bootstrap.layout.Border = function(config){
     
 };
 
-Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
+Roo.bootstrap.layout.Border.regions =  ["center", "north","south","east","west"];
 
 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
     
+       /**
+        * @cfg {Roo.bootstrap.layout.Region} center region to go in center
+        */
+       /**
+        * @cfg {Roo.bootstrap.layout.Region} west region to go in west
+        */
+       /**
+        * @cfg {Roo.bootstrap.layout.Region} east region to go in east
+        */
+       /**
+        * @cfg {Roo.bootstrap.layout.Region} south region to go in south
+        */
+       /**
+        * @cfg {Roo.bootstrap.layout.Region} north region to go in north
+        */
+       
+       
+       
+       
     parent : false, // this might point to a 'nest' or a ???
     
     /**
@@ -38731,16 +42724,25 @@ Roo.bootstrap.layout.North = function(config)
         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
         this.split.el.addClass("roo-layout-split-v");
     }
-    var size = config.initialSize || config.height;
-    if(typeof size != "undefined"){
-        this.el.setHeight(size);
-    }
+    //var size = config.initialSize || config.height;
+    //if(this.el && typeof size != "undefined"){
+    //    this.el.setHeight(size);
+    //}
 };
 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
 {
     orientation: Roo.bootstrap.SplitBar.VERTICAL,
+     
+     
+    onRender : function(ctr, pos)
+    {
+        Roo.bootstrap.layout.Split.prototype.onRender.call(this, ctr, pos);
+        var size = this.config.initialSize || this.config.height;
+        if(this.el && typeof size != "undefined"){
+            this.el.setHeight(size);
+        }
     
-    
+    },
     
     getBox : function(){
         if(this.collapsed){
@@ -38780,14 +42782,22 @@ Roo.bootstrap.layout.South = function(config){
         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
         this.split.el.addClass("roo-layout-split-v");
     }
-    var size = config.initialSize || config.height;
-    if(typeof size != "undefined"){
-        this.el.setHeight(size);
-    }
+    
 };
 
 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
     orientation: Roo.bootstrap.SplitBar.VERTICAL,
+    
+    onRender : function(ctr, pos)
+    {
+        Roo.bootstrap.layout.Split.prototype.onRender.call(this, ctr, pos);
+        var size = this.config.initialSize || this.config.height;
+        if(this.el && typeof size != "undefined"){
+            this.el.setHeight(size);
+        }
+    
+    },
+    
     getBox : function(){
         if(this.collapsed){
             return this.collapsedEl.getBox();
@@ -38826,13 +42836,21 @@ Roo.bootstrap.layout.East = function(config){
         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
         this.split.el.addClass("roo-layout-split-h");
     }
-    var size = config.initialSize || config.width;
-    if(typeof size != "undefined"){
-        this.el.setWidth(size);
-    }
+    
 };
 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
+    
+    onRender : function(ctr, pos)
+    {
+        Roo.bootstrap.layout.Split.prototype.onRender.call(this, ctr, pos);
+        var size = this.config.initialSize || this.config.width;
+        if(this.el && typeof size != "undefined"){
+            this.el.setWidth(size);
+        }
+    
+    },
+    
     getBox : function(){
         if(this.collapsed){
             return this.collapsedEl.getBox();
@@ -38891,6 +42909,9 @@ Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
             return this.collapsedEl.getBox();
         }
         var box = this.el.getBox();
+        if (box.width == 0) {
+            box.width = this.config.width; // kludge?
+        }
         if(this.split){
             box.width += this.split.el.getWidth();
         }
@@ -38910,7 +42931,7 @@ Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
         }
         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
     }
-});Roo.namespace("Roo.bootstrap.panel");/*
+});/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -38921,9 +42942,11 @@ Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
  * <script type="text/javascript">
  */
 /**
- * @class Roo.ContentPanel
+ * @class Roo.bootstrap.paenl.Content
  * @extends Roo.util.Observable
- * A basic ContentPanel element.
+ * @children Roo.bootstrap.Component
+ * @parent builder Roo.bootstrap.layout.Border
+ * A basic ContentPanel element. - a panel that contain any content (eg. forms etc.)
  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
  * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
@@ -38935,18 +42958,19 @@ Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
  * @cfg {String} title          The title for this panel
  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
  * @cfg {String} url            Calls {@link #setUrl} with this value
- * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
+ * @cfg {String} region  [required] (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
+ * @cfg {Boolean} iframe      contents are an iframe - makes showing remote sources/CSS feasible..
  * @cfg {Boolean} badges render the badges
-
+ * @cfg {String} cls  extra classes to use  
+ * @cfg {String} background (primary|secondary|success|info|warning|danger|light|dark)
  * @constructor
  * Create a new ContentPanel.
- * @param {String/HTMLElement/Roo.Element} el The container element for this panel
  * @param {String/Object} config A string to set only the title or a config object
- * @param {String} content (optional) Set the HTML content for this panel
- * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
  */
 Roo.bootstrap.panel.Content = function( config){
     
@@ -38967,16 +42991,33 @@ Roo.bootstrap.panel.Content = function( config){
             this.el = Roo.DomHelper.append(document.body,
                         config.autoCreate, true);
         }else{
-            var elcfg =  {   tag: "div",
-                            cls: "roo-layout-inactive-content",
-                            id: config.id||el
-                            };
+            var elcfg =  {
+                tag: "div",
+                cls: (config.cls || '') +
+                    (config.background ? ' bg-' + config.background : '') +
+                    " roo-layout-inactive-content",
+                id: config.id||el
+            };
+            if (config.iframe) {
+                elcfg.cn = [
+                    {
+                        tag : 'iframe',
+                        style : 'border: 0px',
+                        src : 'about:blank'
+                    }
+                ];
+            }
+              
             if (config.html) {
                 elcfg.html = config.html;
                 
             }
                         
             this.el = Roo.DomHelper.append(document.body, elcfg , true);
+            if (config.iframe) {
+                this.iframeEl = this.el.select('iframe',true).first();
+            }
+            
         }
     } 
     this.closable = false;
@@ -39064,7 +43105,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
         
         
         
@@ -39073,8 +43122,9 @@ Roo.bootstrap.panel.Content = function( config){
 
     
     
-    if(this.autoScroll){
+    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() {
@@ -39106,8 +43156,17 @@ Roo.bootstrap.panel.Content = function( config){
 
 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
     
+    cls : '',
+    background : '',
+    
     tabTip : '',
     
+    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);
@@ -39147,15 +43206,21 @@ Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
         return true;
     },
     /**
-     * Updates this panel's element
+     * Updates this panel's element (not for iframe)
      * @param {String} content The new content
      * @param {Boolean} loadScripts (optional) true to look for and process scripts
     */
     setContent : function(content, loadScripts){
+        if (this.iframe) {
+            return;
+        }
+        
         this.el.update(content, loadScripts);
     },
 
-    ignoreResize : function(w, h){
+    ignoreResize : function(w, h)
+    {
+        //return false; // always resize?
         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
             return true;
         }else{
@@ -39168,10 +43233,14 @@ Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
      * @return {Roo.UpdateManager} The UpdateManager
      */
     getUpdateManager : function(){
+        if (this.iframe) {
+            return false;
+        }
         return this.el.getUpdateManager();
     },
      /**
      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
+     * Does not work with IFRAME contents
      * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
 <pre><code>
 panel.load({
@@ -39186,6 +43255,7 @@ panel.load({
     scripts: false
 });
 </code></pre>
+     
      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
      * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
      * @param {String/Object} params (optional) The parameters to pass as either a URL encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
@@ -39194,6 +43264,11 @@ panel.load({
      * @return {Roo.ContentPanel} this
      */
     load : function(){
+        
+        if (this.iframe) {
+            return this;
+        }
+        
         var um = this.el.getUpdateManager();
         um.update.apply(um, arguments);
         return this;
@@ -39205,9 +43280,14 @@ panel.load({
      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
      * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
      * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
-     * @return {Roo.UpdateManager} The UpdateManager
+     * @return {Roo.UpdateManager|Boolean} The UpdateManager or false if IFRAME
      */
     setUrl : function(url, params, loadOnce){
+        if (this.iframe) {
+            this.iframeEl.dom.src = url;
+            return false;
+        }
+        
         if(this.refreshDelegate){
             this.removeListener("activate", this.refreshDelegate);
         }
@@ -39277,8 +43357,14 @@ panel.load({
                 this.el.setSize(width, height);
             }
             var size = this.adjustForComponents(width, height);
+            if (this.iframe) {
+                this.iframeEl.setSize(width,height);
+            }
+            
             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
             this.fireEvent('resize', this, size.width, size.height);
+            
+            
         }
     },
     
@@ -39392,6 +43478,12 @@ layout.addxtype({
     
     getChildContainer: function () {
         return this.getEl();
+    },
+    
+    
+    onScroll : function(e)
+    {
+        this.fireEvent('scroll', this, e);
     }
     
     
@@ -39442,6 +43534,7 @@ layout.addxtype({
  * @constructor
  * Create a new GridPanel.
  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
+ * @cfg {Roo.bootstrap.nav.Simplebar} toolbar the toolbar at the top of the grid.
  * @param {Object} config A the config object
   
  */
@@ -39532,7 +43625,9 @@ Roo.bootstrap.panel.Grid = function(config)
      
 };
 
-Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
+Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content,
+{
+  
     getId : function(){
         return this.grid.id;
     },
@@ -39545,21 +43640,39 @@ Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
         return this.grid;    
     },
     
-    setSize : function(width, height){
-        if(!this.ignoreResize(width, height)){
+    setSize : function(width, height)
+    {
+     
+        //if(!this.ignoreResize(width, height)){
             var grid = this.grid;
             var size = this.adjustForComponents(width, height);
+            // tfoot is not a footer?
+          
+            
             var gridel = grid.getGridEl();
             gridel.setSize(size.width, size.height);
-            /*
-            var thd = grid.getGridEl().select('thead',true).first();
+            
             var tbd = grid.getGridEl().select('tbody', true).first();
-            if (tbd) {
-                tbd.setSize(width, height - thd.getHeight());
+            var thd = grid.getGridEl().select('thead',true).first();
+            var tbf= grid.getGridEl().select('tfoot', true).first();
+
+            if (tbf) {
+                size.height -= tbf.getHeight();
             }
-            */
+            if (thd) {
+                size.height -= thd.getHeight();
+            }
+            
+            tbd.setSize(size.width, size.height );
+            // this is for the account management tab -seems to work there.
+            var thd = grid.getGridEl().select('thead',true).first();
+            //if (tbd) {
+            //    tbd.setSize(size.width, size.height - thd.getHeight());
+            //}
+             
             grid.autoSize();
-        }
+        //}
+   
     },
      
     
@@ -39586,7 +43699,6 @@ Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
  * Create a new Panel, that can contain a layout.Border.
  * 
  * 
- * @param {Roo.BorderLayout} layout The layout for this panel
  * @param {String/Object} config A string to set only the title or a config object
  */
 Roo.bootstrap.panel.Nest = function(config)
@@ -39619,6 +43731,10 @@ Roo.bootstrap.panel.Nest = function(config)
 };
 
 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
+    /**
+    * @cfg {Roo.BorderLayout} layout The layout for this panel
+    */
+    layout : false,
 
     setSize : function(width, height){
         if(!this.ignoreResize(width, height)){
@@ -40652,7 +44768,7 @@ Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
 *    Availability: https://github.com/jackocnr/intl-tel-input.git
 **/
 
-Roo.bootstrap.PhoneInputData = function() {
+Roo.bootstrap.form.PhoneInputData = function() {
     var d = [
       [
         "Afghanistan (‫افغانستان‬‎)",
@@ -41912,8 +46028,8 @@ Roo.bootstrap.PhoneInputData = function() {
 **/
 
 /**
- * @class Roo.bootstrap.PhoneInput
- * @extends Roo.bootstrap.TriggerField
+ * @class Roo.bootstrap.form.PhoneInput
+ * @extends Roo.bootstrap.form.TriggerField
  * An input with International dial-code selection
  
  * @cfg {String} defaultDialCode default '+852'
@@ -41924,12 +46040,14 @@ Roo.bootstrap.PhoneInputData = function() {
  * @param {Object} config Configuration options
  */
 
-Roo.bootstrap.PhoneInput = function(config) {
-    Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
+Roo.bootstrap.form.PhoneInput = function(config) {
+    Roo.bootstrap.form.PhoneInput.superclass.constructor.call(this, config);
 };
 
-Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
-        
+Roo.extend(Roo.bootstrap.form.PhoneInput, Roo.bootstrap.form.TriggerField, {
+        /**
+        * @cfg {Roo.data.Store} store [required] The data store to which this combo is bound (defaults to undefined)
+        */
         listWidth: undefined,
         
         selectedClass: 'active',
@@ -41954,7 +46072,7 @@ Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
         
         getAutoCreate : function()
         {
-            var data = Roo.bootstrap.PhoneInputData();
+            var data = Roo.bootstrap.form.PhoneInputData();
             var align = this.labelAlign || this.parentLabelAlign();
             var id = Roo.id();
             
@@ -42182,7 +46300,7 @@ Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
         initEvents : function()
         {
             this.createList();
-            Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
+            Roo.bootstrap.form.PhoneInput.superclass.initEvents.call(this);
             
             this.indicator = this.indicatorEl();
             this.flag = this.flagEl();
@@ -42464,8 +46582,8 @@ Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
         
 });
 /**
- * @class Roo.bootstrap.MoneyField
- * @extends Roo.bootstrap.ComboBox
+ * @class Roo.bootstrap.form.MoneyField
+ * @extends Roo.bootstrap.form.ComboBox
  * Bootstrap MoneyField class
  * 
  * @constructor
@@ -42473,13 +46591,13 @@ Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
  * @param {Object} config Configuration options
  */
 
-Roo.bootstrap.MoneyField = function(config) {
+Roo.bootstrap.form.MoneyField = function(config) {
     
-    Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
+    Roo.bootstrap.form.MoneyField.superclass.constructor.call(this, config);
     
 };
 
-Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
+Roo.extend(Roo.bootstrap.form.MoneyField, Roo.bootstrap.form.ComboBox, {
     
     /**
      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
@@ -42544,7 +46662,9 @@ Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
     inputmd : 9,
     inputsm : 9,
     inputxs : 6,
-    
+     /**
+     * @cfg {Roo.data.Store} store  Store to lookup currency??
+     */
     store : false,
     
     getAutoCreate : function()
@@ -43083,7 +47203,7 @@ Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
     
     validateValue : function(value)
     {
-        if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
+        if(!Roo.bootstrap.form.MoneyField.superclass.validateValue.call(this, value)){
             return false;
         }
         
@@ -43778,4 +47898,42 @@ Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
 
  
 
\ No newline at end of file
+ // old names for form elements
+Roo.bootstrap.Form          =   Roo.bootstrap.form.Form;
+Roo.bootstrap.Input         =   Roo.bootstrap.form.Input;
+Roo.bootstrap.TextArea      =   Roo.bootstrap.form.TextArea;
+Roo.bootstrap.TriggerField  =   Roo.bootstrap.form.TriggerField;
+Roo.bootstrap.ComboBox      =   Roo.bootstrap.form.ComboBox;
+Roo.bootstrap.DateField     =   Roo.bootstrap.form.DateField;
+Roo.bootstrap.TimeField     =   Roo.bootstrap.form.TimeField;
+Roo.bootstrap.MonthField    =   Roo.bootstrap.form.MonthField;
+Roo.bootstrap.CheckBox      =   Roo.bootstrap.form.CheckBox;
+Roo.bootstrap.Radio         =   Roo.bootstrap.form.Radio;
+Roo.bootstrap.RadioSet      =   Roo.bootstrap.form.RadioSet;
+Roo.bootstrap.SecurePass    =   Roo.bootstrap.form.SecurePass;
+Roo.bootstrap.FieldLabel    =   Roo.bootstrap.form.FieldLabel;
+Roo.bootstrap.DateSplitField=   Roo.bootstrap.form.DateSplitField;
+Roo.bootstrap.NumberField   =   Roo.bootstrap.form.NumberField;
+Roo.bootstrap.PhoneInput    =   Roo.bootstrap.form.PhoneInput;
+Roo.bootstrap.PhoneInputData=   Roo.bootstrap.form.PhoneInputData;
+Roo.bootstrap.MoneyField    =   Roo.bootstrap.form.MoneyField;
+Roo.bootstrap.HtmlEditor    =   Roo.bootstrap.form.HtmlEditor;
+Roo.bootstrap.HtmlEditor.ToolbarStandard =   Roo.bootstrap.form.HtmlEditorToolbarStandard;
+Roo.bootstrap.Markdown      = Roo.bootstrap.form.Markdown;
+Roo.bootstrap.CardUploader  = Roo.bootstrap.form.CardUploader;// depricated.
+Roo.bootstrap.Navbar            = Roo.bootstrap.nav.Bar;
+Roo.bootstrap.NavGroup          = Roo.bootstrap.nav.Group;
+Roo.bootstrap.NavHeaderbar      = Roo.bootstrap.nav.Headerbar;
+Roo.bootstrap.NavItem           = Roo.bootstrap.nav.Item;
+
+Roo.bootstrap.NavProgressBar     = Roo.bootstrap.nav.ProgressBar;
+Roo.bootstrap.NavProgressBarItem = Roo.bootstrap.nav.ProgressBarItem;
+
+Roo.bootstrap.NavSidebar        = Roo.bootstrap.nav.Sidebar;
+Roo.bootstrap.NavSidebarItem    = Roo.bootstrap.nav.SidebarItem;
+
+Roo.bootstrap.NavSimplebar      = Roo.bootstrap.nav.Simplebar;// deprciated 
+Roo.bootstrap.Menu = Roo.bootstrap.menu.Menu;
+Roo.bootstrap.MenuItem =  Roo.bootstrap.menu.Item;
+Roo.bootstrap.MenuSeparator = Roo.bootstrap.menu.Separator
+