roojs-bootstrap.js
[roojs1] / roojs-bootstrap-debug.js
index 82d078a..6911149 100644 (file)
@@ -1157,7 +1157,7 @@ Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
     
     initEvents: function() {
         
-        if(!this.href){
+        if(!this.href || this.preventDefault){
             this.el.on('click', this.onClick, this);
         }
     },
@@ -3177,6 +3177,7 @@ Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
 Roo.bootstrap.NavGroup = function(config){
     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
     this.navItems = [];
+   
     Roo.bootstrap.NavGroup.register(this);
      this.addEvents({
         /**
@@ -3200,7 +3201,7 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
     navId : '',
     // private
     
-    navItems : false,
+    navItems : false, 
     
     getAutoCreate : function()
     {
@@ -3254,7 +3255,10 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
         
         return cfg;
     },
-    
+    /**
+    * sets the active Navigation item
+    * @param {Roo.bootstrap.NavItem} the new current navitem
+    */
     setActiveItem : function(item)
     {
         var prev = false;
@@ -3275,7 +3279,43 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
         
         
     },
+    /**
+    * gets the active Navigation item
+    * @return {Roo.bootstrap.NavItem} the current navitem
+    */
+    getActive : function()
+    {
+        
+        var prev = false;
+        Roo.each(this.navItems, function(v){
+            
+            if (v.isActive()) {
+                prev = v;
+                
+            }
+            
+        });
+        return prev;
+    },
     
+    indexOfNav : function()
+    {
+        
+        var prev = false;
+        Roo.each(this.navItems, function(v,i){
+            
+            if (v.isActive()) {
+                prev = i;
+                
+            }
+            
+        });
+        return prev;
+    },
+    /**
+    * adds a Navigation item
+    * @param {Roo.bootstrap.NavItem} the navitem to add
+    */
     addItem : function(cfg)
     {
         var cn = new Roo.bootstrap.NavItem(cfg);
@@ -3284,13 +3324,18 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
         cn.onRender(this.el, null);
         return cn;
     },
-    
+    /**
+    * register a Navigation item
+    * @param {Roo.bootstrap.NavItem} the navitem to add
+    */
     register : function(item)
     {
         this.navItems.push( item);
         item.navId = this.navId;
     
     },
+  
+    
     getNavItem: function(tabId)
     {
         var ret = false;
@@ -3303,9 +3348,47 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
             
         });
         return ret;
-    }
-    
+    },
     
+    setActiveNext : function()
+    {
+        var i = this.indexOfNav(this.getActive());
+        if (i > this.navItems.length) {
+            return;
+        }
+        this.setActiveItem(this.navItems[i+1]);
+    },
+    setActivePrev : function()
+    {
+        var i = this.indexOfNav(this.getActive());
+        if (i  < 1) {
+            return;
+        }
+        this.setActiveItem(this.navItems[i-1]);
+    },
+    clearWasActive : function(except) {
+        Roo.each(this.navItems, function(e) {
+            if (e.tabId != except.tabId && e.was_active) {
+               e.was_active = false;
+               return false;
+            }
+            return true;
+            
+        });
+    },
+    getWasActive : function ()
+    {
+        var r = false;
+        Roo.each(this.navItems, function(e) {
+            if (e.was_active) {
+               r = e;
+               return false;
+            }
+            return true;
+            
+        });
+        return r;
+    }
     
     
 });
@@ -3314,14 +3397,26 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
 Roo.apply(Roo.bootstrap.NavGroup, {
     
     groups: {},
-    
+     /**
+    * register a Navigation Group
+    * @param {Roo.bootstrap.NavGroup} the navgroup to add
+    */
     register : function(navgrp)
     {
-       this.groups[navgrp.navId] = navgrp;
+        this.groups[navgrp.navId] = navgrp;
        
     },
+    /**
+    * fetch a Navigation Group based on the navigation ID
+    * @param {string} the navgroup to add
+    * @returns {Roo.bootstrap.NavGroup} the navgroup 
+    */
     get: function(navId) {
-        return this.groups[navId];
+        if (typeof(this.groups[navId]) == 'undefined') {
+            return false;
+            //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
+        }
+        return this.groups[navId] ;
     }
     
     
@@ -3391,6 +3486,8 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
     tagtype : 'a',
     disabled : false,
     
+    was_active : false,
+    
     getAutoCreate : function(){
          
         var cfg = {
@@ -3471,18 +3568,24 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
             if (typeof(this.parent().setActiveItem) !== 'undefined') {
                 this.parent().setActiveItem(this);
             }
-           
-           
-           
         } 
     },
     
     isActive: function () {
         return this.active
     },
-    setActive : function(state, fire)
+    setActive : function(state, fire, is_was_active)
     {
+        if (this.active && !state & this.navId) {
+            this.was_active = true;
+            var nv = Roo.bootstrap.NavGroup.get(this.navId);
+            if (nv) {
+                nv.clearWasActive(this);
+            }
+            
+        }
         this.active = state;
+        
         if (!state ) {
             this.el.removeClass('active');
         } else if (!this.el.hasClass('active')) {
@@ -3491,7 +3594,34 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
         if (fire) {
             this.fireEvent('changed', this, state);
         }
-       
+        
+        // show a panel if it's registered and related..
+        
+        if (!this.navId || !this.tabId || !state || is_was_active) {
+            return;
+        }
+        
+        var tg = Roo.bootstrap.TabGroup.get(this.navId);
+        if (!tg) {
+            return;
+        }
+        var pan = tg.getPanelByName(this.tabId);
+        if (!pan) {
+            return;
+        }
+        // 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);
+            if (nv) {
+                var onav = nv.getWasActive();
+                if (onav) {
+                    onav.setActive(true, false, true);
+                }
+            }
+            
+        }
+        
+        
        
     },
      // this should not be here...
@@ -4023,7 +4153,8 @@ Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
     /**
      * @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 uses the raw data value.
+     * default renderer uses the raw 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 (Optional) For grid editors - returns the grid editor 
@@ -4645,14 +4776,7 @@ Roo.bootstrap.Table = function(config){
          * @param {Roo.bootstrap.Table} this
          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
          */
-        'rowclass' : true,
-        /**
-         * @event afterload
-         * Fires when record have been loaded
-         * @param {Roo.bootstrap.Table} this
-         * @param {Object} records  store records
-         */
-        'afterload' : true
+        'rowclass' : true
         
     });
 };
@@ -4685,6 +4809,8 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     CellSelection : false,
     layout : false,
     
+    // Roo.Element - the tbody
+    mainBody: false, 
     
     getAutoCreate : function(){
         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
@@ -4775,7 +4901,10 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             return;
         }
         
-        Roo.log('initEvents with ds!!!!');
+        //Roo.log('initEvents with ds!!!!');
+        
+        this.mainBody = this.el.select('tbody', true).first();
+        
         
         var _this = this;
         
@@ -4796,6 +4925,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         
         this.store.on('load', this.onLoad, this);
         this.store.on('beforeload', this.onBeforeLoad, this);
+        this.store.on('update', this.onUpdate, this);
         
     },
     
@@ -4843,7 +4973,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     {
         var cell = Roo.get(el);
         
-        if(!cell || !this.CellSelection || !this.RowSelection){
+        if(!cell || (!this.CellSelection && !this.RowSelection)){
             return;
         }
         
@@ -4871,7 +5001,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
     {
         var cell = Roo.get(el);
         
-        if(!cell || !this.CellSelection || !this.RowSelection){
+        if(!cell || (!this.CellSelection && !this.RowSelection)){
             return;
         }
         
@@ -4949,9 +5079,9 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
                 c.cls = 'sortable';
             }
             
-//            if(typeof(config.align) != 'undefined' && config.align.length){
-//                c.style += ' text-align:' + config.align + ';';
-//            }
+            if(typeof(config.align) != 'undefined' && config.align.length){
+                c.style += ' text-align:' + config.align + ';';
+            }
             
             if(typeof(config.width) != 'undefined'){
                 c.style += ' width:' + config.width + 'px;';
@@ -5003,6 +5133,8 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         return footer;
     },
     
+    
+    
     onLoad : function()
     {
         Roo.log('ds onload');
@@ -5010,6 +5142,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         
         var _this = this;
         var cm = this.cm;
+        var ds = this.store;
         
         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
@@ -5023,80 +5156,25 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             }
         });
         
-        var tbody = this.el.select('tbody', true).first();
+        var tbody =  this.mainBody;
         
         var renders = [];
                     
-        if(this.store.getCount() > 0){
-            this.store.data.each(function(d,rowIndex){
-                var row = {
-                    tag : 'tr',
-                    cn : []
-                };
-                
-                for(var i = 0, len = cm.getColumnCount(); i < len; i++){
-                    var config = cm.config[i];
-                    
-                    var renderer = cm.getRenderer(i);
-                    var value = '';
-                    var id = Roo.id();
-                    
-                    if(typeof(renderer) !== 'undefined'){
-                        value = renderer(d.data[cm.getDataIndex(i)], false, d);
-                    }
-                    
-                    if(typeof(value) === 'object'){
-                        renders.push({
-                            container : id,
-                            cfg : value 
-                        })
-                    }
-                    
-                    var rowcfg = {
-                        record: d,
-                        rowIndex : rowIndex,
-                        colIndex : i,
-                        rowClass : ''
-                    }
-
-                    _this.fireEvent('rowclass', this, rowcfg);
-                    
-                    var td = {
-                        tag: 'td',
-                        id: id,
-                        cls : rowcfg.rowClass,
-                        style: '',
-                        html: (typeof(value) === 'object') ? '' : value
-                    };
-                    
-                    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 + ';';
-                    }
-                    
-                    if(typeof(config.width) != 'undefined'){
-                        td.style += ' width:' +  config.width + 'px;';
-                    }
-                    
-                    
-                    row.cn.push(td);
-                   
-                }
+        if(ds.getCount() > 0){
+            ds.data.each(function(d,rowIndex){
+                var row =  this.renderRow(cm, ds, rowIndex);
                 
                 tbody.createChild(row);
                 
-            });
-        }
-        
-        
-        if(renders.length){
-            var _this = this;
-            Roo.each(renders, function(r){
-                _this.renderColumn(r);
-            })
+                var _this = this;
+                
+                if(row.cellObjects.length){
+                    Roo.each(row.cellObjects, function(r){
+                        _this.renderCellObject(r);
+                    })
+                }
+                
+            }, this);
         }
         
         Roo.each(this.el.select('tbody td', true).elements, function(e){
@@ -5107,12 +5185,163 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
             e.on('mouseout', _this.onMouseout, _this);
         });
 
-        this.fireEvent('afterload', this, this.store.data);
         //if(this.loadMask){
         //    this.maskEl.hide();
         //}
     },
     
+    
+    onUpdate : function(ds,record)
+    {
+        this.refreshRow(record);
+    },
+    onRemove : function(ds, record, index, isUpdate){
+        if(isUpdate !== true){
+            this.fireEvent("beforerowremoved", this, index, record);
+        }
+        var bt = this.mainBody.dom;
+        if(bt.rows[index]){
+            bt.removeChild(bt.rows[index]);
+        }
+        
+        if(isUpdate !== true){
+            //this.stripeRows(index);
+            //this.syncRowHeights(index, index);
+            //this.layout();
+            this.fireEvent("rowremoved", this, index, record);
+        }
+    },
+    
+    
+    refreshRow : function(record){
+        var ds = this.store, index;
+        if(typeof record == 'number'){
+            index = record;
+            record = ds.getAt(index);
+        }else{
+            index = ds.indexOf(record);
+        }
+        this.insertRow(ds, index, true);
+        this.onRemove(ds, record, index+1, true);
+        //this.syncRowHeights(index, index);
+        //this.layout();
+        this.fireEvent("rowupdated", this, index, record);
+    },
+    
+    insertRow : function(dm, rowIndex, isUpdate){
+        
+        if(!isUpdate){
+            this.fireEvent("beforerowsinserted", this, rowIndex);
+        }
+            //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));
+        Roo.log(e);
+        
+        var _this = this;
+                
+        if(row.cellObjects.length){
+            Roo.each(row.cellObjects, function(r){
+                _this.renderCellObject(r);
+            })
+        }
+            
+        if(!isUpdate){
+            this.fireEvent("rowsinserted", this, rowIndex);
+            //this.syncRowHeights(firstRow, lastRow);
+            //this.stripeRows(firstRow);
+            //this.layout();
+        }
+        
+    },
+    
+    
+    getRowDom : function(rowIndex)
+    {
+        // not sure if I need to check this.. but let's do it anyway..
+        return (this.mainBody.dom.rows && (rowIndex-1) < this.mainBody.dom.rows.length ) ?
+                this.mainBody.dom.rows[rowIndex] : false
+    },
+    // returns the object tree for a tr..
+  
+    
+    renderRow : function(cm, ds, rowIndex) {
+        
+        var d = ds.getAt(rowIndex);
+        
+        var row = {
+            tag : 'tr',
+            cn : []
+        };
+            
+        var cellObjects = [];
+        
+        for(var i = 0, len = cm.getColumnCount(); i < len; i++){
+            var config = cm.config[i];
+            
+            var renderer = cm.getRenderer(i);
+            var value = '';
+            var id = false;
+            
+            if(typeof(renderer) !== 'undefined'){
+                value = renderer(d.data[cm.getDataIndex(i)], false, d);
+            }
+            // if object are returned, then they are expected to be Roo.bootstrap.Component instances
+            // and are rendered into the cells after the row is rendered - using the id for the element.
+            
+            if(typeof(value) === 'object'){
+                id = Roo.id();
+                cellObjects.push({
+                    container : id,
+                    cfg : value 
+                })
+            }
+            
+            var rowcfg = {
+                record: d,
+                rowIndex : rowIndex,
+                colIndex : i,
+                rowClass : ''
+            }
+
+            this.fireEvent('rowclass', this, rowcfg);
+            
+            var td = {
+                tag: 'td',
+                cls : rowcfg.rowClass,
+                style: '',
+                html: (typeof(value) === 'object') ? '' : value
+            };
+            
+            if (id) {
+                td.id = id;
+            }
+            
+            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 + ';';
+            }
+            
+            if(typeof(config.width) != 'undefined'){
+                td.style += ' width:' +  config.width + 'px;';
+            }
+             
+            row.cn.push(td);
+           
+        }
+        
+        row.cellObjects = cellObjects;
+        
+        return row;
+          
+    },
+    
+    
+    
     onBeforeLoad : function()
     {
         //Roo.log('ds onBeforeLoad');
@@ -5135,8 +5364,10 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
         }
         return this.selModel;
     },
-    
-    renderColumn : function(r)
+    /*
+     * Render the Roo.bootstrap object from renderder
+     */
+    renderCellObject : function(r)
     {
         var _this = this;
         
@@ -5148,7 +5379,7 @@ Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
                     container: t.getChildContainer(),
                     cfg: c
                 }
-                _this.renderColumn(child);
+                _this.renderCellObject(child);
             })
         }
     }
@@ -6428,7 +6659,6 @@ Roo.form.VTypes = function(){
  * @cfg {String} labelAlign (top|left)
  * @cfg {Boolean} readOnly Specifies that the field should be read-only
  * @cfg {String} align (left|center|right) Default left
- * @cfg {Boolean} formatedValue (true | false) Default false
  * 
  * 
  * @constructor
@@ -6965,11 +7195,9 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
      */
     getValue : function(){
         
-        if(this.formatedValue){
-            return this.inputEl().getValue().replace(',', '');
-        }
+        var v = this.inputEl().getValue();
         
-        return this.inputEl().getValue();
+        return v;
     },
     /**
      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
@@ -9838,6 +10066,7 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
  * @cfg {Boolean} append (true|false) default false
  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
+ * @cfg {Boolean} editNotList allow text type,but not show pull down, default false
  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
  * @constructor
  * Create a new ComboBox.
@@ -10098,7 +10327,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
     autoFocus : true,
     tickable : false,
     btnPosition : 'right',
-    
+    editNotList : false,
     // element that contains real text value.. (when hidden is used..)
     
     getAutoCreate : function()
@@ -10509,9 +10738,12 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
         
         this.choices = this.el.select('ul.select2-choices', true).first();
         this.searchField = this.el.select('ul li.select2-search-field', true).first();
-        
+        if(this.editNotList){
+            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.onTriggerClick, this, {preventDefault:true});
+        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();
@@ -11184,6 +11416,8 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             return;
         }
         
+        this.hasFocus = false;
+        
         this.list.hide();
         
         if(this.tickable){
@@ -11251,16 +11485,11 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
 
     // private
     // Implements the default empty TriggerField.onTriggerClick function
-    onTriggerClick : function()
+    onTriggerClick : function(e)
     {
         Roo.log('trigger click');
         
-        if(this.disabled){
-            return;
-        }
-        
-        if(this.tickable){
-            this.onTickableTriggerClick();
+        if(this.disabled || this.editNotList){
             return;
         }
         
@@ -11286,8 +11515,29 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
         }
     },
     
-    onTickableTriggerClick : function()
+    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());
+        }
+    },
+    
+    onSearchFieldClick : function(e)
+    {
+        if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
+            return;
+        }
+        
         this.page = 0;
         this.loadNext = false;
         this.hasFocus = true;
@@ -13526,6 +13776,215 @@ Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
 
  
 
+ /*
+ * - LGPL
+ *
+ * column
+ * 
+ */
+
+/**
+ * @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
+ * 
+ * @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,
+     
+    getAutoCreate : function()
+    {
+        var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
+        
+        cfg.cls += ' tab-content';
+        
+        if (this.carousel) {
+            cfg.cls += ' carousel slide';
+            cfg.cn = [{
+               cls : 'carousel-inner'
+            }]
+        }
+        
+        
+        return cfg;
+    },
+    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)
+    {
+        this.tabs.push( item);
+        item.navId = this.navId; // not really needed..
+    
+    },
+    
+    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)
+    {
+        
+        
+        
+        if (typeof(pan) == 'number') {
+            pan = this.tabs[pan];
+        }
+        if (typeof(pan) == 'string') {
+            pan = this.getPanelByName(pan);
+        }
+        if (pan.tabId == this.getActivePanel().tabId) {
+            return true;
+        }
+        var cur = this.getActivePanel();
+        
+        if (false === cur.fireEvent('beforedeactivate')) {
+            return false;
+        }
+        
+        
+        
+        if (this.carousel) {
+            var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
+            var lr = dir == 'next' ? 'left' : 'right';
+            pan.el.addClass(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.on('transitionend', function() {
+                Roo.log("trans end?");
+                
+                pan.el.removeClass([lr,dir]);
+                pan.setActive(true);
+                
+                cur.el.removeClass([lr]);
+                cur.setActive(false);
+                
+                
+            }, this, { single:  true } );
+            return true;
+        }
+        
+        cur.setActive(false);
+        pan.setActive(true);
+        return true;
+        
+    },
+    showPanelNext : function()
+    {
+        var i = this.indexOfPanel(this.getActivePanel());
+        if (i > this.tabs.length) {
+            return;
+        }
+        this.showPanel(this.tabs[i+1]);
+    },
+    showPanelPrev : function()
+    {
+        var i = this.indexOfPanel(this.getActivePanel());
+        if (i  < 1) {
+            return;
+        }
+        this.showPanel(this.tabs[i-1]);
+    }
+    
+    
+  
+});
+
+
+Roo.apply(Roo.bootstrap.TabGroup, {
+    
+    groups: {},
+     /**
+    * register a Navigation Group
+    * @param {Roo.bootstrap.NavGroup} 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.NavGroup} the navgroup 
+    */
+    get: function(navId) {
+        if (typeof(this.groups[navId]) == 'undefined') {
+            this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
+        }
+        return this.groups[navId] ;
+    }
+    
+    
+    
+});
+
  /*
  * - LGPL
  *
@@ -13539,7 +13998,7 @@ Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
  * Bootstrap TabPanel class
  * @cfg {Boolean} active panel active
  * @cfg {String} html panel content
- * @cfg {String} tabId tab relate id
+ * @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 ()
  * 
  * 
@@ -13550,7 +14009,7 @@ Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
 
 Roo.bootstrap.TabPanel = function(config){
     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
-     this.addEvents({
+    this.addEvents({
         /**
             * @event changed
             * Fires when the active status changes
@@ -13558,8 +14017,19 @@ Roo.bootstrap.TabPanel = function(config){
             * @param {Boolean} state the new state
            
          */
-        'changed': true
+        '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
      });
+    
+    this.tabId = this.tabId || Roo.id();
+  
 };
 
 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
@@ -13572,7 +14042,8 @@ Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
     getAutoCreate : function(){
         var cfg = {
             tag: 'div',
-            cls: 'tab-pane',
+            // item is needed for carousel - not sure if it has any effect otherwise
+            cls: 'tab-pane item',
             html: this.html || ''
         };
         
@@ -13584,26 +14055,38 @@ Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
             cfg.tabId = this.tabId;
         }
         
+        
         return cfg;
     },
+    
+    initEvents:  function()
+    {
+        Roo.log('-------- init events on tab panel ---------');
+        
+        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);
+            Roo.log(['register', tg, this]);
+            tg.register(this);
+        }
+    },
+    
+    
     onRender : function(ct, position)
     {
        // Roo.log("Call onRender: " + this.xtype);
         
         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
         
-        if (this.navId && this.tabId) {
-            var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
-            if (!item) {
-                Roo.log("could not find navID:"  + this.navId + ", tabId: " + this.tabId);
-            } else {
-                item.on('changed', function(item, state) {
-                    this.setActive(state);
-                }, this);
-            }
-        }
+        
+        
+        
         
     },
+    
     setActive: function(state)
     {
         Roo.log("panel - set active " + this.tabId + "=" + state);
@@ -14190,6 +14673,7 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
                 this.show();
             return;
         }
+        
         var dateChanged = false,
         dir, day, month,
         newDate, newViewDate;
@@ -14259,6 +14743,12 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
                 this.setValue(this.formatDate(this.date));
                 this.hide();
                 break;
+            case 16: // shift
+            case 17: // ctrl
+            case 18: // alt
+                break;
+            default :
+                this.hide();
                 
         }
     },
@@ -19053,7 +19543,16 @@ Roo.bootstrap.dash = Roo.bootstrap.dash || {};
 
 Roo.bootstrap.dash.TabBox = function(config){
     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
-    
+    this.addEvents({
+        // raw events
+        /**
+         * @event addpane
+         * When a pane is added
+         * @param {Roo.bootstrap.dash.TabPane} pane
+         */
+        "addpane" : true
+         
+    });
 };
 
 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
@@ -19104,12 +19603,71 @@ Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
 
         return  cfg;
     },
-    
+    initEvents : function()
+    {
+        //Roo.log('add add pane handler');
+        this.on('addpane', this.onAddPane, this);
+    },
+     /**
+     * Updates the box title
+     * @param {String} html to set the title to.
+     */
     setTitle : function(value)
     {
-        this.el.select('.header', true).first().dom.innerHTML = value;
+        this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
+    },
+    onAddPane : function(pane)
+    {
+        //Roo.log('addpane');
+        //Roo.log(pane);
+        // tabs are rendere left to right..
+        var ctr = this.el.select('.nav-tabs', true).first();
+         
+         
+        var existing = ctr.select('.nav-tab',true);
+        var qty = existing.getCount();;
+        
+        
+        var tab = ctr.createChild({
+            tag : 'li',
+            cls : 'nav-tab' + (qty ? '' : ' active'),
+            cn : [
+                {
+                    tag : 'a',
+                    href:'#',
+                    html : pane.title
+                }
+            ]
+        }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
+        pane.tab = tab;
+        
+        tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
+        if (!qty) {
+            pane.el.addClass('active');
+        }
+        
+                
+    },
+    onTabClick : function(ev,un,ob,pane)
+    {
+        //Roo.log('tab - prev default');
+        ev.preventDefault();
+        
+        
+        this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
+        pane.tab.addClass('active');
+        //Roo.log(pane.title);
+        this.getChildContainer().select('.tab-pane',true).removeClass('active');
+        // technically we should have a deactivate event.. but maybe add later.
+        // and it should not de-activate the selected tab...
+        
+        pane.el.addClass('active');
+        pane.fireEvent('activate');
+        
+        
     }
     
+    
 });
 
  
@@ -19125,6 +19683,7 @@ Roo.bootstrap.dash = Roo.bootstrap.dash || {};
  * @extends Roo.bootstrap.Component
  * Bootstrap TabPane class
  * @cfg {Boolean} active (false | true) Default false
+ * @cfg {String} title title of panel
 
  * 
  * @constructor
@@ -19140,12 +19699,11 @@ Roo.bootstrap.dash.TabPane = function(config){
 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
     
     active : false,
-//    
-//    getBox : function()
-//    {
-//        return this.el.findParent('.nav-tabs-custom', false, true);
-//    },
+    title : '',
     
+    // the tabBox that this is attached to.
+    tab : false,
+     
     getAutoCreate : function() 
     {
         var cfg = {
@@ -19158,9 +19716,29 @@ Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
         }
         
         return cfg;
+    },
+    initEvents  : function()
+    {
+        //Roo.log('trigger add pane handler');
+        this.parent().fireEvent('addpane', this)
+    },
+    
+     /**
+     * Updates the tab title 
+     * @param {String} html to set the title to.
+     */
+    setTitle: function(str)
+    {
+        if (!this.tab) {
+            return;
+        }
+        this.title = str;
+        this.tab.select('a'.true).first().dom.innerHTML = str;
+        
     }
     
     
+    
 });