buildSDK/scss-bootstrap.php
[roojs1] / roojs-bootstrap-debug.js
index c30b5b5..58f706c 100644 (file)
@@ -3,15 +3,17 @@
  *
  */
 
-Roo.bootstrap.version = (
-        function() {
-                var ret=3;
-                Roo.each(document.styleSheets, function(s) {
-                    if ( s.href  && s.href.match(/css-bootstrap4/)) {
-                        ret=4;
-                    }
-                });
-        return ret;
+Roo.bootstrap.version = ( function() {
+    var ret=3;
+    Roo.each(document.styleSheets, function(s) {
+        if ( s.href  && s.href.match(/css-bootstrap4/)) {
+            ret=4;
+        }
+    });
+    if (ret > 3) {
+         Roo.Element.prototype.visibilityMode = Roo.Element.DISPLAY;
+    }
+    return ret;
 })(); /*
  * Based on:
  * Ext JS Library 1.1.1
@@ -961,11 +963,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;
@@ -975,12 +977,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
@@ -990,23 +993,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
@@ -1043,6 +1046,7 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
     removeClass: false,
     name: false,
     target: false,
+    group : false,
      
     pressed : null,
      
@@ -1077,9 +1081,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;
@@ -1094,15 +1098,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;
@@ -1117,7 +1121,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;
             }
@@ -1270,17 +1274,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)
@@ -1294,6 +1311,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);
         }
@@ -1301,7 +1337,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
      */
@@ -1333,8 +1378,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
@@ -1361,7 +1406,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') {
@@ -1373,8 +1419,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
@@ -1893,7 +1952,7 @@ Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
  * 
  * @cfg {String} title
  * @cfg {String} subtitle
- * @cfg {String} html -- html contents - or just use children..
+ * @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)
@@ -1907,7 +1966,7 @@ Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
  * @cfg {String} margin_y (0|1|2|3|4|5|auto)
  *
  * @cfg {String} padding (0|1|2|3|4|5)
- * @cfg {String} padding_top (0|1|2|3|4|5)
+ * @cfg {String} padding_top (0|1|2|3|4|5)next_to_card
  * @cfg {String} padding_bottom (0|1|2|3|4|5)
  * @cfg {String} padding_left (0|1|2|3|4|5)
  * @cfg {String} padding_right (0|1|2|3|4|5)
@@ -1927,6 +1986,9 @@ Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
  * 
  * @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
@@ -1940,13 +2002,23 @@ Roo.bootstrap.Card = function(config){
         /**
          * @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.Element} this
          * @param {Roo.Element} n the node being dropped?
-         * @param {Object} dd Drag and drop data
-         * @param {Roo.EventObject} e
-         * @param {Roo.EventObject} data  the data passed via getDragData
+         * @param {Boolean} rotate status
          */
-        'drop' : true
+        'rotate' : true
         
     });
 };
@@ -1989,6 +2061,8 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
 
     collapsable : false,
     collapsed : false,
+    rotateable : false,
+    rotated : false,
     
     dragable : false,
     drag_group : false,
@@ -1996,6 +2070,10 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     drop_group : false,
     childContainer : false,
     dropEl : false, /// the dom placeholde element that indicates drop location.
+    containerEl: false, // body container
+    bodyEl: false, // card-body
+    headerContainerEl : false, //
+    headerEl : false,
     
     layoutCls : function()
     {
@@ -2070,45 +2148,47 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         
         cfg.cls += this.layoutCls(); 
         
-    var hdr = false;
+        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',
-        cn : []
+                cn : []
             };
-        cfg.cn.push(hdr);
-        hdr_ctr = hdr;
+            cfg.cn.push(hdr);
+            hdr_ctr = hdr;
         } else {
-        hdr = {
+            hdr = {
                 tag : 'div',
                 cls : 'card-header d-none',
-        cn : []
+                cn : []
             };
-        cfg.cn.push(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'
-            }
-           
-        ]
-        };
-        hdr.cn.push(hdr_ctr);
-    }
-    if (this.header.length) {
+            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',
-        html : this.header
-        })
-    }
-    
+            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',
@@ -2116,26 +2196,26 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
                 src: this.header_image // escape?
             });
         } else {
-        cfg.cn.push({
-                tag : 'div',
-                cls : 'card-img-top d-none' 
-            });
-    }
-        
+            cfg.cn.push({
+                    tag : 'div',
+                    cls : 'card-img-top d-none' 
+                });
+        }
+            
         var body = {
             tag : 'div',
-            cls : 'card-body',
+            cls : 'card-body' + (this.html === false  ? ' d-none' : ''),
             cn : []
         };
-    var obody = body;
-    if (this.collapsable) {
-        obody = {
-        tag: 'div',
-        cls : 'roo-collapsable collapse ' + (this.collapsed ? '' : 'show'),
-        cn : [  body ]
-        };
-    }
-    
+        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) {
@@ -2144,7 +2224,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
                 cls : 'card-title',
                 src: this.title // escape?
             });
-        }
+        }  
         
         if (this.subtitle.length) {
             body.cn.push({
@@ -2166,13 +2246,18 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
             });
         }
         // fixme ? handle objects?
+        
         if (this.footer.length) {
+           
             cfg.cn.push({
-                tag : 'div',
-                cls : 'card-footer',
-                html: this.footer // escape?
+                cls : 'card-footer ' + (this.rotated ? 'd-none' : ''),
+                html : this.footer
             });
+            
+        } else {
+            cfg.cn.push({cls : 'card-footer d-none'});
         }
+        
         // footer...
         
         return cfg;
@@ -2182,20 +2267,28 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     getCardHeader : function()
     {
         var  ret = this.el.select('.card-header',true).first();
-    if (ret.hasClass('d-none')) {
-        ret.removeClass('d-none');
-    }
+        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.el.select('.card-img-top',true).first();
-    if (ret.hasClass('d-none')) {
-        ret.removeClass('d-none');
-    }
-        
+        if (ret.hasClass('d-none')) {
+            ret.removeClass('d-none');
+        }
+            
         return ret;
     },
     
@@ -2210,9 +2303,9 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     
     initEvents: function() 
     {
-        
-    this.bodyEl = this.getChildContainer();
-    if(this.dragable){
+        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'
@@ -2220,20 +2313,35 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
             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);
-    }
+            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);
-    }
+            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').first();
+         
+        this.footerEl = this.el.select('.card-footer').first();
+        this.collapsableToggleEl = this.el.select('.roo-collapse-toggle');
+        this.headerContainerEl = this.el.select('.roo-card-header-ctr').first();
+        this.headerEl = this.el.select('.card-header',true).first();
+        
+        if (this.rotated) {
+            this.el.addClass('roo-card-rotated');
+            this.fireEvent('rotate', this, true);
+        }
+        
     },
     getDragData : function(e)
     {
@@ -2258,21 +2366,33 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         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.
- */
   *    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.
   */
     getTargetFromEvent : function(e, dragged_card_el)
     {
         var target = e.getTarget();
-        while ((target !== null) && (target.parentNode != this.bodyEl.dom)) {
+        while ((target !== null) && (target.parentNode != this.containerEl.dom)) {
             target = target.parentNode;
         }
+        
+        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'...
-        var ctarget = -1;
-        var cards = [];
+        
+        
         //Roo.log(this.items.length);
-        var lpos = pos = cpos = false;
+        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')) {
@@ -2280,48 +2400,52 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
             }
             pos = this.getDropPoint(e, this.items[i].el.dom);
             
+            cards_len = ret.cards.length;
             //Roo.log(this.items[i].el.dom.id);
-            var ii = cards.length;
-            cards.push(this.items[i]);
-            
-            if (ctarget < 0 && pos == 'above') {
-                ctarget = ii > 0 ? ii - 1 : 0;
-                cpos = ii > 0 ? 'below' : pos;
-            }
+            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;
         }
-        if (!cards.length) {
-            return [ true, 'below' ];
+        // 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 (ctarget < 0) {
-            ctarget = cards.length -1;
-            cpos = 'below';
-        }
-        if (cards[ctarget].el == dragged_card_el) {
+        if (this.items[ret.items_n].el == dragged_card_el) {
             return false;
         }
         
-        if (cpos == 'below') {
-            var card_after = ctarget+1 == cards.length ? false : cards[ctarget+1];
-            
-            // then above should not be dragged_card_el.
-            // and ctarget sho
+        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 [ cards[ctarget], cpos ];
+            return ret;
         }
         
         // its's after ..
-        var card_before = ctarget > 0 ? cards[ctarget-1] : false;
+        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 [ cards[ctarget], cpos, cards, ctarget ];
+        return ret;
     },
     
     onNodeEnter : function(n, dd, e, data){
@@ -2335,7 +2459,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
             this.dropPlaceHolder('hide');
             return false;
         }
-        Roo.log(['getTargetFromEvent', target_info[0].el.dom.id,target_info[1]]);
+        Roo.log(['getTargetFromEvent', target_info ]);
         
          
         this.dropPlaceHolder('show', target_info,data);
@@ -2349,48 +2473,116 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     onNodeDrop : function(n, dd, e, data)
     {
         
-        // call drop - return false if  
-        if (this.fireEvent("drop", this, n, dd, e, data) === false) {
+        // 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;
         }
-        
-        var target_info = this.getTargetFromEvent(e,data.source.el);
-        if (target_info === 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 pt = this.getDropPoint(e, n, dd);
-        var insertAt = (n == this.bodyEl.dom) ? this.items.length : n.nodeIndex;
-        if (pt == "below") {
-            insertAt++;
-        }
-        for (var i = 0; i < this.items.length; i++) {
-            var r = this.items[i];
-            //var dup = this.store.getById(r.id);
-            if (dup && (dd != this.dragZone)) {
-                Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
-            } else {
-            if (data.copy) {
-                this.store.insert(insertAt++, r.copy());
+        var to_items_n = next_to_card ? this.items.indexOf(next_to_card) : 0;
+        
+        
+        var dom = move_card.el.dom;
+        dom.parentNode.removeChild(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 {
-                data.source.isDirtyFlag = true;
-                r.store.remove(r);
-                this.store.insert(insertAt++, r);
+                cardel.parentNode.append(dom);
             }
-            this.isDirtyFlag = true;
+        } else {
+            // card container???
+            this.containerEl.dom.append(dom);
+        }
+        
+        //FIXME HANDLE card = true 
+        
+        // add this to the correct place in items.
+        
+        
+        
+        // remove Card from items.
+        
+        var old_parent = move_card.parent();
+        
+        old_parent.items = old_parent.items.filter(function(e) { return e != move_card });
+        
+        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);
         }
-        this.dragZone.cachedTarget = null;
+        
+        move_card.parentId = this.id;
+        
         return true;
+        
+        
     },
     
+    
     /**    Decide whether to drop above or below a View node. */
     getDropPoint : function(e, n, dd)
     {
         if (dd) {
              return false;
         }
-        if (n == this.bodyEl.dom) {
+        if (n == this.containerEl.dom) {
             return "above";
         }
         var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
@@ -2406,20 +2598,43 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         {
         if (this.collapsed) {
             this.el.select('.roo-collapse-toggle').removeClass('collapsed');
-            this.el.select('.roo-collapsable').addClass('show');
+            this.collapsableEl.addClass('show');
             this.collapsed = false;
             return;
         }
         this.el.select('.roo-collapse-toggle').addClass('collapsed');
-        this.el.select('.roo-collapsable').removeClass('show');
+        this.collapsableEl.removeClass('show');
         this.collapsed = true;
         
     
     },
-    dropPlaceHolder: function (action, where_ar, data)
+    
+    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.bodyEl, {
+            this.dropEl = Roo.DomHelper.append(this.containerEl, {
             cls : 'd-none'
             },true);
         }
@@ -2429,16 +2644,24 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
             this.dropEl.addClass('d-none');
             return;
         }
-        var cardel = where_ar[0].el.dom;
-        
+        // FIXME - info.card == true!!!
         this.dropEl.dom.parentNode.removeChild(this.dropEl.dom);
-        if (where_ar[1] == 'above') {
-            cardel.parentNode.insertBefore(this.dropEl.dom, cardel);
-        } else if (cardel.nextSibling) {
-            cardel.parentNode.insertBefore(this.dropEl.dom,cardel.nextSibling);
+        
+        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 {
-            cardel.parentNode.append(this.dropEl.dom);
+            // 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() );
@@ -2447,6 +2670,10 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     
     
     
+    },
+    setHeaderText: function(html)
+    {
+        this.headerContainerEl.dom.innerHTML = html;
     }
 
     
@@ -2481,6 +2708,39 @@ Roo.extend(Roo.bootstrap.CardHeader, Roo.bootstrap.Element,  {
     
     
    
+});
+
+
+ /*
+ * - 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' 
+    
+     
+    
+    
+   
 });
 
  
@@ -3683,8 +3943,10 @@ Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
  * @cfg {Boolean} fitwindow 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
@@ -3708,7 +3970,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 || [];
 
@@ -3754,6 +4024,7 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
     max_height: 0,
     
     fit_content: false,
+    editableTitle  : false,
 
     onRender : function(ct, position)
     {
@@ -3845,9 +4116,8 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
             html : this.title
         };
 
-        if(this.specificTitle){
+        if(this.specificTitle){ // WTF is this?
             title = this.title;
-
         }
 
         var header = [];
@@ -3861,6 +4131,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',
@@ -3943,7 +4221,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);
+        }
 
     },
   
@@ -4150,6 +4439,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
@@ -4177,7 +4467,7 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
             !child_nodes ||
             child_nodes.length == 0
         ) {
-            return;
+            return 0;
         }
         
         var child_height = 0;
@@ -4230,6 +4520,33 @@ Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
         }
         
         return child_height;
+    },
+    toggleHeaderInput : function(is_edit)
+    {
+        
+        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);
+    
+            
+        
     }
 
 });
@@ -4298,6 +4615,7 @@ Roo.apply(Roo.bootstrap.Modal,  {
         
         zIndex : 10001
 });
+
 /*
  * - LGPL
  *
@@ -8012,6 +8330,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();
@@ -9936,7 +10257,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.
@@ -9959,6 +10280,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
@@ -10209,6 +10531,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;
@@ -10287,7 +10612,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? 
                 });
             }
@@ -10306,7 +10631,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? 
                 });
             }
@@ -10321,11 +10646,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) {
             
@@ -10410,11 +10732,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',
@@ -10428,7 +10753,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
            ];
            
            if(this.indicatorpos == 'right'){
-                
+       
                 cfg.cn = [
                     {
                         tag: 'label',
@@ -10439,7 +10764,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
@@ -10850,6 +11176,7 @@ Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
             return;
         }
         
+           
         if(this.allowBlank && !this.getRawValue().length){
             return;
         }
@@ -11495,7 +11822,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 :  [
@@ -11519,7 +11846,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 :  [
@@ -11990,7 +12317,329 @@ 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
+        });
+    
+    
+};
+
+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',
+                    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,
+            title : file.name,
+            mimetype : file.type,
+            preview : false,
+            is_deleted : 0
+        })
+        
+    },
+    
+    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-11 text-left',
+                                size: 'sm',
+                                weight: 'link',
+                                fa : 'download',
+                                listeners : {
+                                    click : function() {
+                                        this.downloadCard(data.id)
+                                    }
+                                }
+                            },
+                          
+                            {
+                                xns : Roo.bootstrap,
+                                xtype : 'Button',
+                                
+                                size : 'sm',
+                                weight: 'danger',
+                                cls : 'col-1',
+                                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);
+                    this.imgEl = this.el.select('.card-img-top').first();
+                    if (this.imgEl) {
+                        this.imgEl.on('click', function() { t.previewCard( data.id); }, this);
+                        this.imgEl.set({ 'pointer' : 'cursor' });
+                                  
+                    }
+                    
+                  
+                }
+                
+            }
+        );
+        // dont' really need ot update items.
+        // this.items.push(cn);
+        this.fileCollection.add(cn);
+        this.updateInput();
+        
+    },
+    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);
+        
+    },
+    reset: function()
+    {
+        this.fileCollection.each(function(card) {
+            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.
@@ -14105,6 +14754,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
@@ -14231,7 +14881,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>' 
      */
      
      /**
@@ -14431,6 +15081,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..)
     
@@ -14581,6 +15232,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',
@@ -14652,7 +15305,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;
             }
@@ -15167,7 +15822,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'){
@@ -16286,7 +16944,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
         }
         
         var inputblock = {
-            cls : '',
+            cls : 'roo-combobox-wrap',
             cn : [
                 input
             ]
@@ -16423,7 +17081,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
 
                 },
                 {
-                    cls : '', 
+                    cls : 'roo-combobox-wrap ', 
                     cn: [
                         combobox
                     ]
@@ -16453,7 +17111,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                         ]
                     },
                     {
-                        cls : "",
+                        cls : "roo-combobox-wrap ",
                         cn: [
                             combobox
                         ]
@@ -16470,7 +17128,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;
             }
@@ -16671,9 +17329,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){
@@ -16689,7 +17347,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;
@@ -19617,6 +20275,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
@@ -19656,7 +20315,7 @@ Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
     tabId: false,
     navId : false,
     href : '',
-    
+    touchSlide : false,
     getAutoCreate : function(){
         
        
@@ -19701,7 +20360,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);
@@ -22827,7 +23486,6 @@ Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
     // private
     validateValue: function (value)
     {
-        
         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
             return false;
         }
@@ -22846,7 +23504,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;
@@ -23151,10 +23809,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">' +
@@ -24080,6 +24739,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);
             
@@ -25443,7 +26105,96 @@ 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');
+        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
@@ -27665,11 +28416,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'
@@ -27683,7 +28434,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 () {
        
@@ -27737,7 +28493,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) :
@@ -27783,6 +28540,9 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
             }
             
             align = this.alignment[placement];
+            
+            this.arrowEl.setLeft((this.innerEl.getWidth()/2) - 5);
+            
         }
         
         this.el.alignTo(this.bindEl, align[0],align[1]);
@@ -27790,8 +28550,9 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
         //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;
         
@@ -27799,6 +28560,10 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
             // fade it?
         }
         
+        
+        
+        
+        
     },
     hide : function()
     {
@@ -27807,7 +28572,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();
         
     }
@@ -38994,15 +39759,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 -= thd.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();
         }
     },