fix popover issue
[roojs1] / roojs-bootstrap-debug.js
index fd393c2..9e4fb24 100644 (file)
@@ -362,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
@@ -650,6 +655,8 @@ Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
  * @cfg {String} cls class of the element
  * @cfg {Boolean} preventDefault (true|false) default false
  * @cfg {Boolean} clickable (true|false) default false
+ * @cfg {String} role default blank - set to button to force cursor pointer
  * 
  * @constructor
  * Create a new Element
@@ -667,7 +674,9 @@ Roo.bootstrap.Element = function(config){
          * @param {Roo.bootstrap.Element} this
          * @param {Roo.EventObject} e
          */
-        "click" : true
+        "click" : true 
+        
+      
     });
 };
 
@@ -678,6 +687,8 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
     html: '',
     preventDefault: false, 
     clickable: false,
+    tapedTwice : false,
+    role : false,
     
     getAutoCreate : function(){
         
@@ -686,6 +697,9 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
             // cls: this.cls, double assign in parent class Component.js :: onRender
             html: this.html
         };
+        if (this.role !== false) {
+            cfg.role = this.role;
+        }
         
         return cfg;
     },
@@ -698,6 +712,7 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
             this.el.on('click', this.onClick, this);
         }
         
+        
     },
     
     onClick : function(e)
@@ -706,9 +721,14 @@ Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
             e.preventDefault();
         }
         
-        this.fireEvent('click', this, e);
+        this.fireEvent('click', this, e); // why was this double click before?
     },
     
+    
+    
+
+    
+    
     getValue : function()
     {
         return this.el.dom.innerHTML;
@@ -1354,6 +1374,7 @@ Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
     {
         this.disabled = false;
         this.el.removeClass('disabled');
+        this.el.dom.removeAttribute("disabled");
     },
     
     /**
@@ -1363,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, 
@@ -2015,12 +2037,19 @@ Roo.bootstrap.Card = function(config){
          /**
          * @event rotate
          * When a element a card is rotate
-         * @param {Roo.bootstrap.Element} this
+         * @param {Roo.bootstrap.Card} this
          * @param {Roo.Element} n the node being dropped?
          * @param {Boolean} rotate status
          */
-        'rotate' : true
-        
+        'rotate' : true,
+        /**
+         * @event cardover
+         * When a card element is dragged over ready to drop (return false to block dropable)
+         * @param {Roo.bootstrap.Card} this
+         * @param {Object} data from dragdrop 
+         */
+         'cardover' : true
+         
     });
 };
 
@@ -2075,6 +2104,8 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     bodyEl: false, // card-body
     headerContainerEl : false, //
     headerEl : false,
+    header_imageEl : false,
+    
     
     layoutCls : function()
     {
@@ -2285,7 +2316,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     },
     getCardImageTop : function()
     {
-        var  ret = this.el.select('.card-img-top',true).first();
+        var  ret = this.header_imageEl;
         if (ret.hasClass('d-none')) {
             ret.removeClass('d-none');
         }
@@ -2331,17 +2362,19 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         if (this.rotateable) {
             this.el.select('.card-header',true).on('click', this.onToggleRotate, this);
         }
-        this.collapsableEl = this.el.select('.roo-collapsable').first();
+        this.collapsableEl = this.el.select('.roo-collapsable',true).first();
          
-        this.footerEl = this.el.select('.card-footer').first();
-        this.collapsableToggleEl = this.el.select('.roo-collapse-toggle');
-        this.headerContainerEl = this.el.select('.roo-card-header-ctr').first();
+        this.footerEl = this.el.select('.card-footer',true).first();
+        this.collapsableToggleEl = this.el.select('.roo-collapse-toggle',true).first();
+        this.headerContainerEl = this.el.select('.roo-card-header-ctr',true).first();
         this.headerEl = this.el.select('.card-header',true).first();
         
         if (this.rotated) {
             this.el.addClass('roo-card-rotated');
             this.fireEvent('rotate', this, true);
         }
+        this.header_imageEl = this.el.select('.card-img-top',true).first(); 
+        this.header_imageEl.on('load', this.onHeaderImageLoad, this );
         
     },
     getDragData : function(e)
@@ -2369,6 +2402,17 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     /**
     *    Part of the Roo.dd.DropZone interface. If no target node is found, the
     *    whole Element becomes the target, and this causes the drop gesture to append.
+    *
+    *    Returns an object:
+    *     {
+           
+           position : 'below' or 'above'
+           card  : relateive to card OBJECT (or true for no cards listed)
+           items_n : relative to nth item in list
+           card_n : relative to  nth card in list
+    }
+    *
+    *    
     */
     getTargetFromEvent : function(e, dragged_card_el)
     {
@@ -2462,7 +2506,11 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         }
         Roo.log(['getTargetFromEvent', target_info ]);
         
-         
+        
+        if (this.fireEvent('cardover', this, [ data ]) === false) {
+            return false;
+        }
+        
         this.dropPlaceHolder('show', target_info,data);
         
         return false; 
@@ -2487,9 +2535,7 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
         }
         this.dropPlaceHolder('hide');
   
-         
-    
-    
+          
     
         this.acceptCard(data.source, info.position, info.card, info.items_n);
         return true;
@@ -2679,7 +2725,31 @@ Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component,  {
     },
     setHeaderText: function(html)
     {
-        this.headerContainerEl.dom.innerHTML = html;
+        this.header = html;
+        if (this.headerContainerEl) {
+            this.headerContainerEl.dom.innerHTML = html;
+        }
+    },
+    onHeaderImageLoad : function(ev, he)
+    {
+        if (!this.header_image_fit_square) {
+            return;
+        }
+        
+        var hw = he.naturalHeight / he.naturalWidth;
+        // wide image = < 0
+        // tall image = > 1
+        //var w = he.dom.naturalWidth;
+        var ww = he.width;
+        he.style.left =  0;
+        he.style.position =  'relative';
+        if (hw > 1) {
+            var nw = (ww * (1/hw));
+            Roo.get(he).setSize( ww * (1/hw),  ww);
+            he.style.left =  ((ww - nw)/ 2) + 'px';
+            he.style.position =  'relative';
+        }
+
     }
 
     
@@ -2783,6 +2853,174 @@ Roo.extend(Roo.bootstrap.CardImageTop, Roo.bootstrap.Element,  {
 
  
 
+/*
+* Licence: LGPL
+*/
+
+/**
+ * @class Roo.bootstrap.ButtonUploader
+ * @extends Roo.bootstrap.Button
+ * Bootstrap Button Uploader class - it's a button which when you add files to it
+ *
+ * 
+ * @cfg {Number} errorTimeout default 3000
+ * @cfg {Array}  images  an array of ?? Img objects ??? when loading existing files..
+ * @cfg {Array}  html The button text.
+ * @cfg {Boolean}  multiple (default true) Should the upload allow multiple files to be uploaded.
+ *
+ * @constructor
+ * Create a new CardUploader
+ * @param {Object} config The config object
+ */
+
+Roo.bootstrap.ButtonUploader = function(config){
+    
+    
+    Roo.bootstrap.ButtonUploader.superclass.constructor.call(this, config);
+    
+     
+     this.addEvents({
+         // raw events
+        /**
+         * @event beforeselect
+         * When button is pressed, before show upload files dialog is shown
+         * @param {Roo.bootstrap.UploaderButton} this
+         *
+         */
+        'beforeselect' : true,
+         /**
+         * @event fired when files have been selected, 
+         * When a the download link is clicked
+         * @param {Roo.bootstrap.UploaderButton} this
+         * @param {Array} Array of files that have been uploaded
+         */
+        'uploaded' : true
+        
+    });
+};
+Roo.extend(Roo.bootstrap.ButtonUploader, Roo.bootstrap.Button,  {
+    
+     
+    errorTimeout : 3000,
+     
+    images : false,
+   
+    fileCollection : false,
+    allowBlank : true,
+    
+    multiple : true,
+    
+    getAutoCreate : function()
+    {
+        var im = {
+            tag: 'input',
+            type : 'file',
+            cls : 'd-none  roo-card-upload-selector' 
+          
+        };
+        if (this.multiple) {
+            im.multiple = 'multiple';
+        }
+        
+        return  {
+            cls :'div' ,
+            cn : [
+                Roo.bootstrap.Button.prototype.getAutoCreate.call(this),
+                im
+
+            ]
+        };
+           
+         
+    },
+     
+   
+    initEvents : function()
+    {
+        
+        Roo.bootstrap.Button.prototype.initEvents.call(this);
+        
+        
+        
+        
+        
+        this.urlAPI = (window.createObjectURL && window) || 
+                                (window.URL && URL.revokeObjectURL && URL) || 
+                                (window.webkitURL && webkitURL);
+                        
+         
+         
+         
+        this.selectorEl = this.el.select('.roo-card-upload-selector', true).first();
+        
+        this.selectorEl.on('change', this.onFileSelected, this);
+         
+         
+       
+    },
+    
+   
+    onClick : function(e)
+    {
+        e.preventDefault();
+        
+        if ( this.fireEvent('beforeselect', this) === false) {
+            return;
+        }
+         
+        this.selectorEl.dom.click();
+         
+    },
+    
+    onFileSelected : function(e)
+    {
+        e.preventDefault();
+        
+        if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
+            return;
+        }
+        var files = Array.prototype.slice.call(this.selectorEl.dom.files);
+        this.selectorEl.dom.value  = '';// hopefully reset..
+        
+        this.fireEvent('uploaded', this,  files );
+        
+    },
+    
+       
+   
+    
+    /**
+     * addCard - add an Attachment to the uploader
+     * @param data - the data about the image to upload
+     *
+     * {
+          id : 123
+          title : "Title of file",
+          is_uploaded : false,
+          src : "http://.....",
+          srcfile : { the File upload object },
+          mimetype : file.type,
+          preview : false,
+          is_deleted : 0
+          .. any other data...
+        }
+     *
+     * 
+    */
+     
+    reset: function()
+    {
+         
+         this.selectorEl
+    } 
+    
+    
+    
+    
+});
  /*
  * - LGPL
  *
@@ -3341,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
@@ -3349,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);
@@ -3418,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,
     /**
@@ -3436,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;  
     },
@@ -3445,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'
             
         };
@@ -3467,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);
         }
@@ -3596,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
@@ -3617,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?
         
@@ -3660,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()){
            
@@ -3670,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);
         }
@@ -3716,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'){
@@ -6125,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..
            
@@ -6142,7 +6427,8 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
                 {
                     tag: this.tagtype,
                     href : this.href || "#",
-                    html: this.html || ''
+                    html: this.html || '',
+                   cls : ''
                 }
             ];
             if (this.tagtype == 'a') {
@@ -6150,23 +6436,21 @@ Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
         
            }
             if (this.icon) {
-                cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
-            }
-           if (this.fa) {
-                cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
-            }
-            if(this.glyphicon) {
+                cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span class="nav-html">' + cfg.cn[0].html + '</span>';
+            } else  if (this.fa) {
+                cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span class="nav-html">' + cfg.cn[0].html + '</span>';
+            } else if(this.glyphicon) {
                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
-            }
+            } else {
+               cfg.cn[0].cls += " nav-html";
+           }
             
             if (this.menu) {
-                
                 cfg.cn[0].html += " <span class='caret'></span>";
              
             }
             
             if (this.badge !== '') {
-                 
                 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
             }
         }
@@ -6184,6 +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;
     },
       
@@ -6381,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;
+       
+    } 
 });
  
 
@@ -10493,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
     });
 };
 
@@ -10857,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){
@@ -10996,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();
         
@@ -12496,11 +12799,29 @@ Roo.bootstrap.CardUploader = function(config){
     
     this.fileCollection   = new Roo.util.MixedCollection(false,function(r) {
         return r.data.id
-        });
-    
+     });
     
+     this.addEvents({
+         // raw events
+        /**
+         * @event preview
+         * When a image is clicked on - and needs to display a slideshow or similar..
+         * @param {Roo.bootstrap.Card} this
+         * @param {Object} The image information data 
+         *
+         */
+        'preview' : true,
+         /**
+         * @event download
+         * When a the download link is clicked
+         * @param {Roo.bootstrap.Card} this
+         * @param {Object} The image information data  contains 
+         */
+        'download' : true
+        
+    });
 };
-
 Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
     
      
@@ -12528,6 +12849,7 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
                 {
                     tag: 'input',
                     type : 'hidden',
+                    name : this.name,
                     value : this.value,
                     cls : 'd-none  form-control'
                 },
@@ -12659,14 +12981,34 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
             id : Roo.bootstrap.CardUploader.ID--,
             is_uploaded : false,
             src : url,
+            srcfile : file,
             title : file.name,
             mimetype : file.type,
             preview : false,
             is_deleted : 0
-        })
+        });
         
     },
     
+    /**
+     * addCard - add an Attachment to the uploader
+     * @param data - the data about the image to upload
+     *
+     * {
+          id : 123
+          title : "Title of file",
+          is_uploaded : false,
+          src : "http://.....",
+          srcfile : { the File upload object },
+          mimetype : file.type,
+          preview : false,
+          is_deleted : 0
+          .. any other data...
+        }
+     *
+     * 
+    */
+    
     addCard : function (data)
     {
         // hidden input element?
@@ -12678,7 +13020,7 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
             {
                 xns : Roo.bootstrap,
                 xtype : 'CardFooter',
-                items: [
+                 items: [
                     {
                         xns : Roo.bootstrap,
                         xtype : 'Element',
@@ -12689,13 +13031,14 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
                                 xns : Roo.bootstrap,
                                 xtype : 'Button',
                                 html : String.format("<small>{0}</small>", data.title),
-                                cls : 'col-11 text-left',
+                                cls : 'col-10 text-left',
                                 size: 'sm',
                                 weight: 'link',
                                 fa : 'download',
                                 listeners : {
                                     click : function() {
-                                        this.downloadCard(data.id)
+                                     
+                                        t.fireEvent( "download", t, data );
                                     }
                                 }
                             },
@@ -12703,10 +13046,10 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
                             {
                                 xns : Roo.bootstrap,
                                 xtype : 'Button',
-                                
+                                style: 'max-height: 28px; ',
                                 size : 'sm',
                                 weight: 'danger',
-                                cls : 'col-1',
+                                cls : 'col-2',
                                 fa : 'times',
                                 listeners : {
                                     click : function() {
@@ -12721,7 +13064,7 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
             }
             
         ];
-
+        
         var cn = this.addxtype(
             {
                  
@@ -12737,12 +13080,14 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
                 items : footer,
                 initEvents : function() {
                     Roo.bootstrap.Card.prototype.initEvents.call(this);
+                    var card = this;
                     this.imgEl = this.el.select('.card-img-top').first();
                     if (this.imgEl) {
-                        this.imgEl.on('click', function() { t.previewCard( data.id); }, this);
+                        this.imgEl.on('click', function() { t.fireEvent( "preview", t, data ); }, this);
                         this.imgEl.set({ 'pointer' : 'cursor' });
                                   
                     }
+                    this.getCardFooter().addClass('p-1');
                     
                   
                 }
@@ -12752,7 +13097,21 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
         // dont' really need ot update items.
         // this.items.push(cn);
         this.fileCollection.add(cn);
-        this.updateInput();
+        
+        if (!data.srcfile) {
+            this.updateInput();
+            return;
+        }
+            
+        var _t = this;
+        var reader = new FileReader();
+        reader.addEventListener("load", function() {  
+            data.srcdata =  reader.result;
+            _t.updateInput();
+        });
+        reader.readAsDataURL(data.srcfile);
+        
+        
         
     },
     removeCard : function(id)
@@ -12761,16 +13120,20 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
         var card  = this.fileCollection.get(id);
         card.data.is_deleted = 1;
         card.data.src = ''; /// delete the source - so it reduces size of not uploaded images etc.
-        this.fileCollection.remove(card);
+        //this.fileCollection.remove(card);
         //this.items = this.items.filter(function(e) { return e != card });
         // dont' really need ot update items.
         card.el.dom.parentNode.removeChild(card.el.dom);
+        this.updateInput();
+
         
     },
     reset: function()
     {
         this.fileCollection.each(function(card) {
-            card.el.dom.parentNode.removeChild(card.el.dom);    
+            if (card.el.dom && card.el.dom.parentNode) {
+                card.el.dom.parentNode.removeChild(card.el.dom);
+            }
         });
         this.fileCollection.clear();
         this.updateInput();
@@ -12778,12 +13141,15 @@ Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input,  {
     
     updateInput : function()
     {
-        var data = [];
+         var data = [];
         this.fileCollection.each(function(e) {
             data.push(e.data);
+            
         });
-        
         this.inputEl().dom.value = JSON.stringify(data);
+        
+        
+        
     }
     
     
@@ -14854,35 +15220,35 @@ Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
     readRecords : function(o)
     {
         var sid = this.meta ? this.meta.id : null;
-       var recordType = this.recordType, fields = recordType.prototype.fields;
-       var records = [];
-       var root = o;
-       for(var i = 0; i < root.length; i++){
-               var n = root[i];
-           var values = {};
-           var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
-           for(var j = 0, jlen = fields.length; j < jlen; j++){
-               var f = fields.items[j];
-               var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
-               var v = n[k] !== undefined ? n[k] : f.defaultValue;
-               v = f.convert(v);
-               values[f.name] = v;
-           }
-           var record = new recordType(values, id);
-           record.json = n;
-           records[records.length] = record;
-       }
-       return {
-           records : records,
-           totalRecords : records.length
-       };
+        var recordType = this.recordType, fields = recordType.prototype.fields;
+        var records = [];
+        var root = o;
+        for(var i = 0; i < root.length; i++){
+            var n = root[i];
+            var values = {};
+            var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
+            for(var j = 0, jlen = fields.length; j < jlen; j++){
+                var f = fields.items[j];
+                var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
+                var v = n[k] !== undefined ? n[k] : f.defaultValue;
+                v = f.convert(v);
+                values[f.name] = v;
+            }
+            var record = new recordType(values, id);
+            record.json = n;
+            records[records.length] = record;
+        }
+        return {
+            records : records,
+            totalRecords : records.length
+        };
     },
     // used when loading children.. @see loadDataFromChildren
     toLoadData: function(rec)
     {
-       // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
-       return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
-       
+        // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
+        return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
+        
     }
     
     
@@ -16017,7 +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');
         }
@@ -17215,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',
@@ -17254,11 +17625,7 @@ Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
                                 tag : 'span',
                                 html : this.fieldLabel
                             },
-                            {
-                                tag : 'i',
-                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
-                                tooltip : 'This field is required'
-                            }
+                            required
                         ]
                     },
                     {
@@ -17307,11 +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',
@@ -17333,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
                         ]
                     },
                     {
@@ -19872,7 +20231,7 @@ Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
             if (this.parent() && (this.over == 'parent' || (this.over === false))) {
                 on_el = this.parent().el;
             } else if (this.over) {
-                Roo.get(this.over);
+                on_el = Roo.get(this.over);
             }
             
         }
@@ -20040,15 +20399,18 @@ Roo.apply(Roo.bootstrap.Popover, {
 
     clickHander : false,
     
+    
 
     onMouseDown : function(e)
     {
-        if (!e.getTarget(".roo-popover")) {
+        if (this.popups.length &&  !e.getTarget(".roo-popover")) {
+            /// what is nothing is showing..
             this.hideAll();
         }
          
     },
     
+    
     popups : [],
     
     register : function(popup)
@@ -20057,15 +20419,23 @@ Roo.apply(Roo.bootstrap.Popover, {
             Roo.bootstrap.Popover.clickHandler = Roo.get(document).on("mousedown", Roo.bootstrap.Popover.onMouseDown, Roo.bootstrap.Popover);
         }
         // hide other popups.
-        this.hideAll();
-        this.popups.push(popup);
+        popup.on('show', Roo.bootstrap.Popover.onShow,  popup);
+        popup.on('hide', Roo.bootstrap.Popover.onHide,  popup);
+        this.hideAll(); //<< why?
+        //this.popups.push(popup);
     },
     hideAll : function()
     {
         this.popups.forEach(function(p) {
             p.hide();
         });
-    }
+    },
+    onShow : function() {
+        Roo.bootstrap.Popover.popups.push(this);
+    },
+    onHide : function() {
+        Roo.bootstrap.Popover.popups.remove(this);
+    } 
 
 });/*
  * - LGPL
@@ -21580,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 ){
@@ -25763,8 +26133,8 @@ Roo.HtmlEditorCore.cblack= [
 
 
 Roo.HtmlEditorCore.swapCodes   =[ 
-    [    8211, "--" ], 
-    [    8212, "--" ], 
+    [    8211, "&#8211;" ], 
+    [    8212, "&#8212;" ], 
     [    8216,  "'" ],  
     [    8217, "'" ],  
     [    8220, '"' ],  
@@ -28641,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;
@@ -28730,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;
             }
@@ -28747,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();
@@ -28939,6 +29318,22 @@ Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
             
         }
         
+        var elems = document.getElementsByTagName('div');
+        var highest = Number.MIN_SAFE_INTEGER || -(Math.pow(2, 53) - 1);
+        for (var i = 0; i < elems.length; i++) {
+          var zindex = Number.parseInt(
+                document.defaultView.getComputedStyle(elems[i], null).getPropertyValue("z-index"),
+                10
+          );
+          if (zindex > highest) {
+            highest = zindex;
+          }
+        }
+        
+        
+        
+        this.el.dom.style.zIndex = highest;
+        
         this.el.alignTo(this.bindEl, align[0],align[1]);
         //var arrow = this.el.select('.arrow',true).first();
         //arrow.set(align[2], 
@@ -29467,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
@@ -29485,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()
     {
@@ -29494,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'
@@ -29515,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;
@@ -29526,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()