fix popover issue
[roojs1] / roojs-bootstrap-debug.js
index 48a8ef5..9e4fb24 100644 (file)
  *
  */
 
-Roo.bootstrap.version = (
-        function() {
-                var ret=3;
-                Roo.each(document.styleSheets, function(s) {
-                    if (typeof(s.href) != 'undefined' && 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;
 })(); /*
+ * 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.Shadow
+ * Simple class that can provide a shadow effect for any element.  Note that the element MUST be absolutely positioned,
+ * and the shadow does not provide any shimming.  This should be used only in simple cases -- for more advanced
+ * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
+ * @constructor
+ * Create a new Shadow
+ * @param {Object} config The config object
+ */
+Roo.Shadow = function(config){
+    Roo.apply(this, config);
+    if(typeof this.mode != "string"){
+        this.mode = this.defaultMode;
+    }
+    var o = this.offset, a = {h: 0};
+    var rad = Math.floor(this.offset/2);
+    switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
+        case "drop":
+            a.w = 0;
+            a.l = a.t = o;
+            a.t -= 1;
+            if(Roo.isIE){
+                a.l -= this.offset + rad;
+                a.t -= this.offset + rad;
+                a.w -= rad;
+                a.h -= rad;
+                a.t += 1;
+            }
+        break;
+        case "sides":
+            a.w = (o*2);
+            a.l = -o;
+            a.t = o-1;
+            if(Roo.isIE){
+                a.l -= (this.offset - rad);
+                a.t -= this.offset + rad;
+                a.l += 1;
+                a.w -= (this.offset - rad)*2;
+                a.w -= rad + 1;
+                a.h -= 1;
+            }
+        break;
+        case "frame":
+            a.w = a.h = (o*2);
+            a.l = a.t = -o;
+            a.t += 1;
+            a.h -= 2;
+            if(Roo.isIE){
+                a.l -= (this.offset - rad);
+                a.t -= (this.offset - rad);
+                a.l += 1;
+                a.w -= (this.offset + rad + 1);
+                a.h -= (this.offset + rad);
+                a.h += 1;
+            }
+        break;
+    };
+
+    this.adjusts = a;
+};
+
+Roo.Shadow.prototype = {
+    /**
+     * @cfg {String} mode
+     * The shadow display mode.  Supports the following options:<br />
+     * sides: Shadow displays on both sides and bottom only<br />
+     * frame: Shadow displays equally on all four sides<br />
+     * drop: Traditional bottom-right drop shadow (default)
+     */
+    /**
+     * @cfg {String} offset
+     * The number of pixels to offset the shadow from the element (defaults to 4)
+     */
+    offset: 4,
+
+    // private
+    defaultMode: "drop",
+
+    /**
+     * Displays the shadow under the target element
+     * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
+     */
+    show : function(target){
+        target = Roo.get(target);
+        if(!this.el){
+            this.el = Roo.Shadow.Pool.pull();
+            if(this.el.dom.nextSibling != target.dom){
+                this.el.insertBefore(target);
+            }
+        }
+        this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
+        if(Roo.isIE){
+            this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
+        }
+        this.realign(
+            target.getLeft(true),
+            target.getTop(true),
+            target.getWidth(),
+            target.getHeight()
+        );
+        this.el.dom.style.display = "block";
+    },
+
+    /**
+     * Returns true if the shadow is visible, else false
+     */
+    isVisible : function(){
+        return this.el ? true : false;  
+    },
+
+    /**
+     * Direct alignment when values are already available. Show must be called at least once before
+     * calling this method to ensure it is initialized.
+     * @param {Number} left The target element left position
+     * @param {Number} top The target element top position
+     * @param {Number} width The target element width
+     * @param {Number} height The target element height
+     */
+    realign : function(l, t, w, h){
+        if(!this.el){
+            return;
+        }
+        var a = this.adjusts, d = this.el.dom, s = d.style;
+        var iea = 0;
+        s.left = (l+a.l)+"px";
+        s.top = (t+a.t)+"px";
+        var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
+        if(s.width != sws || s.height != shs){
+            s.width = sws;
+            s.height = shs;
+            if(!Roo.isIE){
+                var cn = d.childNodes;
+                var sww = Math.max(0, (sw-12))+"px";
+                cn[0].childNodes[1].style.width = sww;
+                cn[1].childNodes[1].style.width = sww;
+                cn[2].childNodes[1].style.width = sww;
+                cn[1].style.height = Math.max(0, (sh-12))+"px";
+            }
+        }
+    },
+
+    /**
+     * Hides this shadow
+     */
+    hide : function(){
+        if(this.el){
+            this.el.dom.style.display = "none";
+            Roo.Shadow.Pool.push(this.el);
+            delete this.el;
+        }
+    },
+
+    /**
+     * Adjust the z-index of this shadow
+     * @param {Number} zindex The new z-index
+     */
+    setZIndex : function(z){
+        this.zIndex = z;
+        if(this.el){
+            this.el.setStyle("z-index", z);
+        }
+    }
+};
+
+// Private utility class that manages the internal Shadow cache
+Roo.Shadow.Pool = function(){
+    var p = [];
+    var markup = Roo.isIE ?
+                 '<div class="x-ie-shadow"></div>' :
+                 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
+    return {
+        pull : function(){
+            var sh = p.shift();
+            if(!sh){
+                sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
+                sh.autoBoxAdjust = false;
+            }
+            return sh;
+        },
+
+        push : function(sh){
+            p.push(sh);
+        }
+    };
+}();/*
  * - LGPL
  *
  * base class for bootstrap elements.
@@ -163,6 +362,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
@@ -435,6 +639,204 @@ Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
     }
 });
 
+ /*
+ * - LGPL
+ *
+ * element
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.Element
+ * @extends Roo.bootstrap.Component
+ * Bootstrap Element class
+ * @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
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.Element = function(config){
+    Roo.bootstrap.Element.superclass.constructor.call(this, config);
+    
+    this.addEvents({
+        // raw events
+        /**
+         * @event click
+         * When a element is chick
+         * @param {Roo.bootstrap.Element} this
+         * @param {Roo.EventObject} e
+         */
+        "click" : true 
+        
+      
+    });
+};
+
+Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
+    
+    tag: 'div',
+    cls: '',
+    html: '',
+    preventDefault: false, 
+    clickable: false,
+    tapedTwice : false,
+    role : false,
+    
+    getAutoCreate : function(){
+        
+        var cfg = {
+            tag: this.tag,
+            // cls: this.cls, double assign in parent class Component.js :: onRender
+            html: this.html
+        };
+        if (this.role !== false) {
+            cfg.role = this.role;
+        }
+        
+        return cfg;
+    },
+    
+    initEvents: function() 
+    {
+        Roo.bootstrap.Element.superclass.initEvents.call(this);
+        
+        if(this.clickable){
+            this.el.on('click', this.onClick, this);
+        }
+        
+        
+    },
+    
+    onClick : function(e)
+    {
+        if(this.preventDefault){
+            e.preventDefault();
+        }
+        
+        this.fireEvent('click', this, e); // why was this double click before?
+    },
+    
+    
+    
+
+    
+    
+    getValue : function()
+    {
+        return this.el.dom.innerHTML;
+    },
+    
+    setValue : function(value)
+    {
+        this.el.dom.innerHTML = value;
+    }
+   
+});
+
+
+ /*
+ * - LGPL
+ *
+ * dropable area
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.DropTarget
+ * @extends Roo.bootstrap.Element
+ * Bootstrap DropTarget class
+ * @cfg {string} name dropable name
+ * 
+ * @constructor
+ * Create a new Dropable Area
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.DropTarget = function(config){
+    Roo.bootstrap.DropTarget.superclass.constructor.call(this, config);
+    
+    this.addEvents({
+        // raw events
+        /**
+         * @event click
+         * When a element is chick
+         * @param {Roo.bootstrap.Element} this
+         * @param {Roo.EventObject} e
+         */
+        "drop" : true
+    });
+};
+
+Roo.extend(Roo.bootstrap.DropTarget, Roo.bootstrap.Element,  {
+    
+    
+    getAutoCreate : function(){
+        
+         
+    },
+    
+    initEvents: function() 
+    {
+        Roo.bootstrap.DropTarget.superclass.initEvents.call(this);
+        this.dropZone = new Roo.dd.DropTarget(this.getEl(), {
+            ddGroup: this.name,
+            listeners : {
+                drop : this.dragDrop.createDelegate(this),
+                enter : this.dragEnter.createDelegate(this),
+                out : this.dragOut.createDelegate(this),
+                over : this.dragOver.createDelegate(this)
+            }
+            
+        });
+        this.dropZone.DDM.useCache = false // so data gets refreshed when we resize stuff
+    },
+    
+    dragDrop : function(source,e,data)
+    {
+        // user has to decide how to impliment this.
+        Roo.log('drop');
+        Roo.log(this);
+        //this.fireEvent('drop', this, source, e ,data);
+        return false;
+    },
+    
+    dragEnter : function(n, dd, e, data)
+    {
+        // probably want to resize the element to match the dropped element..
+        Roo.log("enter");
+        this.originalSize = this.el.getSize();
+        this.el.setSize( n.el.getSize());
+        this.dropZone.DDM.refreshCache(this.name);
+        Roo.log([n, dd, e, data]);
+    },
+    
+    dragOut : function(value)
+    {
+        // resize back to normal
+        Roo.log("out");
+        this.el.setSize(this.originalSize);
+        this.dropZone.resetConstraints();
+    },
+    
+    dragOver : function()
+    {
+        // ??? do nothing?
+    }
+   
+});
+
+
  /*
  * - LGPL
  *
@@ -581,11 +983,11 @@ Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
  * @extends Roo.bootstrap.Component
  * Bootstrap Button class
  * @cfg {String} html The button content
- * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
- * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
+ * @cfg {String} weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default
+ * @cfg {String} badge_weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default (same as button)
  * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
- * @cfg {String} size ( lg | sm | xs)
- * @cfg {String} tag ( a | input | submit)
+ * @cfg {String} size (lg|sm|xs)
+ * @cfg {String} tag (a|input|submit)
  * @cfg {String} href empty or href
  * @cfg {Boolean} disabled default false;
  * @cfg {Boolean} isClose default false;
@@ -595,12 +997,13 @@ Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
  * @cfg {String} theme (default|glow)  
  * @cfg {Boolean} inverse dark themed version
  * @cfg {Boolean} toggle is it a slidy toggle button
- * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
+ * @cfg {Boolean} pressed   default null - if the button ahs active state
  * @cfg {String} ontext text for on slidy toggle state
  * @cfg {String} offtext text for off slidy toggle state
  * @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  target for a href. (_self|_blank|_parent|_top| other)
+ * @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.
  * 
  * @constructor
  * Create a new button
@@ -610,23 +1013,23 @@ Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
 
 Roo.bootstrap.Button = function(config){
     Roo.bootstrap.Button.superclass.constructor.call(this, config);
-    this.weightClass = ["btn-default btn-outline-secondary", 
-                       "btn-primary", 
-                       "btn-success", 
-                       "btn-info", 
-                       "btn-warning",
-                       "btn-danger",
-                       "btn-link"
-                      ],  
+    
     this.addEvents({
         // 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
@@ -663,6 +1066,7 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
     removeClass: false,
     name: false,
     target: false,
+    group : false,
      
     pressed : null,
      
@@ -697,9 +1101,9 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
                     }
                 ]
             };
-            
-            if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
-                cfg.cls += ' '+this.weight;
+            // why are we validating the weights?
+            if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
+                cfg.cls +=  ' ' + this.weight;
             }
             
             return cfg;
@@ -714,15 +1118,15 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
             
             return cfg;
         }
+             
         
-         
         if (this.theme==='default') {
             cfg.cls = 'btn roo-button';
             
             //if (this.parentType != 'Navbar') {
             this.weight = this.weight.length ?  this.weight : 'default';
             //}
-            if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
+            if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
                 
                 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
                 var weight = this.weight == 'default' ? 'secondary' : this.weight;
@@ -737,7 +1141,7 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
             cfg.tag = 'a';
             cfg.cls = 'btn-glow roo-button';
             
-            if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
+            if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
                 
                 cfg.cls += ' ' + this.weight;
             }
@@ -890,17 +1294,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)
@@ -914,6 +1331,25 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
             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);
         }
@@ -921,7 +1357,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
      */
@@ -929,6 +1374,7 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
     {
         this.disabled = false;
         this.el.removeClass('disabled');
+        this.el.dom.removeAttribute("disabled");
     },
     
     /**
@@ -938,6 +1384,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, 
@@ -953,8 +1400,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
@@ -981,7 +1428,8 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
     
     setWeight : function(str)
     {
-       this.el.removeClass(this.weightClass);
+       this.el.removeClass(Roo.bootstrap.Button.weights.map(function(w) { return 'btn-' + w; } ) );
+        this.el.removeClass(Roo.bootstrap.Button.weights.map(function(w) { return 'btn-outline-' + w; } ) );
         this.weight = str;
         var outline = this.outline ? 'outline-' : '';
         if (str == 'default') {
@@ -993,8 +1441,21 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
     
     
 });
-
- /*
+// fixme - this is probably generic bootstrap - should go in some kind of enum file.. - like sizes.
+
+Roo.bootstrap.Button.weights = [
+    'default',
+    'secondary' ,
+    'primary',
+    'success',
+    'info',
+    'warning',
+    'danger',
+    'link',
+    'light',
+    'dark'              
+   
+];/*
  * - LGPL
  *
  * column
@@ -1060,7 +1521,8 @@ Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
         };
         
         var settings=this;
-        ['xs','sm','md','lg'].map(function(size){
+        var sizes =   ['xs','sm','md','lg'];
+        sizes.map(function(size ,ix){
             //Roo.log( size + ':' + settings[size]);
             
             if (settings[size+'off'] !== false) {
@@ -1072,7 +1534,13 @@ Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
             }
             
             if (!settings[size]) { // 0 = hidden
-                cfg.cls += ' hidden-' + size + ' hidden' + size + '-down';;
+                cfg.cls += ' hidden-' + size + ' hidden-' + size + '-down';
+                // bootsrap4
+                for (var i = ix; i > -1; i--) {
+                    cfg.cls +=  ' d-' + sizes[i] + '-none'; 
+                }
+                
+                
                 return;
             }
             cfg.cls += ' col-' + size + '-' + settings[size] + (
@@ -1487,6 +1955,1072 @@ 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
+ *
+ *
+ * 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
+ * @cfg {String|Boolean} html -- html contents - or just use children.. use false to hide it..
+ * @cfg {String} footer
+ * @cfg {String} weight (primary|warning|info|danger|secondary|success|light|dark)
+ * 
+ * @cfg {String} margin (0|1|2|3|4|5|auto)
+ * @cfg {String} margin_top (0|1|2|3|4|5|auto)
+ * @cfg {String} margin_bottom (0|1|2|3|4|5|auto)
+ * @cfg {String} margin_left (0|1|2|3|4|5|auto)
+ * @cfg {String} margin_right (0|1|2|3|4|5|auto)
+ * @cfg {String} margin_x (0|1|2|3|4|5|auto)
+ * @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)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)
+ * @cfg {String} padding_x (0|1|2|3|4|5)
+ * @cfg {String} padding_y (0|1|2|3|4|5)
+ *
+ * @cfg {String} display (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
+ * @cfg {String} display_xs (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
+ * @cfg {String} display_sm (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
+ * @cfg {String} display_lg (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
+ * @cfg {String} display_xl (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
+ * @config {Boolean} dragable  if this card can be dragged.
+ * @config {String} drag_group  group for drag
+ * @config {Boolean} dropable  if this card can recieve other cards being dropped onto it..
+ * @config {String} drop_group  group for drag
+ * 
+ * @config {Boolean} collapsable can the body be collapsed.
+ * @config {Boolean} collapsed is the body collapsed when rendered...
+ * @config {Boolean} rotateable can the body be rotated by clicking on it..
+ * @config {Boolean} rotated is the body rotated when rendered...
+ * 
+ * @constructor
+ * Create a new Container
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.Card = function(config){
+    Roo.bootstrap.Card.superclass.constructor.call(this, config);
+    
+    this.addEvents({
+         // raw events
+        /**
+         * @event drop
+         * When a element a card is dropped
+         * @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.Card} this
+         * @param {Roo.Element} n the node being dropped?
+         * @param {Boolean} rotate status
+         */
+        '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
+         
+    });
+};
+
+
+Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
+    
+    
+    weight : '',
+    
+    margin: '', /// may be better in component?
+    margin_top: '', 
+    margin_bottom: '', 
+    margin_left: '',
+    margin_right: '',
+    margin_x: '',
+    margin_y: '',
+    
+    padding : '',
+    padding_top: '', 
+    padding_bottom: '', 
+    padding_left: '',
+    padding_right: '',
+    padding_x: '',
+    padding_y: '',
+    
+    display: '', 
+    display_xs: '', 
+    display_sm: '', 
+    display_lg: '',
+    display_xl: '',
+    header_image  : '',
+    header : '',
+    header_size : 0,
+    title : '',
+    subtitle : '',
+    html : '',
+    footer: '',
+
+    collapsable : false,
+    collapsed : false,
+    rotateable : false,
+    rotated : false,
+    
+    dragable : false,
+    drag_group : false,
+    dropable : false,
+    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()
+    {
+        var cls = '';
+        var t = this;
+        Roo.log(this.margin_bottom.length);
+        ['', 'top', 'bottom', 'left', 'right', 'x', 'y' ].forEach(function(v) {
+            // in theory these can do margin_top : ml-xs-3 ??? but we don't support that yet
+            
+            if (('' + t['margin' + (v.length ? '_' : '') + v]).length) {
+                cls += ' m' +  (v.length ? v[0]  : '') + '-' +  t['margin' + (v.length ? '_' : '') + v];
+            }
+            if (('' + t['padding' + (v.length ? '_' : '') + v]).length) {
+                cls += ' p' +  (v.length ? v[0]  : '') + '-' +  t['padding' + (v.length ? '_' : '') + v];
+            }
+        });
+        
+        ['', 'xs', 'sm', 'lg', 'xl'].forEach(function(v) {
+            if (('' + t['display' + (v.length ? '_' : '') + v]).length) {
+                cls += ' d' +  (v.length ? '-' : '') + v + '-' + t['display' + (v.length ? '_' : '') + v]
+            }
+        });
+        
+        // more generic support?
+        if (this.hidden) {
+            cls += ' d-none';
+        }
+        
+        return cls;
+    },
+       // Roo.log("Call onRender: " + this.xtype);
+        /*  We are looking at something like this.
+<div class="card">
+    <img src="..." class="card-img-top" alt="...">
+    <div class="card-body">
+        <h5 class="card-title">Card title</h5>
+         <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
+
+        >> this bit is really the body...
+        <div> << we will ad dthis in hopefully it will not break shit.
+        
+        ** card text does not actually have any styling...
+        
+            <p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
+        
+        </div> <<
+          <a href="#" class="card-link">Card link</a>
+          
+    </div>
+    <div class="card-footer">
+        <small class="text-muted">Last updated 3 mins ago</small>
+    </div>
+</div>
+         */
+    getAutoCreate : function(){
+        
+        var cfg = {
+            tag : 'div',
+            cls : 'card',
+            cn : [ ]
+        };
+        
+        if (this.weight.length && this.weight != 'light') {
+            cfg.cls += ' text-white';
+        } else {
+            cfg.cls += ' text-dark'; // need as it's nested..
+        }
+        if (this.weight.length) {
+            cfg.cls += ' bg-' + this.weight;
+        }
+        
+        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 ' + (this.header_weight ? 'bg-' + this.header_weight : ''),
+                cn : []
+            };
+            cfg.cn.push(hdr);
+            hdr_ctr = hdr;
+        } else {
+            hdr = {
+                tag : 'div',
+                cls : 'card-header d-none ' + (this.header_weight ? 'bg-' + this.header_weight : ''),
+                cn : []
+            };
+            cfg.cn.push(hdr);
+            hdr_ctr = hdr;
+        }
+        if (this.collapsable) {
+            hdr_ctr = {
+            tag : 'a',
+            cls : 'd-block user-select-none',
+            cn: [
+                    {
+                        tag: 'i',
+                        cls : 'roo-collapse-toggle fa fa-chevron-down float-right ' + (this.collapsed ? 'collapsed' : '')
+                    }
+                   
+                ]
+            };
+            hdr.cn.push(hdr_ctr);
+        }
+        
+        hdr_ctr.cn.push(        {
+            tag: 'span',
+            cls: 'roo-card-header-ctr' + ( this.header.length ? '' : ' d-none'),
+            html : this.header
+        });
+        
+        
+        if (this.header_image.length) {
+            cfg.cn.push({
+                tag : 'img',
+                cls : 'card-img-top',
+                src: this.header_image // escape?
+            });
+        } else {
+            cfg.cn.push({
+                    tag : 'div',
+                    cls : 'card-img-top d-none' 
+                });
+        }
+            
+        var body = {
+            tag : 'div',
+            cls : 'card-body' + (this.html === false  ? ' d-none' : ''),
+            cn : []
+        };
+        var obody = body;
+        if (this.collapsable || this.rotateable) {
+            obody = {
+                tag: 'div',
+                cls : 'roo-collapsable collapse ' + (this.collapsed || this.rotated ? '' : 'show'),
+                cn : [  body ]
+            };
+        }
+        
+        cfg.cn.push(obody);
+        
+        if (this.title.length) {
+            body.cn.push({
+                tag : 'div',
+                cls : 'card-title',
+                src: this.title // escape?
+            });
+        }  
+        
+        if (this.subtitle.length) {
+            body.cn.push({
+                tag : 'div',
+                cls : 'card-title',
+                src: this.subtitle // escape?
+            });
+        }
+        
+        body.cn.push({
+            tag : 'div',
+            cls : 'roo-card-body-ctr'
+        });
+        
+        if (this.html.length) {
+            body.cn.push({
+                tag: 'div',
+                html : this.html
+            });
+        }
+        // fixme ? handle objects?
+        
+        if (this.footer.length) {
+           
+            cfg.cn.push({
+                cls : 'card-footer ' + (this.rotated ? 'd-none' : ''),
+                html : this.footer
+            });
+            
+        } else {
+            cfg.cn.push({cls : 'card-footer d-none'});
+        }
+        
+        // footer...
+        
+        return cfg;
+    },
+    
+    
+    getCardHeader : function()
+    {
+        var  ret = this.el.select('.card-header',true).first();
+        if (ret.hasClass('d-none')) {
+            ret.removeClass('d-none');
+        }
+        
+        return ret;
+    },
+    getCardFooter : function()
+    {
+        var  ret = this.el.select('.card-footer',true).first();
+        if (ret.hasClass('d-none')) {
+            ret.removeClass('d-none');
+        }
+        
+        return ret;
+    },
+    getCardImageTop : function()
+    {
+        var  ret = this.header_imageEl;
+        if (ret.hasClass('d-none')) {
+            ret.removeClass('d-none');
+        }
+            
+        return ret;
+    },
+    
+    getChildContainer : function()
+    {
+        
+        if(!this.el){
+            return false;
+        }
+        return this.el.select('.roo-card-body-ctr',true).first();    
+    },
+    
+    initEvents: function() 
+    {
+        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,
+                    ddGroup: this.drag_group || 'default_card_drag_group'
+            });
+            this.dragZone.getDragData = this.getDragData.createDelegate(this);
+        }
+        if (this.dropable) {
+            this.dropZone = new Roo.dd.DropZone(this.el.select('.card-body',true).first() , {
+                containerScroll: true,
+                ddGroup: this.drop_group || 'default_card_drag_group'
+            });
+            this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
+            this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
+            this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
+            this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
+            this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
+        }
+        
+        if (this.collapsable) {
+            this.el.select('.card-header',true).on('click', this.onToggleCollapse, this);
+        }
+        if (this.rotateable) {
+            this.el.select('.card-header',true).on('click', this.onToggleRotate, this);
+        }
+        this.collapsableEl = this.el.select('.roo-collapsable',true).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)
+    {
+        var target = this.getEl();
+        if (target) {
+            //this.handleSelection(e);
+            
+            var dragData = {
+                source: this,
+                copy: false,
+                nodes: this.getEl(),
+                records: []
+            };
+            
+            
+            dragData.ddel = target.dom ;    // the div element
+            Roo.log(target.getWidth( ));
+            dragData.ddel.style.width = target.getWidth() + 'px';
+            
+            return dragData;
+        }
+        return false;
+    },
+    /**
+    *    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.containerEl.dom)) {
+            target = target.parentNode;
+        }
+        
+        var ret = {
+            position: '',
+            cards : [],
+            card_n : -1,
+            items_n : -1,
+            card : false 
+        };
+        
+        //Roo.log([ 'target' , target ? target.id : '--nothing--']);
+        // see if target is one of the 'cards'...
+        
+        
+        //Roo.log(this.items.length);
+        var pos = false;
+        
+        var last_card_n = 0;
+        var cards_len  = 0;
+        for (var i = 0;i< this.items.length;i++) {
+            
+            if (!this.items[i].el.hasClass('card')) {
+                 continue;
+            }
+            pos = this.getDropPoint(e, this.items[i].el.dom);
+            
+            cards_len = ret.cards.length;
+            //Roo.log(this.items[i].el.dom.id);
+            ret.cards.push(this.items[i]);
+            last_card_n  = i;
+            if (ret.card_n < 0 && pos == 'above') {
+                ret.position = cards_len > 0 ? 'below' : pos;
+                ret.items_n = i > 0 ? i - 1 : 0;
+                ret.card_n  = cards_len  > 0 ? cards_len - 1 : 0;
+                ret.card = ret.cards[ret.card_n];
+            }
+        }
+        if (!ret.cards.length) {
+            ret.card = true;
+            ret.position = 'below';
+            ret.items_n;
+            return ret;
+        }
+        // could not find a card.. stick it at the end..
+        if (ret.card_n < 0) {
+            ret.card_n = last_card_n;
+            ret.card = ret.cards[last_card_n];
+            ret.items_n = this.items.indexOf(ret.cards[last_card_n]);
+            ret.position = 'below';
+        }
+        
+        if (this.items[ret.items_n].el == dragged_card_el) {
+            return false;
+        }
+        
+        if (ret.position == 'below') {
+            var card_after = ret.card_n+1 == ret.cards.length ? false : ret.cards[ret.card_n+1];
+            
+            if (card_after  && card_after.el == dragged_card_el) {
+                return false;
+            }
+            return ret;
+        }
+        
+        // its's after ..
+        var card_before = ret.card_n > 0 ? ret.cards[ret.card_n-1] : false;
+        
+        if (card_before  && card_before.el == dragged_card_el) {
+            return false;
+        }
+        
+        return ret;
+    },
+    
+    onNodeEnter : function(n, dd, e, data){
+        return false;
+    },
+    onNodeOver : function(n, dd, e, data)
+    {
+       
+        var target_info = this.getTargetFromEvent(e,data.source.el);
+        if (target_info === false) {
+            this.dropPlaceHolder('hide');
+            return false;
+        }
+        Roo.log(['getTargetFromEvent', target_info ]);
+        
+        
+        if (this.fireEvent('cardover', this, [ data ]) === false) {
+            return false;
+        }
+        
+        this.dropPlaceHolder('show', target_info,data);
+        
+        return false; 
+    },
+    onNodeOut : function(n, dd, e, data){
+        this.dropPlaceHolder('hide');
+     
+    },
+    onNodeDrop : function(n, dd, e, data)
+    {
+        
+        // call drop - return false if
+        
+        // this could actually fail - if the Network drops..
+        // we will ignore this at present..- client should probably reload
+        // the whole set of cards if stuff like that fails.
+        
+        
+        var info = this.getTargetFromEvent(e,data.source.el);
+        if (info === false) {
+            return 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;
+        }
+        
+        var to_items_n = next_to_card ? this.items.indexOf(next_to_card) : 0;
+        
+        move_card.parent().removeCard(move_card);
+        
+        
+        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 (position == 'above' ) {
+                cardel.parentNode.insertBefore(dom, cardel);
+            } else if (cardel.nextSibling) {
+                cardel.parentNode.insertBefore(dom,cardel.nextSibling);
+            } else {
+                cardel.parentNode.append(dom);
+            }
+        } else {
+            // card container???
+            this.containerEl.dom.append(dom);
+        }
+        
+        //FIXME HANDLE card = true 
+        
+        // add this to the correct place in items.
+        
+        // remove Card from items.
+        
+       
+        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 == to_items_n && position == 'above') {
+                    nitems.push(move_card);
+                }
+                nitems.push(this.items[i]);
+                if (i == to_items_n && position == 'below') {
+                    nitems.push(move_card);
+                }
+            }
+            this.items = nitems;
+            Roo.log(this.items);
+        } else {
+            this.items.push(move_card);
+        }
+        
+        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. */
+    getDropPoint : function(e, n, dd)
+    {
+        if (dd) {
+             return false;
+        }
+        if (n == this.containerEl.dom) {
+            return "above";
+        }
+        var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
+        var c = t + (b - t) / 2;
+        var y = Roo.lib.Event.getPageY(e);
+        if(y <= c) {
+            return "above";
+        }else{
+            return "below";
+        }
+    },
+    onToggleCollapse : function(e)
+        {
+        if (this.collapsed) {
+            this.el.select('.roo-collapse-toggle').removeClass('collapsed');
+            this.collapsableEl.addClass('show');
+            this.collapsed = false;
+            return;
+        }
+        this.el.select('.roo-collapse-toggle').addClass('collapsed');
+        this.collapsableEl.removeClass('show');
+        this.collapsed = true;
+        
+    
+    },
+    
+    onToggleRotate : function(e)
+    {
+        this.collapsableEl.removeClass('show');
+        this.footerEl.removeClass('d-none');
+        this.el.removeClass('roo-card-rotated');
+        this.el.removeClass('d-none');
+        if (this.rotated) {
+            
+            this.collapsableEl.addClass('show');
+            this.rotated = false;
+            this.fireEvent('rotate', this, this.rotated);
+            return;
+        }
+        this.el.addClass('roo-card-rotated');
+        this.footerEl.addClass('d-none');
+        this.el.select('.roo-collapsable').removeClass('show');
+        
+        this.rotated = true;
+        this.fireEvent('rotate', this, this.rotated);
+    
+    },
+    
+    dropPlaceHolder: function (action, info, data)
+    {
+        if (this.dropEl === false) {
+            this.dropEl = Roo.DomHelper.append(this.containerEl, {
+            cls : 'd-none'
+            },true);
+        }
+        this.dropEl.removeClass(['d-none', 'd-block']);        
+        if (action == 'hide') {
+            
+            this.dropEl.addClass('d-none');
+            return;
+        }
+        // FIXME - info.card == true!!!
+        this.dropEl.dom.parentNode.removeChild(this.dropEl.dom);
+        
+        if (info.card !== true) {
+            var cardel = info.card.el.dom;
+            
+            if (info.position == 'above') {
+                cardel.parentNode.insertBefore(this.dropEl.dom, cardel);
+            } else if (cardel.nextSibling) {
+                cardel.parentNode.insertBefore(this.dropEl.dom,cardel.nextSibling);
+            } else {
+                cardel.parentNode.append(this.dropEl.dom);
+            }
+        } else {
+            // card container???
+            this.containerEl.dom.append(this.dropEl.dom);
+        }
+        
+        this.dropEl.addClass('d-block roo-card-dropzone');
+        
+        this.dropEl.setHeight( Roo.get(data.ddel).getHeight() );
+        
+        
+    
+    
+    
+    },
+    setHeaderText: function(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';
+        }
+
+    }
+
+    
+});
+
+/*
+ * - LGPL
+ *
+ * Card header - holder for the card header elements.
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.CardHeader
+ * @extends Roo.bootstrap.Element
+ * Bootstrap CardHeader class
+ * @constructor
+ * Create a new Card Header - that you can embed children into
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.CardHeader = function(config){
+    Roo.bootstrap.CardHeader.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.CardHeader, Roo.bootstrap.Element,  {
+    
+    
+    container_method : 'getCardHeader' 
+    
+     
+    
+    
+   
+});
+
+
+ /*
+ * - LGPL
+ *
+ * Card footer - holder for the card footer elements.
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.CardFooter
+ * @extends Roo.bootstrap.Element
+ * Bootstrap CardFooter class
+ * @constructor
+ * Create a new Card Footer - that you can embed children into
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.CardFooter = function(config){
+    Roo.bootstrap.CardFooter.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.CardFooter, Roo.bootstrap.Element,  {
+    
+    
+    container_method : 'getCardFooter' 
+    
+     
+    
+    
+   
+});
+
+
+ /*
+ * - LGPL
+ *
+ * Card header - holder for the card header elements.
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.CardImageTop
+ * @extends Roo.bootstrap.Element
+ * Bootstrap CardImageTop class
+ * @constructor
+ * Create a new Card Image Top container
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.CardImageTop = function(config){
+    Roo.bootstrap.CardImageTop.superclass.constructor.call(this, config);
+};
+
+Roo.extend(Roo.bootstrap.CardImageTop, Roo.bootstrap.Element,  {
+    
+   
+    container_method : 'getCardImageTop' 
+    
+     
+    
+   
+});
+
+
+/*
+* Licence: LGPL
+*/
+
+/**
+ * @class Roo.bootstrap.ButtonUploader
+ * @extends Roo.bootstrap.Button
+ * Bootstrap Button Uploader class - it's a button which when you add files to it
+ *
+ * 
+ * @cfg {Number} errorTimeout default 3000
+ * @cfg {Array}  images  an array of ?? Img objects ??? when loading existing files..
+ * @cfg {Array}  html The button text.
+ * @cfg {Boolean}  multiple (default true) Should the upload allow multiple files to be uploaded.
+ *
+ * @constructor
+ * Create a new CardUploader
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.ButtonUploader = function(config){
+    
+    
+    Roo.bootstrap.ButtonUploader.superclass.constructor.call(this, config);
+    
+     
+     this.addEvents({
+         // raw events
+        /**
+         * @event beforeselect
+         * When button is pressed, before show upload files dialog is shown
+         * @param {Roo.bootstrap.UploaderButton} this
+         *
+         */
+        'beforeselect' : true,
+         /**
+         * @event fired when files have been selected, 
+         * When a the download link is clicked
+         * @param {Roo.bootstrap.UploaderButton} this
+         * @param {Array} Array of files that have been uploaded
+         */
+        'uploaded' : true
+        
+    });
+};
+Roo.extend(Roo.bootstrap.ButtonUploader, Roo.bootstrap.Button,  {
+    
+     
+    errorTimeout : 3000,
+     
+    images : false,
+   
+    fileCollection : false,
+    allowBlank : true,
+    
+    multiple : true,
+    
+    getAutoCreate : function()
+    {
+        var im = {
+            tag: 'input',
+            type : 'file',
+            cls : 'd-none  roo-card-upload-selector' 
+          
+        };
+        if (this.multiple) {
+            im.multiple = 'multiple';
+        }
+        
+        return  {
+            cls :'div' ,
+            cn : [
+                Roo.bootstrap.Button.prototype.getAutoCreate.call(this),
+                im
+
+            ]
+        };
+           
+         
+    },
+     
+   
+    initEvents : function()
+    {
+        
+        Roo.bootstrap.Button.prototype.initEvents.call(this);
+        
+        
+        
+        
+        
+        this.urlAPI = (window.createObjectURL && window) || 
+                                (window.URL && URL.revokeObjectURL && URL) || 
+                                (window.webkitURL && webkitURL);
+                        
+         
+         
+         
+        this.selectorEl = this.el.select('.roo-card-upload-selector', true).first();
+        
+        this.selectorEl.on('change', this.onFileSelected, this);
+         
+         
+       
+    },
+    
+   
+    onClick : function(e)
+    {
+        e.preventDefault();
+        
+        if ( this.fireEvent('beforeselect', this) === false) {
+            return;
+        }
+         
+        this.selectorEl.dom.click();
+         
+    },
+    
+    onFileSelected : function(e)
+    {
+        e.preventDefault();
+        
+        if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
+            return;
+        }
+        var files = Array.prototype.slice.call(this.selectorEl.dom.files);
+        this.selectorEl.dom.value  = '';// hopefully reset..
+        
+        this.fireEvent('uploaded', this,  files );
+        
+    },
+    
+       
+   
+    
+    /**
+     * addCard - add an Attachment to the uploader
+     * @param data - the data about the image to upload
+     *
+     * {
+          id : 123
+          title : "Title of file",
+          is_uploaded : false,
+          src : "http://.....",
+          srcfile : { the File upload object },
+          mimetype : file.type,
+          preview : false,
+          is_deleted : 0
+          .. any other data...
+        }
+     *
+     * 
+    */
+     
+    reset: function()
+    {
+         
+         this.selectorEl
+    } 
+    
+    
+    
+    
+});
  /*
  * - LGPL
  *
@@ -2045,7 +3579,9 @@ Roo.bootstrap.MenuMgr = function(){
  * @cfg {bool} hidden  if the menu should be hidden when rendered.
  * @cfg {bool} stopEvent (true|false)  Stop event after trigger press (default true)
  * @cfg {bool} isLink (true|false)  the menu has link disable auto expand and collaspe (default false)
- * 
+  * @cfg {bool} hideTrigger (true|false)  default false - hide the carret for trigger.
+  * @cfg {String} align  default tl-bl? == below  - how the menu should be aligned. 
  * @constructor
  * Create a new Menu
  * @param {Object} config The config object
@@ -2053,6 +3589,13 @@ Roo.bootstrap.MenuMgr = function(){
 
 
 Roo.bootstrap.Menu = function(config){
+    
+    if (config.type == 'treeview') {
+       // normally menu's are drawn attached to the document to handle layering etc..
+       // however treeview (used by the docs menu is drawn into the parent element)
+       this.container_method = 'getChildContainer'; 
+    }
+    
     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
     if (this.registerMenu && this.type != 'treeview')  {
         Roo.bootstrap.MenuMgr.register(this);
@@ -2122,7 +3665,7 @@ Roo.bootstrap.Menu = function(config){
 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
     
    /// html : false,
-    //align : '',
+   
     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
     type: false,
     /**
@@ -2140,6 +3683,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;  
     },
@@ -2149,11 +3699,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'
             
         };
@@ -2171,18 +3720,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);
         }
@@ -2300,8 +3853,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
@@ -2321,18 +3897,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?
         
@@ -2364,9 +3939,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()){
            
@@ -2374,8 +3949,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);
         }
@@ -2420,7 +3998,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'){
@@ -2651,10 +4230,13 @@ Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
  * @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) default empty
+ * @cfg {String} size (sm|lg|xl) default empty
  * @cfg {Number} max_width set the max width of modal
+ * @cfg {Boolean} editableTitle can the title be edited
+
  *
  *
  * @constructor
@@ -2678,7 +4260,15 @@ Roo.bootstrap.Modal = function(config){
          * @param {Roo.bootstrap.Modal} this
          * @param {Roo.EventObject} e
          */
-        "resize" : true
+        "resize" : true,
+        /**
+         * @event titlechanged
+         * Fire when the editable title has been changed
+         * @param {Roo.bootstrap.Modal} this
+         * @param {Roo.EventObject} value
+         */
+        "titlechanged" : true 
+        
     });
     this.buttons = this.buttons || [];
 
@@ -2724,6 +4314,7 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
     max_height: 0,
     
     fit_content: false,
+    editableTitle  : false,
 
     onRender : function(ct, position)
     {
@@ -2803,20 +4394,20 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
 
     getAutoCreate : function()
     {
+        // we will default to modal-body-overflow - might need to remove or make optional later.
         var bdy = {
-                cls : 'modal-body',
+                cls : 'modal-body ' + (this.bodyOverflow ? 'overflow-auto' : ''), 
                 html : this.html || ''
         };
 
         var title = {
-            tag: 'h4',
+            tag: 'h5',
             cls : 'modal-title',
             html : this.title
         };
 
-        if(this.specificTitle){
+        if(this.specificTitle){ // WTF is this?
             title = this.title;
-
         }
 
         var header = [];
@@ -2830,6 +4421,14 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
 
         header.push(title);
 
+        if (this.editableTitle) {
+            header.push({
+                cls: 'form-control roo-editable-title d-none',
+                tag: 'input',
+                type: 'text'
+            });
+        }
+        
         if (this.allow_close && Roo.bootstrap.version == 4) {
             header.push({
                 tag: 'button',
@@ -2912,7 +4511,18 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
             this.closeEl.on('click', this.hide, this);
         }
         Roo.EventManager.onWindowResize(this.resize, this, true);
-
+        if (this.editableTitle) {
+            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.RETURN , e.TAB , e.ESC ].indexOf(e.keyCode) > -1) {
+                        this.toggleHeaderInput(false)
+                    }
+                }, this);
+            this.headerEditEl.on('blur', function(e) {
+                this.toggleHeaderInput(false)
+            },this);
+        }
 
     },
   
@@ -2926,7 +4536,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
@@ -2982,7 +4592,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';
@@ -3119,6 +4729,7 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
      */
     setTitle: function(str) {
         this.titleEl.dom.innerHTML = str;
+        this.title = str;
     },
     /**
      * Set the body of the Dialog
@@ -3146,7 +4757,7 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
             !child_nodes ||
             child_nodes.length == 0
         ) {
-            return;
+            return 0;
         }
         
         var child_height = 0;
@@ -3199,6 +4810,35 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
         }
         
         return child_height;
+    },
+    toggleHeaderInput : function(is_edit)
+    {
+        if (!this.editableTitle) {
+            return; // not editable.
+        }
+        if (is_edit && this.is_header_editing) {
+            return; // already editing..
+        }
+        if (is_edit) {
+    
+            this.headerEditEl.dom.value = this.title;
+            this.headerEditEl.removeClass('d-none');
+            this.headerEditEl.dom.focus();
+            this.titleEl.addClass('d-none');
+            
+            this.is_header_editing = true;
+            return
+        }
+        // flip back to not editing.
+        this.title = this.headerEditEl.dom.value;
+        this.headerEditEl.addClass('d-none');
+        this.titleEl.removeClass('d-none');
+        this.titleEl.dom.innerHTML = String.format('{0}', this.title);
+        this.is_header_editing = false;
+        this.fireEvent('titlechanged', this, this.title);
+    
+            
+        
     }
 
 });
@@ -3267,6 +4907,7 @@ Roo.apply(Roo.bootstrap.Modal,  {
         
         zIndex : 10001
 });
+
 /*
  * - LGPL
  *
@@ -4224,7 +5865,7 @@ Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
         
         cn.push({
             tag: 'div',
-            cls: Roo.bootstrap.version == 4  ? 'nav flex-row roo-navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
+            cls: Roo.bootstrap.version == 4  ? 'nav flex-row roo-navbar-collapse collapse navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
             cn : []
         });
         
@@ -4274,6 +5915,13 @@ Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
         return this.getChildContainer();
     },
     
+    getChildContainer : function()
+    {
+        
+       return this.el.select('.roo-navbar-collapse',true).first();
+        
+       
+    },
     
     initEvents : function()
     {
@@ -4368,7 +6016,7 @@ Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
  * @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
@@ -4401,6 +6049,7 @@ Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
     type: 'nav',
     navId : '',
     // private
+    pilltype : true,
     
     navItems : false, 
     
@@ -4662,8 +6311,8 @@ Roo.apply(Roo.bootstrap.NavGroup, {
  * @extends Roo.bootstrap.Component
  * 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
@@ -4672,7 +6321,7 @@ 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?
@@ -4731,7 +6380,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
     was_active : false,
     button_weight : '',
     button_outline : false,
-    
+    linkcls : '',
     navLink: false,
     
     getAutoCreate : function(){
@@ -4741,8 +6390,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';
@@ -4757,8 +6408,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..
            
@@ -4774,30 +6427,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>';
             }
         }
@@ -4815,6 +6468,7 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
        
         var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
        this.navLink = this.el.select('.nav-link',true).first();
+       this.htmlEl = this.el.hasClass('nav-html') ? this.el : this.el.select('.nav-html',true).first();
        return ret;
     },
       
@@ -4827,11 +6481,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);
@@ -4890,7 +6544,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);
             }
@@ -4980,7 +6634,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)
@@ -5012,7 +6666,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;
+       
+    } 
 });
  
 
@@ -5242,6 +6906,142 @@ Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
 });
  
 
+ /*
+ * - 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
+ * Bootstrap Breadcrumb Nav Class
+ *  
+ * @children Roo.bootstrap.breadcrumb.Component
+ * @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
  *
@@ -5276,95 +7076,6 @@ Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
 
  
 
- /*
- * - LGPL
- *
- * element
- * 
- */
-
-/**
- * @class Roo.bootstrap.Element
- * @extends Roo.bootstrap.Component
- * Bootstrap Element class
- * @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
- * 
- * @constructor
- * Create a new Element
- * @param {Object} config The config object
- */
-
-Roo.bootstrap.Element = function(config){
-    Roo.bootstrap.Element.superclass.constructor.call(this, config);
-    
-    this.addEvents({
-        // raw events
-        /**
-         * @event click
-         * When a element is chick
-         * @param {Roo.bootstrap.Element} this
-         * @param {Roo.EventObject} e
-         */
-        "click" : true
-    });
-};
-
-Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
-    
-    tag: 'div',
-    cls: '',
-    html: '',
-    preventDefault: false, 
-    clickable: false,
-    
-    getAutoCreate : function(){
-        
-        var cfg = {
-            tag: this.tag,
-            // cls: this.cls, double assign in parent class Component.js :: onRender
-            html: this.html
-        };
-        
-        return cfg;
-    },
-    
-    initEvents: function() 
-    {
-        Roo.bootstrap.Element.superclass.initEvents.call(this);
-        
-        if(this.clickable){
-            this.el.on('click', this.onClick, this);
-        }
-        
-    },
-    
-    onClick : function(e)
-    {
-        if(this.preventDefault){
-            e.preventDefault();
-        }
-        
-        this.fireEvent('click', this, e);
-    },
-    
-    getValue : function()
-    {
-        return this.el.dom.innerHTML;
-    },
-    
-    setValue : function(value)
-    {
-        this.el.dom.innerHTML = value;
-    }
-   
-});
-
-
  /*
  * - LGPL
  *
@@ -7063,6 +8774,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();
@@ -7316,17 +9030,22 @@ 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) {
             
-            tbd.setSize(ctr.getWidth(),
-                        ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
-            );
+            tbd.setWidth(ctr.getWidth());
+            // if the body has a max height - and then scrolls - we should perhaps set up the height here
+            // this needs fixing for various usage - currently only hydra job advers I think..
+            //tdb.setHeight(
+            //        ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
+            //); 
             var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
             cw -= barsize;
         }
         cw = Math.max(cw, this.totalWidth);
-        this.getGridEl().select('tr',true).setWidth(cw);
+        this.getGridEl().select('tbody tr',true).setWidth(cw);
+        
         // resize 'expandable coloumn?
         
         return; // we doe not have a view in this design..
@@ -8984,7 +10703,7 @@ Roo.form.VTypes = function(){
  * @extends Roo.bootstrap.Component
  * Bootstrap Input class
  * @cfg {Boolean} disabled is it disabled
- * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
+ * @cfg {String} (button|checkbox|email|file|hidden|image|number|password|radio|range|reset|search|submit|text) inputType 
  * @cfg {String} name name of the input
  * @cfg {string} fieldLabel - the label associated
  * @cfg {string} placeholder - placeholder to put in text.
@@ -9007,6 +10726,7 @@ Roo.form.VTypes = function(){
  * @cfg {String} indicatorpos (left|right) default left
  * @cfg {String} capture (user|camera) use for file input only. (default empty)
  * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
+ * @cfg {Boolean} preventMark Do not show tick or cross if error/success
 
  * @cfg {String} align (left|center|right) Default left
  * @cfg {Boolean} forceFeedback (true|false) Default false
@@ -9068,7 +10788,14 @@ Roo.bootstrap.Input = function(config){
          * @param {Roo.form.Field} this
          * @param {Roo.EventObject}  e The event Object
          */
-        keyup : true
+        keyup : true,
+        /**
+         * @event paste
+         * Fires after the user pastes into input
+         * @param {Roo.form.Field} this
+         * @param {Roo.EventObject}  e The event Object
+         */
+        paste : true
     });
 };
 
@@ -9257,6 +10984,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;
@@ -9335,7 +11065,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? 
                 });
             }
@@ -9354,7 +11084,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? 
                 });
             }
@@ -9369,11 +11099,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) {
             
@@ -9432,7 +11159,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){
@@ -9458,11 +11185,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',
@@ -9476,7 +11206,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
            ];
            
            if(this.indicatorpos == 'right'){
-                
+       
                 cfg.cn = [
                     {
                         tag: 'label',
@@ -9487,7 +11217,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
@@ -9567,6 +11298,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();
         
@@ -9898,6 +11630,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             return;
         }
         
+           
         if(this.allowBlank && !this.getRawValue().length){
             return;
         }
@@ -10543,7 +12276,7 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
                 cls: 'glyphicon form-control-feedback'
             };
             
-            if(this.removable && !this.editable && !this.tickable){
+            if(this.removable && !this.editable  ){
                 inputblock = {
                     cls : 'has-feedback',
                     cn :  [
@@ -10567,7 +12300,7 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
             }
 
         } else {
-            if(this.removable && !this.editable && !this.tickable){
+            if(this.removable && !this.editable ){
                 inputblock = {
                     cls : 'roo-removable',
                     cn :  [
@@ -10917,7 +12650,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'
         });
         
@@ -11038,7 +12771,392 @@ Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
      */
     onTriggerClick : Roo.emptyFn
 });
- /*
+/*
+* Licence: LGPL
+*/
+
+/**
+ * @class Roo.bootstrap.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
+ * @cfg {Array}  images  an array of ?? Img objects ??? when loading existing files..
+ * @cfg {Array}  html The button text.
+
+ *
+ * @constructor
+ * Create a new CardUploader
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.CardUploader = function(config){
+    
+    
+    Roo.bootstrap.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,  {
+    
+     
+    errorTimeout : 3000,
+     
+    images : false,
+   
+    fileCollection : false,
+    allowBlank : true,
+    
+    getAutoCreate : function()
+    {
+        
+        var cfg =  {
+            cls :'form-group' ,
+            cn : [
+               
+                {
+                    tag: 'label',
+                   //cls : 'input-group-addon',
+                    html : this.fieldLabel
+
+                },
+
+                {
+                    tag: 'input',
+                    type : 'hidden',
+                    name : this.name,
+                    value : this.value,
+                    cls : 'd-none  form-control'
+                },
+                
+                {
+                    tag: 'input',
+                    multiple : 'multiple',
+                    type : 'file',
+                    cls : 'd-none  roo-card-upload-selector'
+                },
+                
+                {
+                    cls : 'roo-card-uploader-button-container w-100 mb-2'
+                },
+                {
+                    cls : 'card-columns roo-card-uploader-container'
+                }
+
+            ]
+        };
+           
+         
+        return cfg;
+    },
+    
+    getChildContainer : function() /// what children are added to.
+    {
+        return this.containerEl;
+    },
+   
+    getButtonContainer : function() /// what children are added to.
+    {
+        return this.el.select(".roo-card-uploader-button-container").first();
+    },
+   
+    initEvents : function()
+    {
+        
+        Roo.bootstrap.Input.prototype.initEvents.call(this);
+        
+        var t = this;
+        this.addxtype({
+            xns: Roo.bootstrap,
+
+            xtype : 'Button',
+            container_method : 'getButtonContainer' ,            
+            html :  this.html, // fix changable?
+            cls : 'w-100 ',
+            listeners : {
+                'click' : function(btn, e) {
+                    t.onClick(e);
+                }
+            }
+        });
+        
+        
+        
+        
+        this.urlAPI = (window.createObjectURL && window) || 
+                                (window.URL && URL.revokeObjectURL && URL) || 
+                                (window.webkitURL && webkitURL);
+                        
+         
+         
+         
+        this.selectorEl = this.el.select('.roo-card-upload-selector', true).first();
+        
+        this.selectorEl.on('change', this.onFileSelected, this);
+        if (this.images) {
+            var t = this;
+            this.images.forEach(function(img) {
+                t.addCard(img)
+            });
+            this.images = false;
+        }
+        this.containerEl = this.el.select('.roo-card-uploader-container', true).first();
+         
+       
+    },
+    
+   
+    onClick : function(e)
+    {
+        e.preventDefault();
+         
+        this.selectorEl.dom.click();
+         
+    },
+    
+    onFileSelected : function(e)
+    {
+        e.preventDefault();
+        
+        if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
+            return;
+        }
+        
+        Roo.each(this.selectorEl.dom.files, function(file){    
+            this.addFile(file);
+        }, this);
+         
+    },
+    
+      
+    
+      
+    
+    addFile : function(file)
+    {
+           
+        if(typeof(file) === 'string'){
+            throw "Add file by name?"; // should not happen
+            return;
+        }
+        
+        if(!file || !this.urlAPI){
+            return;
+        }
+        
+        // file;
+        // file.type;
+        
+        var _this = this;
+        
+        
+        var url = _this.urlAPI.createObjectURL( file);
+           
+        this.addCard({
+            id : Roo.bootstrap.CardUploader.ID--,
+            is_uploaded : false,
+            src : url,
+            srcfile : file,
+            title : file.name,
+            mimetype : file.type,
+            preview : false,
+            is_deleted : 0
+        });
+        
+    },
+    
+    /**
+     * addCard - add an Attachment to the uploader
+     * @param data - the data about the image to upload
+     *
+     * {
+          id : 123
+          title : "Title of file",
+          is_uploaded : false,
+          src : "http://.....",
+          srcfile : { the File upload object },
+          mimetype : file.type,
+          preview : false,
+          is_deleted : 0
+          .. any other data...
+        }
+     *
+     * 
+    */
+    
+    addCard : function (data)
+    {
+        // hidden input element?
+        // if the file is not an image...
+        //then we need to use something other that and header_image
+        var t = this;
+        //   remove.....
+        var footer = [
+            {
+                xns : Roo.bootstrap,
+                xtype : 'CardFooter',
+                 items: [
+                    {
+                        xns : Roo.bootstrap,
+                        xtype : 'Element',
+                        cls : 'd-flex',
+                        items : [
+                            
+                            {
+                                xns : Roo.bootstrap,
+                                xtype : 'Button',
+                                html : String.format("<small>{0}</small>", data.title),
+                                cls : 'col-10 text-left',
+                                size: 'sm',
+                                weight: 'link',
+                                fa : 'download',
+                                listeners : {
+                                    click : function() {
+                                     
+                                        t.fireEvent( "download", t, data );
+                                    }
+                                }
+                            },
+                          
+                            {
+                                xns : Roo.bootstrap,
+                                xtype : 'Button',
+                                style: 'max-height: 28px; ',
+                                size : 'sm',
+                                weight: 'danger',
+                                cls : 'col-2',
+                                fa : 'times',
+                                listeners : {
+                                    click : function() {
+                                        t.removeCard(data.id)
+                                    }
+                                }
+                            }
+                        ]
+                    }
+                    
+                ] 
+            }
+            
+        ];
+        
+        var cn = this.addxtype(
+            {
+                 
+                xns : Roo.bootstrap,
+                xtype : 'Card',
+                closeable : true,
+                header : !data.mimetype.match(/image/) && !data.preview ? "Document": false,
+                header_image : data.mimetype.match(/image/) ? data.src  : data.preview,
+                header_image_fit_square: true, // fixme  - we probably need to use the 'Img' element to do stuff like this.
+                data : data,
+                html : false,
+                 
+                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.fireEvent( "preview", t, data ); }, this);
+                        this.imgEl.set({ 'pointer' : 'cursor' });
+                                  
+                    }
+                    this.getCardFooter().addClass('p-1');
+                    
+                  
+                }
+                
+            }
+        );
+        // dont' really need ot update items.
+        // this.items.push(cn);
+        this.fileCollection.add(cn);
+        
+        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)
+    {
+        
+        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.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) {
+            if (card.el.dom && card.el.dom.parentNode) {
+                card.el.dom.parentNode.removeChild(card.el.dom);
+            }
+        });
+        this.fileCollection.clear();
+        this.updateInput();
+    },
+    
+    updateInput : function()
+    {
+         var data = [];
+        this.fileCollection.each(function(e) {
+            data.push(e.data);
+            
+        });
+        this.inputEl().dom.value = JSON.stringify(data);
+        
+        
+        
+    }
+    
+    
+});
+
+
+Roo.bootstrap.CardUploader.ID = -1;/*
  * Based on:
  * Ext JS Library 1.1.1
  * Copyright(c) 2006-2007, Ext JS, LLC.
@@ -11824,6 +13942,16 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
         var r = this.reader.readRecords(o);
         this.loadRecords(r, {add: append}, true);
     },
+    
+     /**
+     * using 'cn' the nested child reader read the child array into it's child stores.
+     * @param {Object} rec The record with a 'children array
+     */
+    loadDataFromChildren : function(rec)
+    {
+        this.loadData(this.reader.toLoadData(rec));
+    },
+    
 
     /**
      * Gets the number of cached records.
@@ -12128,14 +14256,16 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
  * Small helper class to make creating Stores from Array data easier.
  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
  * @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
  * @constructor
  * @param {Object} config
  */
-Roo.data.SimpleStore = function(config){
+Roo.data.SimpleStore = function(config)
+{
     Roo.data.SimpleStore.superclass.constructor.call(this, {
         isLocal : true,
-        reader: new Roo.data.ArrayReader({
+        reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
                 id: config.id
             },
             Roo.data.Record.create(config.fields)
@@ -12312,6 +14442,9 @@ Roo.data.DataReader = function(meta, recordType){
 };
 
 Roo.data.DataReader.prototype = {
+    
+    
+    readerType : 'Data',
      /**
      * Create an empty record
      * @param {Object} data (optional) - overlay some values
@@ -12332,6 +14465,7 @@ Roo.data.DataReader.prototype = {
         return new this.recordType(Roo.apply(da, d));
     }
     
+    
 };/*
  * Based on:
  * Ext JS Library 1.1.1
@@ -12870,6 +15004,8 @@ Roo.data.JsonReader = function(meta, recordType){
 };
 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
     
+    readerType : 'Json',
+    
     /**
      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
      * Used by Store query builder to append _requestMeta to params.
@@ -13011,6 +15147,14 @@ Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
             records : records,
             totalRecords : totalRecords
         };
+    },
+    // used when loading children.. @see loadDataFromChildren
+    toLoadData: function(rec)
+    {
+       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+       var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+       return { data : data, total : data.length };
+       
     }
 });/*
  * Based on:
@@ -13060,44 +15204,54 @@ var myReader = new Roo.data.ArrayReader({
  * 
  * created using {@link Roo.data.Record#create}.
  */
-Roo.data.ArrayReader = function(meta, recordType){
-    
-     
+Roo.data.ArrayReader = function(meta, recordType)
+{    
     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
 };
 
 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
-    /**
+    
+      /**
      * Create a data block containing Roo.data.Records from an XML document.
      * @param {Object} o An Array of row objects which represents the dataset.
      * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
      * a cache of Roo.data.Records.
      */
-    readRecords : function(o){
+    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 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 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;
+        
     }
+    
+    
 });/*
  * - LGPL
  * * 
@@ -13117,6 +15271,7 @@ 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
@@ -13243,7 +15398,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
      */
 
      /**
-     * @cfg {String/Roo.Template} tpl The template to use to render the output
+     * @cfg {String/Roo.Template} tpl The template to use to render the output default is  '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' 
      */
      
      /**
@@ -13443,6 +15598,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
     emptyResultText: 'Empty',
     triggerText : 'Select',
     emptyTitle : '',
+    width : false,
     
     // element that contains real text value.. (when hidden is used..)
     
@@ -13593,6 +15749,8 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             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',
@@ -13664,7 +15822,9 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             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;
             }
@@ -14179,7 +16339,10 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
     },
 
     // private
-    onResize: function(w, h){
+    onResize: function(w, h)
+    {
+        
+        
 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
 //        
 //        if(typeof w != 'number'){
@@ -14220,7 +16383,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             this.inputEl().on('mousedown', this.onTriggerClick,  this);
             this.inputEl().addClass('x-combo-noedit');
         }else{
-            this.inputEl().dom.setAttribute('readOnly', false);
+            this.inputEl().dom.removeAttribute('readOnly');
             this.inputEl().un('mousedown', this.onTriggerClick,  this);
             this.inputEl().removeClass('x-combo-noedit');
         }
@@ -15298,7 +17461,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
         }
         
         var inputblock = {
-            cls : '',
+            cls : 'roo-combobox-wrap',
             cn : [
                 input
             ]
@@ -15418,16 +17581,21 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             combobox.cls += ' roo-select2-container-multi';
         }
         
+        var required =  this.allowBlank ?  {
+                    tag : 'i',
+                    style: 'display: none'
+                } : {
+                   tag : 'i',
+                   cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
+                   tooltip : 'This field is required'
+                };
+        
         var align = this.labelAlign || this.parentLabelAlign();
         
         if (align ==='left' && this.fieldLabel.length) {
 
             cfg.cn = [
-                {
-                   tag : 'i',
-                   cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
-                   tooltip : 'This field is required'
-                },
+                required,
                 {
                     tag: 'label',
                     cls : 'control-label col-form-label',
@@ -15435,7 +17603,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
 
                 },
                 {
-                    cls : '', 
+                    cls : 'roo-combobox-wrap ', 
                     cn: [
                         combobox
                     ]
@@ -15457,15 +17625,11 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                                 tag : 'span',
                                 html : this.fieldLabel
                             },
-                            {
-                                tag : 'i',
-                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
-                                tooltip : 'This field is required'
-                            }
+                            required
                         ]
                     },
                     {
-                        cls : "",
+                        cls : "roo-combobox-wrap ",
                         cn: [
                             combobox
                         ]
@@ -15482,7 +17646,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
             if(this.labelWidth > 12){
                 labelCfg.style = "width: " + this.labelWidth + 'px';
             }
-            
+           
             if(this.labelWidth < 13 && this.labelmd == 0){
                 this.labelmd = this.labelWidth;
             }
@@ -15510,11 +17674,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                 
         } else if ( this.fieldLabel.length) {
             cfg.cn = [
-                {
-                   tag : 'i',
-                   cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
-                   tooltip : 'This field is required'
-                },
+               required,
                 {
                     tag: 'label',
                     cls : 'control-label',
@@ -15536,11 +17696,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                         cls : 'control-label',
                         html : this.fieldLabel,
                         cn : [
-                            {
-                               tag : 'i',
-                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
-                               tooltip : 'This field is required'
-                            }
+                            required
                         ]
                     },
                     {
@@ -15683,9 +17839,9 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
 
         if(this.animate){
             var _this = this;
-            (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
+            (function(){ _this.touchViewEl.addClass(['in','show']); }).defer(50);
         }else{
-            this.touchViewEl.addClass('in');
+            this.touchViewEl.addClass(['in','show']);
         }
         
         if(this._touchViewMask){
@@ -15701,7 +17857,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
     
     hideTouchView : function()
     {
-        this.touchViewEl.removeClass('in');
+        this.touchViewEl.removeClass(['in','show']);
 
         if(this.animate){
             var _this = this;
@@ -17810,9 +19966,12 @@ Roo.extend(Roo.bootstrap.Calendar, 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|function} (right|top|bottom|left|auto) 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 {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
@@ -17844,43 +20003,56 @@ Roo.bootstrap.Popover = function(config){
 
 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
     
-    title: 'Fill in a title',
+    title: false,
     html: false,
     
     placement : 'right',
     trigger : 'hover', // hover
-    
+    modal : false,
     delay : 0,
     
-    over: 'parent',
+    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.el.select('.popover-content',true).first();
+        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',
+           cls : 'popover roo-dynamic shadow roo-popover' + (this.modal ? '-modal' : ''),
            style: 'display:block',
            cn : [
                 {
                     cls : 'arrow'
                 },
                 {
-                    cls : 'popover-inner',
+                    cls : 'popover-inner ',
                     cn : [
                         {
                             tag: 'h3',
                             cls: 'popover-title popover-header',
-                            html : this.title
+                            html : this.title === false ? '' : this.title
                         },
                         {
-                            cls : 'popover-content popover-body',
-                            html : this.html
+                            cls : 'popover-content popover-body '  + (this.cls || ''),
+                            html : this.html || ''
                         }
                     ]
                     
@@ -17890,20 +20062,35 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
         
         return cfg;
     },
+    /**
+     * @param {string} the title
+     */
     setTitle: function(str)
     {
         this.title = str;
-        this.el.select('.popover-title',true).first().dom.innerHTML = str;
+        if (this.el) {
+            this.headerEl.dom.innerHTML = str;
+        }
+        
     },
+    /**
+     * @param {string} the body content
+     */
     setContent: function(str)
     {
         this.html = str;
-        this.el.select('.popover-content',true).first().dom.innerHTML = 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();
@@ -17918,21 +20105,60 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
             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 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;
+        
+        this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
+        Roo.EventManager.onWindowResize(this.resizeMask, this, true);
+        
+        
+        
         this.initEvents();
     },
     
+    resizeMask : function()
+    {
+        this.maskEl.setSize(
+            Roo.lib.Dom.getViewWidth(true),
+            Roo.lib.Dom.getViewHeight(true)
+        );
+    },
+    
     initEvents : function()
     {
-        this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
+        
+        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();
-        if (this.over === false) {
+        
+        if (this.over === false && !this.parent()) {
             return; 
         }
         if (this.triggers === false) {
             return;
         }
-        var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
+         
+        // 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) {
         
@@ -17946,7 +20172,6 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
                 on_el.on(eventOut, this.leave, this);
             }
         }, this);
-        
     },
     
     
@@ -17992,88 +20217,259 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
             }
         }, this.delay.hide)
     },
-    
-    show : function (on_el)
+    /**
+     * 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) {
-            on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
-        }
-        
-        // 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 (this.parent() && (this.over == 'parent' || (this.over === false))) {
+                on_el = this.parent().el;
+            } else if (this.over) {
+                on_el = Roo.get(this.over);
+            }
+            
         }
         
-        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';
+        this.alignEl = Roo.get( on_el );
+
+        if (!this.el) {
+            this.render(document.body);
         }
         
-        //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);
+         
         
-        var p = this.getPosition();
-        var box = this.el.getBox();
+        if (this.title === false) {
+            this.headerEl.hide();
+        }
         
-        if (autoPlace) {
-            // fixme..
+       
+        this.el.show();
+        this.el.dom.style.display = 'block';
+         
+        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)] );
+            
         }
-        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.el.addClass('in');
         
-        
-        if (this.el.hasClass('fade')) {
-            // fade it?
-        }
+         
         
         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);
         
     },
+    /**
+     * 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)
+    {
+        // allow for calling with no parameters
+        placement = placement   ? placement :  this.placement;
+        try_move = typeof(try_move) == 'undefined' ? true : try_move;
+        
+        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);
+        
+        if (!this.alignEl ) {
+            return false;
+        }
+        
+        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);
+                
+            
+        }
+        
+        
+        return false;
+    },
+    
     hide : function()
     {
         this.el.setXY([0,0]);
         this.el.removeClass('in');
         this.el.hide();
         this.hoverState = null;
-        
+        this.maskEl.hide(); // always..
         this.fireEvent('hide', this);
     }
     
 });
 
-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']
+
+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);
+    } 
+
+});/*
+ * - LGPL
+ *
+ * Card header - holder for the card header elements.
+ * 
+ */
+
+/**
+ * @class Roo.bootstrap.PopoverNav
+ * @extends Roo.bootstrap.NavGroup
+ * Bootstrap Popover header navigation class
+ * @constructor
+ * Create a new Popover Header Navigation 
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.PopoverNav = function(config){
+    Roo.bootstrap.PopoverNav.superclass.constructor.call(this, config);
 };
 
+Roo.extend(Roo.bootstrap.PopoverNav, Roo.bootstrap.NavSimplebar,  {
+    
+    
+    container_method : 'getPopoverHeader' 
+    
+     
+    
+    
+   
+});
+
+
  /*
  * - LGPL
  *
@@ -18629,6 +21025,7 @@ Roo.apply(Roo.bootstrap.TabGroup, {
  * @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..
+ * @cfg {Boolean} touchSlide if swiping slides tab to next panel (default off)
  * 
  * 
  * @constructor
@@ -18668,7 +21065,7 @@ Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
     tabId: false,
     navId : false,
     href : '',
-    
+    touchSlide : false,
     getAutoCreate : function(){
         
        
@@ -18713,7 +21110,7 @@ Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
         
         this.el.on('click', this.onClick, this);
         
-        if(Roo.isTouch){
+        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);
@@ -19553,8 +21950,8 @@ Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
                 //Roo.log(className);
                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
                     var day = parseInt(html, 10) || 1;
-                    var year = this.viewDate.getUTCFullYear(),
-                        month = this.viewDate.getUTCMonth();
+                    var year =  (this.viewDate || new Date()).getUTCFullYear(),
+                        month = (this.viewDate || new Date()).getUTCMonth();
 
                     if (className.indexOf('old') > -1) {
                         if(month === 0 ){
@@ -19885,7 +22282,7 @@ Roo.apply(Roo.bootstrap.DateField,  {
   
     template : {
         tag: 'div',
-        cls: 'datepicker dropdown-menu roo-dynamic',
+        cls: 'datepicker dropdown-menu roo-dynamic shadow',
         cn: [
         {
             tag: 'div',
@@ -19993,13 +22390,20 @@ Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
      * 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.TimeField.superclass.getAutoCreate.call(this);
+        
+         
+    },
     onRender: function(ct, position)
     {
         
         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
                 
-        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
+        this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.TimeField.template);
         
         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
         
@@ -20014,10 +22418,10 @@ Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
         this.fillTime();
         this.update();
             
-        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('.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);
 
@@ -20061,7 +22465,7 @@ Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
     
     picker : function()
     {
-        return this.el.select('.datepicker', true).first();
+        return this.pickerEl;
     },
     
     fillTime: function()
@@ -20082,8 +22486,8 @@ Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
                             cls: 'btn',
                             cn: [
                                 {
-                                    tag: 'span',
-                                    cls: 'hours-up glyphicon glyphicon-chevron-up'
+                                    tag: 'i',
+                                    cls: 'hours-up fa fas fa-chevron-up'
                                 }
                             ]
                         } 
@@ -20102,8 +22506,8 @@ Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
                             cls: 'btn',
                             cn: [
                                 {
-                                    tag: 'span',
-                                    cls: 'minutes-up glyphicon glyphicon-chevron-up'
+                                    tag: 'i',
+                                    cls: 'minutes-up fa fas fa-chevron-up'
                                 }
                             ]
                         }
@@ -20176,7 +22580,7 @@ Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
                             cn: [
                                 {
                                     tag: 'span',
-                                    cls: 'hours-down glyphicon glyphicon-chevron-down'
+                                    cls: 'hours-down fa fas fa-chevron-down'
                                 }
                             ]
                         }
@@ -20196,7 +22600,7 @@ Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
                             cn: [
                                 {
                                     tag: 'span',
-                                    cls: 'minutes-down glyphicon glyphicon-chevron-down'
+                                    cls: 'minutes-down fa fas fa-chevron-down'
                                 }
                             ]
                         }
@@ -20269,21 +22673,27 @@ Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
             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'){
-                _this.picker().setTop(_this.inputEl().getHeight());
+                (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().setTop(0 - _this.picker().getHeight());
+                 _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;
@@ -20292,6 +22702,7 @@ Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
                 return;
             }
+            */
         });
         
     },
@@ -20379,48 +22790,7 @@ Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
     
    
 });
-
-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,  {
   
@@ -20436,8 +22806,43 @@ Roo.apply(Roo.bootstrap.TimeField,  {
                     tag: 'table',
                     cls: 'table-condensed',
                     cn:[
-                    Roo.bootstrap.TimeField.content,
-                    Roo.bootstrap.TimeField.footer
+                        {
+                            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'
+                                            }
+                                        ]
+                                    }
+                    
+                                    ]
+                                }
+                            ]
+                        }
                     ]
                 }
                 ]
@@ -20898,6 +23303,11 @@ Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
     inline: false,
     tooltip : '',
     
+    // checkbox success does not make any sense really.. 
+    invalidClass : "",
+    validClass : "",
+    
+    
     getAutoCreate : function()
     {
         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
@@ -20906,10 +23316,10 @@ Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
         
         var cfg = {};
         
-        cfg.cls = 'form-group ' + this.inputType; //input-group
+        cfg.cls = 'form-group form-check ' + this.inputType; //input-group
         
         if(this.inline){
-            cfg.cls += ' ' + this.inputType + '-inline';
+            cfg.cls += ' ' + this.inputType + '-inline  form-check-inline';
         }
         
         var input =  {
@@ -20998,6 +23408,22 @@ Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
             }
             
         }
+        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.tooltip){
+                boxLabelCfg.tooltip = this.tooltip;
+            }
+             
+        }
+        
         
         if (align ==='left' && this.fieldLabel.length) {
 //                Roo.log("left and has label");
@@ -21016,6 +23442,10 @@ Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
                 }
             ];
             
+            if (boxLabelCfg) {
+                cfg.cn[1].cn.push(boxLabelCfg);
+            }
+            
             if(this.labelWidth > 12){
                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
             }
@@ -21059,29 +23489,22 @@ Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
                     inputblock
                     
                 ];
+                if (boxLabelCfg) {
+                    cfg.cn.push(boxLabelCfg);
+                }
 
         } else {
             
 //                Roo.log(" no label && no align");
                 cfg.cn = [  inputblock ] ;
-                
+                if (boxLabelCfg) {
+                    cfg.cn.push(boxLabelCfg);
+                }
+
                 
         }
         
-        if(this.boxLabel){
-             var 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;
-            }
-             
-            cfg.cn.push(boxLabelCfg);
-        }
+       
         
         if(this.inputType != 'radio'){
             cfg.cn.push(hidden);
@@ -21821,7 +24244,6 @@ Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
     // private
     validateValue: function (value)
     {
-        
         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
             return false;
         }
@@ -21840,7 +24262,7 @@ Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
             return true;
         }
         
-        if ('[\x21-\x7e]*'.match(value)) {
+        if (!value.match(/[\x21-\x7e]+/)) {
             this.markInvalid(this.errors.PwdBadChar);
             this.errorMsg = this.errors.PwdBadChar;
             return false;
@@ -22145,10 +24567,11 @@ 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) { 
+                st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
+            }
+            
         }
         
         st +=  '<style type="text/css">' +
@@ -22165,7 +24588,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             //<style type="text/css">' +
             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
             //'</style>' +
-            ' </head><body class="' +  cls + '"></body></html>';
+            ' </head><body contenteditable="true" data-enable-grammerly="true" class="' +  cls + '"></body></html>';
     },
 
     // private
@@ -22320,17 +24743,32 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             html = this.cleanHtml(html);
             // fix up the special chars.. normaly like back quotes in word...
             // however we do not want to do this with chinese..
-            html = html.replace(/([\x80-\uffff])/g, function (a, b) {
-                var cc = b.charCodeAt();
-                if (
+            html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
+                
+                var cc = match.charCodeAt();
+
+                // Get the character value, handling surrogate pairs
+                if (match.length == 2) {
+                    // It's a surrogate pair, calculate the Unicode code point
+                    var high = match.charCodeAt(0) - 0xD800;
+                    var low  = match.charCodeAt(1) - 0xDC00;
+                    cc = (high * 0x400) + low + 0x10000;
+                }  else if (
                     (cc >= 0x4E00 && cc < 0xA000 ) ||
                     (cc >= 0x3400 && cc < 0x4E00 ) ||
                     (cc >= 0xf900 && cc < 0xfb00 )
                 ) {
-                        return b;
-                }
-                return "&#"+cc+";" 
+                        return match;
+                }  
+         
+                // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
+                return "&#" + cc + ";";
+                
+                
             });
+            
+            
+             
             if(this.owner.fireEvent('beforesync', this, html) !== false){
                 this.el.dom.value = html;
                 this.owner.fireEvent('sync', this, html);
@@ -22514,7 +24952,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
     insertTag : function(tg)
     {
         // could be a bit smarter... -> wrap the current selected tRoo..
-        if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
+        if (tg.toLowerCase() == 'span' ||
+            tg.toLowerCase() == 'code' ||
+            tg.toLowerCase() == 'sup' ||
+            tg.toLowerCase() == 'sub' 
+            ) {
             
             range = this.createRange(this.getSelection());
             var wrappingNode = this.doc.createElement(tg.toLowerCase());
@@ -23010,6 +25452,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         
         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..
         
@@ -23030,6 +25477,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
         }
         
         if (!node.attributes || !node.attributes.length) {
+            
+          
+            
+            
             this.cleanUpChildren(node);
             return;
         }
@@ -23046,6 +25497,9 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             if (v.match(/^#/)) {
                 return;
             }
+            if (v.match(/^\{/)) { // allow template editing.
+                return;
+            }
 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
             node.removeAttribute(n);
             
@@ -23126,11 +25580,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             
             if (a.name == 'class') {
                 if (a.value.match(/^Mso/)) {
-                    node.className = '';
+                    node.removeAttribute('class');
                 }
                 
                 if (a.value.match(/^body$/)) {
-                    node.className = '';
+                    node.removeAttribute('class');
                 }
                 continue;
             }
@@ -23188,16 +25642,20 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
             node.parentNode.removeChild(node);
             return;
         }
-        
+        //Roo.log(node.tagName);
         // remove - but keep children..
-        if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
+        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);
-            this.iterateChildren(node, this.cleanWord);
+            /// no need to iterate chidlren = it's got none..
+            //this.iterateChildren(node, this.cleanWord);
             return;
         }
         // clean styles
@@ -23675,8 +26133,8 @@ Roo.HtmlEditorCore.cblack= [
 
 
 Roo.HtmlEditorCore.swapCodes   =[ 
-    [    8211, "--" ], 
-    [    8212, "--" ], 
+    [    8211, "&#8211;" ], 
+    [    8212, "&#8212;" ], 
     [    8216,  "'" ],  
     [    8217, "'" ],  
     [    8220, '"' ],  
@@ -24405,7 +26863,102 @@ Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,
 
 
 
+/*
+ * - LGPL
+ */
 
+/**
+ * @class Roo.bootstrap.Markdown
+ * @extends Roo.bootstrap.TextArea
+ * Bootstrap Showdown editable area
+ * @cfg {string} content
+ * 
+ * @constructor
+ * Create a new Showdown
+ */
+
+Roo.bootstrap.Markdown = function(config){
+    Roo.bootstrap.Markdown.superclass.constructor.call(this, config);
+   
+};
+
+Roo.extend(Roo.bootstrap.Markdown, Roo.bootstrap.TextArea,  {
+    
+    editing :false,
+    
+    initEvents : function()
+    {
+        
+        Roo.bootstrap.TextArea.prototype.initEvents.call(this);
+        this.markdownEl = this.el.createChild({
+            cls : 'roo-markdown-area'
+        });
+        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);
+    },
+    
+    toggleTextEdit : function()
+    {
+        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;
+        }
+        // show showdown...
+        this.updateMarkdown();
+        this.markdownEl.removeClass('d-none');
+        this.editing = false;
+        return;
+    },
+    updateMarkdown : function()
+    {
+        if (this.getValue() == '') {
+            this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
+            return;
+        }
+        this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
+    },
+    
+    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)));
+    },
+    setValue : function(val)
+    {
+        Roo.bootstrap.TextArea.prototype.setValue.call(this,val);
+        if (!this.editing) {
+            this.updateMarkdown();
+        }
+        
+    },
+    focus : function()
+    {
+        if (!this.editing) {
+            this.toggleTextEdit();
+        }
+        
+    }
+
+
+});
 /**
  * @class Roo.bootstrap.Table.AbstractSelectionModel
  * @extends Roo.util.Observable
@@ -24446,6 +26999,12 @@ Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
      */
     isLocked : function(){
         return this.locked;
+    },
+    
+    
+    initEvents : function ()
+    {
+        
     }
 });
 /**
@@ -25173,7 +27732,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,
@@ -26452,7 +29011,7 @@ Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
     getAutoCreate : function(){
         var cfg = {
             tag : 'li',
-            cls: 'divider'
+            cls: 'dropdown-divider divider'
         };
         
         return cfg;
@@ -26541,10 +29100,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;
             }
@@ -26558,7 +29126,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();
@@ -26621,11 +29189,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'
@@ -26639,7 +29207,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 () {
        
@@ -26693,7 +29266,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) :
@@ -26739,15 +29313,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;
         
@@ -26755,6 +29349,10 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
             // fade it?
         }
         
+        
+        
+        
+        
     },
     hide : function()
     {
@@ -26763,7 +29361,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();
         
     }
@@ -27264,7 +29862,10 @@ Roo.apply(Roo.bootstrap.LocationPicker, {
  * @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} 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
@@ -27282,7 +29883,10 @@ Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
     title: '',
     html: '',
     weight: false,
-    faicon: false,
+    fa: false,
+    faicon: false, // BC
+    close : false,
+    
     
     getAutoCreate : function()
     {
@@ -27291,6 +29895,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'
@@ -27312,6 +29923,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;
@@ -27323,38 +29937,43 @@ 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();
+        if (this.seconds > 0) {
+            this.hide.defer(this.seconds, this);
+        }
     },
     
     setTitle : function(str)
     {
-        this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
+        this.titleEl.dom.innerHTML = str;
     },
     
     setText : function(str)
     {
-        this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
+        this.titleEl.dom.innerHTML = str;
     },
     
     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);
     },
     
     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: function() 
@@ -35201,7 +37820,7 @@ 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, {
     
@@ -37132,16 +39751,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){
@@ -37181,14 +39809,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();
@@ -37227,13 +39863,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();
@@ -37292,6 +39936,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();
         }
@@ -37340,7 +39987,10 @@ Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
  * @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.
@@ -37368,16 +40018,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;
@@ -37474,7 +40141,7 @@ Roo.bootstrap.panel.Content = function( config){
 
     
     
-    if(this.autoScroll){
+    if(this.autoScroll && !this.iframe){
         this.resizeEl.setStyle("overflow", "auto");
     } else {
         // fix randome scrolling
@@ -37507,8 +40174,14 @@ Roo.bootstrap.panel.Content = function( config){
 
 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
     
+    cls : '',
+    background : '',
+    
     tabTip : '',
     
+    iframe : false,
+    iframeEl : false,
+    
     setRegion : function(region){
         this.region = region;
         this.setActiveClass(region && !this.background);
@@ -37548,11 +40221,15 @@ 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);
     },
 
@@ -37569,10 +40246,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({
@@ -37587,6 +40268,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}
@@ -37595,6 +40277,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;
@@ -37606,9 +40293,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);
         }
@@ -37678,8 +40370,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);
+            
+            
         }
     },
     
@@ -37950,15 +40648,30 @@ Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
         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();
         }
     },